지속 성장 가능한 소프트웨어를 만들어가는 방법 (제미니의 개발실무 강의 정리)

tony·2024년 5월 14일

코드 패러다임

목록 보기
3/6
post-thumbnail

Intro

평소에 좋아라하는 개발자들이 있는가?

나는 있다. 내가 선망하는 개발자들은 다음과 같이 공통된 특성을 가지고 있다.

  • 본인만의 관점으로 바라보는 개발자
  • 이를 공유하고 소통하며 성장하는 개발자
  • 개발자로서의 "나"는 역할이 무엇인지의 자기객관화

그 중에 한 분이 제미니 님이시다.

정말 애청하는 유튜브인데, 너무 좋은 내용이 묵직하게 올라와 -- 강의 준비하신 자료보니 너무나도 깔끔해서 눈물이 날 정도다 -- 이렇게 정리해보았다.

** 꼭 원본인 지속 성장 가능한 소프트웨어를 만들어가는 방법 을 보시길

Layer 의 역할

  • Business Layer / Implement Layer
    • Business : 유스케이스에 대한 로직,제어
    • Implement : 해당 도메인에 대한 상세 조건 처리
  • 각각의 레이어의 역할은 명확하다.
    • Presentation : 노출,요청,응답 등등 (Controller)
    • Business : 비즈니스로직들 (Service)
    • Implement : 상세구현로직들 (유저정보를 어떻게 읽어오기)
    • DataAccess : 외부시스템 접근 시 거쳐가는 레이어 (SFTP,File,DB 등등)
  • 레이어 규칙은 다음과 같이 4가지 규칙이 존재
    1. 순방향 참조 O
    2. 역류 참조 X
    3. 레이어 참조 시, 하위 레이어를 건너뛰지 않는다.
    4. 동일 레이어 간 상호참조 X. 다만 Implement Layer 예외. 해당 Layer 는 재사용성을 위한 Layer 이기 때문이다.

Module 관리

각각의 구현에 대한 모듈관리는 확장성이 떨어진다.

Untitled

위와 같이 구성되어있다면, 확장성이 떨어진다. 왜냐고?

사내에서 JPA 스택이 아닌 NoSQL 로 마이그레이션을 해야만 하는 상황이라고 하자.

JPA 스택을 걷어내려면 API 모듈과 Batch 모듈 둘 다 걷어내는 작업을 해야한다.

그것도 “안정적으로”

그런데 만약 사내 모듈이 30개가 넘어간다면???

의존성에 대한 모듈을 따로 분리하자.

Untitled

Untitled

각각의 기능구현에 대한 모듈의 “의존성에 대해서 따로 모듈을 만들어”주는 것 이다.

이렇게 구성하게 되면 모듈을 수정 및 추가가 굉장히 편해진다는 이점이 있다.

또한 위 gradle 코드와 같이 의존성 분리가 잘 이루어진다는 점도 이점으로 뽑을 수 있다.

api() vs implemenation()

Untitled

implemenation()을 사용하게 되면, Inner Module 에 대해 Outer Module 이 접근하지 못 하게 된다.

즉, 위와 같은 그림에서 SFTP 모듈이 제공하고 있는 인스턴스나 메서드들을 Batch 에서 사용하고자 한다면,

import 를 하지 못 하게 되어 사용하지 못 한다.

Untitled

이를 api()를 사용하여 해결할 수 있다.

api()를 사용하면 Outer Module 에서 import 를 할 수 있게한다.

따라서 Batch 에서 import 문을 사용해 SFTP 모듈이 제공하고 있는 인스턴스나 메서드들을 사용할 수 있게된다.

그렇다면 언제 implementation()을 사용해야하는가?

API로 오픈해야한다면 api(), 확장가능한 기술, 즉 변경된다면 implementation()

Untitled

위와 같이 implmentation() 을 사용하여 단계 별 모듈을 의존하게 되면,

Outer Module 은 “Bridge Module 을 통해서” Inner Module 을 의존하고 있게된다.

( Bridge Module 은 내가 만든 용어다 ^^)

따라서 Outer Module 는 Inner Module 이 어떻게 변경되든 변경의 영향을 받지 않는다.

이에 따라 Inner Module 은 다음과 같이 변경될 수 있다.

Untitled

요컨대, 변경될 수 있는 Inner Module 이라면 implementation() 을, API 처럼 외부에 공통적으로 제공되어야하는 Common Module api() 를 사용하자.

이해가 안 되는 것들, 공부해야할 것들

이제 "경험 상 이렇게 하는 게 좋더라" 라는 걸 들었으니,
"어떻게 하는가?" 가 궁금했다.
실제로 어떻게 처리하셨고 어떻게 할 수 있는지 의문인 부분이 있었다.
직접 만들어보며 어떻게 처리했는지를 확인해야겠다..

  • Layer 관련해서는 Facade Pattern 을 종종 사용해왔으므로 고개를 끄덕이고 넘어갔다.
  • 어떻게 의존성 별로 모듈을 따로 분리했는가?
    • 각각의 Outer Module 에 대해 메서드를 따로 열어두셨을까?
    • 또한 내부적으로 메서드의 publicity 를 정하는 기준이 무엇일까?
      • 가령 어떤 메서드는 public 하게 할 지, 어떤 메서드는 private 하게 할 지
  • 의존성 별로 모듈을 분리하게 되면 테스트 코드를 짤 때 어떻게 해야할까?
    • Inner Module Test 에 대해서는 최대한 잘게 쪼개어 단위테스트를, 기능 별 Test 에 대해서는 통합테스트를 짜게 되지 않을까?
      • 가령 “사용자를 생성 테스트” 를 위해 JPA Module, DB Module, User Module 이 모두 필요하지 않을까?
    • Kpring 의 Auth 모듈과 같이 분리한 것일까?
profile
내 코드로 세상이 더 나은 방향으로 나아갈 수 있기를

0개의 댓글