TDD (Android Unit Test) + QnA

현재 속해있는 팀은 사용자중심, Pairing, TDD 를 핵심 프랙티스로 사용하고 있고,
PM, CX, DEV 세 역할자가 한공간에서 일을 한다.
PM은 비지니스 및 도메인을 분석하고 사용자에게 가치가 있을 기능 들을 찾는다.
CX는 이 기능들에 대해서 사용자가 어떻게 사용하면 좋을 지에대해 분석하고 UI를 디자인한다.
DEV는 유저스토리와 UI를 받아 실제 제품을 만들어 나간다.
제품은 반복, 지속적으로 고객 또는 사용자의 피드백을 반영해 나간다.
사용자 피드백에 의해서 요구사항은 언제든 변경됐다. 심지어 이터레이션 중간에도 변경된다.
이런 개발환경에서 개발팀은 계속되는 요구사항 변경을 빠르게 반영하면서, 언제든 배포가 가능하도록 준비해야 된다.

빠르게 요구사항을 반영하고, 언제든 배포하고 시연할 수 있으려면 어떻게 해야 할 까?
내가 수정한 소스 코드가 다른 소스에 영향을 주지 않았다는 것을 어떻게 알 수 있을까?
빠르게 요구사항을 반영해 나가면서 어떻게 리팩토링도 하고 일정한 수준의 설계 품질을 유지 할 수 있을까?

난 이 팀에 합류 했을땐 TDD도 처음이었고, Android 개발도 처음이었다.
그저 자바 개발자로서 unit test와 OOP에 대한 지식 정도만 갖고 있을 뿐이었다.
약 8개월간 안드로이드 개발을 하면서 위 문제들에 대해 대응하면서 얻은 경험을 공유하고 싶어서 슬라이드를 만들었다.
다른 팀에 공유하고 느낀 것은.. 테스트 코드를 작성하는 팀이 거의 없다는 것이다.
더 많은 사람들에게 경험을 공유 할 수 있었으면 좋겠다.

현재 속한 회사나 팀의 모든 개발자가 이렇게 일한다거나 일해야 한다는 것은 아니다.
같은 개발팀 개발자들과 여러 상황을 대처하며 끊임없이 토론하고 개선해가며 얻은 경험일 뿐이다.

슬라이드에는 없지만, Q&A 를 받았던 질문에 대해서도 공유하고자 한다.
질문을 받을 때만다 지속적으로 업데이트 할 예정이다.

QnA

Test Coverage는 어느정도 나오나?

커버리지가 높다고 좋은 코드 품질을 가졌다거나, 오류가 없는 제품이라고 보기 힘들기 때문에
개발팀원들은 테스트 커버리지를 중요하게 생각하지는 않는다.
하지만 jacoco를 통해 CI환경에서 매번 빌드 시 측정이 되고 있다.
프로젝트 초반에는 자주 모니터링 했지만, Test code 작성하는 것이 습관이된 이후에는 신경을 쓰진 않았다.
보통 Line Coverage 기준으로 89~90% 를 유지했다.

브랜치 전략은 어떻게 하나?

git을 사용하고 remote에 master와 development 브랜치가 있다.
우리 팀은 개발자의 개발리듬을 매우 짧고 반복적으로 가져가기를 원한다.
또한 요구사항 변경에 대해 빠르게 반영하기를 원한다.
그렇기 때문에 commit/push 단위가 매우 짧다.
로컬에 브랜치를 만들거나 Feature 단위로 브랜치를 만들고 merge 하는 것이 불필요하다고 생각했다.
development 브랜치에 바로 commit/push 한다.

TDD를 하면 정말 설계가 좋아지나?

TDD는 프로그래밍 목적을 명확하게 해준다는 것 뿐이다.
좋은 개발자가 좋은 설계를 만든다. 개발자가 누구냐에 따라 설계가 좋아지는 것이다.
테스트 코드는 좋은 설계를 만들수 있게 도와주는 도구일 뿐이다.
그렇기 때문에 계속 객체지향 설계에 대해 함께 강조하는 것이다.

주석도 잘 안다는 것으로 알고 있는데, 문서화는 어떻게 하나?

주석은 메소드 이름으로 대신하길 원한다. 왜 이렇게 짤 수 밖에 없었는지에 대해서 주석을 단다.
개발팀의 문서화가 UML에 대한 질문이라면 작성하지 않는다.
싱크를 유지하는 것이 매우 큰 병목이라고 생각한다.
복잡한 경우 페어와 함께 화이트 보드에 다이어그램을 그리면서 설계를 하고
다른 개발팀원들을 모아서 그 자리에서 바로 리뷰를 한다.
일정 시간이 지나고 공유가 됐다고 생각하면 사진으로 남긴 후 지워버린다.

mocking 할 객체가 너무 많다. 정말 테스트 대상객체 이외에 전부 mocking 해야하나?

한 method를 테스트하려는데 mocking 할 객체가 많다면,
거대한 객체를 만들고 있는 것이 아닌지 의심해 봐야한다.
생성자나 onCreate() 에서 너무 많은 일을 하고 있는지도 확인해 봐야 한다.
객체가 가지고 있는 책임이 명확하게 나눠져 있고, 협력관계가 잘 형성되어 있다면
mocking 할 객체가 많지 않을 것이다.

객체를 만들기 보다는 Activity 하나에 기능을 다 넣어 두는 것이 변경할 대상이 하나여서 더 좋은 것 아닌가?

무질서 속에 질서가 있듯이, 내 방이 아무리 어질러져 있더라도 나는 어떤 물건이든 쉽게 찾을 수 있다.
하지만, 다른 사람도 쉽게 찾을 수 있을까? 물건을 찾기 위해 더 어지르고 나름의 질서마져도 깨트릴 것이다.

Activity에 모든 기능을 다 넣고, 주석도 잘 달고 메소드도 잘 식별해 놨다고 하더라도,
개발자가 바뀌는 순간 모든 것이 무질서하게 된다고 생각한다.
그 개발자가 몇 주 뒤의 본인이 될 수도 있는 것이다.

개발자들은 변경될 것 같은 부분을 경험적으로 혹은 본능적으로 파악할 수 있다.
interface를 적절하게 사용하면 변경을 지역화 할 수 있다.

객체망을 만들 듯 설계하면서 TDD를 한다고 했는데, 레거시 코드 리팩토링을 위해 테스트 코드는 어떻게 만드나?

TDD는 method 하나에 대해서 단위 테스트를 짠다는 느낌보다는
객체망을 형성해가며 실행 흐름을 테스트 한다는 느낌이 크다.
하지만 이미 존재하는 레거시 코드에 대해서 그렇게 하는 것은 쉽지 않다고 생각한다.
우선 외부 라이브러리에 대해서 통합테스트 하는 느낌으로
method 레벨로 테스트 코드를 작성하고 리팩토링 해나가는 것이 좋지 않을까..

좋은 설계를 하려면 어떻게 해야 하나?

우리 팀 또한 최고 좋은 설계가 어떤 모습인지 모르고 그렇게 하려고 하지 않는다.
처음 부터 디자인 패턴을 생각하고 그렇게 만들려고 하지 않는다.
객체 지향 원칙을 따라 개발하다 보면 어느순간 그 패턴이 되어 있는 경우가 많다.
한가지 팁은 extract method 를 하는 것이 중요한 것 같다.
일단 메소드로 추출되어 있다면 언제든지 다른 객체에게 책임을 넘겨 줄 수 있다.

계속 QnA를 추가 할 수 있기를…

Share