2013년 5월 27일 월요일

Time Period Library for JVM

기업용 솔루션을 만드는 경우 시간에 대한 계산이 참 많습니다.
특히, 일반적인 산술적 계산이 아니라 주말, 공휴일, 개인 휴가 (반차 포함), 팀 공가 등등을 고려한 작업 계획을 작성하려면 좀 복잡한 계산이 필요합니다.

이런 걸 일반적으로 Company Working Calendar 라고 하는데, 기간별 투입시간 등의 리소스 관리에 많은 기법이 동원됩니다.

예전 회사에서도 이 문제로 여러번에 걸쳐 발전시켰습니다만, 워낙 좋은 라이브러리가 있어서 이 넘의 forking 해서 사용했습니다.

원본 : Time Period Library for .NET

원본을 보면, 제가 원하는 기간 계산이나 최종일 계산등이 아주 구조적으로 할 수 있도록 구성되어 있습니다.

제가 여기에 몇가지 기능을 추가해서 사용했었는데요. .NET의 TPL 을 이용한 병렬 처리가 가장 기억에 남습니다.

올 1월에 scala 공부 겸 해서 scala 로 제작해 보자 해서 porting 을 수행하였습니다.

1. Time Period Library by Scala

뭐 Scala 로 제작했으니 JVM에서 돌구요. Scala의 Collection 지원과 여러가지 기능 (curry 등) 을 사용하였으니, scala 공부 시에는 도움이 될 듯 합니다.

문제는 제가 이넘 제작하다가 테스트 코드를 많이 못 만들어 버그가 많을 것이라는 것입니다^^

다음은 java 로 porting 한 소스입니다.

2. Time Period Library by Java

이넘은 debop4j 라이브러리 내에서 개발한 거라 debop4j-core 를 사용합니다.
기능은 위의 두 개와 같구요. java 코드라 좀 지저분하다는 점이 단점이지요^^

이 글을 빌어 원작자에게 감사드리며,  허락도 받지 않은 상태라 걱정도 되네요.

2013년 5월 22일 수요일

hibernate-ogm 을 이용한 검색서비스 개발

올 3월 갑작스레 맡게 된 검색 서비스 개발 업무를 어떻게 할까 고민하다가 그래도 내가 잘하는 방법대로 얼른 만들어보자^^ 하면서 검색 관련 정보를 수집했습니다.

1. hibernate-search + lucene 를 사용한다.
2. 한글형태소 분석기가 있어야 한다.
3. 한글형태소 분석기의 품질은 사전이 정의한다.

라는 몇가지 룰과 정보를 얻었습니다...
검색 품질을 생각하지 않는다면 n-gram 을 사용하는 CJKAnalyzer 를 사용해도 됩니다만... 이 놈은 마지막 쵸이스로 놓고, 대강 hibernate-search 와 lucene 을 이용하여 개발했습니다...

몇가지 새로운 사실도 알아내고, 성능을 높힐 수 있었지만, 좀 더 욕심을 내서 다음과 같은 작업을 더 수행했습니다.
hibernate-search가 Index 정보를 sharding 할 수도 있더군요. 비동기 방식으로 index 작업할 수도 있구요.

1. hibernate-ogm 을 사용해보자. - MongoDB를 저장소로 사용한다.
2. 한글형태소 분석기를 써보자 (이수명씨 것을 기본으로 몇가지 수정 및 추가)

위 두 가지를 성공적으로 적용했습니다.

간단하게나마 발표자료로 만들었습니다.




다음에는 hibernate-ogm 자체에 대한 글을 써 볼까 합니다.

2013년 5월 19일 일요일

PostgreSQL 관련 추천 자료

PostgreSQL 을 공부하다보니, 한글 자료 및 국내 사례는 거의 없네요^^ 그래도 미국, 유럽, 일본에서는 상당히 많은 적용사례가 있고,  제게는 기능 상 MySQL 보다 더 매력적으로 다가오네요.

몇가지 PostgreSQL 관련 자료를 정리해 봅니다.


  1. 한눈에 살펴보는 PostgreSQL
  2. PostgreSQL 용 유용한 Extensions 
  3. pgpool-ii tutorial ( connection pool, load balancing, replication 제공)
  4. hstore 란?  
  5. hstore for java, java-hstore-sample ( key-value for PostgreSQL)
  6. pgmemcache Setup and Usage (memcache 를 이용한 캐시)
  7. PostreSQL 9.0 streaming replication + pgpool-ii


특히 제게는 PostgreSQL 자체의 많은 기능도 좋지만, pgpool-ii 같이 좋은 load balancing 이 있다는 것과 엄청난 extensions 들이 굳이 상용을 쓸 필요 있을까 싶네요^^

2013년 5월 7일 화요일

Spring framework 에서 static field에 injection 하기

Spring 전문가라면 모두 아시리라 믿습니다만, 전 .NET 에서 Castle.Windsor 를 주로 이용하여 Spring 이 좀 낫섭니다. 특히 static field 나 class 에 대한 정보가 별로 없더군요.

물론 제가 아직 Spring에 대한 내공이 부족하기도 하고, .NET의 Extension Methods 를 자주 사용하다보니 static class 를 습관적으로 많이 써서 생기는 문제일 수 있습니다. (이거 좋은 습관은 아닌데...) 
어쨌든 기존 소스 중에 Singleton으로 써야 하고, static field 를 가진 클래스에 대해 injection을 수행해야 하는 것이 있었습니다.  다음과 같은 Class 가 있었습니다.

UnitOfWorks.java



UnitOfWorks 는 static field로 UnitOfWorkFactory를 가지고 있습니다. 이 필드를 Spring 이 injection을 할 수 있도록 해주고 싶었습니다.

xml 에서 작업하려면 MethodInvokingFactoryBean 을 이용하여 static method 를 호출하면 됩니다.

application-context.xml


xml 에서도 되는데 java configuration에서도 되겠지요?
그래서 구글링을 했더니 다행히, 몇번만에 해답을 찾았습니다.
원문: Spring annotations static injection tutorial
이 문서를 보고, 핵심은 원하는 클래스를 @Component로 지정하여 Spring Container에서 관리하도록하고, injection을 수행하도록 @Autowired를 지정하면 됩니다.

새로운 UnitOfWorks.java


UnitOfWorks 클래스는 @Component로 지정하고, @Autowired 해야 할 메소드는 static 이 아닌 instance method로 변경한 것으로 끝났다^^

마지막으로 Spring java configuration 에서 위의 UnitOfWorks를 ComponentScan 으로 등록해주면 됩니다.

StaticInjectionConfig.java



ComponentScan에서 UnitOfWorks class 를 지정해서 Component로 등록하게 하면, Bean으로 등록된 UnitOfWorkFactory가 injection이 됩니다^^
이로서 static field에 대해서도 java configuration에서 설정할 수 있게 되었습니다.
흠... Spring 에 대해 좀 더 공부해야겠네요...

2013년 5월 3일 금요일

Hibernate Criteria 의 장점

ORM의 대표격인 Hibernate 는 여러가지 장점 중에서도 질의어에 대한 지원 방식 풍부하다는 점이다.


  1. Criteria
    • 프로그램 언어로 빌더 패턴을 차용한 방식으로 질의를 빌드합니다.
    • 사용자 정의의 Criteria 를 정의하여 사용할 수 있습니다.
    • Criteria 를 실제 SQL 문으로 변환하는데 비용이 드는 단점이 있습니다.
  2. HQL (Hibernate Query Language)
    • hibernate 고유의 질의어입니다. 
    • SQL 표준 문법과 유사하지만 새로 배워야 합니다.
    • 변환에 드는 비용이 한번만 있고, 캐시하여 사용하므로 성능 상 유리합니다.
  3. SQL String
    • 기존 표준 문법이므로 장단점이 따로 없습니다.
    • ORM 에서도 그냥 사용해도 된다는 점

이 있다.

SQL 에 익숙한 개발자들은 Criteria 의 가능성 및 효용성에 대해 느껴보지 못하고, 과소평가하는 경우가 많은데, 이 때 제가 아주 간단한 과제를 통해, Criteria 의 장점을 체험하게 합니다.

간단한 과제:  작업 기간에 대해 검색 조건으로 시작시각과 완료시각을 입력 받아 겹치는 기간에 있는 작업 정보를 조회하는 SQL 쿼리를 작성해 보시오.

위의 과제를 주면 99.9% 다 틀립니다. 0.1% 해결한다 하더라도, 너무 복잡해 다른 사람들은 사용하기에도 힘들 것입니다.

위 문제의 첫번째 난관은 기간에 해당하는  시작시각과 완료시각이 nullable 임을 인지하는 것입니다. 두 번째는 검색하고자하는 시작시각과 완료시각도 nullable 일 수 있다는 것입니다. 그럼 이런 조건 하에서 검색을 위한 질의어를 만드는데 경우의 수는 몇이나 될까요?
간단하게 2*2*2*2 = 2^4 이죠?
뭐 중딩 1차원 그래프까지 그려가면서 설명할 필요 없겠죠?
이걸 SQL 쿼리문으로 나타내라구요?

뭐 할 수는 있겠지요... 다만, 차라리 Criteria 라는 좋은 방식이 있으니 그걸 이용해 보라는 겁니다.

결론부터 말하면 다음과 같이 구현하면 됩니다.
OverlapCriteria

뭐 null 값인지 검사해서 알맞은 메소드를 호출하면 되네요^^
헐... 근데 내부에 보니 Between 과 InRange 라는 연산자를 사용하네요... 이건 뭐죠?

Between (일반적인 쿼리문에서는 A <= X <= B 이다. 경계값을 포함하는 closed 이다)

InRange 는 Between 과 대상과 검사 값이 반대일 뿐이다.


자 이제 Criteria 가 SQL 문보다 논리적으로 쉽게 구현되는지 알겠는가?
SQL문을 먼저 배웠다고, 좀 더 익숙하다고 그게 진리는 아닙니다.
java가 되었건, csharp 이 되었건, scala 가 되었건 익숙한 것보다 유용하게 표현할 수 있는 방식이 있다면 그게 진리입니다.


2013년 5월 2일 목요일

redis 를 hibernate 2nd cache 로 사용하기 - part 2


hibernate-redis 제작 - part 1
hibernate-redis 제작 - part 2


redis 가 캐시 시스템으로 사용하기 좋다는 것은 여러 사례에서 알 수 있고, SNS 같은 경우에는 Timeline 정보를 캐싱하는데 자주 사용하지요.

이런 redis 를 hibernate 의 2nd cache  저장소로 사용하면 좋겠다고 생각해서, hibernate-redis 를 제작했습니다.

첫번째 버전은 제가 Redis에 대해 잘 몰라, 그냥 Spring Data Redis 를 사용하여, 구현했습니다.
개발하다보니 Jedis 만을 사용하여 개발하는 것이 더 가볍게 개발 할 수 있을 것 같아, Spring Data Redis 를 걷어내고, Jedis 만을 사용하여 개발했습니다.

hibernate-redis 는 현재 0.9.0 이고, 단위 테스트를 통과한 상태입니다.
아직 실전 테스트가 남아 있습니다^^

이번 글에서는 일반적인 캐시로서 Redis를 이용할 때, 직접 jedis 를 사용할 수도 있지만,  좀 더 쉽게 만든 JedisClient 에 대해 소개하기로 하겠습니다.

JedisClient.java


JedisClient 를 굳이 따로 만든 이유는 JedisPool 사용과 Transactional 작업이 반복적인 코드라 Jedis 만 사용하게되면 코드가 많아질까봐 Spring Data Redis 와 유사하게 만들었습니다.

물론 Jedis 의 모든 메소드를 지원하지는 않습니다. 캐시로 사용할 때 필요한 기능만을 구현했습니다.

이를 바탕으로 일반 저장소로 사용 가능하도록 확장할 수 있을겁니다.
특히 ShardedJedis 를 사용하려면, 다른 방법을 사용해야 합니다. 이 방식은 대용량 캐시나 저장소로 사용할 때 고려해 봐야 겠습니다.

참고로 JedisPool 설정 정보도 도움이 될겁니다.