TDD, Clean Code - first cycle

Evan Lee ㅣ 2023. 8. 13. 20:41

우테코 지원해볼때 한번 해봤던 콘솔 기반 단순 게임을 기반으로한 TDD, CleanCode 스터디를 진행하게 됬었고, 지난 3주가량 code review 및 피드백 받은것과 기억에 남는 것을 기록해보려고 합니다. 

 

TDD ( Test driven Development ) 란 ? 


테스트를 먼저 작성하고, 그 후 실제 코드를 작성하는 방법인데 단순 먼저 테스트 코드를 짜는게 아닌 주어진 문제를 정의하고 그 해답을 찾아가는 과정이라고 합니다. 

 


TDD 사이클 7단계  ( 예시 - 자동차 경주  )

1. 전체 문제가 해결되었을 때 어떤 상태일지 상상해보기, 결국 내가 뭐하려는 건지에 대해 ? 

경주 결과로 우승자를 표시하여 보여준다.

 

2. 적당한 난이도로 핵심을 포함하여 문제를 쪼개서 변형하기

  #1 경주 셋팅 
       - 자동차 이름을 입력받는다
 #2 경주 진행
       - 전진 조건 정하기
       - 랜덤으로 차를 전진시킨다.
       - 경주하고, 자동차 별 진행결과 출력 
 #3 우승자 출력 
       - 우승자를 출력하고, 여러명인 경우 ','를 이용해서 출력
       - 제일 멀리간 사람이 우승자 

 

3. 핵심과 가까우면서, 지금 내 상태에서 쉽게 할 수 있는 적절한 것을 하나 선택한다.  

입력받기
전진시키기/전진 조건 정하기
랜덤값을 생성 

 

4.결과의 모습이 뭔지 구체화하고 시뮬레이션 

자동차 입력 받기
자동차 이름을 입력 받는 그 인터렉션에서 어떤 상황들이 있을 수 있을지,

예외케이스
- 빈값인 상태에서 엔터를 치는 경우
- 자동차를 너무 많이 입력하는 경우
- 같은 자동차 이름을 입력하는 경우
- 특수문자를 넣은경우
- 너무 긴 이름의 자동차 이름을 입력한 경우도 있을 수 있고

 

5. 동작 가능한 가장 작은 버전의 솔루션을 만들고, 테스트가 통과하는지 확인 

일반적으로 보는 TDD 사이클이 여기서 진행된다

1. 실패하는 테스트 코드를 작성한다.

2. 테스트를 통과할 만큼의 개발 코드를 작성

 

6. 리팩토링을 하면서 중복을 줄이거나 의도를 드러나게 한다. 

리팩터링하고 나서는 기존의 테스트 코드가 잘 동작하는지 확인한다

 

7. 다시 1번이나 2번으로 돌아간다. 


eslint의 다양한 rules

 

 아래와 같은 규칙이 기본적으로 깔렸는데, 

  • 변수 선언시 var를 사용하지 않는다. let, const를 사용한다.
  • 전역 변수를 만들지 않는다.
  • 축약하지 않는다.
  • 동등 연산자는 === 로만 사용한다.
  • 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다.
  • 함수(또는 메서드)의 들여쓰기 depth는 2단계까지만 허용한다.
  • else 예약어를 쓰지 않는다.

 

어지간한 규칙같은 경우는 eslint에 rule을 추가하면서 컨벤션을 맞춰갈 수 있었다.

 


YAGNI ( You Ain't Gonan Need it ) 

개인적으로 미션을 진행하면서 console.log()를 따로 util로 빼서 print()라고 모듈화를 해서 사용하라고 했는데, YAGNI 법칙과 관련해서 피드백을 받았었고.. 투머치하다고 본인도 생각을 해서 rollback을 했었다. 그리고 관련한 개발자 3대 법칙이 있다고 하는데, 한번 쯤 알아두면 좋을 것 같다. 

 

- YAGNI( You Ain't Gonna Needit )

 It is a principle in clean code that suggests that code should not be written for functionality that is not currently needed. This means that developers should avoid adding features or functionality to the codebase that are not required by the current requirements or specifications. 

현재 필요하지 않은 기능을 위해 코드를 작성해서는 안 된다는 클린 코드의 원칙입니다. 즉, 개발자는 현재 요구 사항이나 사양에서 요구하지 않는 기능이나 기능을 코드베이스에 추가하지 말아야 합니다.

 

- KISS ( Keep it simple, stupid )

It is a principle in clean code that suggests that code should be kept simple and easy to understand. This means avoiding unnecessary complexity and keeping the code as straightforward as possible.

코드는 간단하고 가독성이 좋도록 유지하도록 권장하는 클린 코드안에서의 원칙이고, 불필요한 복잡성을 피하고 코드는 가능한 직관적으로 하라는 뜻이다. 

 

- DRY ( Don't Repeat Yourself ) 

it is a principle in clean code that suggests that code should not contain duplicate logic or functionality. This means that code should be designed in a way that promotes reuse and modularity.

코드는 중복되는 로직이나 기능이 포함되서는 안된다는 클린코드 원칙이고, 재사용과 모듈화를 추구하는 방식으로 코드를 설계해야한다는 뜻이다. 

 

 


Object.freeze() with nested object 

피드백임

모든 상수에 대해서는 혹시 모를 수정, 삭제에 방지하기위해 Object.freeze를 적용했었는데, 문제는 nesting된 객체에 최상단에서 한번만 씌우게 되면, nesting된 친구들은 수정이 가능케 된다. 

 

재귀를 사용해서서 다 얼려버리면 아래처럼 네스팅 객체들도 다 얼리기가 가능하다.

 

https://medium.com/@nikhil_gupta/how-to-deepfreeze-a-nested-object-array-800671147d53

 

How to DeepFreeze a nested Object/Array

So I believe you’ve read my previous article — ‘Differences between Object.freeze( ) & Object.seal( ) in Javascript’ and now you’re…

medium.com

 


명령형 VS 선언형

피드백중에서는 명령형 보다는 선언형의 프로그래밍 패러다임을 격려하게된다. 이유는 아래와같이 컴퓨터에게 'How is to be done' 하나하나 지정하기보다는 간단하게 'What is to be done' 하는게 클린코드 측명에서 낫다고 하셨는데. 

 


Array().fill() X -> Array.from O 

 

명령형 -> 선언형으로 리팩토링하던중 

 

for문을 Array().fill()을 통해 배열 내장 메소드를 사용하기 위해 배열을 만드는 부분이 있었는데, Array.fill()은 사용을 안하는게 맞을거 같다는 말씀을 해주셨습니다. 

 

https://dev.to/mayankav/array-fill-is-secretly-broken-28k4

 

Array().fill is secretly broken

There's something weird about Array().fill(). Well, some of you would say Array itself is weird and...

dev.to

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill#polyfill

 

Array.prototype.fill() - JavaScript | MDN

The fill() method of Array instances changes all elements within a range of indices in an array to a static value. It returns the modified array.

developer.mozilla.org

이 코드를 보면 결과가 어떻게 찍힐지 예상이 가는가 ? 놀랍게도 콘솔에는 아래와 같이 출력된다. 

사실 fill다음에 map을 돌려서, 참조주소를 아예 바꿔서 work-around로 수정이 가능하지만 일단 그런 작업조차 필요하다는게 말이 안되고, 이런 간단한 Array 생성 관련에 대해서는 배열 생성자를 쓰지않는방향으로 생각해보자. 

 


Naming of Unit Test 

Feed back

가뜩이나 함수나 변수에 관해 네이밍 관련한 피드백을 받고 있었는데, 해당 피드백을 받게 되었다. 

 

https://stackoverflow.com/questions/45778192/what-is-the-difference-between-it-and-test-in-jest

 

What is the difference between 'it' and 'test' in Jest?

I have two tests in my test group. One of the tests use it and the other one uses test. Both of them seem to be working very similarly. What is the difference between them? describe('updateAll', ()...

stackoverflow.com

 

내가 test안에 넣은 test title을 읽어본다면, test보다는 it이 어울린다는 것을 알수 있고, jest도 또한 특별히 다른 기능은 없지만 저런 BDD 느낌이 강한 Test에 대해서는 다른 네이밍을 제공하고 있음을 알 수 있다 .

 

일단 내 Test Code는 it should 패턴을 써넣어기 때문에 나는 개인적으로 이를 통해서 내가 테스트하는게 무엇인지 좀 더 직관적으로 볼 수 있다고 생각을 했다. 그리고 그 테스트 안에서 테스트 시나리오를 설명하기 위해서 given/when/then을 넣었었는데 이는 BDD 스타일의 네이밍이라고 한다. 원래는 각각 쓰는거 같지만 나는 테스트 코드를 작성할때 뭔가 가독성이 더 좋아지는 것 같아서 같이 쓰긴했다. 

https://markus.oberlehner.net/blog/naming-your-unit-tests-it-should-vs-given-when-then/

 

Naming Your Unit Tests: It Should vs. Given/When/Then

Learn more about my thoughts about naming unit tests applying patterns from BDD.

markus.oberlehner.net


MVC패턴.. 그리고 Naming 

그리고 정말 많았던 MVC 패턴과 네이밍 관련 피드백들... 사실 해당 미션을 진행하면서 예전의 기억들을 더듬어서 MVC 패턴이 최적에 패턴이다 약간 머릿속에 박혀서 아무래도.. 전반적인 흐름을 이해하고 코드를 짜기보다는 패턴을 먼저그리고, 미션을 진행했었는데 그게 바로 눈에 바로 보이셨던 모양이였다. 

그래서 다시한번 다 뒤집고 패턴을 신경을 안쓰고 다시 작업을 하게되었고 패턴에 얽메이지않고 문제 자체에 포커싱해서 풀어서 패스를 받아내었던.. 

 

 

 

 

너무 부족한게 많다...

'Study > TDD' 카테고리의 다른 글

TDD, Clean Code - Second Cycle  (0) 2023.09.10