최근 블로그에 비즈니스 로직의 복잡성와 의존성에 대한 이야기를 많이 적었는데, 마침 업무를 진행중에 재미있는 일이 발생을 했다.

우리 팀에 초보 개발자인 막내는 경력이나 경험에 비해서 센스가 꽤 있는 편이다.
그 초보 개발자가 어느날부터 jakarta-POI를 열심히 API를 익히면서 코딩을 하고 있었다. 간단한 API이기때문에 빠른 시간에 습득해서 잘 사용하고 있었다.

어제 코드리뷰 시간에 그 내용에 대해서 언급을 하는 자리가 있었는데, 아주 흥미로운 일이 벌어졌다..^^

초보 개발자가 구현해야 할 업무는 테스트로 진행되고 있는 데이터를 실디비로 마이그레이션을 하는 업무였다. 한번 쓰고 내다버릴 배치성 업무였다.

2가지의 문제가 거론이 되었는데, 이것이 흥미롭다.

1. 테스트 DB에서 데이터를 가져와서 자바빈에 바인딩을 하고 그것을 다시 실디비에 데이터를 넣고 있었다. 중간에 DTO를 십분 활용을 하는 것이다.

어쨌든 우리가 가장 일반적으로 사용하는 방법이다.
하지만,
한번 밖에 호출되지 않은 심플한 로직과 업무처리에서 굳이 빈에 담아서 어렵게 할 필요없이 컨넥션을 2개 열어서 ResultSet에서 바로 loop를 돌면서 실디비로 데이터를 이관을 할수 있을 것이다.

EP
님이 조언을 해주셨다. 약간의 생각만 바꾸어도 코드량이 줄어들뿐만 아니라 의미없는 코드로 노가다를 하는 작업이 대량 줄어들었다.

2. 초보개발자는 기획자가 엑셀로 데이터를 줄 것으로 예상을 했다. 엑셀에서 키값 데이터를 읽어서 그것을 처리하는 방식으로 개발을 한 것이다.

기획자뿐만 아니라 우리 나라 직장인은 엑셀을 선호하는 경향이 있다. 아마 구현을 하기전에 그렇게 준다고 커뮤니케이션을 했을 수도 있다. 리뷰를 시작하면서 테스트 엑셀 파일을 열었는데, 컬럼 2개에 데이터가 있었다. 정말 심플한 데이터였다. 이것을 CSV로 변환을 해서 단순하게 text파일을 읽어서 구분자(,)로 구분해서 데이터를 읽었더라면, POI 라이브러리 의존성도 없이 구현이 가능했을 것이다. 같이 리뷰하던 고수의(?) 개발자분들은 이구동성으로 얘기를 했다. 물론 자주 사용되는 어플리케이션이라 CSV로 바꾸는 것 조차 귀찮다고 한다면, POI를 이용한 어플리케이션이 더 빛을 발할수도 있었겠지만, 이번 건은 CSV로 넣는 것이 더 좋은 선택으로 보인다.

실제로 전에 있던 회사에서 업무를 진행할 때 CSV로 넣었던 import데이터를 엑셀도 추가로 가능하게 구현한 적도 있다. 그 때는 엑셀으로 임포트가 명확한 요구사항이고, 자주 사용하던 기능이었다.



우리는 개발을 진행을 하다보면 과다 설계과 디자인의 홍수 속에서 살게 된다.
과연 이렇게까지 해야만 할까? 이게 정말 옳은 일인까? 수많은 고민을 하게 된다.

dependency가 많고 코드량이 많으면 버그가 증가할 수 밖에 없다. 최소주의의 코딩이 절실하게 필요하다. 최소주의 코딩은 당연한 이야기지만, testability도 확연히 좋아진다.

문제의 해결점은 최대한 비즈니스 로직을 심플하게 정리를 하고(개발에 쓰는 머리에 5%만 사용을 해도 단순하게 바꿀수 있다) 여러가지 문제 해결 방법이 있다면, 가능한 의존성이 적은 구현, 테스트를 하기 쉬운 구현으로 생각을 해보자


당연한 이야기지만, 의존성이 적을 수록 테스트하기는 쉬워 질 것이다.
갑자기 테스트가 웬말이라는 사람이 있을까봐 한줄 더 적는다..^^



주위를 둘러보면 초과근무에 늪에서 빠져나오지 못하는 사람들이 많다.

얼마나 시간이 모자라고 그 시간을 확보해야 하는가?

몇 가지 진단을 해보자.
1. 이미 달력을 보면 빨간 날이 정해져있다. 그 날들을 일정을 산정을 할때 워킹타임으로 만들지는 않았는지?

2. 업무과 지연되지 않았다면, 변경에 의해서 업무량이 늘어나지는 않았는지?

3. 지금 해야할 일을 자꾸 야근이나 주말으로 미루지는 않는지?

4.. 그냥 불안감때문에 초과근무를 하지는 않은지?

사실상 초과근무를 하면서 업무를 효율적으로 하기는 쉽지가 않다.

업무의 우선순의들이 있는데, 그것을 어떻게 잘 정렬해서 일하는지도 중요한 포인트이다. 선행작업이 되어야 그 다음이 진행되는데, 엉뚱한 것에 시간을 허비하면서 다른 쪽 일정에 영향을 끼치는 것은 별로 좋지 않은 방법이다.

평소에 회의가 많아서 일할 시간이 부족한 사람은 회의를 제외한 시간에 할수 있는 만큼의 업무를 가져야 한다. 좀더 욕심을 부리다가 큰 일 치르기 쉽다.

야근을 하면서 무얼해야 한다. 주말에 무얼해야 한다는 이야기를 해야 하는 사람이 많은데 그것을 깨달았으면 가능한 근무시간에 처리를 빠르게 해야 한다.

절대적으로 시간이 부족해서 라는 이야기들도 많이 하는데, 정말 그것이야 말로 잘못된 일정산정 및 설계를 인정한 이야기가 되는 것이다. 자신의 부족함을 인정하게 되는 것이다. 하지만, 여기에도 문제가 있다.자신의 의도와 상관없이 빠듯하게 진행되는 일정에서는 어쩌란 말이냐? 이것은 너무 독재적이고, 강제적인 문제라 논외로 하자.

1주동안 1을 할수가 있는데, 자꾸 2를 하라는 얘기는 너죽고 나살자는 이야기 밖에 안되고, 그런 것을 강요하는 사람 밑에서 일하고 있다면, 서둘러 떠나야 한다.

자신이 가진 시간을 잘 알고, 자신의 능력을 잘 알때, 적정한 시간의 조절이 가능해진다.
이것 또한 경험이나 깨달음을 통해서 예상과 많이 가까워진다.

물론, 외부적인 요인에 의하여 불가피하게 이루어질 때, 그 외부요인의 리스크에 대해서 사전에 많은 고민을 해보자. 사실 시작부터 그렇게 될걸 예상한 경우가 허다하다.

하지 않아도 될 것들을 "야근을 하면서 해야되요. 주말근무를 하면서 해야되요."라고 얘기를 하면서 동정심을 유발하지 말자.

그리고, 강요하지 말자. 대부분의 보통의 사람들은 필요하다고 느끼면서 알아서 다 하기 마련이다.
여기에 주로 오시는 분들은 별로 관심이 없는 얘기일수 있지만...^^
내가 지금하고 있는 프로젝트 이야기를 좀 해보자.

블로그 시즌2 에피소드2 베타테스터 모집이 걸렸다.
http://nboard.naver.com/nboard/read.php?board_id=paper_notice&nid=951

2007년의 절반을 같이 보내는 프로젝트이기도 하고, 지금도 진행중이지만 슬슬 공개될 생각을 하니 반응이 궁금하기도 하다.

User inserted image

오래동안 너무 많은 사람들이 고생을 한 프로젝트고 현재도 좀 더 좋은 툴을 위해서 노력을 하고 있다. 한가지 확실한 것은 블로거들이 포스트를 쉽고, 편하게 올릴 수 있는데 관점을 두었다는 것이다.

지금도 여러가지 개발이 진행중이긴 하지만, 이번 프로젝트의 오픈은 더 좋은 블로그를 만들기 위한 기초를 다졌다는 생각을 한다.

앞으로도 남은 에피소드를 통해서 점점 더 지능적이고, 더 깔끔해진 블로그를 기대해보자~
 
webwork에는 xwork.xml에 컨트롤러 dispatch정보를 기술을 한다.

webwork를 사용하면서 정말 좋다고 느낀 점중의 하나가, OGNL으로 사용하는 변수가 뷰단인 JSP, freemarker뿐만 아니라 configuration에서도 동적으로 셋팅이 된다.

내가 개발하고 있는 코드의 configuration이다.

<action name="TemplateWriteFormAsync"   class="TemplateWriteFormAsyncAction">
            <result name="success"            type="freemarker">/WEB-INF/view/${sourceType}_TemplateForm.ftl</result>
</action>


<action name="PostWrite" class="PostWriteAction">
           <result name="success" type="redirect">PostWrite.nhn?blogId=${blogId}</result>
</action>

action에서 sourceType의 getter를 만들어서 expose를 하면 configuration에서도 동적으로 값이 할당이 되서 url을 만든 후 dispatch가 된다는 이야기다.

이 점을 잘 이용하면, 매우 유연하게 Action의 dispatch를 잘 활용을 할수가 있다.
그 밖에 다양한 result지원으로 struts보다 한결 깔끔하고 막강한 configuration을 유지할 수가 있다.
현재 개발중인 어플리케이션은 다양한 UI를 제공해야 하는 이슈가 있다. 그것을 위해 템플릿 엔진의 적용이 필요했고, freemarker의 선택은 사용할 수록 나를 기쁘게 한다.서버에서 만들어지는 html이지만, 테스트 코드를 통해서 테스트도 용이한 것은 큰 장점이다.

list에 대한 사용은 화면을 만드는데 자주 사용이 된다. 부가적인 옵션 기능을 통해서 어떤 뷰를 만들수 있는지 본다.

list된 데이터를 화면에 디스플레이를 할때, 다음과 같은 결과를 만들고 싶다.
pathList가 string타입의 collection이라면, pathList : ["서울","대구","부산"]
display:
서울 -> 대구 -> 부산

원하는 collection형태를 디스플이를 할때 구분자를 이어주고, 마지막에는 구분자가를 사용하지 않는 너무나 자주 쓰는 디스플레이 방법중의 하나이다.

freemarker로 우리는 편하게 할수 있다.
다음 코드를 보자.

<#list travel.pathList as path>
${path} <#if path_has_next> -> </#if>
</#list>

너무나 편안하고 손쉽게 사용할 수도 있을 뿐더라 이해하기도 쉽다.

freemarker list, break
http://fmpp.sourceforge.net/freemarker/ref_directive_list.html
사실 매뉴얼에 너무나 자세히 잘 나와있다..^^
프로젝트 진행시 계획대로 순조롭게 잘 되어서 끝나면 가장 이상적이겠지만, 세상은 그리만만치 않다. 변수가 너무나 많기 때문이다.

모든 사람이, 모든 팀들이 stakeholder들이 솔직하고, 서로를 이해한다면, 더 좋은 결과를 얻을 수 있을 텐데, 세상은 그렇지 않다는 것이 아쉽다.

프로젝트 진행시 아마도 가장 큰 변수는 사람이 가지는 이기심이 아닐까 생각한다.

대표적인 것은 클래스의 멤버변수로 있는 Collection인터페이스이다.
어떤 책인지 기억이 잘 나지는 않지만, 이미 여러군데의 책에서 다룬 내용이기는 하다.

아래에서 다룰 내용은 추상화, 캡슐화에 대한 이야기다.

클래스에서 get을 써서 외부에 어떤 behvior나 자신의 상태를 expose를 할 때 주의를 해야 할 상황이기도 하다.

첫번째 코드

public class SimpleSet{

   private List<Simple> simpleList = new ArrayList<Simple>();
  
   public List<Simple> getSimpleList() {
       return simpleList ;
   }
}


위와 같은 코드의 문제점은 무엇인가? 우리가 쉽게 쓴 패턴이다. 하지만, 클라이언트 코드에서 simpleList의 레퍼런스를 받은 후 수많은 조작이 가능하다.

심지어 이런 코드도 가능하다.
simpleList.clear()

필요하다면 SimpleSet에 clear를 행위로 만들어줘야한다.
직접적인 호출은 수많은 버그들을 만들 가능성이 커진다. 의도하지 않는 곳에서의 조작으로 디버깅도 어렵게 만든다.

두번째 코드

public class SimpleSet{

   private List<Simple> simpleList = new ArrayList<Simple>();
  
   public List<Simple> getSimpleList() {
       return Collections.unmodifiableList(addedInfoList);
   }
}


위와 같은 코드의 문제점은 무엇인가? 리스트를 바꿀 수 없게 collection API는 위와 같은 proxy(decorator) pattern의 인터페이스를 제공한다. 이제는 외부에서 simpleList 를 readonly만 접근이 가능하다.

세번째 코드

public class SimpleSet{

   private List<Simple> simpleList = new ArrayList<Simple>();
  
   public Iterator<simple> iterator(){
       return this.simpleList .iterator();
   }
}

한번더 생각을 해보자. 외부로 제공할 때 iterator패턴으로 위와 같이 제공을 한다면, 어떨까? 내부에 collection의 인터페이스마져 숨길 수가 있다. 항상 리스트만이 내부적인 알고리즘이나 로직을 처리하기 위해서 최선이라고 얘기를 할수는 없다.

SimpleSet의 로직을 처리할 때 List보다 더 나은 자료구조가 생겼을 때 아주 쉽게 갈아탈수가 있다. 위와 같은 코드는 가장 추상화가 잘된 클래스이다.

사실 첫번째 코드가 아니라면, 두번째나 세번째 코드를 권장하고 가능한 세번째 코드를 이야기를 하고 싶다. 두번째 코드도 collection자체가 워낙에 유연해서 쉽게 만들수 있는 인터페이스이기 떄문이다. 물론, 출력자체를 iterator로 하는 거 자체에 많은 이점도 있기때문에 개발자가 심사숙고해서 선택할 expose 인터페이스이다.

하지만, 첫번째 코드를 사용하지 말자!!

참고문서
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html
우리는 자바 코딩을 하다가 보면, 아래와 같이 사용하는 경우 종종 있다.
public static final int SEASON_WINTER = 0;
public static final int SEASON_SPRING = 1;
public static final int SEASON_SUMMER = 2;
public static final int SEASON_FALL = 3;

이제는 enum클래스로 이것들을 깔금하게 정리를 하고, typesafe한 구현을 손쉽게 할수가 있다.
enum Season { WINTER, SPRING, SUMMER, FALL }

물론, switch문에서 사용이 가능하다.
아래 sun의 링크를 확인해보자.

http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

외부와의 연동 작업이 많은 어플리케이션 구축을 하다가 보면, 클라이언트 서비스가 다수 존재를 하게 된다. 우리 서비스 입장에서는 그들을 구별할 방법을 정리를 해야 한다.

string형태로 서비스 이름도 좋겠지만, 대부분 숫자상수로 그 서비스의 identity를 나타낸다. 그 서비스가 무엇이냐? 코드 내부적으로는 35, 36, ... 이런 숫자로 구별을 할 수가 있다. 아마도 자주 쓰는 표현 중의 하나일 것이다.

어디에서 동시등록을 한데?
어디에서 스크랩을 한데?

이 어디를 나타내는 그들의 이름이 되는 것이다. 이 alias이름을 행위마다 따로 가져가야 할까? 특별한(?) 경우를 빼고는 나는 적극 반대이다.

카페에서 동시등록을 할 때는 alias상수가 2가 되고, 카페에서 스크랩을 할 때는 20이 된다. 뭔가? 꺼름칙하지 않은가? 현실 세계에서 너무 동떨어져 보인다. 밥먹을 때는 주선이라고 부르고, 밥을 할 때에는 선주라고 부른다? 주선아 밥먹어, 선주야 밥해! 좀 이상하지 않은가?

구분이 필요해서라고 얘기를 한다면,
굳이 구분을 하고 싶으면, 두가지 행위의 경우에 2로 넘기면, 카페인 것을 알수가 있고, actionType을 넘겨서 어떤 행위를 하고 싶은지를 알아내는 것이 일반적인 생각일 것이다.

identity라는 것은 하나일 때 더 가치가 있는 것이지 많아질수록 더욱 복잡해질 것이다. 행위가 많아지만, 계속 다른 이름으로 그들을 부를 것인가 생각을 해봐야 한다.
정신을 차려야 한다.

BLOG main image
OOP and Java by ologist

공지사항

카테고리

All (649)
private!! (106)
WEB & IT (140)
Developer (400)