테스트 암 Test Cancer

TestCancer design 2007년 12월 6일 Reactions

전업을 저자로 전환함에 따라, 시간이 갈수록 소프트웨어 개발 현장과 멀어져 가는 내 자신이 걱정된다. 다른 유명한 거장들이 현실과 동떨어진 모습을 본 적이 있는데, 내가 그와 동일한 불안감을 느끼고 있다. 이런 불안감과 싸우는데 가장 큰 도움이 되는 것은 바로 ThougtWorks다. 그곳에서 평상시처럼 현실감을 느낄 수 있다.

ThoughtWorks는 또한 현장의 아이디어를 얻을 수 있는 원천이며, 나는 동료들이 알아내거나 개발한 유용한 것들에 대해 글을 쓰는 것을 좋아한다. 보통 그것들은 나의 몇몇 독자들이 사용할 수 있길 바라던 유용한 아이디어들이었다. 나의 이번 주제는 그러한 선물과도 같은 주제는 아니다. 이번 것은 답변을 할 수 없는 문제에 관한 것이다.

그 시나리오는 다음과 같다. 우린 프로젝트를 고객으로부터 요청 받은 뒤 멋진 새로운 소프트웨어를 만들어 준다. 근래의 유행처럼, 이 소프트웨어에 대한 다양한 자동화된 테스트를 제공한다(보통 기능 코드의 라인 수 만큼의 테스트 코드가 존재한다.). 이런 테스트들은 보통 단위 테스트와 경계 기능 그리고 인수 테스트를 포함하고 있다. 두 방법의 테스트 모두 소프트웨어가 무엇을 하는지 그리고 소프트웨어를 개선시킬 때 어떤 버그가 발생하는지 빠르게 알아낼 수 있는 유용한 설명서다. 우린 이런 테스트들을 소프트웨어 시스템 개발을 성공시킬 수 있는 요소로써, 중요시하고 있다.

몇 개월 후에 우리는 행복한 고객으로부터 소프트웨어에 새로운 특징이나 기능을 추가하기 위한 작업 요청을 받게 된다. 그럼 작업에 돌입하고 문제가 있을 만한 부분을 중심으로 열심히 일하기 시작한다. 최소한 우리가 실수했을 만한 부분부터 말이다. 바로 그 순간 불쾌한 상황을 맞이하게 된다.

테스트가 더 이상 동작하지 않는다.

가끔 테스트가 빌드 스크립트에 포함되어있지 않아서, 몇 달 동안이나 실행된 적이 없을 수도 있다. 가끔 “테스트들”이 실행은 되지만, 그들 중 상당부분이 손실됐을 수 있다. 두 경우 모두, 우리의 중요한 테스트들을 엄청난 시간 소비를 야기하고 박멸하기조차 힘든 지독한 암에 걸리게 한다.

그럼 우린 대체 무슨 일이 발생했는지 물어보게 되고 “코드에 약간 손을 댔더니 테스트가 깨져서, 그 테스트들을 제거했습니다.”와 비슷한 답변을 듣게 된다. 여러분들은 이것을 우리의 실수라고 생각할 수 있다. 테스트에 대한 가치를 고객팀에게 충분히 설명하도록 관리하지 못했기 때문이다. 그냥 무시할 수 있는 것이 아니라 조사해야 할 필요가 있는 테스트가 무사히 통과하도록 하려면 더 많은 무언가를 해야 한다. 그러나 뭐라고 하든, 누군가는 이렇게 이야기할 것이다. 그런 테스트의 암은 흔히 발생하는 질병이라고.

테스트 암의 발생 원인이 테스트를 작성했기 때문이라고 생각하지 않는다. 비록 우리가 떠나자마자 맹독 기질이 있는 변경으로 인해 모든 테스트를 지워버렸다 하더라도, 그들의 가치는 이미 시스템을 개발할 때 얻을 수 있었기 때문이다. 그리고 테스트들이 항상 암에 걸리는 것은 아니다. 우리가 이미 수 년 전에 끝낸 시스템을 관리하고 있는 개발자로부터 자신이 TDD로 전향하게 되었다는 이야기를 들었다. 테스트는 우리의 코드가 다른 회사가 나중에 추가한 코드보다 더 쉽게 동작하도록 해준다.

선언된 순서를 변경하는 것은 리팩터링인가?

원문 : IsDeclarationOrderingRefactoring     refactoring     1 September 2004

RefactoringBoundary.

자바 프로그램 내부에 있는 메소드와 필드가 선언된 순서를 변경하는 것은 리팩터링인가요?

근래의 프로그래밍 언어들은 내부에 선언되어 있는 요소들의 순서가 프로그램에 전혀 영향을 주지 않는다. 만약 텍스트 파일 내부에 있는 두 개의 메소드 위치를 서로 바꾸더라도, 프로그램은 아무런 영향을 받지 않는다. 이것을 리팩터링이라고 할 수 있는 이유는 변경으로 인해서 프로그램이 동작하는 방법에 영향을 주지 않기 때문이다. 이것은 설계를 변경하지 않으며, 만약 설계가 바뀐다면 리팩터링이라고 할 수 없다.

리팩터링 정의에서, “이해하기 쉽고 수정하는 비용을 최소화 하도록” 이라는 구문을 사용했다. 선언된 위치를 변경하는 것이 이에 해당하는가? 몇몇 경우에 그럴 수 있다고 생각한다. 클래스 내부에서 서로 관련되어 있는 속성들을 묶어두는 것이 좋다. 그러한 방법으로 속성들을 정렬하면 클래스가 어떻게 동작하는지 이해하는데 도움이 된다. 특히 테스트 케이스를 작성할 때 유용하다. (비록 특정 xunit 구현체에서는, 순서가 실행 결과에 영향을 줄 수 있지만 말이다.) 결국 코드의 이해도를 높여주기 때문에, 선언된 순서 변경을 리팩터링이라고 볼 수 있다.

이것이 내부 구현을 변경하지 않는다는 사실은 중요하지 않다. 메소드의 이름 변경은 실행하는 내용을 변경하지는 않는다. 하지만 이름 변경은 프로그램의 이해도를 높이는 매우 중요한 리팩터링이다.

리팩터링 정의

원문 : DefinitionOfRefactoring     refactoring     

나(Martin Fowler)의 리팩터링 책에서, 리팩터링에 대한 몇몇 정의를 내렸다.

리팩터링 (명사): 소프트웨어의 내부 구조를 보다 이해하기 쉽고 수정하는 비용을 최소화 하도록 하는 변경. 이 때 “주목할 만한” 행동의 변경이 있으면 안 된다.

리팩터링 (동사): “주목할 만한” 행동의 변경 없이, 몇몇 리팩터링들을 적용하여 소프트웨어의 내부 구조를 변경하다.

발견하지 못한 버그를 수정하는 것은 리팩터링인가?

원문 : IsFixingAnUnknownBugRefactoring     refactoring     3 September 2004

RefactoringBoundary.

Przemyslaw Pokrywka가 매우 난해한 질문을 했다. 에서 소개한 리팩터링 중에 하나로 Introduce Null Object라는 것이 있는데, (이것은 매우 유용한 리팩터링으로 Josh의 새 책에서도 다루고 있다) Przemyslaw의 요지는 이 리팩터링이 행동을 바꿀 수 있다는 것이었다. 만약 여러분이 null을 반환하는 메소드를 가지고 있고, 그 반환 값인 null에게 메소드 호출을 하면 null pointer exception을 받게 될 것이다. 이럴 때 Null Object를 사용해서 (예외를 발생시키는 것이 아니라) 기본 행동을 수행하도록 정의할 수 있다.

요즘 다수의 리팩터링들이 행동을 바꾸고 있는데, 이들은 근본적으로 그렇게 하도록 의도된 것 들이다. 예를 들어 Form Template Method를 적용하면, 프로그램이 다르게 동작한다. 핵심적으로 질문해야 할 것은 리팩터링 정의에서 언급한 “주목할 만한” 행동에 해당하는가 이다. “주목할 만한” 행동이란 프로그램이 원래 의도했던 것을 변경했는지 여부를 뜻한다. Introduce Null Object를 사용하면 프로그램에서 반환된 레퍼런스 변수를 조작하는 부분 (특히 null인지 확인하는 부분)을 살펴보아야 한다. 그렇기 때문에 이 리팩터링이 다소 복잡한 것이다.

질문 중에서 가장 흥미로운 부분은 만약에 버그가 있는 부분을 놓치면 어떤 일이 발생하는가 이다. 프로그램 내부의 어디에선가 null 레퍼런스에게 메소드를 호출하는 부분이 있다고 하자. 이 부분을 간과하여 놓쳤고 최종 사용자에게까지 전달되었다면, 리팩터링 전에는 예외를 발생시켰을 것이다. 리팩터링 후에는 기본 행동을 가지게 되고 이것은 사실상 버그를 고친 것에 해당한다. 미처 발견하지 못했던 버그를 고치는 것은 리팩터링일까?

그렇다. 왜냐면 스스로가 지각하지 못했거나 충분히 살펴보지 못한 (버그를 발생시키는) 행동은 “눈에 띄는” 행동이라고 할 수 없기 때문이다. 비록 버그를 알고 있었다 하더라도, 행동을 변함없이 유지하려고 인식했던 버그가 아니라면, 여전히 그것을 리팩터링이라고 불러도 좋다.

이것은 흥미로운 경우이기 때문에, 내 생각을 쉽게 바꿀 수도 있고 이와 비슷한 경계 사례들을 더 조사해 봐야겠다.

여기서 생각해 볼 것 한 가지는 수작업으로 하는 리팩터링과 툴 기반의 리택퍼링의 차이점이다. 손수 하는 리팩터링은 이런 식의 스스로 판단을 할 수 있는 반면에, 툴을 사용할 때는 좀 더 주의해야 한다. 아직은 툴들이 행동을 유지하는 것을 항상 보장하지는 못한다. 심지어, 파일로부터 읽어 들인 이름으로 리플렉션을 사용하여 메소드를 호출하는 경우 rename method는 리팩터링 도중 깨질 수 도 있다.

Active Record

원문 : http://www.martinfowler.com/eaaCatalog/activeRecord.html

번역

액티브 레코드


테이터베이스의 테이블 또는 뷰의 레코드를 랩핑한 것에 해당 데이터를 사용할 도메인 로직을 추가한 객체이다.


자세한 설명은 P of EAA 페이지 160을 참조.

사용자 삽입 이미지데이터와 행위를 가지고 있는 객체이다. 여기 있는 데이터의 대부분은 영속성을 가지며 데이터베이스에 저장된다.  액티브 레코드는 데이터에 접근하는 로직을 도메인 객체에 넣는 가장 노골적인(명백한, 분명한) 접근 방법이다. 이 방법을 사용하면 누구든지 해당 데이터를 데이터베이스에서 어떻게 읽어오고 저장할지 알 수 있다.