(loop (print (eval (read))))

;;닭집을 차리기 위한 여정

Spring aop example

guice가 참 좋은데.. 정말 좋은데

이런 어노테이션이 있다고 하자.

1
2
3
4
5
6
7
8
9
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorized {
Type to();
enum Type {
PUBLIC, ADMIN
}
}

이런 쥬스 모듈에 의해 바인딩되고,

1
2
3
4
5
6
7
8
public class AuthorizeModule extends AbstractModule {
@Override
protected void configure() {
AuthorizeInterceptor authorizeInterceptor = new AuthorizeInterceptor();
requestInjection(authorizeInterceptor);
bindInterceptor(Matchers.inSubpackage("com.foo.example"), Matchers.any(), authorizeInterceptor);
}
}

이런 인터셉터를 호출한다 ㅎㅎ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AuthorizeInterceptor implements MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AuthorizeInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Authorized authorized = invocation.getMethod().getAnnotation(Authorized.class);
if(authorized != null && authorized.to() == Authorized.Type.PUBLIC)
return invocation.proceed();
// FIXME: authorize! and delete below line.
logger.info("authorizing . . . ");
return invocation.proceed();
}
}

놀랍게도, 이게 다다. 아오.. 너무 좋다..

하지만 쥬스는 돈이 안 된다. 따라서 이걸 스프링으로 해 보자.

스프링에서의 aop

먼저 advice 를 만든다.

1
2
3
4
5
6
7
8
public class FooAdvice implements MethodBeforeAdvice {
private static final Logger LOGGER = LoggerFactory.getLogger(FooAdvice.class);
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
LOGGER.warn("Capitalism, ho!");
}
}

그 다음 pointcut 을 만든다.

1
2
3
4
5
6
7
8
9
@Bean
Pointcut pointcut(){
return new ComposablePointcut().union(
clazz -> clazz.getPackage().getName().equals("com.foo.example.controller") &&
clazz.getAnnotation(Controller.class) != null
).intersection(
new AnnotationMethodMatcher(FooAnnotation.class)
);
}

위에서 ComposablePointcut 이 쥬스에서 하던 바인딩과 유사하여 꽤나 쓸만하다. jdk8 과 만나 드디어 사람이 읽을 수 있는 표현이 되었다!!

다음 pointcut advisor 를 만든다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Bean
PointcutAdvisor pointcutAdvisor(){
return new DefaultPointcutAdvisor(pointcut(),advice());
}
```
위에서 만든 `pointcut` , `adivce` , `pointcut advisor` 는 반드시 다음 `DefaultAdvisorAutoProxyCreator` 를 통해야만 프록시가 생성된다.
```java
@Bean
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}

이렇게 하면 쥬스로 했던거랑 딱히 다를것도 없다. 우왕!

Best Practice

이번에 이직준비를 하면서 한 회사로부터 면접 주제를 받았는데 바로 저 베스트 프랙티스에 대한 PT 였다.
주제도 주제이고, 정장입고 하래서 바로 포기했음.
여튼 이것에 대해서는 사실 기존에 하던 생각이 있어서 오랫만에 글을 적어봄.

무얼위한?

사전적 의미로는 모범사례. 하지만 이 IT하는 바닥에서는 여기에 여러 의미가 덧칠해져 마치 어떤 사상이나 종교 비슷한게 되버린다.
예를 들어 뭔가 할때 그것은 spring-way- 하지 안항요 라던가 엔터프라이즈 규격에 맞게 해주세요 라는 식.
좀 더 노골적으로 말하면 어떤 무리 가 있고 그들의 생각은 시간은 없고 일은 간지나게 해야겠으니 복사 붙여넣기 하여도 문제 없을만한 코드 가 바로 베스트 프랙티스 정도가 되는거시다.

도입부가 논리비약이 아주 심한데 뭐, 재밌으니까 계속 가봄.

Guice vs Spring

유명한 DI 프레임워크로 스프링과 구글쥬스가 있다. 자 어떤게 Best Practice 인가?

Autowire vs Inject

위에서 스프링을 선택했다면 또 선택지가 두 개 생긴다. 자 @Autowire@Inject 어노테이션 중 무엇이 Best Practice 인가?
참고로 자바 표준은 @Inject 어노테이션이다.

XML vs Java Config

자 스프링을 선택했다면 또 선택지가 있다. xml로 applicationContext.xml 파일을 만들것인가? 하는것.
참고로 구글쥬스를 선택했다면 autowire 니 xml 이니 하는것을 고민할 필요가 없다. 없으니까. 10년도 더 전부터.

jdk proxy vs cglib proxy

jdk 프록시를 선택할 것이냐 아니면 cglib 프록시를 선택할 것이냐?
바꿔말해 interface 기반의 di를 할껀지? class 기반의 di를 할껀지?
또 바꿔말해 runtime 에 proxy를 생성할건지 아니면 거의- compile-time에 bytecode 조작을 통한 subclass를 만들건지?
다시말해 근본주의 노선인지? 아니면 실용주의 노선인지?

myBatis vs hibernate

단순하고 반복되는 코드를 패턴화해서, 유지보수까지는 바라지도 않고 개발중 정신이 혼미해지는거를 방지하는것은 좋다.
하지만 java -> orm 노선은 현실적인 문제 몇가지를 해결하지 못하고 있다..
반면 myBatis는 존내 딱 자기 역할만하는데 그걸 참 잘함.

java vs clojure

그래서 말인데, orm 중 clojure 의 sqlKorma 같은게 정말 좋아보인다. 그냥 java 말고 clojure 만 쓰거나 두개를 같이 쓰는것은 어떤가?

그래서, 그래서…

적어도, IT하는 바닥에서 어떤 진짜 사상 (예를들어 OOP 같은거) 을 좀더 잘 드러내기 위한 Best Practice 같은건 있을 수 있다.
하지만 대부분의 사람들이 그걸 원하는지는 별개 문제임.
자신이 바라는게 복붙 가능한 코드라면 사실은 Best Practice 의 반대를 바라는게 아닐까?