호주에 살고 있는 소프트웨어 개발자입니다. 30년간 다양한 분야의 시스템과 서비스를 개발해본 경험이 있습니다.
스프링 프레임워크와 관련 기술을 좋아하고 JVM 기반 언어를 주로 사용합니다.
한국스프링사용자모임(KSUG)을 설립하고 활동했고, 토비의 스프링이라는 책을 쓰기도 했습니다.
개발과 관련된 다양한 주제에 관해 이야기하는 것을 좋아합니다.
강의
수강평
- [밋업 Vod] 31년차 개발자가 전하는 "AI시대, 개발자로 살아가는 법"
- 토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
- 토비의 스프링 부트 - 이해와 원리
게시글
질문&답변
애그리거트 루트의 하위 도메인들의 depth가 깊어질 때 문의
좋은 질문을 해주셨네요. 이렇게 위임을 여러 단계에 걸쳐서 하는 듯한 코드를 보면 뭔가 잘못된 것 같다는 생각이 들기도 합니다. 그래서 불필요한 중간자를 줄이는 리팩터링도 있죠.하지만 얼핏 복잡해 보이는 이런 구조를 선택한 이유가 있고, 이게 뭔가 더 단순한 접근이 나을 것 같아 보이지만 여러 관점으로 따져봤을때 이 정도의 복잡함은 감수할만한 트레이드 오프가 있다고 생각이 됩니다. 우리가 쓰는 대부분의 클래스 라이브러리들은 앞에서 보기엔 간단한 인터페이스나 대표 클래스들의 메소드를 사용하면 됩니다. 하지만 내부 구조를 보면 꽤 여러 단계로 다른 오브젝트에게 작업을 위임하는 경우가 많습니다. 스프링은 말할 것도 없고, 많이 쓰이는 유틸리티 클래스나 자바 JDK의 라이브러리들도 마찬가지죠. 여러 오브젝트가 협력해서 일을 하다보면 이렇게 여러 단계에 걸쳐서 위임을 하는 경우가 종종 있습니다. 사실 이건 우리가 만드는 백엔드 소프트웨어 자체도 그렇지 않을까요? 뭔가 간단한 업데이트를 하는데 왜 API를 JSON으로 던져서 그걸 앞에 웹 서버와 프레임워크가 여러 처리를 하고 컨트롤러를 거쳐서 서비스와 도메인 오브젝트 리포지토리, ORM에 JDBC 등등을 타고 최종 SQL이 되어서 또 DB로 전달되자나요. 굳이 설명 드리지 않아도 왜 그런 여러 단계를 거쳐서 클라이언트/프론트가 간단한 정보 하나를 변경하는 작업을 하도록 만들었는지는 이해하실 겁니다.애그리거트의 특징은 변경될 때 같이 변경될 가능성이 높다는 것이죠. 그래서 하나의 트랜잭션으로 묶여야 하고, 그리고 변경과 관련된 로직이 애그리거트 내의 여러 엔티티나 값 객체가 서로 협력해서 책임을 맡아서 진행하게 됩니다. 그러면서 외부에서 볼 때는 루트 하나만 존재한다고 보고 사용할 수 있게 하는 것이죠.프로필 조회와 변경이 독립적이고, 아주 자주 일어나고, 그때 다른 조건이 없다고 하면 프로필 엔티티를 애그리거트 밖으로 빼도 됩니다. 그 자체로 하나의 애그리거트 루트가 될 수 있는 거죠. 그런데 당장 프로필 변경을 할 때는 회원의 상태가 ACTIVE이어야 한다라는 조건이 붙었다고 생각해보죠. 애그리거트를 안 쓰면, 아마도 서비스에서 회원 기본 엔티티 가져와서 상태 체크하고, 그리고 다시 프로필 엔티티 조회해서 변경하고 저장하는 기능을 만들겠죠. 프로필 변경을 독립적으로 구성되는 순간, 어떤 개발자가 프로필 변경과 관련된 새로운 방식의 기능을 추가하게 됐을 때 서비스에서 그냥 프로필 가져와서 변경해버릴 수도 있습니다. 회원 상태 체크와 상관없이요. 그 순간 도메인의 일관성이 깨지고, 일종의 논리적인 버그가 들어가죠. 그게 나중에 결과만 발견되어서 어디서 이런 문제가 발생했는지 확인하려면 꽤 어려운 작업을 해야 합니다. 결국 프로필을 수정하고 그걸 체크하는 코드가 사방에 여러 방식으로 중복되는 걸 볼 수도 있겠죠.그런 차원에서 애그리거트가 주는 효용성이 있습니다. 물론 프로필 수정 자체는 워낙 간단한 거라 굳이라고 생각할 수도 있겠죠. 사실 도메인 모델에서 말하는 애그리거트 패턴은 꽤나 복잡한 도메인에서 더 유효할 겁니다. 우선은 강의에서 회원 등록과 관련된 단순한 예제를 써서 이런 구성을 해서 그런 장점이 크게 보이지 않겠지만, 이런 구성을 선택하는 것이 앞으로 더 복잡한 모델과 도메인 구조에서는 매우 유용할 수도 있습니다. 또, 회원 정보 업데이트할 때 한번에 여러 개의 정보가 같이 변경된다는 도메인 모델의 규칙도 있었죠. 그런 걸 지키는 것도 만들 수 있고요. 물론 단순히 조회활 때는 애그리거트 내부트의 엔티티를 노출해도 좋다고 생각합니다. 단, 이때는 그 엔티티를 읽기 전용이라고 생각하고 다뤄야 하겠죠.그런데 이런 장점을 취하려면 또 놓치게 되는 불편함도 분명 있습니다. 무엇인가를 선택하면 어떤 다른 것은 손해를 보게 되는 상황을 트레이드 오프라고 합니다. 무조건 모든 게 다 좋은 설계는 없어요. 그래서 매번 트레이드 오프를 하게 됩니다. 저는 여기서 멤버와 디테일을 분리하는 것이 그냥 멤버 하나에 다 속성을 넣는 것을 포기하기 때문에 손해보는 것을 넘어서 더 많은 장점이 있을 거라고 보고 트레이드 오프를 한 것입니다. 프로필에 대해서도 마찬가지 일 거에요. 어떤 경우엔 위에서 언급한 대로 프로필을 독립된 애그리거트로 분리하는 것이 나을 수도 있습니다. 그런 경우가 어떨 때일지 한번 생각해보세요. 시스템이 사용되는 시나리오와 헥사곤이 받게 되는 요청, 의도 등을 잘 정리해보면 어떨 때는 하나로 할지, 어떨 때는 분리하는 것이 나을지가 달라질 겁니다. 시스템이 성장하면서 설계는 계속 발전하고 변경 될 거라서, 스프런도 앞으로 애그리거트 구조가 달라질 수도 있어요.
- 0
- 2
- 39
질문&답변
페이징 처리를 해야한다면 어떻게 해야할까요?
안녕하세요."spring-data에서 제공하는 것들이라 컨트롤러나 애플리케이션(서비스)에서 사용하면 안 될 것 같아서" 라고 하셨는데요. 왜 안 되는 거라고 생각하셨나요?혹시 Spring Data 프로젝트를 사용하지 않게 되면, 그때 Pageable과 같은 인터페이스도 쓸 수 없다고 생각하시는 것인지요? 저는 세 가지 이유로 그냥 사용하시라고 말씀드리고 싶습니다.스프링 기반의 애플리케이션을 개발하시면서 알려진 대부분의 저장 기술을 사용하신다면 Spring Data 프로젝트만한 좋은 도구는 없다고 생각합니다. 그 안에서 RDB와 NoSQL도 바꿔서 사용할 수도 있고, DB 종류도 당연히 제한없이 변경 가능하죠. Pageable 같이 특정 데이터 기술(예를 들어 JPA)에 의존하지 않은 공통 기능으로 제공되는 것은 데이터 기술의 변경에도 영향을 받지 않고 동일하게 사용할 수 있도록 설계되고 구현되어 있습니다. 페이징 방식을 적용하신다면요. 두 번째로 설령 스프링을 안 쓰고 완전 다른 기술로 대체하신다면, 그때도 Pagaeble을 그냥 기술에 의존성이 없는 인터페이스로 사용하시면 됩니다. Pageable을 쓰면서 그 인터페이스를 구현한 클래스는 직접 정의해서 쓰거나 다른 기술에 맞게 개발하도 됩니다. Pageable 자체는 그게 정의된 패키지 이름을 제외하면 스프링 기술에 전혀 의존하지 않습니다. 잘 정의된 인터페이스를 쓰기 위한 라이브러리로 spring data commons를 추가해서 쓰거나, 인터페이스 파일 하나만 뽑아서 계속 쓰셔도 상관없습니다. Spring Data 프로젝트에 정의되어 있다고 이게 스프링이나 스프링 데이터 기술을 풀로 쓰지 않으면 사용할 수 없다는 것은 사실이 아닙니다. 애노테이션도 그 자체로 어떤 기본 구현을 사용하겠다는 선언으로 본다면, 이 애노테이션을 단순한 각주로 남겨둬도 되고, 그걸 사용하는 인터셉터나 스프링 MVC 확장 기능을 만들어 쓰셔도 되죠. 그러니까 Spring Data를 설령 안 쓰게 된다고 해도 Pageable과 같은 인터페이스는 그대로 사용하실 수 있습니다.그리고 데이터 처리와 관련된 라이브러리인데 이걸 웹 쪽에서 사용해도 되는가라는 생각을 하실 수도 있는데요. 이것도 아무 상관이 없습니다. 이 인터페이스와 이걸 사용하는 스프링MVC 코드에는 어디서도 스프링 데이터에 의존해서 동작하는 기능이 들어가지 않습니다. 설령 들어간다고 하더라도 이게 개발자의 코드에 의존성을 부여하지 않습니다. 보통 프레임워크는 특정 레이어에 종속된다고 생각하실 필요가 없습니다. 개발자가 작성하는 코드가 특정 구현에 의존해서 환경이나 기술에 종속되는 코드로 만들어지지 않는다면 상관없다는 것이죠. 그래서 프레임워크는 여러 계층에 걸쳐서 기반이 되는 베이스로 동작한다고 봐도 됩니다. 특정 패키지 이름이 코드에 들어가는 것으로 해당 코드가 특정 기술에 의존하는 것은 아닙니다. 이걸 억지로 피하려고 또 추상화를 해서 한 단계 인터페이스를 더 위에 만든다고 했을 때 얻게 되는 유익이 제가 보기엔 거의 없습니다. 그러니 편하게 Pageable을 사용하세요. 그렇게 추가한 코드가 테스트를 만들기 어렵게 한다거나(웹 컨트롤러만 단위 테스트 하는데 DB까지 동작해야 한다 같은 일이 강제되지 않는다면요), 특정 기술을 위한 환경에서만 실행시킬 수 있는게 아니라면 아무 문제 없습니다. 두 번째 질문 @HttpExchange 질문은 제가 잘 이해를 못하겠네요. 조금 풀어서, 코드와 함께 질문해주시면 다시 답변 드리겠습니다.
- 0
- 2
- 67
질문&답변
11강에서 cmd에서 spring shell에 $ init 하면 Fail 메세지
안녕하세요. 에러 메시지를 봐서는 일시적인 서버의 인증서 또는 보안 프로토콜 문제로 보입니다. 저는 잘 연결이 되는데요. 다시 해보시고 갈은 문제가 계속 반복되는지 확인해보고 알려주세요. 터미널의 springboot 명령 외에도 프로젝트를 생성하는 다양한 방법이 있으니 다른 방식으로 접근하셔도 됩니다.
- 0
- 2
- 27
질문&답변
애그리거트의 repository
애그리거트는 이상적으로 보이지만 실제 설계하기란 쉽지 않습니다. 고려할 점도 많고, 절대적인 정답이 있는 것도 아닙니다. 항상 여러가지 트레이드 오프가 따르게 됩니다. 만약 이 둘을 에그리거트로 묶고 A를 루트로 결정했다면 리포지토리는 A에 대해서만 있어야 합니다. B는 A가 어떤 식으로든 로딩될 때 그때 같이 올라오도록 조인이 되거나 탐색이 되게 만듭니다. 따라서 B 리포지토리는 필요하지 않습니다. 애그리거트라면 생명주기도 일치해야 하니 A와 B는 같이 등록되고, 수정되고, 삭제될 겁니다. 항상 같은 트랜잭션 안에서 변경이 일어나죠. JPA의 cascading과 각종 페칭 전략만 적용해 놓으면 B 리포지토리가 존재할 이유가 없습니다.애그리거트 내부의 엔티티는 루트를 통해서만 접근하게 되고, 다른 엔티티와 직접 연결되지 않으며, 따로 조회되지도 않아야 합니다.이렇게 사용하는 것이 원칙입니다. 하지만 현실적으로 성능이나 기타 필요에 의해서, 특히 어드민이나 데이터 분석쪽의 조회 때문에 B 엔티티를 직접 조회할 필요도 있습니다. 단순 조회만 있고 이후 변경이 일어나지 않는다면 이건 애그리거트 관점에서 조금 예외로 둬도 괜찮습니다. 그런 경우라면 B는 특별한 조회 로직을 가질 뿐이니 굳이 CRUD를 다 지원하는 리포지토리로 만들 필요는 없고, A 리포지토리 안에 B에 대한 조회 메소드를 하나 추가해두면 됩니다. 그런데 애플리케이션이 발전하다보면 A와 B가 다른 트랜잭션으로 쪼개지거나, B가 직접 다른 엔티티와 관계를 맺어야 자연스러운 경우가 발생할 수도 있습니다. 이때는 어쩔 수 없이 A, B를 각각 다른 애그리거트로 쪼개면 됩니다. 이건 도메인 중심의 개발을 할 때 개발이 진행되면서 자연스럽게 일어나기도 하는 일입니다. A가 루트이고 항상 A를 통해서 B에 접근한다면 B의 @ManyToOne은 제거할 수도 있습니다. 그러면 A의 컬렉션이 오너십을 가지는 구조로 매핑 설정을 하게 됩니다. B의 추가도 당연히 A를 통해서 일어나야겠죠. 아마 파트2에서는 이런 구조의 애그리거트 예가 등장할 겁니다. 그때 좀 더 자세한 설명을 해볼게요.
- 0
- 2
- 50
질문&답변
Domain Expert가 정확히 어떤 역할을 하는 사람인가요?
안녕하세요.예전에는 소프트웨어를 개발해서 적용하는 업무 영역과 대상, 즉 도메인이 시스템을 개발하기 이전에 이미 존재했고, 비즈니스가 동작하던 경우가 대부분이었죠. 그 시절에는 보통 IT 부서 외의 실무 업무와 구조, 비즈니스를 잘 알고 있는 사람을 도메인 전문가라고 불렀습니다. 그런데 인터넷 기반의 비즈니스들이 등장하고 발전하면서 이제 소프트웨어 개발자들도 비즈니스에 대해서 처음부터 이해하고, 여러 업무와 의사 결정에 참여하기도 하면서 회사에서 일을 오래 해온 개발자가 도메인 전문가로서 충분한 지식을 가지고 있는 경우도 많이 있죠. 그 분들이 도메인 전문가로서의 역할도 해낼 수 있습니다. 아직 시작한지 얼마 안 된 스타트업의 경우도 마찬가지죠.그런데 도메인 중심의 소프트웨어 개발팀에서 도메인 전문가는 단순히 업무에 대한 지식과 경험이 많기만 해서는 안 됩니다. 도메인에 익숙하지 않은 개발자들과 적극적으로 소통하면서 자신의 경험과 지식을 도메인 모델로 만들어가는데 적극적으로 참여하고, 개발 기간 내내 꾸준한 협업을 지속할 수 있어야 합니다. 또, 보편 언어를 개발자들과 함께 "개발"해나가는 의지도 중요하죠. 원래 현장에서 쓰이던 언어를 그대로 가져오는 것이 보편 언어는 아닙니다. 도메인 모델을 만들고 발전시켜 가면서 모델에 사용되는 언어를 기존에 현업에서 정확하지 않은 의미로 사용해오던 것, 또는 기존에 없던 언어를 새롭게 개발할 수도 있어야 합니다. 그런 작업에도 적극적으로 참여할 수 있어야겠죠. 때로는 개발자들이 좋은 아이디어를 제시하고, 그게 도메인 모델의 보편언어가 되어 도메인 전문가들이 그걸 수용해서 소통하게 되기도 합니다. 결론적으로 질문하신 내용이 맞습니다. 온라인 서비스라면 도메인 자체가 기술로 만들어진 서비스 또는 시스템이기 때문에 그에 대한 이해를 가장 잘 하고 있고, 이걸 기반으로 개발자들과 소통하면서 도메인 모델을 발전시켜나가는 사람이라고 보시면 됩니다. 그런데 규모가 커지면 한 명이 모든 도메인의 영역을 다 자세히 알지 못하는 경우가 있습니다. 또, 현장에서는 업무 부서마다 유사하지만 다른 용어를 쓰기도 하고, 언어가 혼란스러워 지기도 합니다. 이 정도가 되면 좀 복잡한 전략이 필요할 때도 있습니다. 이걸 DDD에서는 전략 패턴이라고 말합니다. 실제로 규모가 큰 조직인 경우 도메인 모델은 하나 이상이 되고, 보편 언어도 그에 따라 여러개가 되기도 합니다. 이건 좀 고급 주제이긴한데, 어쨌든 그런 경우에도 도메인 전문가가 참여하는 것이 필요하겠죠.
- 0
- 1
- 61
질문&답변
28. 회원 애플리케이션... / 이메일 중복 검사를 도메인 서비스로 수행하는 방식에 대해서
말씀하신 대로 회원의 이메일은 중복되지 않는다는 도메인 지식을 인터페이스로 만들어 도메인 서비스로 정의하고, 메소드 호출 주입 방식을 써서 필요할 때 엔티티에 전달해서 생성 로직 과정중 검증 기능으 사용하게 만들 수 있습니다.이런 경우 도메인 규칙이 도메인 모델을 직접 반영한 코드에 더 명시적으로 드러나고 풍부한 모델로서 가치가 있습니다. 다만, 이번 강의에서는 제가 이메일 중복을 체크하는 것은 같은 도메인 로직을 담당하지만 도메인 계증 내부가 아닌 애플리케이션 서비스에 두는 방식을 선택했습니다. 우선 외부 자원을 이용하는 시스템에 의존해야 하고, 애플리케이션이 포트를 통해 제공하는 기능의 흐름에 절차적으로 들어가기에 적당하다고 생각을 했고요. 다른 도메인 로직에 비해 단순 조회를 이용한 검증 로직이라서 도메인 서비스까지 동원해서 작성할 필요가 있을까라고 생각을 했습니다. 물론 리포지토리를 이용해서 동작하는 기능이 내부에 들어갈 수 있다고 해서 도메인 서비스로 만들면 안 되는 것은 아닙니다. 복잡한 도메인 규칙, 예를 들어 포인트 정책이나 결제 한도 계산 등의 도메인 로직은 구현이 자주 바뀌고 다양한 외부 리소스에 의존할 가능성이 높지만, 이건 도메인 모델로 표현되는 핵심적인 기능이기 때문에 이런 경우엔 도메인 서비스로 만들어 사용할 것입니다. 이때 도메인 모델 내부에서 동작하는 코드가 런타임시에 외부 리소스까지 연결되기 때문에 발생하는 복잡성 보다 중요한 핵심 도메인 로직을 처리하는 코드이기 때문에 도메인 모델 내에 두고, 개발팀 내에서 소통하고 테스트로 검증하는 등의 작업이 더 가치를 줄 수 있기 때문에 그런 선택을 하게 되는 것이죠.제가 이번엔 그런 선택을 했지만, 만약 개발팀이 아직 도메인 서비스를 작성하는 것에 익숙하지 않고, 메소드 주입을 이용해서 도메인 서비스를 사용하면서 그 구현은 도메인 외부에 작성하는 방식의 접근 방법을 한번 손쉽게 적용하는 연습을 해본다면, 그때는 이메일 중복 체크를 위한 도메인 서비스를 따로 만들어 사용했을 것입니다. 이 접근 방법도 꽤 여러가지가 있습니다. 이어지는 강의에서 이에 대해서 여러가지 접근 방법을 한번 보여드리도록 할게요.
- 0
- 1
- 45
질문&답변
회원 애플리케이션 서비스 테스트 (1)
앗. 제가 코딩 영상을 편집하다가 getTos() 추가하는 부분을 잘못 삭제한 듯합니다. 14분 36초 부분을 보시면 getTos() 메소드가 있는 걸 보실 수 있습니다. 당연히 메소드가 있어야겠죠.(사진)
- 0
- 2
- 46
질문&답변
정적 팩토리 메서드 관련 질문드립니다!
네. 보통은 생성자를 통해서 한번에 인스턴스를 만드는 것이 완결성이 있어서 좋다고 여겨집니다. 저도 동의하고요.그런데 여기서 정적 팩토리 메소드를 사용하려고 했던 이유 중에는 생성자 파라미터가 길어지고 같은 타입의 파라미터가 연속으로 나올 때 순서가 잘못 되어서 버그가 생기는 문제를 피하기 위함도 있었습니다. 그런데 팩토리 메소드에서도 생성자를 호출하는 방식을 쓴다면 그 문제는 여전히 남아있겠죠.그래서 여기서는 마치 빌더패턴을 사용하듯이 하나씩 프로퍼티를 설정하는 방식을 사용해봤습니다. 팩토리 메소드도 일종의 생성자라고 생각한다면 그 안에서 완결성을 가지는 오브젝트를 초기화하는 코드를 넣는 것도 나쁘지 않겠다고 생각합니다. 물론 저도 익숙한 방법은 아니긴합니다. 생성자를 private으로 만들고, 팩토리 메소드를 단일 오브젝트 생성 구조로 만드는 경우라면 이 안에서 초기화와 검증까지 모두 완료할 수 있습니다. 더더욱 필드 이름과 파라미터로 전달된 오브젝트에서 꺼내는 값의 이름을 일치시키면서 코딩을 할 수 있기 때문에 나중에 생성 시점에 전달할 파라미터가 변경되거나 순서가 바뀔 때 실수할 확률이 줄어듭니다.final은 어짜피 JPA 엔티티이고 필드 액세스를 디폴트로 적용했기 때문에 쓸 수 없습니다. JPA 엔티티는 가변 객체로 선언해야 합니다. 사실 생성자를 써도 파라미터로 넘어온 값을 모두 필드에 할당하지 않을 수도 있습니다. 그러면 부분 초기화 문제가 발생하고요. 검증 누락도 마찬가지죠. 어디선가는 생성 로직을 완벽하게 구성해야 할 책임이 있습니다. 그걸 팩토리 메소드로 가져오는 것도 하나의 옵션으로 생각하시면 좋겠습니다. 물론 저도 생성자만 쓰기도 하고, 프로퍼티 갯수가 많지 않다면 생성자에 파라미터로 풀어서 전달하기도 합니다.
- 0
- 2
- 56
질문&답변
백오피스 개발에도 헥사고날 아키텍처가 유용할까요?
우선 헥사고날 아키텍처를 사용하는 것이 도메인 모델 패턴을 사용하거나 DDD 스타일의 패턴을 적용해야 하는 것은 아닙니다. 강의에서는 이 두가지를 결합해서 적용했지만, 순수하게 헥사고날 아키텍처 패턴만 따라서 개발하더라도 유익이 많습니다. 반복적인 CRUD가 많이 등장하는 데이터 처리 중심의 애플리케이션이더라도, 20%쯤에 해당하는 간단하지 않은 로직을 처리하는 코드는 테스트가 잘 작성되는 것이 중요할 겁니다. 백오피스라면 더더욱 버그 없이 작성된 코드를 만드는 것이 중요하고 그런 면에서 헥사고날 스타일로 작성해서 충실한 테스트를 만드는 것이 주는 장점이 많습니다. 그런데 요즘 스프링을 이용한 개발을 충실하게 하시면 사실 대부분 헥사고날 아키텍처에 거의 가깝게 개발하고 계실 겁니다. 스프링 데이터 JPA를 쓴다면 더더욱 그렇고요. 그렇다면 계층형 스타일과 다른 점은 크지 않습니다. 중요한 것은 서비스에 인터페이스를 반드시 정의하고, 어떤 의도로 어떤 기능을 사용하는지를 잘 담아두고요. 서비스 계층의 비즈니스 로직이 외부로 노출되지 않도록 주의하면 됩니다. 그리고 리포지토리를 비롯해 서비스에서 외부 시스템을 사용하는 코드도 인터페이스를 충실하게 작성하고 이를 서비스 모듈 안에 정의해두고, 어떤 환경에서는지 테스트하기 좋게 만들어서 중요하다고 생각되는 작업에는 반드시 테스트를 작성하시면 됩니다.헥사고날 아키텍처 자체는 그리 어려운 것이 아니고, 스프링에서는 계층형 아키텍처와 구조적으로 거의 차이가 없습니다. 강의에서 강조드린 헥사고날 아키텍처의 특징과 요구사항이 어떤 것인지만 잘 생각해보시고 그걸 따를 수 있도록 하시면 좋겠습니다.CRUD에 대해서 다 테스트를 만들어야 할지도 고민이 될 수 있는데, 매번 동일한 형식의 구조이고 별다른 로직이 없다면 처음부터 안 만드셔도 괜찮습니다. 그보다는 상태 변화와 복잡한 조회, 여러 엔티티가 한번에 바뀌는 로직 등에 대해서만 테스트를 잘 작성해보세요. 도메인 모델 패턴은 헥사고날 아키텍처가 요구하는 것은 아닙니다. CRUD 중심이라면 도메인 모델 패턴을 쓴다고 해도 아주 단순한 구조가 되겠죠. 하지만 20%에 해당하는 로직을 처리하는 코드에서 엔티티가 가진 정보를 이용하는 코드는 엔티티 내부에 작성하는 정도만 충실하게 하셔도 충분합니다. 제 생각에는 헥사고날 아키텍처가 오버엔지니어링이 될 가능성은 거의 없습니다. 시중에 잘못 알려진 복잡한 형식을 요구하는 오해를 가진 잘못된 헥사고날 아키텍처를 따르지만 않는다면요.
- 0
- 2
- 97
질문&답변
spotbug + @NonNullApi 로만 Null 방어가 될까요?
안녕하세요.@NonNullApi와 이를 체크하는 SpotBug과 같은 도구는 빌드 과정에서 명시적으로 해당 체크를 요구할 때만 검증을 해줍니다. 만약 SpotBug 체크를 빌드에 추가하지 않으면, 자바 언어의 기본 빌드에서는 이 애노테이션은 아무런 역할을 해주지 못하겠죠. 그래서 직접 null 체크하는 코드를 requireNonNull()을 넣은 것입니다.Null 값을 잘못 전달하는 상황을 막아주는 것은 런타임에 동작하는 requireNonNull() 입니다. 이게 가장 중요하죠. 자칫 null 값이 DB에 들어가게 되면 이후 여러가지 복잡한 버그가 발생하고 데이터가 망가질 겁니다. 이걸 복구하는 건 꽤나 어려운 작업입니다. 하지만 이렇게 런타임에 안전장치를 해두는 것은 실제 해당 코드가 실행되기 전에는 문제가 있다는 것을 알 수가 없습니다. 서버를 배포하고 2-3일 지나서 처음으로 requireNonNull() 코드가 실행이 된다면, 그때까지 코드의 결함이 있었음에도 확인을 못하고 방치하게 되는 거죠.그래서 100% 완벽하게 null 문제를 발견해주지는 못하지만(왜냐하면 API 등을 통해서 외부에서 전달되는 값에 의한 null 문제나, 우리가 작상한 코드 외의 라이브러리나 다른 모듈을 통해서 잘못 사용되는 경우도 있으니까요) 그래도 검토 가능한 코드 레벨에서 명백하게 null 값이 들어갈 수 있는 오류가 있다면 미리 체크할 수 있게 하기 위해서 SpotBug 같은 빌드 시점에 동작하는 정적인 체크 기능을 사용해서 결함을 일부라도 미리 발견할 수 있도록 한 것입니다. 이런 정적인 코드 분석을 통한 결함 사전 발견은 IntelliJ 같은 IDE에서도 일부 제공됩니다. 이것도 역시 100% 문제를 다 체크해주지 못하기 때문에 우리가 코드에서 항상 주어진 값을 검증하는 코드를 넣어서 실행시점에서라도 확인이 가능하도록 만드는 것이 필요합니다.
- 0
- 2
- 52






