2015년 12월 21일 월요일

웹페이지에 눈내리게 하자

크리스마스를 맞아서 운영중인 웹페이지에 눈내리는 효과를 내보고 싶어졌다.

1.
js snow effect로 구글링 해서 첫번째 링크가 10 Top jQuery Snow Falling effect Plugin로 나와서 바로 하나씩 클릭해봤다. 특히, 내 웹페이지가 모바일이 기본이어서 스마트폰을 꺼내서 모바일로 하나씩 접속해봤다.

2.
효과가 너무 심심하거나. 눈이 눈같지 않은 플러그인은 제외
효과가 너무 강하거나 스마트폰에서 버벅이는 플러그인도 제외
최종 선택한 플러그인은 바로

3.
플러그인의 웹페이지에는 문서가 딱히 눈에 띄지 않았는데, 소스를 내려 받아보니 js안에 설명이 자세히 있었다.

flakeCount,
flakeColor,
flakeIndex,
minSize,
maxSize,
minSpeed,
maxSpeed,
round, true or false, makes the snowflakes rounded if the browser supports it.
shadow true or false, gives the snowflakes a shadow if the browser supports it.

내 웹페이지가 흰색 배경이어서 flakeColor만 적당히 눈에 띄게 #dddddd 정도로 주고 실행시키니까 그럴듯 했다.

4.
눈내리는 효과를 시작하는 버튼명은 Let it snow. 마음 같아서는 let it snow 노래도 넣고 싶지만, 음원 저작권을 신경쓰고 싶지 않아서 효과만 넣었다. 대신 버튼은 붉은색으로...

2015년 10월 6일 화요일

Handlebarjs로 생성하는 HTML을 서버에서 생성하기

underscorehandlebarjs로 생성하는 HTML조각을 서버에서 생성해야 하는 경우가 생겼다. 현재 서버에서 정형화된 데이터를 JSON으로 받아서 javascript에서 underscore로 자료구조를 변경한 뒤에, handlebarjs로 템플릿을 씌워서 jquery로 DOM에 붙이는 작업이 있는데, 이를 클라이언트에서 변경하지 못하도록 서버에서 생성해야 하는 것이다. 결국에는 서버에서 모든 HTML을 생성하여 PDF로 바로 생성하는데 그 목적이 있다.

1.
javascript 엔진을 java에서 구현한 게 있으니 그걸 사용해서 해보자. java 1.7까지는 rhino가 있고, 1.8부터는 nashorn이 있다. 현재 프로젝트가 1.7을 사용 중이어서 rhino에 underscore와 handlebajs를 load해서 실행시키는 것 까지는 성공했다.

        Context cx = Context.enter();
        Global global = new Global(cx);
        cx.evaluateString(global, "print('Hello World!')", "helloWorld.js", 1, null);
        cx.evaluateString(global, "print('Hello World!')", null, 1, null);
        cx.evaluateString(global, "function a() { print('this is a') }", null, 1, null);
        cx.evaluateString(global, "a();a();", null, 1, null);
        cx.evaluateString(global, "load('underscore.js')", null, 1, null);
        cx.evaluateString(global, "load('handlebars-v4.0.1.js')", null, 1, null);
        cx.evaluateString(global, "print(_.now())", null, 1, null);
        cx.evaluateString(global, "print(Handlebars.Utils.isFunction(_.now))", null, 1, null);
        Context.exit();

2.
그런데 jquery를 안된다. rhino 내부에 window 객체가 없어서 에러가 난다. 구글링을 해봐도 전부 2008년도 즈음의 웹페이지들만 검색이 되고, 대부분 안된다는 내용이다.

3.
1번에서 사용한 javascript context에 java의 VO객체 유형의 데이터를 넣고 underscore로 데이터를 조작한 다음, 바로 handlebarjs에 넣어서 템플릿을 만들고 그걸 java로 다시 받아와서 이어 붙이는 형태를 해볼까 생각해봤다.

4.
그러던 와중에 handlebarjs의 java 버전이 있는 것을 찾아 냈다. 블로그는 여기. 예제를 따라하니 금방된다.

Handlebars handlebars = new Handlebars();
Template template = handlebars.compileInline("Hello {{this}}!");
System.out.println(template.apply("Handlebars.java"));
template = handlebars.compile("mytemplate");
System.out.println(template.apply("Handlebars.java"));

5.
jsp에 <script> 태그로 선언한 템플릿을 hbs 파일로 나누거나, 하나의 파일을 읽어서 나누거나 해서 서버에서 충분히 HTML코드를 만들 수 있게 되었따.

6.
underscore로 정형화된 데이터를 재구성하는 것은 DB조회시부터 원하는 모양으로 조회하도록 변경할 예정

7.
템플릿을 미리 컴파일해놓고 쓸 수 있게 최적화하는 것도 이번에 고려할 예정

2015년 9월 14일 월요일

javascript로 csv, tsv 파일 저장하기

브라우저에서 javascript로 csv, tsv 형식의 파일을 로컬로 저장해야한다.

1.
javascript object를 csv, tsv 형식의 문자열로 변환해주는 라이브러리, PapaParse

2.
브라우저에서 파일로 저장하는 라이브러리, FileSaver.js

3.
csv, tsv 형식의 정의와 각각의 media type, csv, tsv

4.
UTF-8 인코딩으로 만들고, 엑셀에서 잘 읽을 수 있게 UTF-8의 BOM추가

5.
완성된 javascript fucntion

var downloadAsCsv = function(data, filename) {
saveAs(new Blob(["\uFEFF" + Papa.unparse(data)], {type: "text/csv;charset=utf-8"}), filename);
};

var downloadAsTsv = function(data, filename) {
saveAs(new Blob(["\uFEFF" + Papa.unparse(data, {delimiter: "\t"})], {type: "text/tab-separated-values;charset=utf-8"}), filename);
};


2015년 7월 14일 화요일

디즈니 후짝짝에 딸래미 사진 넣기

내일 만 4세 생일을 맞는 5살 딸래미가 있다. 평소에 디즈니 주니어 티비를 즐겨 보는 편인데, 생일파티 후짝짝을 보면서 본인도 거기에 나올거라는 굳은 믿음을 가지고 있었다. 한달에 30명을 뽑기 때문에 되기도 어려울 것 같은데, 신청기간마저 지나버렸다. 이걸 잘 설명해주니까 바로 울음을 터트린다.

예전에 동영상 편집을 몇번 해봤던 기억을 가지고, 실제로 할 수 있을지 가늠해보지 않고서 "아빠가 만들어줄게~!"를 질러버렸다. 울음을 그치고 달래긴 했는데, 이제 이걸 어떻게 만들지란 고민이 시작됐다.

1.
일단 원본을 확보했다. 디즈니 주니어 홈페이지에서도 영상을 유투브에 올려놨다. 후짝짝으로 검색하면 유투브에 월별로 영상이 나온다. 유투브 다운로더 프로그램를 이용해서 원본을 고화질(1280x720)로 다운로드받을 수 있다. 

2.
동영상 편집 프로그램이 필요해서 무료 프로그램을 찾아보니, Lightworks란 프로그램이 좋다고 하여 설치했다. 그런데 프로그램 사용이 직관적이지 않고, 관련된 강좌나 매뉴얼이 (프리미어 프로에 비해) 부실해서 원하는 작업을 빨리빨리 하기가 어려웠다.

3.
예전에 써본 프리미어 프로를 알아보니 요즘에는 프리미어 프로 CC라고 해서 월별로 구매해서 사용이 가능했다. 난 한번만 쓸꺼니까 30일 시험판을 설치했다. 설치도 클라우드 어쩌구를 설치해서 그 안에서 로그인도 하고 설치도 하는 구조이다. 그리고 구매로도 이어지게 해놨다.설치 중간에 .net framework과 window media player 설치가 필요했다.

4.
미리 다운로드한 원본(mp4)을 불러와서 필요한 부분만 자르고 다시 내보내는 것은 따로 강좌를 찾아보지 않아도 이것저것 눌러보면서 작업이 가능했다. 바로 내보내기도 되고, 대기열에 넣어서 백그라운드로 작업할 수도 있었다.

5.
1분짜리 하나의 영상에서 10명의 아이들의 생일을 축하해준다. 처음에는 10명 모두를 딸래미로 바꾸려고 했는데, 작업시간에 한계가 있었다. 그래서 딸래미가 좋아하는 캐릭터가 같이 나오고, 사진의 모양이 작업하기 쉬운 동그라미인 장면만 작업대상으로 정했다. 물음표표시에 아이 얼굴이 나오고, 모자이크된 부분에 이름과 생일이 표시된다.


6.
영상에 넣을 사진을 고르고, 온라인 포토샵 사이트를 이용해서 동그라미 부분을 제외하고 투명하게 만들었다. 영억선택도구 오른쪽에 선택모양을 원으로 바꾸고, 가로세로비율이 바뀌지 않도록 하면 이쁘게 동그라미 선택을 할 수 있다. 복사하고 새 이미지를 만들때 배경 투명 옵션으로 만들고 붙여넣으면 된다.

7.
편집된 사진을 동영상 중간에 넣는 작업은 유투브 강좌를 보고 쉽게 할 수 있었다. 그리고 좀더 자연스런 움직임을 위해서, 시간(프레임)에 따라서 위치와 크기가 바뀌어야 했다. 이것도 유투브 강좌가 도움이 됐다. 타임라인의 프레임을 하나씩 움직이면서 사진의 Position과 Scale을 변경해서 배경 움직임에 맞추도록 조정했다.

8.
딸래미 이름과 생일날짜는 픽픽에서 비슷하게 만들었다. 원본 영상에서 사용한 색을 뽑아와서 최대한 비슷하게 만들었는데, 더 비슷한 글꼴을 찾으면 똑같이 만들 수도 있을 듯 하다. 이름과 생일도 사진과 동일하게 동영상에 넣고 프레임마다 위치를 바꿔주었다.

다 만들고 나서 가족에게 보여주니 반응이 좋다. USB에 담아서 큰 TV화면으로 보여주니 딸래미도 좋아한다. 대만족!

2015년 6월 27일 토요일

나만의 개발환경

내가 좋아하는 개발환경 중에서 이클립스와 관련된 내용

1. 버전
별다른 특이사항이 없으면 최신 버전을 이용한다. 현재는 luna. 링크

2. Package
Eclipse IDE for Java EE Developers로 받아야 Web과 관련된 개발을 편하게 할 수 있다. 일반 Package를 받으면 HTML Editor도 없어서 html파일을 더블 클릭으로 열면 이클립스에 내장된 브라우저로 열린다 -.- 여기서 패키지별 기능 비교가 가능하다.

3. Workspace
root에 dev와 같은 특정 이름으로 디렉토리를 만들어서 그 안에 이클립스가 설치되는 폴더와 workplace 폴더를 만든다. 포맷을 대비하여 d 드라이브를 선호한다. root에 만드는 디렉토리는 이클립스를 설치하는 의도가 드러나도록 이름을 짓는다. 일부러 과거 버전의 이클립스를 쓰는 경우에는 kepler, indigo와 같은 이름으로 만들거나, 특정 프로젝트를 위한 개발환경이라면 해당 프로젝트 이름으로 만드는 식이다. root에 만드는 이유는 소스파일들의 전체 경로가 너무 길어지지 않게 하기 위해서 이다.

4. Perspective
기본적으로 Java Perspective를 사용하지만, 아래처럼 View 구성을 약간씩 변경한다. 

- 왼쪽 View에 JUnit View를 추가한다. JUnit을 돌리는 시점이라면 테스트 대상이 되는 Java 파일에만 집중하게 되므로 전체 트리 구조는 볼 필요 없기 때문이다.

- Server, Ant View를 왼쪽 아래에 넣는다. 둘다 위아래로 긴 목록이 나오지 않는 스타일의 View이지만, 자주 접근하게 되므로 왼쪽 아래에 필요한 만큼만 보이게 줄여서 넣는다.

- 오른쪽 View를 최소화한다. 기본 설정에 Task List와 Outline이 있는데 둘다 항상 보고 싶은 정보는 아니고, 특정 시점에 뭔가 있는지 궁금해지는 View이다. Task List는 Mylyn을 쓰지 않으면 제거하고, Tasks를 추가하여 넣는다.

- 아래쪽 View도 필요한 것만 남기고 제거한다. Problems, Console, Progress, Search만 남겨놓는다. Javadoc은 필요할때 마우스 오버해서 보는 편이다.

여기 까지 설정하면 아래 처럼 된다.


5. Colors
밝은 계열의 테마를 선호한다. 그래서 이클립스의 기본 설정색을 변경하지 않고 그냥 사용한다. 오히려 cmd.exe나 putty 사용할 때에 기본 설정인 검정색 바탕에 회색 글씨를 희색 바탕의 검정색 글씨로 변경해서 사용하는 편이다.

6. Fonts
글씨체는 무조건 나눔고딕코딩으로 변경한다. 개발하기에 이보다 좋은 폰트는 못 찾은 것 같다. 이 주제에 대해서 나름의 관심이 있어서 많은 Font를 써봤지만, 한글까지 정확하고 이쁘게 표현하는 Font는 나눔고딕코딩이 유일한 듯 한다. 그리고 큰 글씨를 선호하기 때문에 기본 크기도 14로 올려서 사용한다.

7. Keys
단축키도 몇가지를 추가한다. File Search에 Ctrl + Shift + F 를 지정해서 패키지 익스플로러에서 바로 Selected 범위로 파일내용을 찾기에 편하게 만든다. Copy Qualified Name에 Ctrl + Shift + C 를 지정해서 전체 경로를 폼함한 파일명이나 패키지명을 포함한 클래스명을 손휩게 복사할 수 있게 만든다.

... 더 있지만 블로그가 너무 길어지므로 여기까지...


JSON 문자열의 데이터를 HTML escape 할때 주의점

브라우저에서 AJAX로 JSON을 요청한 경우, 서버에서 JSON 문자열을 리턴해주는데, XSS 방지를 위해 특수문자 6개( & < > " ' / )는 HTML 엔티티로 변환해서 넘겨준다.

return input.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("\\\\\"", "&quot;")
.replaceAll("'", "&#x27;")
.replaceAll("/", "&#x2F;");

그런데 "의 경우에는 " 자체가 JSON에서 사용하는 특수문자이기 때문에 \"와 같이 표현되도록 JSON이 생성된다. 그래서 "를 &quot;로 변경하면 실제로는 \" 가 \&quot;가 되므로 escape 문자인 \가 데이터인 것처럼 변경된다. 그래서 \"를 &quot;로 변경해야 한다.

그런데 값이 \일때는 또다른 문제가 발생한다.

name이라는 항목의 실제값이 \ 라고 가정하면,
JSON인코딩 문자열은 {"name":"\\"} 가 된다.
이게 위 XSS 치환 로직을 거치면 {"name":"\&quot;}가 되면서 JSON 규칙에서 어긋나게된다.

JSON spec에 따르면 값(value)는 쌍따옴표(")로 둘러싸여져 있고, 값 바로뒤에는 특수문자 } , ]만 나올 수 있다. 쌍따옴표(")가 값(value)이 아닌 이름(name)일 수 도 있으므로 : 도 나올 수 있다. 그래서 정규식에 negative lookahead를 적용해서 \\\"(?!,|]|:|})를 &quot;로 변경하도록 적용하니 값이 \일때도 정상적으로 처리된다. 그리고 Java String의 escape 문자도 적용되어야 하니 Java String에 넣을려면 \\\\\"(?!,|]|:|}) 가 되어야 한다.
실제 데이터가 ":" 일 때는 \":\" 처럼 데이터가 생성된다. 그래서 위에 취소선을 그은 방법대로 하면 , } ] : 앞에 나타나는 "는 치환되지 않는다. 그래서 negative lookbehind를 적용해서 짝수개의 \\\\가 발생하고 바로 나타나는 \"에 대해서 치환하도록 정규식을 변경했더니 정상적으로 치환이 된다.
특정 패턴이 0번 혹은 짝수번 나타나는지를 확인하기 위해 negative lookbehind와 짝수번 패턴의 *를 사용했다. 참고 \\가 안나오고 \\\\가 0번이상 발생하는 패턴. 만들어진 정규식은 (?<!\\)(\\\\)*
Java String의 replaceAll 사용시 짝수번패턴은 치환하지 않고 그대로 유지하기 위해 치환할 부분을 제외한 전체부분은 그룹으로 묶고 치환해서 들어갈 문자열에 $1으로 지정. 참고


return input.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("((?<!\\\\)(\\\\\\\\)*)(\\\\\\\")", "$1&quot;")
.replaceAll("'", "&#x27;")
.replaceAll("/", "&#x2F;");

2015년 5월 29일 금요일

흥분하지 않는 이유

최근 회사에서 주변 사람들이 나에게 이런 말을 몇번 들었다. 흥분하는 모습을 한 번 보고싶다고, 기분에 up and down이 별로 없지 않냐고.

집에서도 와이프한테 한번인가 들었던 말이어서 딱히 놀라진 않았다. 그리고 그런 내 성격이 나름 인생살이에서 좋은 점이라고 생각하고 있었다. 그래서 그런 모습으로 나를 보는 사람이 있다는 것도 기분이 괜찮았다.

나는 왜 그런 성격을 가지게 됐을까? 당연한 말이지만 처음부터 그렇진 않았다.  회사에서 개발을 하고 여러 사람들과 같이 업무를 하다보니, 나만의 기준이 생기고 그 기준에 따라서 행동하다보니 성격으로 굳어진 듯 하다.

아래 3가지는 내가 진리라고 믿고, 따를 만한 가치가 있다고 여기는 기준이다. 즉, 인생에 대한 가치관이고 삶에 대한 행동양식이다.

1. 모든 사건에는 그럴만한 이유가 있다고 믿는다.

2. 내가 바꿀 수 없는 것은 고민하지 않는다.

3. 객관적인 사실을 확인하고 결정한다.

이라한 것들이 흥분하지 않는, 기분의 동요가 적은 나를 만든다고 생각한다.

위에 언급한 번호 하나하나에 대해서 다른 블로그에서 자세하게 쓰겠다. 안그러면 블로그가 너무 길어질 것 같다.

2015년 5월 25일 월요일

delacourt at a glance 만들면서...

최근에 취미 코딩으로 회사 지하식당의 메뉴를 좀 더 보기 좋게 제공하는 사이트를 만들었다. 이걸 만들면서 경험한 내용을 블로그로 남겨놓는다. 아마도 내용이 제법 길어질 수 있을므로 여러개의 블로그로 올릴 것 같다.

1.
처음에는 생각만 했었다. 지하1층 메뉴와 지하2층 메뉴를 한 페이지에서 확인 할 수 없고, 한번씩 링크를 눌러서 2개의 페이지에서 메뉴를 확인한다는게 좀 불편했었다. 아~ 좀 불편하네~ 좀 길어져도 한 페이지에 해 놓으면 페이지 전환없이 편하게 볼텐데...

2.
전혀 상관없는 계기로 웹페이지를 긁어서 원하는 데이터를 뽑아내고 원하는 형식으로 표시하는 작업을 2번 정도 진행했다. 첫번째는 로컬시스템의 html파일에서 JQuery의 ajax를 이용해서 작업했고, 두번째는 nodejs로 만든 서버를 AWS에 띄워서 request로 호출하고, 결과 html 문자열은 cheerio로 파싱해서 작업했다. 더 상세한 내용은 다른 블로그에서....

3.
비슷한 작업을 2번정도 연습하고, 그 와중에 AWS에 서버도 셋팅을 하고 나니, 식당 메뉴를 보기 좋게 만드는 작업을 해보고 싶어졌다.

4.
소스는 GitHub에 올렸다. 서버는 AWS를 쓰기로 했다. 자바스크립트로 nodejs로 구현해서 별도 웹서버는 필요없었다. 도메인은 생각하지 않고 시작했는데, 결국 여기에서 kr.pe의 서브도메인을 무료로 받았다.

5.
단순히 서버를 하나 띄워서 사용자의 요청이 들어올 때마다 공식홈페이지에서 데이터를 가져와서 뿌리기로 했다. 접속주소도 루트로 들어올때만 준비한 페이지를 보여주게 하고 그 외의 주소는 아무 표시없이 무시했다.

2개 페이지의 결과를 합쳐서 응답해야 해서, async라는 모듈을 사용했다. html template을 쉽게 만들기 위해 swig도 썼다. 위에서도 언급했지만, html 파싱은 cheerio를 썼다.

6.
하루 정도 서비스를 해보니까 하루에 몇명이나 들어올까가 궁금해졌다. 좀 찾아보니 구글 어날리틱스가 있어서 출근길에 붙였다. 하루종일 통계가 안나와서 답답했는데 하루가 지나니 자 나온다.

7.
빌드를 자동화해야 할 것 같아서 travis를 붙이긴 했는데, travis에서 실제로 AWS 서버에 배포하는 것 까지 붙이진 않았다. 대신 AWS 콘솔에서 사용할 작은 shell 프로그램만 하나 만들었다. nodejs 프로세스를 죽이고(kill), git pull 한다음 nohup으로 실행하는 것 까지 한다.

8.
공식홈페이지에서 제공하던 기능은 다 포함했기에 GitHub에서 1.0.0으로 릴리즈를 했다. 현재 버전이기도 하다. 현재 버전에 포함되지 않은 기능들은 GitHub의 Issue로 등록했다. 앞으로는 Issue 기반으로 작업할 생각이다.

여기까지가 큰 흐름이고, 자세한 내용은 번호마다 다른 블로그에서 더 자세하게 다루겠다.

2015년 5월 21일 목요일

java feature toggle

프로그램이 가지고 있는 특정 기능을 상황에 따라서 켜고 끄는 기능이 필요하다. 구글링을 조금 해보니 이런 걸 feature toggle이라고 하는 듯 하다. 지금 개발중인 시스템에서 이런 기능이 자주 필요해졌고, 이번에도 나 혼자 이런게 필요한 건 아니겠지라는 생각에 구글링을 시작.

1.
feature toggle의 구글링 첫번째 결과는 마틴 파울러의 블로그이다. 글 중반에 feature toggle의 유형을 다시 2가지로 나눈다. release toggle과 business toggle이다.

release toggle은 새로 개발된 기능을 일부 적용하고 손쉽게 되돌릴 수 있게 릴리즈하는 장치이다. 이건 내가 찾던 것은 아니다. 새로운 기능이 안정적으로 안착되면 toggle을 지우라고 권장하고 있다. 이게 시간이 지나면 Technical dept이 된단다.

business toggle이 내가 필요한 유형이라고 할 수 있겠다. 프로그램 runtime 시점에 특정 기능을 적용하거나 적용된 기능을 제외시키는 기능이고, 이게 관리자 역할의 사용자에게 권한이 부여되서 직접 시스템의 기능을 제어할 수 있어야 한다. (오피스 프로그램의 옵션처럼)

2.
feature toggle java로 검색해봤다. 이 기능을 쉽게 구현하게 도와주는 프레임웍들을 모아놓은 페이지가 있다. 4개의 프레임웍에 대한 링크가 존재하고, 구글링 검색결과와도 대략 일치한다. 이것들만 검토해보고 1개를 선택하거나, 직접 구현하는 경우에 대비해서 insight를 얻을 수 있을 것 같다.

3. Togglz
http://www.togglz.org/ 구글링 검색에서도 처음으로 링크되어 있고, 문서화도 잘 되어있고, 기능도 많다. 2014년 12월이 마지막 릴리즈이니까 죽은 상태도 아닌 듯. ENUM을 활용하고, enable/disable 개념과 active/inactive 개념을 가지고 있다. enable이어도 user나 time등의 기준에 의해서 inactive한 상태도 제어가 가능하다. admin기능을 자체적으로 web view와 함께 제공한다. feature들을 memory/file/DB에서 관리가 가능한데, DB는 테이블을 알아서 만들어서 사용하는 듯.

4. FF4J
http://ff4j.org/ 최근 한달전까지 커밋이 있었다. PDF로 된 문서는 잘 작성되어 있는데, 막판에 DB쪽이 나오면서 미작성된 부분이 있다. FeatureStore를 직접 구현하면 DB로도 가능할 듯. feature을 String으로 지칭한다. 설정없이 초기화하여 동적으로 feature를 추가할 수 있다.

5. Fitchy
https://github.com/akomtur/fitchy 프러퍼티 파일 기반이고 특정 interface를 구현한 클래스에 toggle이 필요한 메서드에 annotation을 달아서 특정값 또는 null을 리턴하도록 하는 구성이다. 리턴이 boolean이 아니고 Object가 가능하다는 게 특징인 듯. 마지막 커밋이 2년전인데, 실제 소스는 3년 전인 듯.

6. Flip
https://github.com/tacitknowledge/flip 3년전이 마지막 커밋이고 문서화도 부족함.

7.
기존 프레임웍들을 보면 xml이나 DB에서 feature 기본값을 읽어서 ENUM이나 Proxy Interface로 On/Off를 체크하는 방식을 모두 사용하고 있다. 그리고 Web Page를 통해서 그 값들을 변경가능하게 만들었다. 현재 개발중인 시스템에 구현한 내용도 동일하다. 굳이 추가적인 프레임웍을 붙여서 구현할 필요는 없을 듯.

8.
feature가 추가되면
-> DB에 행 추가
-> 관련VO에 member field, getter/setter 추가
-> Util의 메서드 추가
-> js object에 property 추가
이런 식으로 진행이 될 것 같다.


2015년 5월 11일 월요일

솔루션의 git branch 전략

지금 진행하고 있는 솔루션에서 갑작스럽게 git을 적용하다보니 branch를 어떻게 운영해야 할지에 대해서 막막했는데, 여러 자료들을 보면서 나름의 branch 전략을 세우려고 한다.

당연히 누군가는 이런 고민을 했겠지라는 생각으로 구글링을 시작.

1.
A successful Git branching model 번역 이게 제일 유명한 포스팅인 듯 하다. 특별한 이름은 없고 대부분 "성공적인 모델"이라고 지칭하는 듯. 길지 않은 글이지만, 한글로 짧게 요약한 글도 있다. 이게 더 잘 요약한 것 같다. 이 전략을 기반으로 gitflow라는 것도 누가 만들었다. 그리고 적용후기 (한글)

2.
branch 전략은 아니지만 분산 저장소들을 어떻게 관리할지에 대해서 그림으로 설명한 글도 있다. 같은 블로그에서 비공개 소규모 팀 운영을 위한 예제 시나리오도 읽어볼 만 하다.

이제 회사업무에 적용할 생각을 해보면...

3.
사내 ALM시스템을 사용하면 자연스럽게 1번에서 언급한 "성공적인 모델"을 사용하게 된다. master, develpoment, release-*, feature-* 까지는 그대로 사용하고, hotfix-*만 bugfix-*라는 prefix를 사용하게 된다. 아마도 master에서만 가져오는게 아니라 development나 release-*에서도 가져올 수 있는 구조이므로 일부러 이름을 다르게 잡은 것 같다.

4.
우리 솔루션만의 문제가 더 있다. 솔루션이 고객사 시스템에 설치되는 구축형이다 보니 고객사마다 릴리즈된 버전을 관리할 필요가 있다. 아직 버전에 대한 경험이 없어서 특정 시점의 소스형상으로 설치가 된다. 그 시점의 소스형상을 "고객사A" branch로 만든다. 고객사가늘어날 때마다 만들어지는 branch인데, 고객사가 많아지기 전에 고객사에 "특정 시점의 소스형상"이 아니라 "특정 버전의 소스형상"을 릴리즈하는 형태가 만들어져야 할 것 같다.

5.
팀내의 퍼블리셔가 만드는 이미지 파일과 HTML소스는 "publish" branch에서 관리된다. 언듯 생각하면 퍼블리셔에게 퍼블리싱하는 대상 기능에 맞는 feature-*에 commit하라고 하면 될 것 같지만, 그렇게 하지 못 하는 이유가 있다. 이미지 파일의 경우 여러 이미지를 합쳐서 하나의 이미지로 만들고 잘라서 쓰는 경우가 있고, css 파일도 하나의 파일에서 모든 css를 관리하고 있기 때문이다. 즉, branch를 나눠서 얻는 이점보다 merge할때 생기는 conflict를 해결하는 게 더 힘들어질 것으로 예상했다. 게다가 퍼블리셔 입장에서도 여기 저기 feature-*를 변경하면서 개발하는 것은 너무 번거롭다.

6.
결국 지속적으로 관리되어야 하는 branch가 4개가 된다. master, "고객사A", developement, publish. 
"고객사A" branch는 버전관리를 잘 해서 특정 버전 branch가 되도록 유도하여 결국에는 branch자체를 없에야 겠다. publish는 그냥 두고 진행한다. 퍼블리싱 대상 소스만를 위한 devleopment처럼 개념을 잡고 수시로 development쪽으로 merge를 수행하도록 해야 겠다.

7.
ALM에 bug가 등록되면 hotfix인지 여부를 제품책임자와 개발리더가 판단하여 branch를 hotfix면 master에서, 그렇지 않으면 development에서 가져오도록 해야 겠다. hotfix인 경우, 사내 ALM시스템에서 새로운 patch version을 생성해서 릴리즈 절차를 진행할 수 있도록 해야겠다. (그런 의도의 기능이라면) patch version의 bug에서 branch를 생성할 때 기본적으로 master에서 가져오는지 확인해야 한다. [TODO]

8.
6번과 7번처럼 정리가 되면 한번 사용한 branch들은 "성공적인 모델"에서 언급한 것 처럼 merge된 직후에 삭제되어도 된다. merge request를 개발리더가 accept한 직후에 삭제해버리면 될 듯. git remote repo에서 삭제한 branch를 이클립스 eGit에서 pull할때 자동으로 삭제되도록 개발자로컬환경 셋팅이 필요하다. 그래야 없어진 branch에서 개발하는 실수를 막을 수 있을 듯 하다. 이렇게 eGit의 버전을 올리고 prune 옵션을 설정해서 해결하면 된다.

3줄정리
- branch 전략은 "성공적인 모델"을 따른다.
- "고객사A" branch는 특정 version의 branch로 대체한다.
- publish는 상시 유지하고 수시로 development에 merge한다.

회사업무 중 문제해결 시나리오 정리 시작~

회사업무를 진행하면서 만나게 되는 문제들을 블로그로 정리하려고 한다. 어떤 문제들이 있는지, 어떤 과정을 거쳐서 해결책을 찾아내는지, 최종 선택은 무엇이고 그 근거는 무엇인지를 정리할 예정.