Back End/유지보수

커스텀 어노테이션을 직접만들어 개발비용을 줄여보자!

DevPing9_ 2023. 3. 26. 16:26

 

 

개인적인 주관이 섞여있는 포스팅으로 정답은 아닙니다.
범용적이고 관례적인 어노테이션은 동료개발자와 협업에 유리한 이점이 있다는 것 고려하시며 Trade-off 를 저울질 해보시길 바랍니다.
커스텀 어노테이션을 동료개발자와 충분한 협의 없이 사용 시 유지보수비용이 증가하게 됩니다.

 

 

필자가 불편했던 어노테이션들


대표적으로 @PreAuthorize, @Sql, @RequestMapping 등과 같이 String 값을 반복적으로 넣어주어야 하는 어노테이션들이 매우 불편하게 느껴졌다. 사용빈도는 꽤 큰 것에 비해, IDE 자동완성 기능 이후 따로 String 값을 지정해주어야 하는 두번의 작업으로 느껴졌다.

 

@GetMapping("/product/vip")
@PreAuthorize("hasRole('ROLE_VIP')")
fun productsForVip() {
	return "This is the product for Vip."
}
@RestController
@RequestMapping("/api/user")
class UserApi {
}
@Sql(
    value = [
        "classpath:db/user.sql",
        "classpath:db/product.sql",
        "classpath:db/product_detail.sql",
        "classpath:db/order_history.sql",
    ]
)
class OrderAcceptanceTest{
}

 

위의 3가지 예시코드가 대표적이다.

 

새로운 API 를 작성할때마다 붙여야하는 @RequestMapping, @PreAuthorize 정도는 귀엽게 볼 수 있다.

가독성도 나쁘지 않다. 그저 매번 작성해야 한다는 귀찮음뿐...

 

하지만 테스트코드를 작성할때마다 포함되는 @Sql 은 정말 지독하다.

포함되는 파일갯수가 많을 수록, 가독성이 좋지 않아도 너무 좋지 않다.

 

 

예쁘게 변신한 어노테이션들


기능 변경은 없다. 

그저 반복적인 작업을 덜어내고 가독성을 더 좋게 만들고 싶었을뿐...

하지만 동료개발자와 협의 없이 이런 어노테이션들이 프로젝트에 범벅이 된다면 정말 크게 혼나야 한다.

 

@GetMapping("/product/vip")
@HasRoleVip
fun productsForVip() {
	return "This is the product for Vip."
}

@GetMapping("/product/public")
@HasNoRole
fun productsForVip() {
	return "This is the product for public accsess."
}

@GetMapping("/product/common")
@HasRoleUser
fun productsForVip() {
	return "This is the product for common user."
}
@InsertUser
@InsertProductRelated
@InsertOrderHistory
class OrderAcceptanceTest{
    @Test
    fun test1(){}
}

 

 

커스텀 어노테이션 만들기


거창한 커스텀 어노테이션을 만드는 법이 아니라, 기존 기능을 그대로 가져오면서 이름만 바꾼다.

@Inherited 를 사용한다.

 

@Sql(
    value = [
        "classpath:db/user.sql",
    ]
)
@Inherited
annotation class InsertUser
@Sql(
    value = [
        "classpath:db/product.sql",
        "classpath:db/product_detail.sql",
    ]
)
@Inherited
annotation class InsertProductRelated
@Inherited
annotation class HasNoRole

@PreAuthorize("hasRole('ROLE_VIP')")
@Inherited
annotation class HasRoleVip

@PreAuthorize("hasRole('ROLE_USER')")
@Inherited
annotation class HasRoleUser

 

 

 

 

 

 

728x90