본문 바로가기
기록/IT

NEXTSTEP] TDD, Clean Code with Java

by 무심한고라니 2022. 5. 9.

요즘 근황(겸 공부한 내용)을 간략하게나마 남겨보려고 합니다. 혹시 글 내용 중 틀린 부분이나 피드백이 있으면 댓글 남겨주시면 감사하겠습니다.

-----

 

NEXTSTEP에서 주관하는 TDD, Clean Code with Java 14기[1]를 신청해 수강중이다. 이 강의과정은 약 두 달간 4개의 자바 미션을 수행하며 다음과 같은 학습을 하게 된다.

 

  • TDD, 리팩토링, 클린코드
  • 순수 자바로 객체지향 프로그래밍
  • 레거시 코드 리팩토링

 

약 80만원이라는 작지 않은 금액, 일하면서 미션을 잘 수행할 수 있을까 하는 부담이 좀 망설여졌는데, 비전공 자바 개발자로 일하면서 멀리서 대단하다고 생각했던 많은 사람들이 이 강의를 수강했다는 것을 알고 있었기에 신청을 눌렀다. 결론적으로는 잘 했다는 생각이 든다. SI만 경험했던 내겐 TDD는 커녕, 테스트 코드도 짜본 적이 없었다. 주변에서 꼭 해야한다고 추천을 받긴 했었지만 이해가 쉽지 않아 몇 번 포기했었는데, 적어도 이 과정을 통해 좋은 개발 회사라고들 하는 서비스 회사에서 쓰는 기술들[2]을 얕게나마 경험해볼 수 있다. 뿐만 아니라 미션마다 다른 리뷰어들을 만날 수 있는데, 교육이라는 특수성은 있지만 협업을 간접적으로나마 경험해볼 수 있는 기회라고 생각한다. 내 경우에는 한 리뷰어분께서 페어 프로그래밍 제안을 해주셔서 게더 타운에서 새로운 경험을 해보기도 했다.

 

이미 많은 교육 후기들에도 언급되어 있듯, 이 과정에서 포비님은 객체지향 생활 체조 원칙을 언급한다. 이는 레거시 코드를 리팩토링하기 위한 정량적인 원칙이다. 읽어보면 별 거 아닐지도 모르지만 직접 해보니 간과하는 것이 훨씬 많았고, 스스로 느끼고 체화하는 과정이 필요하다고 느꼈다. 예를 들어, 객체 지향은 객체에 메세지를 보내[3]는 것이라는 것은 익히 들었었다. 스프링 웹 개발을 하며 이를 단지 컨트롤러가 서비스에게 작업을 위임[4]한다 정도로 인식하고 있었다. 허나 이제는 이렇게 묶을 수 있을 것 같다.

 

객체에 메세지를 보낸다
→ GETTER/SETTER/프로퍼티를 쓰지 않는다

 

즉, 처리를 위해 객체에 시켜야지, 객체에서 값을 꺼내(GETTER) 외부에서 처리하도록 하면 안된다는 것이다. 한편 GETTER는 부득이하게 사용될 수 있지만(빈번한 사용시 응집성 감소) SETTER/프로퍼티는 사용하면 안 좋은데, 동시성의 문제가 있을 수 있기 때문이다. 이 때문에 값 객체가 중요하게 된다. 실제로 포비님은 모든 필드에 final 키워드를 붙인[5] 후 이후 필요시 제거하는 식으로 개발했다.

 

SETTER/프로퍼티를 쓰지 않는다
→ 모든 원시 값과 문자열을 포장한다

 

포장한다는 말은 결국 객체[6]를 생성한다는 말이다. 만약 자동차에 대한 이동거리가 자료구조로 관리되었다면 외부에서 언제든 접근 및 수정이 가능했을거다. 반면 객체로 관리하였다면 SETTER가 존재하지 않는 한 내부 데이터는 변경에 안전할 것이다. 이것이 메소드와 달리 생성자가 안전한 이유[7]이며, 유효성 체크도 생성자에서 해주어야 함을 의미한다[8]. GETTER도 이런 맥락에서 내부 데이터를 노출하면 안 되기에 방어적 복사 혹은 깊은 복사를 통해[9] 내부 데이터를 외부로 노출해야 한다(그냥 노출해서 문제된 적이 굉장히 많았다...).

 

외에 여러 간략한 팁들을 얻었다.

 

  • 객체에 꼭 필요한 상태(데이터)인지 고민하고, 더 나아가 꼭 필요한 객체인지 고민해보라
  • Enum도 하나의 객체와 다름 없어서 메세지를 보내는 식으로 개발하라
  • 가독성을 위해 else문 대신 early return을 사용하라
  • 일급 컬렉션을 활용하라[10]
  • TDD가 설계가 필요 없는 게 아니다, 설계에 따라 테스트가 단순해질 수 있기에 오히려 더 중요할 수 있다
  • 설계는 객체지향적으로 하되, 각 객체의 메소드 내부는 자바8의 장점을 활용하면 좋다
  • 일급 컬렉션 등 포장했을 때 외부에서 메세지를 보내기 위해 내부에 메소드를 생성해주는 것이 좋다(ex. contains)

 

이 과정은 총 4번의 미션이 있는데 처음부터 TDD를 요구하진 않는다. 처음엔 테스트 코드로 작성부터 시작한다. 뿐만 아니라 클래스 분리 이전에 메소드 분리부터 시작하고, 인자가 많거나 한 경우 클래스를 분리해나간다. 이처럼 과정명에도 드러나 있듯, 단계를 밟아 차근차근 다음 단계로 도약하는 느낌이 있다. 처음 포비님께서 언급하신 것이 교육 이후에도  수강생들의 지속적인 변화를 가져가고 싶다는 거였는데, 느리더라도 꾸준히 공부해야겠다는 생각이 든다.

 

PS. 메소드 분리 등은 이중 반복문과 다를 바 없고, 최근 하드웨어 속도가 좋아졌기에 그런 부분은 무시하고 가독성 등에 치중하여 코드를 작성해도 좋다고.. 강의 중에 언급하신 것 같다.

 

 

- - -

1. 2022.04.04(월) ~ 2022.06.01(수)

2. TDD가 단지 테스트 코드가 아닌, 설계와 리팩토링을 한 사이클로 가지는 개발 방법론이라는 것을 알게 되었다. 또한 혼자 개발하는 미션이긴 해도 단계별로 브런치를 생성해, 로컬에서 개발하고 원격으로 PR 후 머지하는 단계를 통해 단순하게나마 협업을 경험해볼 수도 있었다.

3. 굉장히 추상적인 느낌인데, 이 말이 어디선가 들어본 순수 함수와 혼동이 되었다. 자바스크립트의 순수함수처럼 뭔가 처리한 후 그 값을 그대로 반환하는 게 맞지 않나 해서 메소드 역시 마찬가지로 반환을 void로 하면 안 되지 않나 하는 이상한 생각을 했다. 불변성만 보장한다면 객체를 반환해도 관계 없고... 다만 반환 시에 NullPointerException 나는 건 지양해야 하니 주의가 필요한 것 같다.

4. (아직 강의를 다 듣진 않아 뇌피셜이긴 하나) 서비스단과 도메인이 다르다는 생각을 갖게 되었다.

5. 자동차 객체를 생각할 수 있다.

public class Car {
    private final String name;
    private final int distance;
}

6. 객체는 외부에 데이터가 노출되어 있는 자료구조와 다르다.

7. 포비는 테스트 코드 작성을 위해 생성자는 얼마든지 오버로딩해도 된다고 얘기한다. 생성자 생성은 프로그램을 유연하게 해줄 뿐 아니라 테스트 픽스쳐를 간소화해준다.

8. 자동차 객체는 자동차 이름에 제한이 있는 경우, 다음과 같이 리팩토링할 수 있다.

public class Car {
    private final CarName name;
    private final int distance;
}

9. 다만 빈번한 객체 생성 시 성능 상에 문제가 있을 수 있기 때문에 캐싱 등을 고려해본다.

10. 일급 컬렉션

11.

'기록 > IT' 카테고리의 다른 글

독서  (7) 2024.11.05
점핏 프론트 개발자 세미나  (0) 2023.04.30
부러진 개발자 이야기  (0) 2021.12.24
파이썬 교육 수료  (0) 2021.12.19
NHN FORWARD 2020  (0) 2021.01.03

댓글