개발자 99% 커뮤니티에서 수다 떨어요!
오늘 TIL 3줄 요약
나에게 통제권이 없는 코드와는 최대한 접촉할 일을 줄이자
테스트는 빨리보다 '잘' 짜는 게 중요함을 기억하자
테스트 코드와 실제 코드는 목적이 다르다. 다른 코드 규칙들은 잊어버리자. 테스트 코드에서 제일 중요한 건 가독성!
TIL (Today I Learned) 날짜
2022.03.06
오늘 읽은 범위
8장. 경계 ~ 9장. 단위 테스트
책에서 기억하고 싶은 내용을 써보세요.
경계 인터페이스를 사용할 때에는 클래스로 감싸줌으로써 해당 경계 인터페이스가 전체 프로그램에 끼치는 의도치 않은 영향을 방지하고 프로그램에 필요한 기능만을 추출한다. (p.145)
외부 코드를 사용할 때에는 먼저 자기 프로그램을 작성하는 것이 아니라 간단한 테스트를 작성하여 외부 코드의 사용법을 익히는 학습 테스트를 이용하자. (p. 146)
경계를 최대한 줄이고 그 외의 요소들로부터 분리시킴으로써 프로그램에 대한 통제성을 높이자. 경계를 잘 관리하지 않으면 우리가 통제할 수 없는 영역의 외부 코드에 의해 너무 휘둘릴 수 있다. 최소한 경계 코드는 우리가 통제권을 쥘 수 있다. (p.152)
TDD의 세 가지 법칙 : 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다. / 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다. / 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다. (p.155)
실제 코드가 변경되면 테스트 코드 역시 변경이 필요할 수 있다. 테스트 코드를 복잡하게 마음대로 작성하면 이 과정이 매우 골치아파진다. 따라서 테스트 코드의 품질은 실제 코드만큼이나 중요하다. (p.156)
실제 코드에 유연성, 유지보수성, 재사용성을 제공하는 버팀목이 바로 단위 테스트다. 테스트 케이스가 있으면 버그를 찾아낼 수 있기 때문에 변화를 두려워하지 않아도 된다. (p.157)
테스트 코드에서 가장 중요한 것은 가독성이다. 깨끗한 테스트 코드가 테스트 코드의 유지보수를 보장하고 잘 작성된 테스트 코드가 실제 코드가 발전할 수 있게 해준다. (p.158)
테스트 코드는 바로 본론에 돌입해 진짜 필요한 자료와 함수만을 사용한다. (p.160)
실제 코드와 테스트 코드는 요구사항이 다르다. 테스트 코드는 가독성을 위해 기존 실제 코드에 적용되는 규칙들을 깨도 되며 리소스가 제한적인 실제 환경과 다르게 메모리, CPU 등에서 제한을 가지지 않는다. (p.162)
테스트 하나당 개념은 하나만 테스트한다. 그리고 개념당 asset문은 최소한으로 사용한다. 만약 하나의 개념을 테스트하는 데 assert문이 2개 이상 필요한 것 같다면 최대한 개념을 잘 쪼개보자. (p.167)
테스트는 FIRST라는 다섯 가지 규칙을 따른다. (p.167)
Fast : 테스트는 빨리 돌아가야 한다. (테스트 시간이 오래 걸리면 테스트를 덜 하게 되고 이는 코드 성능의 저하로 이어진다.)
Independent : 테스트끼리 의존성을 가지면 안 된다. 예를 들어서 한 테스트가 다른 테스트를 준비하면 안 된다. 그렇게 되면 테스트 실패시 원인 추적이 어렵다.
Repeatable : 테스트는 어떠한 환경에서도 돌아갈 수 있어야 한다. (반복 가능해야 한다.)
Self-Validating : 테스트 결과는 무조건 성공, 실패 둘 중 하나다.
Timely : 테스트는 적시, 즉 실제 코드를 작성하기 직전에 작성해야 한다.
오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요
사실 처음 챕터 제목을 읽었을 때에는 에러 경계같은 내용을 생각했는데 전혀 다른 내용이 나와서 당황했다. 외부 코드를 사용하는 것은 정말 조심해야 하는 영역인 것 같다. 내가 통제권을 가지지 못한 영역이 내 코드 여기저기에 스며들어있다면 가뜩이나 내 프로그램의 목적에 맞춰서 유지보수하기도 힘든데 외부 코드에 의해 이리 휘둘렸다 저리 휘둘렸다 할 테니까. 당연한 말이지만 외부코드가 아니더라도 프로그램의 모든 부분을 잘 쪼개는 것이 참 중요한 것 같다. 오늘 포트폴리오 사이트를 새로 만드는 과정에서 에러 경계의 위치를 고민하다 느낀 점이다. 코드는 분리를 잘 하고 분리한 코드들은 서로 인터렉션을 줄이는 것이 참 중요한 것 같다. 어떻게 보면 먼 과거의 성들을 보는 것 같아서 재미있다. 벽을 굳건하게 세우고 왕래가 필요하면 성문에서 문지기에게 검사받은 후에만 입장할 수 있으니 클래스, 인터페이스와 비슷한 느낌 아닌가? 요즘 사람들에게 '너는 MBTI N이 확실하구나'라는 말을 자주 듣는데 이래서인가 싶다.
궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.
경계 인터페이스 : 어떠한 메소드에서 Map, List와 같은 자료구조를 반환하거나 공개 API 인수로 넘겨서 클라이언트에서 해당 인터페이스를 사용하는 것을 말한다. 경계 인터페이스는 클라이언트 측에서 예상하지 못한 동작으로 프로그램에 문제를 일으킬 수 가능성이 있다. 이러한 경계 인터페이스를 클래스로 감싸준다면 원하는 기능만을 도출(일부 기능을 직접 사용하던 변환시키던)하고 코드의 직관성 역시 향상시킬 수 있다. 또한 경계 인터페이스 내부가 변화하더라도 그것이 외부에 노출되지 않으며 감싼 클래스만을 수정하면 된다는 장점이 있다.
학습 테스트 : 자신이 개발하지 않은 코드를 사용할 때 테스트하면서 사용법을 익히는 방식을 말한다. 테스트 코드를 작성하고 구체적으로 테스트를 돌리는 과정에서 프로그램의 사용법을 익힐 수 있다. 학습 테스트는 코드의 테스팅이 아니라 학습에 그 목적이 있다는 점이 중요하다. 학습 테스트에서는 프로그램에서 원하는 방식으로 테스트를 작성한다. 이 때 작성한 테스트는 이후에 해당 외부 코드가 변경되었을 때 해당 코드가 자신의 프로그램(+그 기능)과 호환되는지 점검하는데 지속적으로 활용될 수 있다.
어뎁터 패턴 (Adapter Pattern) : 클래스의 인터페이스가 클라이언트에서 사용될 수 있도록 변환(적응)시켜주는 역할을 수행하는 어뎁터가 포함된 디자인 패턴이다. 어뎁터를 활용하면 호환되지 않은 클래스를 사용하거나 여러 클래스, 구조 사이에서 유연한 전환이 가능하다.
BUILD-OPERATE-CHECK 패턴 : 테스트 자료를 만들고(Build), 테스트 자료를 조작하고(Operate), 조작 결과를 확인하는(Check) 테스트 방법으로 given-when-then을 각각 주석으로 활용하는 것이 관례이다.
템플릿 메소드 패턴 (Template-Method Pattern) : 어떤 작업을 처리하는 일부분을 서브 클래스로 캡슐화해 전체 일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴이다. 즉, 전체적으로는 동일하면서 부분적으로는 다른 구문으로 구성된 메서드의 코드 중복을 최소화 할 때 유용하다.
오늘 읽은 다른사람의 TIL
mamaemee님의 TIL (https://nomadcoders.co/community/thread/3396)