Whiteship's Note


테스트 암 Test Cancer



TestCancer design 2007년 12월 6일 Reactions

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

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

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

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

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

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

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

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

top

Write a comment.


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



원문 : IsDeclarationOrderingRefactoring     refactoring     1 September 2004

RefactoringBoundary.

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

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

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

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

top

Write a comment.


리팩터링 정의



원문 : DefinitionOfRefactoring     refactoring     

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

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

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

top

Write a comment.


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



원문 : 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는 리팩터링 도중 깨질 수 도 있다.

top

Write a comment.


Active Record

RUBY/on Rails : 2007.06.01 21:38


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

번역

액티브 레코드

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

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

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

top

Write a comment.


Self Testing Code design



원문 : http://www.martinfowler.com/bliki/SelfTestingCode.html

‘자체 테스트 코드’는 리팩토링에서 기능적인 소프트웨어와 결합되어 전체적으로 자동화된 테스트를 언급하기 위해 사용했던 단어다. 이 단어를 이야기 할 때는 제일 먼저 XUnit 군의 테스트 프레임워크들이 생각난다.

테스트 주도 개발(TDD)
은 자체 테스트 코드를 작성할 때 선호하는 방법이지만 이 방법밖에 없는 것은 아니다. 기능 코드를 개발하기 전에 테스트를 작성하는 것은 그렇지 않은 경우에 비해 많은 장점을 얻을 수 있다. 자체 테스트 코드에서 가장 중요한 것은 테스트 코드를 가지고 있다는 것이지 그것들을 어떻게 만들어 냈는가가 아니다.
top

Write a comment.


TestDrivenDevelopment design



TestDrivenDevelopment design

원문 : http://www.martinfowler.com/bliki/TestDrivenDevelopment.html

테스트 주고 개발(TDD)는 테스트를 통해서 개발을 이끌어 내는 설계 기술이다. 본질적으로 다음 세 개의 단순한 단계를 반복하는 것이다.

•    다음으로 추가하고 싶은 기능을 위한 테스트를 작성한다.
•    테스트가 통과 하도록 기능 코드를 작성하라.
•    전체적으로 구조화 되도록 새로운 코드와 기존의 코드를 재구성한다.

시스템의 기능을 구현할 때 한번에 하나씩 테스트 하면서 지속적으로 이 세 단계를 반복한다. XPE2가 선 테스트 프로그래밍(Test First Programming)이라고 부르는 대로 Test를 먼저 작성하는 것은 두 가지 주요 장점이 있다. 그 중 가장 명백한 것으로 테스트를 통과하는 기능 코드만을 작성할 수 있기 때문에 자체 테스트 코드를 얻을 수 있다. 두 번째로 테스트를 먼저 생각하게 되면 코드의 인터페이스를 먼저 생각하게 된다. 인터페이스 그리고 클래스를 어떻게 사용할 것인지에 초점을 맞추는 것은 구현으로부터 인터페이스를 분리해 내는데 도움이 된다.

TDD의 효율성을 올리는 가장 흔한 방법으로 세 번째 단계를 생략하는 것이라고 들었다. 깔끔하게 유지하기 위해 코드를 재구성 하는 것은 TDD 프로세스의 핵심이다. 그렇게 하지 않으면 난잡한 코드 조각 덩어리들의 모임을 보게 될 것이다. (그래도 최소한 테스트는 가지고 있을 것이기 때문에 대부분의 설계 실패에 대한 고통보다는 덜 할 것이다.)

top

Write a comment.


3장 코드 속의 나쁜 냄새 - 중복된 코드

Refactoring/1~4장 : 2006.10.06 22:00


1장2장을 통해서 리팩토링이 어떻게 돌아가는지 알게 됐습니다. 하지만 리팩토링을 어떻게 하는지 안다고 해서 할 수 있는 것은 아닙니다. 언제 해야 하는지를 알아야 하는데... 그게 어려운 것 같네요. 3장을 Kent Beck이랑 Martin Fowler가 썼는데도 명확한 시점이라기 어떤 "냄새"가 날 때 라는 모호한 시점을 제기했네요. 경험적으로 인간의 직관보다 나은 기분은 없기 때문이라고 합니다. 그럼 이제 부터 어떠한 "냄새"들이 있으며 그런 "냄새"들은 어떻게 제거할지 살펴봅시다.

중복된 코드(Duplicated Code)

악취 중에 일등이 중복된 코드라고 하네요.
  • 한 클래스의 서로 다른 두 메소드 안에 같은 코드가 있는 경우 => Extract Method로 메쏘드로 뽑아내고 호출하도록 변경.
  • 동일한 슈퍼클래스를 갖는 두 서브 클래스에서 같은 코드가 나타나는 경우 => 양쪽 클래스에서 Extract Method를 한 뒤 Pull UP Method를 사용할 수 있슴.
  • 만약 메소드들이 같은 작업을 하지만 다른 알고리즘을 사용한다면 => 더 명확한 것을 선택하여 Substitute Algorithm을 사용할 수 있습니다.
  • 서로 관계가 없는 두 클래스에서 중복된 코드가 있는 경우에는 한쪽 클래스에서 Extract Class를 사용한 다음 양 쪽에서 이 클래스를 사용하도록 하는 것을 고려할 것.
  • 다른 가능성 : 메소드가 클래스 중 하나에 포함되어 있고, 다른 클래스에서 호출되어야 하거나 또는 세 번째 클래스에 속하는 그 메소그가 원래 두 클래스에서 참조되어야 하는 경우. => 뭔말인지...전혀 감이 안잡히는데요;;;


top

Write a comment.


1장 리팩토링, 첫 번째 예제

Refactoring/1~4장 : 2006.10.03 01:01


먼저 리팩토링이란? 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방법으로, 소프트웨어 시스템을 변경하는 프로세스이다. 이것은 버그가 끼어 들 가능성을 최소화하면서 코드를 정리하는 정형화된 방법이다.

"코드가 작성된 후에 디자인을 개선한다."

물론 그 코드는 디자인을 거쳐 작성이 되었겠지만 코드가 디자인을 잘 따르지 않았거나 디자인이 잘 못 됐을 수도 있기 때문에 어감이 반대로 된 듯해도 맞는 말이다.
새로운 기능을 추가해야 하는데 프로그램의 코드가 새로운 기능을 추가하기 쉽도록 구조화되어 있지 않은 경우에는 먼저 리팩토링을 해서 프로그램에 기능을 추가하기 쉽게 하고, 그 다음에 기능을 추가한다.

유지보수에는 네 종류의 유지보수가 있는데 기억이 가물가물 하지만 억지로라도 떠올려 보면
에러가 발생하여 수정하는 유지보수(corrective maintanance)
환경의 변화에 따라 적응시키는 유지보수(adaptive maintanance)
미래에 발생할 문제를 미리 예방하는 유지보수
완벽을 기하기 위한 기능을 추가하는 유지보수 가 있다고 배웠다.(시스템 분석 및 설계 시간에...)
여기서는 네번째 유지보수 측면을 고려한 듯하다. 하긴 리팩토링 자체를 유지보수로 본다면 위 네가지 모두 고려대상인 듯하다.

리팩토링을 시작하기 전에 견고한 테스트 세트를 가지고 있는지 확인하라. 이 테스트는 자체 검사여야 한다.

테스트의 중요함을 할 수 있다. 요새 Agile Java 책을 스터디 하면서 TDD(Test Driven Development)를 공부하고 있는데 하나의 습관인지라 역시 쉽지 않다. 습관을 바꾸는게 가장 힘든일인듯 하다.(내 글씨는 악필인데 초등학교 때 서예학원도 다녀보고 맞기도 엄청 맞았지만 아직도 악필이다 --)

리팩토링은 작은 단계로 나누어 프로그램을 변경한다. 실수를 하게 되더라도 쉽게 버그를 찾을 수 있다.

조금씩 고쳐 나갈 때마다 계속해서 test를 해줘야 한다. 그래야 쉽게 버그도 찾을 수 있고 오히려 한번에 왕창 해두고 버그가 발생해서 어디가 문제인지 찾는데 시간이 더 오래 걸린다.

컴퓨터가 이해할 수 있는 코드는 어느 바보나 다 짤 수 있다. 좋은 프로그래머는 사람이 이해할 수 있는 코드를 짠다.

아~ 감명깊은 말이다. 주석의 중요함에 대해 써있는 책을 몇 번 봤었다. 그러나 주석이 잘 달린 프로그램 보다는 주석이 없어도 이해가 되는 프로그램인 듯하다. 물론 주석도 없고 이해도 안되는 코드는...최악이겠지만 말이다. 그러려면 역시 작명에도 신경을 잘 써야 하지만 대부분의 프로그램 언어가 영어인 관계로 작명+작문 이 합쳐지게 된다는 태생적인 문제가 있다.(영어 공부도 열심히?ㅋ)

오늘은 여기까지 보고 자야겠다. 내일 데이트를 해야한다.

Good Night!

1장을 다 보았다.(자랑인가? ㅋ) 보기만 했고 손으로 안따라 해봤기 때문에 아직 제대로 본건 아니다.

추가할 요약사항이 있어서 수정한다.

리팩토링의 리듬!

테스트 -> 조금 수정 -> 테스트 -> 조금 수정

top

  1. Favicon of http://younghoe.info/ BlogIcon 영회 2006.10.03 01:25 PERM. MOD/DEL REPLY

    유지보수를 잘 하기 위해서는...

    '유지보수에는 네 종류의 유지보수가 있는데'

    이런 것들을 빨리 잊어버리고, 이런 것들은 시험 보기 직전에 메모해서 암기하고
    당일날 까먹는 것이 좋다. :)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.10.03 06:57 신고 PERM MOD/DEL

    넵 ㅋㅋ 시험에 너무 자주 나오는 바람에 ㅋ :)

  2. Favicon of https://www.ikpil.com BlogIcon 최익필 2009.02.12 02:26 신고 PERM. MOD/DEL REPLY

    저도 이 책 읽기 시작했습니다. 자바는 하나도 몰라, 자바 문법도 보면서 같이 보고 있습니다. 더 자주 오게 될꺼 같습니다.

    Favicon of http://whiteship.me BlogIcon 기선 2009.02.12 09:22 PERM MOD/DEL

    네. 멋진 책이죠. 트랙백 감사합니다. :)

Write a comment.