얼마 전까지 SpringSource.org 에서 제공하는 STS 를 이용해서 개발해왔다.


그러다가 아는 분이 저렴하게 구매하신 인텔리제이intelliJ 라이센스를 넘겨받아 사용하기 시작하고 있다. 처음에는 인텔리제이의 강력한 리팩토링 기능이 마음에 들어서 STS에서 작성한 코드들에 대해서 리팩토링을 할 때에만 주로 사용해왔었는데, STS(현재 우분투 13.04에서 openjdk-7-sdk 를 사용하고, STS 3.2.0 에서 3.3.0으로 업그레이드하여 사용)에서 Interface 에 정의되어 있는 메소드를 자동완성시켜주지 않는 버그가 발생하면서 인텔리제이로 마음이 확 기울어져버렸다.


인텔리제이를 사용하면서 가장 아쉬웠던 것이 하나 있었는데, 이클립스에서 별다른 설정없이 사용했던 'Auto publicsing'이었다. 웹 프로젝트를 열어놓은 상태로 로컬 웹서버에 배포하여 테스트하면서 개발할 때, 클래스 파일이나 JSP 파일 등을 수정했을 때, 자동으로 컴파일되고 서버에 배포되는 기능이 인텔리제이에서 제공하지 않는다고 아쉬워했었다(다 방법이 있었다!).

위에서 보는 것처럼, 모듈의 Run/Debug Configurations 에서  'On frame deactivation' 항목을 'Update classess and resources'를 설정해 놓으면, 애플리케이션이 잠시 대기하고 있는 동안에 변경사항을 확인하여 변경된 클래스와 리소스를 갱신시켜준다. 

그리고 실행할 때는 디버그Debug 모드로 실행시킨다.

혹은


왼쪽 하단에 있는 서버 항목 중에서 'Update Resources On Frame Deaction'을 클릭해서 활성화시켜도 된다. 이렇게 설정해두면, 애플리케이션이 대기상태에 들어가면 주기적으로 변동사항들을 확인하는 작업을 하면서 자동 배포가 된다.


NHN 그린팩토리 주변에 보면 고급 아파트들이 둘러쳐져 있다. 

  처음으로 와본 그린 팩토리. 2층과 1층은 일반인에게 개방되어 있기에 인근 주민들이 찾아와 시간을 보내는 모습이 색다르다. 하지만, 이 주민들 중 누군가는 그린팩토리의 창으로 비치는 태양이 눈부시다고 넣은 민원에 서명을 한 이도 있지 않을까? ㅋㅋ


  접수창구에는 올드멤버중 한분이신 채수원님이 주말알바로 접수요원을 하고 계셨다. 오랜만에 뵙기에 반갑게 인사드리고 약간의 기념품(스티커, 배지, 군것질류, 생수)을 챙기며 커넥트 홀로 들어섰다.




  앞자리로 이동하니, 첫발표자인 정상혁님과 다다음 발표자인 백기선님을 뵐 수 있었다.




  정상혁님은 '[Spring 3.0 -> 3.1 -> 3.2 따라하기]'라는 주제로 발표를 시작하신다. 소스코드가 많은 발표이기에 github 에 마크다운으로 작성된 문서를 기반으로 발표를 진행하신다. 이런 방법도 괜찮다 싶다. 개발과 관련된 발표자료를 만들때 소스코드를 이쁘게 표현하기가 참 쉽지 않은데, 그럴바에는 차라리 마크다운 문서로 보여주고 이를 공요하는 것이 적절해보인다. 프리젠테이션 파일로 만들어진 발표자료는 나중에 보기가 쉽지 않고, 시스템에서 텍스트 검색도 되지 않아서 나중에 다시볼 가능성이 극히 희박하다.


  스프링의 버전이 3.0에서 3.1로 넘어가면서 많은 변화가 일어났다. 스프링이 하위호환성(새로 출시된 프레임워크가 이전 프레임워크에 맞춰 개발된 기능을 그대로 유지-지원하는 것)을 강조하는 프레임워크지만, 코드의 개선을 위해서 3.1에서는 꽤 많은 부분이 변경되었다. 이 변경된 항목들에 대해서 찬찬히 짚어가는 시간이 지속되었다. 여전히 스프링 3.0을 이용하고 있는 프로젝트가 많은 상황에서 스프링 3.1 이상으로 업그레이드를 하려고 하는 이들에게 도움이 되었으리라고 본다.


  다음 발표는, 성능테스트 툴로 사람들의 많은 관심을 받고 있는 nGrinder에 관한 발표였다. 'nGrinder 초딩도 하는 성능 테스트'라는 제목으로 윤준호님이 발표하셨다. 낼모레 불혹을 앞두고 있는 '디자이너 출신'의 개발자는 nGrinder의 미려함에 대해서 강조하셨다.

  창조자인 개발자에게 자신의 창조물을 파괴하는 행위인 '테스트'는 참 힘든 일이다. 하지만, 자신이 만든 창조물의 성능과 안정성을 높이는 일은 외면해서는 안될 일이다. 어느 개발자들은 '테스트'는 품질관리QA(Quility Assurance)자에 의해서 진행이 되어야 한다고 말하지만, 나는 개발자가 일정수준 이상의 품질을 갖춘 제품을 만들어낼 의무가 있다고 본다.

  개발자가 일정수준 이상의 품질을 갖춘 제품을 만들어내기 위해서는 '테스트'를 진행해야 하는데, 그 테스트를 개발자 스스로 하게 하려면 어떻게 해야할까? '테스트'가 쉬워야 한다. 쉬워야 테스트를 쉽게 하고 제품의 품질을 높이면 자랑할 수가 있다. 테스트를 하면할수록 성능이 개선된다면 개발자는 자발적으로 테스트를 수행하게 될 것이다.


  nGrinder는 Grinder에서 시작되었다. Java 이외의 Jython과 Groovy를 지원하며, 테스트에 사용되는 스크립트를 자동생성하고 자체 SVN으로 관리해주고 테스트 결과를 저장하여 살펴볼 수 있는 기능을 제공한다. IDE와 클러스터링을 지원하면서 개발자의 '제품'에 대한 성능 테스트를 용이하게 한다. 이렇게 테스트를 용이하게 하면서 NHN내부에서도 620여명의 사용자가 11,000건의 테스트를 진행하며 성능 테스트 활동이 10배이상 증가하는 테스트를 달성했다고 한다.

  내가 만든 제품에 대해서도 성능테스트를 진행해봐야겠어. ㅡ_-);;


  세번째 발표는, whiteship 이라는 닉네임으로 '스프링 프레임워크'와 관련해서 잘 알려진 백기선님이 'Vert.x와 socket.io 이해 및 활용'이라는 주제로 발표하셨다. 특이하게, 자신의 큰 딸 '서연이'와 함께하는 발표였다. 발표 중간중간에 서연이의 돌발 행동에 참석자들은 흐뭇한 '아빠미소'를 짓고 있지 않았을까?



  시작에 '왕좌의 게임'에 나오는 말을 인용하며 '개발이 딸보다 쉬웠다' 라는 그의 말을 조금은 이해할 수 있는 순간이었달까?

Vert.x는 매우 쉽게 확장 가능한 차세대 비동기 애플리케이션 개발 플랫폼이다.

  Vert.x는 자바스크립트 엔진을 이용한 node.js와 비교되는 Java를 기반으로 하는 비동기 애플리케이션 개발 플랫폼이다. 백기선님은 Vert.x에 관심을 가지고 관련한 글을 꾸준하게 작성하고 있다. 지금도 꾸준하게 관련한 소식들을 게재하고 있다.

  Vert.x의 핵심요소는 Netty(IO 처리), Hazelcast(메모리형 데이터를 분산처리할 수 있는 그리스 시스템 제공)이다.

  Vert.x 의 주요 개념으로 Verticle, Vert.x. instance, Ployglot, Concurrency 에 대해서 하나하나 짚어나간다.

  Verticle은 Vert.x 에서 배포가능한 애플리케이션 단위이며 개별적인 클래스로더를 사용하여 실행해주며, 손쉽게 클러스터링할 수 있다. 수평적인 확장을 지원하며, 확장된 Verticle 간에는 메시지를 주고 받을 수 있다.

  Polyglot은 JVM에서 실행가능한 다양한 언어들로 작성할 수 있다.JavaScript, Ruby, Java, and Groovy 등의 언어를 지원하고 있으며 추가적으로 Clojure, Scala and Python 등의 다양한 언어를 지원할 것으로 보인다.

  Vert.x 를 이용할 때는 vertx-core, vertx-platform을 이용하면 된다. 버전업 되면서 사용하는 방법이 달라졌다고 한다. 라이브코딩을 하다가 당황하셨지만 능숙하게 대처하는 모습에서 그의 발표경험의 연륜을 짐작하게 만든다.



  node.js가 많은 인기를 끌게 만든 모듈 중 하나가 socket.io(전송 방식을 추상화하여 모든 브라우저와 모바일 기기용 실시간 애플리케이션을 개발가능하도록 하는 것이 목적)다. Socket.io를 이용해서 실시간 웹 기술을 이용하여 요즘 많이 관심받는 푸쉬Push 기술을 구현하기가 용이해진다. Socket.io 는 node.js의 모듈이다보니 자바쪽에서 아쉬워하는 녀석 중에 하나였는데, 기선님이 keesun/mod-socket-io 를 만들어내어 오픈소스로 제공하고 있다.

  스프링 4.0에서는 자체로 웹소켓WebSocket을 지원하는데, SockJS 구현체가 들어 있어 지원한다고 한다. SockJS가 서버의 연결이 끊어졌을 때 서버와 클라이언트가 서로 그 정보를 주고 받는 핑퐁(Ping-Pong, 이걸 핑퐁이라고 하는 것이군!)을 지원하지 않아 아쉽다고 하였는데, 과연 스프링에 포함되었을 때는 어떤 모습을 가질 수 있을지... 궁금하군.


개인적인 일정으로 여기까지만 듣고 Helloworld 세미나장을 나온다.

비가 내리는 날에도 많은 사람들이 참여한 세미나였고, 나로서는 처음 그린팩토리를 살펴볼 수 있는 좋은 기회였다. ㅎㅎ 하지만, 우리집(경기도 남양주시)에서 정자동까지는 멀고먼 여정이었다. Orz... 집에 돌아와서는 10시에 체력저하로 다운.

출처 : 


자바스크립트 핵심 가이드

저자
더글라스 크락포드 지음
출판사
한빛미디어 | 2008-09-30 출간
카테고리
컴퓨터/IT
책소개
자바스크립트 전문가 더글라스 크락포드가 정리해낸 자바스크립트 언...
가격비교 글쓴이 평점  

이 책에 나온 예문을 그대로... 사용..! 두둥.


var tempArray = new Array();

tempArray.push({id: 1, name: 'a'});

tempArray.push({id: 4, name: 'd'});

tempArray.push({id: 2, name: 'b'});

tempArray.push({id: 3, name: 'c'});

tempArray.push({id: 5, name: 'e'});



var by = function(name) {

    return function(o, p) {

        var a, b;

        if (typeof o === 'object' && typeof p === 'object' && o && p) {

            a = o[name];

            b = p[name];


            if (a === b) {

                return 0;

            }

            if (typeof a === typeof b) {

                return a < b ? -1 : 1;

            }

            return typeof a < typeof b ? -1 : 1;

        } else {

            throw {

                name : 'Error',

                message : 'Expected an object when sorting by ' + name

            };

        }

    };

};


tempArray.sort(by('id'));

결과확인
[Object { id=1, name="a"}, Object { id=2, name="b"}, Object { id=3, name="c"}, Object { id=4, name="d"}, Object { id=5, name="e"}]


Helloworld를 살펴보자! 

public class Helloworld {
	public static void main(String[] args) {
		System.out.println("Hello world.");
	}
}

javac Helloworld.java

생성된 Helloworld.class를 살펴보자.

javap -c -l -v Helloworld.class

javap [번역] 는 클래스(.class) 파일 역어셈블러(역컴파일러는 이상한가? ㅡ_-)?)이다. 컴파일되어서 바이트코드가 된 클래스파일을 살펴본 적이 없었다. ㅡ0-);;

Classfile /ihoneymon/Documents/Helloworld.class
  Last modified 2013. 6. 26; size 426 bytes
  MD5 checksum 1c34705a72fff1557ef69c977ce53552
  Compiled from "Helloworld.java"
public class Helloworld
  SourceFile: "Helloworld.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#15         //  java/lang/Object."<init>":()V
   #2 = Fieldref           #16.#17        //  java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #18            //  Hello world.
   #4 = Methodref          #19.#20        //  java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #21            //  Helloworld
   #6 = Class              #22            //  java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               SourceFile
  #14 = Utf8               Helloworld.java
  #15 = NameAndType        #7:#8          //  "<init>":()V
  #16 = Class              #23            //  java/lang/System
  #17 = NameAndType        #24:#25        //  out:Ljava/io/PrintStream;
  #18 = Utf8               Hello world.
  #19 = Class              #26            //  java/io/PrintStream
  #20 = NameAndType        #27:#28        //  println:(Ljava/lang/String;)V
  #21 = Utf8               Helloworld
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/System
  #24 = Utf8               out
  #25 = Utf8               Ljava/io/PrintStream;
  #26 = Utf8               java/io/PrintStream
  #27 = Utf8               println
  #28 = Utf8               (Ljava/lang/String;)V
{
  public Helloworld();
    Signature: ()V
    flags: ACC_PUBLIC
    LineNumberTable:
      line 1: 0
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return        
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    Signature: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    LineNumberTable:
      line 3: 0
      line 4: 8
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello world.
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return        
      LineNumberTable:
        line 3: 0
        line 4: 8
}

이 Helloworld 클래스의 경우에는 main() 메소드에 의해서 실행되다 보니 더욱 절차적인 형태를 띄게 되지 않았을까? 

역컴파일된 클래스파일을 보면, 실행순서와 참조하는 라이브러리들을 확인할 수가 있다. 이런거였군~!


이제 조금은 자바를 대하는 태도가 변하고 있는 듯 하다. 얼마 전까지만 해도 구현하는 것에만 집착했었는데, 최근에는 개발환경 구축, CI, 변경이력관리, 아키텍처 등에 대해서 조금씩 시선이 돌아가고 있다. 그만큼, 내 역량이 성장했다는 증거가 되길 바란다.

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head>

    <title th:text="${title}">Report mail</title>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

</head>

<body>

    <h1>Send Test Report Email</h1>

    <table>

        <thead>

        </thead>

        <tbody>

        <colcolgroup>

        <col style="width: 100px;"/>

        <col/>

        </colcolgroup>

            <tr>

                <td th:text="#{mail.th.project.id}">Proejct</td>

                <td th:text="${projectId}">Project</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.sub.project.id}">Sub Project</td>

                <td th:text="${subProjectId}">Sub Project</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.duration}">Duration</td>

                <td th:text="${duration}">Duration</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.format}">Report Format</td>

                <td th:text="${format}">Document</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.start.datetime}">Start Datetime</td>

                <td th:text="${startDateTime}"></td>

            </tr>

            <tr>

                <th th:text="#{mail.th.end.datetime}">End Datetime</th>

                <td th:text="${endDateTime}"></td>

            </tr>

        </tbody>

    </table>

</body>

</html> 

위의 템플릿 코드는 그대로 둔 채,

<!-- Thymeleaf template -->

<dependency>

    <groupId>org.thymeleaf</groupId>

    <artifactId>thymeleaf</artifactId>

    <version>2.0.17</version>

</dependency>

<dependency>

    <groupId>org.thymeleaf</groupId>

    <artifactId>thymeleaf-spring3</artifactId>

    <version>2.0.17</version>

</dependency>

아래의 오류가 발생한다. 

ERROR: org.thymeleaf.TemplateEngine - [THYMELEAF][http-bio-8080-exec-7] Exception processing template "report/testReportMail": Exception evaluating SpringEL expression: "title" (report/testReportMail:4)

thymeleaf 의 version을 2.0.17 에서 2.0.16으로 변경해보자.

정상동작한다. 

현재 사용하고 있는 스프링은 '3.2.0.RELEASE'


+ Recent posts