객체지향 어떻게 하는건데 는 객체 지향 프로그래밍 패러다임에 대해 공부한 내용과 멘토님께 들은 내용에 대해 고민하며, 생각을 정리한 글이다.
간단히 요약하면 다음과 같다.
이번 포스트에선 공부를 진행하며 느낀 너무 매몰되지 말자 와 KISS, YAGNI 원칙에 대한 생각을 정리해볼까 한다.
Spring framework 연습 프로젝트 는 간단한 게시판 서비스이며 게시글과 댓글의 CRUD가 주 기능이다. 진행하며 몇가지 고민을 했는데, 그 중 한가지를 주제로 글을 써보려 한다.
Post, Comment 등 Member 가 작성한 모든 것들을 annotation 기반으로 처리하면 좋지 않을까?
예를 들어, @OwnerOnly 어노테이션을 만들고, AOP를 통해 구현한다면 생산성 및 코드의 재사용성이 향상될 것 같았다.
public void deleteComment(Comment comment) {
if (isOwner(comment)) {
Comment mergedComment = entityManager.merge(comment);
commentRepository.delete(mergedComment);
}
}
@Transactional(readOnly = true)
public boolean isOwner(Comment comment) {
Member member = loginService.getLoggedInMember();
if (comment.getMember() != member) {
throw new UnAuthorizationException();
}
return true;
}
구현은 다음과 같다. entity의 주인인지 체크하는 메서드가 각각의 Service에 존재한다. 해당 메소드를 직접 호출하며, 새로운 entity와 처리 로직이 추가될 때마다 동일한 로직을 반복하여 작성해야 한다.
만약 어노테이션 기반으로 변경된다면 어떻게 될까?
@OwnerOnly(Comment.class)
public void deleteComment(Comment comment) {
Comment mergedComment = entityManager.merge(comment);
commentRepository.delete(mergedComment);
}
위와 같이 주인 체크 라는 공통 관심사를 비즈니스 로직에서 제거할 수 있게 되었다.
추후 동일한 로직 발생 시, 어노테이션만 붙이면 해결된다니!

@Before("@annotation(hello.hellospring.common.annotation.OwnerOnly)&& args(.., comment)")
public void checkOwnership(Comment comment) {
Member member = loginService.getLoggedInMember();
if (member != comment.getMember()) {
throw new UnAuthorizationException();
}
}
다만, 처리할 클래스에 대한 로직을 각각 적어줘야 하는 불편함이 또 발생한다. 새로운 entity가 추가될 시 AOP 클래스에 변경이 발생해야 하는 것이다.
이러한 문제는 전략 패턴 등을 도입해 충분히 해결할 수 있다고 생각한다.
글을 시작할 때 위 프로젝트는 Spring framework 연습 프로젝트 라고 명시했다. 프로그램 규모 또한 굉장히 작으며, 새로운 entity의 추가가 일어날 확률이 현저히 적다.
사용자가 작성하는 Entity가 Post, Comment 두가지만 존재하는 상황에서 매우 낮은 확률의 확장 가능성을 생각하여 추상 계층을 만들고, AOP를 적용하는 것은 합리적인 프로그래밍일까?
이러한 Over Engineering이 과거부터 현재까지 존재했음을 증명하는 개발 원칙들이 있다.
Keep it short and simple.
- 짧고 단순하게 하라.
You aren't gonna need it
- 필요하지 않을 것이다.
두 개발 원칙이 의미하는 바는 다음과 같다.
- 불필요한 코드를 경계하고 되도록 단순하게 설계하라.
- 미래에 사용될 것으로 예측되는 기능을 추가하지 말고, 현재 필요한 것만 개발하라.
두 원칙에 의거하면, 위에서 작성한 프로그램은 좋지 않을 것이다.
불확실한 확장에 대비하여 복잡성을 늘렸으며, 그만큼 더 많은 시간을 개발에 투자했다는 것이다.
스타트업에서 6개월간 인턴을 진행하며 느낀점은 빠듯한 개발 일정과, 그에 맞춰 구현 위주의 개발이 필연적으로 발생할 수 밖에 없다는 것이었다.
처음 겪어본 회사 생활이라, 이게 일반적인지는 아직도 모르지만 함께 일하고 싶은 사람 에서 관련된 내용을 볼 수 있었다.
초기 서비스는 기능 하나가 나오고, 안 나오고가 고객의 유입과 이탈, 투자유치의 성패를 결정하곤 합니다.
해당 포스트엔 적절한 수준의 엔지니어링을 할 수 있는 사람 이라는 파트가 존재한다.
빠르게 개발한 기능 하나가 서비스의 존망을 결정하는데, 이런 상황에서 좋은 아키텍처, 확장성을 최대로 고려한 객체 지향적 설계를 지향하는 것은 과연 옳은 것일까?
적절한 엔지니어링. 그게 무엇인지 아직까진 잘 모르겠지만, 이러한 문제에 대해 탐구하며 자신만의 답을 찾아 나가는 과정이 좋은 개발자로 성장하는 길이 아닐까..! 라고 조심스럽게 생각해본다.
객체 지향 프로그래밍에 대해 처음 접했을 땐 그저 어려웠다.
처음 이해가기 시작했을 땐 재밌었고, 튼튼하게 설계된 다른 사람들의 완성된 프로젝트를 보며 "나도 저렇게 만들 수 있을까" 라는 걱정부터 앞섰던 것 같다.
이번 글을 작성하며 많은 고민을 하게 된 것 같다.
"잘" 만드는 것
다른 사람이 작성한 프로젝트는 대부분 "잘" 만들어져 있었다. 그렇기에 "잘" 만들어야 한다는 막연한 두려움이 더 크게 느껴졌던 것 같다.
잘 만들어진 프로젝트는 과연 처음부터 완벽하게 설계되었을까? 이제와서 생각해보면 그렇지 않을 것이라 생각한다. 적절한 수준의 엔지니어링을 반복하며, 결국 거대한 서비스가 만들어지지 않았을까!
