Your SlideShare is downloading. ×
Devon 2011-b-5 효과적인 레거시 코드 다루기
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Devon 2011-b-5 효과적인 레거시 코드 다루기

319
views

Published on


0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
319
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 초록 좋은 설계와 개발 과정에 대한 많은 노력이 기울여져 왔다. 불행히도 이러한 노력은 프로젝트가 아무 것도 없 는 단계에서 시작하는 것을 간주했다. 하지만 대부분의 프로젝트는 레거시 코드를 수반한다. 레거시 코드는 신규 코드보다 100:1의 비율로 더 많다. 신규 코드로 작업하는 것 보다 레거시 코드로 작업하는 것은 더 많은 노력을 요한다. 이 발표에서는 레거시 코드에 기능을 추가, 수정하는 전 략과 몇가지 리팩토링, TDD 기법을 사례 중심으로 알아 보도록 한다.아무리 좋은 설계로 시작한 프로젝트라도 테스트가 없으면 변경이 두려워 리팩토링, 개선을 못하게 되고 점진적으로는 코드가 부폐하게 된다.아무리 나쁜 설계로 시작한 프로젝트라도 포괄적인 테스트가 있다면 변경에 대한 두려움이 없어서 점진적으로 리팩토링, 개선을 하여 좋은 구조를 갖게된다.
  • 2. 효과적으로레거시 코드 다루기 서비스플랫폼개발팀 백명석
  • 3. Contents The Way We Work The Way We Have To Do Working Effectively with Legacy Code Case Studies우리가 어떻게 일해 왔는지,우리가 일해야 하는지,그리고 테스트가 없는 레거시 코드를 효과적으로 다루는 전략과사례에 대해서 말씀드리겠습니다.
  • 4. The Way We Work “Quick & Dirty” ➜ “Slow & Dirty”그린필드 프로젝트라고 불리는 신규 프로젝트는 3개월 정도의 짧은 시간에 개발됩니다. 시간이 없이니 테스트, 리팩토링 없이 개발합니다. 사전 작업에 대한 제약이 없으므로이때는 아무런 문제가 없습니다.서비스가 런칭되면 대개 3년 이상 운영됩니다. 신규 요구사항은 넘치고, 버그 수정에 대부분의 시간을 보내게됩니다. 테스트가 없는 dirty 코드는 테스트, 리팩토링이 어려워많은 비용을 유발하고, 기존 기능에 버그를 유발할 수도 있기에 Quick & dirty는 결국 slow & dirty됨
  • 5. The Way We Have To Do We Already Have Dirty Working Code Work Effectively with Legacy Code그럼 어떻게 해야 할까요 ? 이미 동작하고 있는 지저분한 코드가 있는데.우리는 테스트가 없는 레거시 코드를 효과적으로 다룰 수 있어야 합니다.
  • 6. Working Effectively with Legacy Code Wait Until A New Feature is Needed Change a little bit of design Add few tests in the affected area Eventually spread the test throughout the legacy code레거시에 코드를 다루는 기본적인 전략은 레거시에 테스트 추가하기 위해 특공대를 투입해서 거대한 새로운 프로젝트를 하는 것이 아니라 “새로운 기능이 필요할때까지 기다리는 것입니다”그리고 설계를 조금씩 개선하고, 영향받는 코드들에 대한 테스트를 조금씩 추가해서 최종적으로는 레거시 코드 전체에 테스트를 확산시키는 것입니다.
  • 7. One More: Automation Tools또 하나의 전략으로 자동화 툴이 있습니다.MoreUnit, EclEmma와 같은 eclipse plugin,eclipse의 hot fix, content assist, refactoring와 같은 자동화 기능mockito와 같은 유닛 테스트 작성을 위한 라이브러리등을 활용하는 것이 도움이 됩니다.
  • 8. Case Studies Sprout Method Characterization Test Subclass and Override Method Extract Method Object & Extract Method이제부터는 레거시 코드 활용의 사례에 대해서 말씀드리겠습니다.
  • 9. Have to Change But Not Enough Time Not Enough Time to Break Dependency and Add Tests기존 코드에 새로운 기능을 추가해야 하는데 의존성을 제거하고 테스트를 추가하기에는 시간이 너무 부족한 경우를 생각해 보겠습니다.필요한 새로운 메소드를 기존 클래스에 10분이면 추가할 수 있는데, 이 클래스에 대한 테스트를 만드려면 2시간은 걸릴 것 같은 상황이 있을 수 있습니다.
  • 10. Sprout Method You Need to Add a Feature to a System Can be formulated completely as new code Write the code in a new method Call it where the new functionality is supposed to be시스템에 새로운 기능을 추가해야 하는데 새로운 기능이 완전히 분리된 새로운 메소드로 구현할 수 있다면새로운 기능을 새로운 메소드로 작성하고 새로운 메소드를 해당 기능이 필요한 기존 코드에서 호출하는 방법이 sprout method의 개념입니다.
  • 11. Steps Identify where you need to make your code change. Write down a call for a new method then comment it out. Develop the sprout method using TDD Remove the comment to enable the call.1. 변경이 필요한 곳을 식별2. 새로운 메소드 호출을 추가하고, 커멘트 처리3. 새로운 메소드를 TDD로 구현4. 커멘트를 제거하여 메소드 호출이 일어나도록 한다.
  • 12. Sprout Method Example Add Synchronized Token Pattern to EditArticleController for prohibiting abusing compare session token and request token게시글 수정 컨트롤러에 어뷰징 방지를 위해 synchronized token pattern을 적용하는 예제
  • 13. Need to Make Change But Don’t Know What Tests to Write이와 같이 복잡한 상속구조를 가지고 있는 SearchEngineCreateArticleRequestFactory라는 클래스를 변경해야 하는데 어떻게 테스트를 작성할 지 모르는 경우를 생각보겠습니다.
  • 14. Need to Make Change But Don’t Know What Tests to Write Need to Know What the S/W Supposed To Do Write Tests Based on Those Ideas Dig up Old Requirements Documents and Project Memos ???- 변경을 가하기 전에 시스템이 어떻게 동작하도록 되어 있는지 알아내야 할 필요가 있다.- 이러한 요구사항에 기반하여 테스트를 작성할 수 있다.- 어떻게 해야 하나 ? 오래된 요구 사항 문서를 조사해야 하나 ? 프로젝트 메모들을 뒤져야 하나 ?
  • 15. Characterization Test What the systems does is more important than what it is supposed to do. We want preserve behavior Test that characterizes the actual behavior of a piece of code.- 시스템이 어떻게 동작하기로 약속되었는지 보다 실제로 어떻게 동작하는지가 훨씬 중요하다.- 비록 코드에 잘못이 있더라도 그 행위를 보존하기를 원합니다.- 코드가 실제로 어떤 행동을 하는지를 나타낼 수 있는 테스트를 작성하는 것.이러한 기법을 Characterization Test라고 한다.
  • 16. Steps Write an assertion that you know will fail Let the failure tell you what the behavior is Change the test so that it expects the behavior that the code produces절차1. 실패할 것이라고 알고 있는 assert 문장을 작성한다.2. 이 실패를 통해 실제 행위가 무엇인지 발견한다.3. 코드가 생산하는 행위를 기대하도록 테스트를 변경한다.
  • 17. Characterization Test ExampleXML 요청을 만드는 팩토리에 대한 테스트이 테스트는 다소 복잡해서 설명의 편의를 위해 미리 슈퍼 클래스에 복잡한 부분을 구현해 놓았습니다.
  • 18. Hard to Add Test Because of Unwanted Dependencystatic funciton등과 같은 원치 않는 의존성으로 인해 테스트를 작성하기 어려운 경우가 있습니다.
  • 19. Subclass and Override Method A core technique for breaking dependencies in OOP Use inheritance in the context of a test to nullify behavior that you don’t care about to get access to behavior that you do care aboutsubclass and override method는 OOP에서 의존성 제거를 위한 핵심 기능이다.테스트에서 subclassing을 아래와 같은 목적으로 사용한다.1. 원치 않는 행위를 무효화하기 위해2. 관심있는 행위에 접근하기 위해
  • 20. Steps Identify the dependencies that you want to separate Make each method overridable(adjust the visibility of the methods) Create a subclass that overrides the methods.분리하고 하는 의존성을 식별한다.메소드의 가시성을 protected 등으로 변경하여 메소드가 override 가능하도록 한다.해당 메소드들을 override할 서브클래스를 생성한다.
  • 21. Subclass and Override Method Examplestatic 함수는 powermock을 사용해서 mocking이 가능하다.하지만 static 함수 자체가 싱글톤과 마찬가지로 전역변수를 사용하는 것과 같은 잘못된 습관이다.그러므로 Static 함수로 인한 테스트 어려움을 제거하는 방법을 알아보자.
  • 22. Big Function쉽게 이해하기 어려운 큰 함수를 개선하는 경우를 생각해 보자.
  • 23. Big function hides classes큰 함수는 (인자, 로컬 변수로 표현되는 일련의 변수들)과 (이 변수들에 동작하는 들여쓰기로 구분되는 기능들)을 가지고 있다.클래스 = (일련의 변수(필드)들_ + (이 변수들에 동작하는 함수들)의 집합이다.그리므로 큰 함수는 클래스로 추출되어야 한다.
  • 24. Extract Method Object Steps Extract Method(invoke) Create New Inner Class Convert Arg. to Field Convert Local Var. to Field Move Initialization Logic to constructor1. 큰 메소드를 invoke라는 이름의 메소드로 추출한다.2. invoke 메소드를 갖는 inner 클래스를 생성한다. - 함수의 인자는 클래스의 생성자에 인자로 전달하고, invoke 메소드에서는 인자를 제거합니다.3. 생성자에 전달된 인자를 필드로 변경한다.4. 함수의 로컬 변수를 필드로 변경한다. 이러한 변경은 클래스 내부에서 메소드 호출시 불필요한 인자를 없애준다.5. 변수들의 initialization 로직은 constructor로 이동한다.
  • 25. Extract Method Object Parameterize Steps Differences Extract Methods Till You Drop Move Type to New File Rename class / method Method Ordering(Top-Down, To-paragraph)6. 이제 클래스에 더 이상 extract할 메소드가 없을 때 까지 extract method를 수행한다. 이때 반복적으로 나타나는 중복 문장들에서 약간씩 다른 점들이 존재한다면 이를 파라미터로 처리합니다.7. inner 클래스를 일반 클래스로 변경8. 클래스 이름과 메소드 이름을 의미있게 변경한다.9. 메소드 순서를 변경해서 top-down(to paragraph)으로 읽기 쉽게 변경한다.
  • 26. Extract Method Object Example Fitness이 예제에서는 큰 함수를 extract method object 기법을 통해 새로운 클래스로 추출하고,extract method를 수행하는 예를 보이도록 하겠다.
  • 27. Usage of Extract Method ObjectExtract Method Object는 TDD에서도 유용하게 사용될 수 있다. 이 예제는 켄트벡이 TDD 스크린 캐스트에서 사용한 예제인데, key-value 스토어의 일종이tyrant의 클라이언트를 만드는 예제이다.1. 이와 같이 클라이언트를 생성하고, put하고 get하여 동일한 값인지 확인하는 테스트로 시작한다. 이 기능을 구현하려면 많은 시간이 소요된다. 켄트벡 자신이2시간 가량 걸릴 것이라고 했으니.
  • 28. Usage of Extract Method Object이 보다는 본래의 의도는 커멘트 처리하고 소켓을 생성해서 서버에 연결이 되는지 부터 확인하는 것이 쉽다.디버깅 필요 없이 바로 실행이 되니
  • 29. Usage of Extract Method Object이렇게 테스트 코드에서 실제 구현을 다 해보는 것이다. 바로 수행해 볼 수 있으니 매우 편리하고 스피디하게 진행된다.
  • 30. Usage of Extract Method Object기능이 다 구현되면 extract method object 기법을 이용해서 production class로 추출한다.
  • 31. Usage of Extract Method Object약간의 리팩토리을 통해 상수를 제거하고, open, close, get 메소드를 추출하면 이와 같이 된다.테스트에서 시작해서 production code을 추출했기 때문에 대한 테스트가 자연적으로 생기는 것을 알 수 있다.항상 테스트부터 시작함으로써 테스트가 없는 레거시를 만들지 않고 항상 설계 개선을 위해 리팩토링을 할 수 있는 구조가 된다.
  • 32. Quick & Dirty is OK If you had tests It’ll remove Fear to clean itTDD debugging time / low level documentation / decoupling
  • 33. ReferenceWorking Effectively with Legacy CodeClean Coders Code Cast by Uncle BobTDD Code Cast by Kent beck토비의 스프링 3
  • 34. Q&A msbaek@daumcorp.com http://twitter.com/ctemplate. Grady Booch: Clean code should read like well written prose.. Martin Fowler: 어떤 바보도 컴퓨터가 이해할 수 있는 코드를 작성할 수 있다. 하지만 사람이 이해할 수 있는 코드를 작성하는 것은 좋은 프로그래머를 요한다.
  • 35. End
  • 36. Etc. Adding New Feature TDD / Programming by Difference Reuse What Study TestProgramming by Difference OO에서 새로운 기능을 추가하는 방법 중 하나 기존 클래스를 직접 수정하지 않고 새로운 기능을 추가하기 위해 상속을 사용 새로운 기능을 추가한 후에 어떻게 기능이 통합되어지길 원하는지 정확히 파악할 수 있다. 상속을 후에 위임으로 변경 가능상속의 문제점 다중 상속 불가(2개 이상의 클래스에 구현된 기능을 상속을 통해 사용할 수 없다). 상위 클래스의 기능을 하위 클래스에서 재사용(???) 한다면 상위 클래스 변경시 많은 하위 클래스의 변경이 유발됨상위 클래스에 로직을 구성하고 변경 가능한 부분은 인터페이스로 정의하고 필요에 따라 구현 클래스를 추가해야함.객체지향은 새로운 타입 추가에 열려있음. 새로운 함수 추가가 아니라.우리가 재사용하고자 하는 것은 상위 레벨의 로직이지 하위 레벨의 API가 아님 Independent Deployable(Development) Layered Architecture
  • 37. Don’t Start Big Project New Project for Refactoring or Testing Everything is fine at start Doing New design Cause Double-duty Impossible to replace the old system- 처음엔 좋다. 모든 것을 원하는 대로 할 수 있다.- 좋은 디자인을 위해서도 시간을 좀 보낸다.- 기존 시스템에 버그 수정, 기능 추가 요청이 들어온다. PM이 신 시스템이 나올때까지 요구사항 반영을 미뤄보려 하지만 고객은 기다리지 않는다.- 신규 프로젝트 팀은 기존 기능을 개선해서 구현하는 것 외에 새로운 요구사항도 구현해야 하는 이중고에 시달린다.- 더 이상 신규 프로젝트를 완료해서 신 시스템이 기존 시스템을 교체할 수 있다고 믿지 못한다.- 이 접근법은 항상 실패한다.
  • 38. Wait Until New Feature is Needed Change little bit of design Add a few tests in the affected area Eventually spread the test through out the legacy code Not all but important/vital bits are get tested
  • 39. Always Prefer Test First For all new code you write write test first Option either modify or add a new module write a new module with TFD
  • 40. Have to Understand but Function is Too Big Function Size(Screenful) Function Should Do One Thing Extract Major Sections into Function Extract Different levels of abstract함수 내에서 주요 섹션을 새로운 함수로 추출하는 것은 쉽다.하지만 추상화 수준이 다른 것을 모두 추출하는 것은 모호하다.
  • 41. Extract Different Levels of Abstraction Extract Till You Drop Until simply restates the code without changing abstraction level Most basic refactoring technique Safe with tool support- 이 코드가 한가지 일을 하는 것인가 ? 세가지 일을 하는 것인가 ? 이 코드를 한가지로 줄인다면includeSetupsAndTeardownsIfTestPage로 extract하면 추상화 수준의 변경 없이 단순히 코드를 재인용하는 것 밖에는 안된다. 이런 경우는 더 이상 extract할수 없는 것이다.- 리팩토링의 가장 기본 기법- 이클립스와 같은 툴의 지원으로 테스트 없이도 안전하게 수행할 수 있음.
  • 42. As a ResultComposed Method Pattern To ParagraphsAll class’s methods are less than 4 lines{} in if, while stmt removedComment removedEasy to read in top-down way