백엔드 클린코드, 테스트코드 회고 2주차

백엔드 클린코드, 테스트코드 회고 2주차

해당 회고는 'Readable Code : 읽기 좋은 코드를 작성하는 사고법' 강의에 대한 회고입니다.

2주차 동안..

강의 완강은 하지 못했지만 한 것들을 정리하고자 합니다.

강의를 따라 리팩토링 해보면서 가장 느낀 점은 리팩토링은 정해진 답이 있지 않고 상황에 따라 유연한 생각이 뒷받침되어야 한다는 것이었습니다. 따라서 앞으로 코드를 칠 때 고려할 수 있는 아이템을 많이 만든다는 생각으로 수강했습니다.

 

배운 것들

 

객체와 고려할 점


추상화된 객체의 구성

  • 비공개 필드 (데이터)

  • 비공개 로직 (기능 구현부)

  • 공개 메서드 선언부 → 외부에서 어떤 기능을 제공하는지 알 수 있게 해줌

 

고려할 점

  • 객체 생성 시 1개의 관심사로 책임이 정의되어 있는지 확인하자

     

    • 메서드 추상화랑 비슷

    • 시간이 지나면서 객체의 요구사항이 변경되면서 책임이 변경될 수 있음.. 잘 변경해야 함

     

  • 생성자, 정적 팩토리 메서드에서 유효성 검증이 가능

     

    • 검증 로직도 같은 관심사로 취급될 수 있는지 확인 필요

 

  • setter 사용은 자제하고 getter는 웬만하면 자제

    • 데이터는 불변이 최고, 변해도 객체가 핸들링 가능해야 함

    • 외부에서 데이터 변경 요청을 해야 하는 경우 set같은 남용될만한 단어가 아닌 update와 같이 의도를 명확하게 드러내는 단어를 선택!

    • getter는 반드시 필요한 경우에 추가

    • Don't Tell, Ask

 

  • 필드 수는 적을 수록 좋다

    • 필드 계산 기능이 있다면 메서드의 기능으로써 제공하자

    • 미리 가공하는 것이 성능 상 이점이 있다면 필드로 빼도 무방

 

객체 설계하기


지뢰 찾기 게임을 객체 지향적으로 리팩토링!

String 배열을 사용해서 구현하고 있던 지뢰 보드를 Cell이라는 객체를 만들어 지뢰 보드의 각 셀의 상태를 물어보는 방식으로 바꾸었다.

리팩토링 중 몇가지...

  • Cell 객체 생성

image정적 팩토리 메서드를 사용

 

  • 모든 셀에 대해서 sign 확인하기

imageCell 객체에 대해 getSign을 해서 가져오고 싶지만 객체에 물어볼 수 있는지 확인 후 메서드를 만들었다

image

  • 보드 그리기

반대로 보드를 그릴 때는 객체에게 부탁하는게 이상하다. 내가 그리면서 객체에게 부탁하는 것은 맞지 않다.

이때는 과감하게 getter를 사용해서 객체에게 데이터를 받아서 그릴 때인 것이다.

image

 

  • 지뢰 수 board와 지뢰 여부 board 적용

Cell에 근처 지뢰 수 필드와 지뢰 여부 필드 추가한다, 생성자도 변경한다.

그러면 팩토리 메서드도 변경되고.. 나머지 Cell을 리턴하는 메서드들은 어떻게 값을 주어야 할까???

 

Cell의 필드와 필드들이 가질 수 있는 상태에 대해 생각해 보았을 때

Cell의 필드 : nearbyLandMineCount, isLandMine

Cell이 가질 수 있는 상태 : 깃발 있음/없음, 셀 열림/닫힘, 사용자가 확인함

 

여기서 깃발이 꽂힌 셀은 사용자가 지뢰가 있을 것을 예상해 닫힘과 동시에 확인한 셀이다.

깃발을 꽂는 것을 생각했을 때 셀이 열렸다, 닫혔다와 사용자가 확인했다는 서로 개념이 다르다!

깃발을 꽂는 경우 셀은 닫혀있지만 사용자가 확인한 셀이다.

현재 게임종료 조건에 모든 셀이 열렸을 경우 끝내는 것이었지만 사실은 닫혀있어도 이미 확인된 셀이 존재했다. 따라서 현재 게임종료조건은 부적절하다!

강의에서는 이런 고려들을 새롭게 알게된 도메인 지식이라고 했다.

결론은..

주변 지뢰 개수나 지뢰 여부 같은 경우 별도의 String기반 배열로 관리했기 때문에 해당 기능이 가능했다.

(별도의 BOARD를 확인해 원래 BOARD에 값을 넣는 식)

Cell이라는 데이터와 기능을 가지는 객체를 생성함으로써 사용자의 입력에 따라 Cell의 상태를 변화하는 로직으로 바꿔야 한다!!

Cell로 인해 관련 데이터들이 캡슐화되어서 Cell 자체를 변경하는 것이 아닌 상태를 변경시켜 달라고 Cell 내부의 상태를 변경하는 식으로 변경해야 한다

  • 원래 Cell의 상태

image

  • 변경 후 Cell의 상태

image

 

 

  • board의 Cell객체가 가지는 정보에 따라 Cell의 sign 상태를 리턴하기

Cell 객체는 상태를 보여주는 필드들을 관리했다. 이들에 기반해서 현재 Cell의 sign은 무엇인지 리턴해준다.

image

 

 

중간 점검

스케줄 상 readable code 강의를 완강한 주에 다같이 모여 중간점검을 진행했습니다.

전체적인 리뷰와 미션 피드백을 해주셨는데요, 좋은 질문과 답을 들을 수 있었습니다.

들으면서 작성한 메모입니다.

  • 코드 짤 때 사용자와의 구체적인 인터렉션이 도메인에 직접적으로 영향을 미치는 것은 좋지 않다

  • static메서드를 인스턴스 메서드로 대체할 수 없는 경우..는 인스턴스 메서드로 할 수 없는지 충분히 고려하자

  • 객체지향에서는 내부에 있는 객체의 상태를 확인하기 위해 bypass되는 메서드가 있을 수 밖에 없다

  • 충분한 설계에 대한 고민을 하다가 도메인을 새로 배우게 되는 계기가되고 그에 맞게 리팩토링을 하면된다

  • totalPrice라는 변수는 view일까 domain일까.. 3:7로 domain 왜냐하면 totalPrice라는 변수가 단순 결과를 내는 것 외에도 여러 곳에서 쓰일 수 있다. 예를 들어 그 후에 합계금액에 대한 결제 로직을 진행할 때 도메인안에서 해당 변수가 쓰인다면? 도메인의 발전 방향을 예측했을 때 어디 두는 것이 쓰임이 편할지 고려하자

  • 중복을 정말 꼭 고려하자 유지보수 시 중복되는 만큼 작업을 해줘야 한다!

  • 다르게 처리해줘야 하는 부분이 있으면 왜 다르게 처리해주는지를 명확하게 보일 수 있는 것이 좋다!

  • enum(정적)이나 config(동적)를 적용할 때 어디까지 적용하는 것이 좋을지 고려해보자

  • null대신 NPE를 방지할 수 있는 emtpy 개념을 고려해볼 수 있다.. 만약 여러 군데에서 디비나 API를 통해 데이터를 가져와야 한다면 NPE는 절대 나면 안된다

 

마무리 회고

앞으로 코드를 짤 때 유용한 자원이 되어줄 리소스를 모은 듯한 한 주였습니다.

다음 주도 이런저런 준비로 할 일이 산더미지만 커리큘럼을 조금씩 잘 따라갔으면 좋겠습니다.

다음 주도 화이팅!!

댓글을 작성해보세요.

채널톡 아이콘