1. 레거시 코드 활용 전략
4장 봉합 모델
5장 레거시 코드를 위한 도구
아꿈사
http://cafe.naver.com/architect1
최유림
http://blog.naver.com/sikyungelove
2. 천공 카드 프로그래밍
• 데이터를 표현하기 위해 규칙에 따라 구멍을 뚫어
사용하는 종이 카드로서 초기의 저장매체
• 천공 위치에 구멍을 뚫거나 뚫지 않음으로서 하나의
비트를 나타날 수 있음
http://ko.wikipedia.org/wiki/%EC%B2%9C%EA%B3%B5_
%EC%B9%B4%EB%93%9C
11. • 전처리란 컴파일 전에 처리하는 매크로
• #로 시작 ex. #include <stdio.h>
• 전처리기를 통하여 동작을 변화시키지만 코드는
편집하지 않도록 정의
• 많은 봉합의 기회 제공
• 전처리기 사용시 코드의 명료성이 떨어짐
• #define으로 정의되는 매크로는 단순히 텍스트 치환만
수행
• 불명확한 버그를 숨기기 위한 매크로를 만들기 쉬움
13. 연결 봉합
• 링커는 컴파일러를 통해 만
들어진 여러 Object File들을
하나의 실행파일로 만듦
• C, C++은 독립된 링커 존재
• 자바는 링크 작업이
보이지 않음
14. • 연결 봉합을 이용하는 가장 쉬운 방법은 바꾸고자
하는 클래스나 함수를 위해서 별도의 라이브러리를
만드는 것
• 테스트 해야 할 때 클래스나 함수 제작에 연결하지
않고, 새로 생성된 클래스나 함수에 연결되도록 빌드
스크립트를 변경하면 동작을 변화시키지만 코드는
편집하지 않음
• 제 3의 라이브러리를 호출하는 코드 베이스를 가진
경우 유용함
15. bool CAsyncSslRec::Init()
{
if(m_bSslInitialized){
return true;
}
m_smutex.Unlock();
m_nSslRefCount++;
m_bSslInitialized = true; PostReveiveError가 전역함수
FreeLibrary(m_hSslDll1); -> 라이브러리 생성
m_hSslDll1 = 0;
-> 동작 제거를 위해 라이브러리 연결
FreeLibrary(m_hSslDll2);
m_hSslDll2 = 0; -> 테스트 할때는 테스트 라이브러리와 연결
if(!m_bFailureSent){ -> 실제 시스템 빌드시, 제작 라이브러리와 연결
m_bFailureSent = true;
PostReceiveError(SOCKETCALLBACK, SSL_FAILURE);
}
CreateLibrary(m_hSslDll1, "syncesel1.dll");
CreateLibrary(m_hSslDll2, "syncesel2.dll");
m_hSslDll2->Init();
m_hSslDll2->Init();
return true;
}
16. 객체 봉합
• 객체지향 프로그램은 어떤 메소드가 실행될지
정의하지 않음
• 같은 이름을 가지는 메소드가 하나 이상 있을 수
있음
• 주변 코드 변화 없이 어떤 메소드가 호출될지 변
경할 수 있는 경우가 객체 봉합
17. bool CAsyncSslRec::Init()
{
if(m_bSslInitialized){
return true;
}
m_smutex.Unlock();
m_nSslRefCount++;
m_bSslInitialized = true;
PostReveiveError를 오버라이드 하는
FreeLibrary(m_hSslDll1);
m_hSslDll1 = 0; 테스트용 하위 클래스 객체 생성
FreeLibrary(m_hSslDll2); -> 동작을 변화시키지만
m_hSslDll2 = 0;
코드는 편집하지 않도록 함
if(!m_bFailureSent){
m_bFailureSent = true;
PostReceiveError(SOCKETCALLBACK, SSL_FAILURE);
}
CreateLibrary(m_hSslDll1, "syncesel1.dll");
CreateLibrary(m_hSslDll2, "syncesel2.dll");
m_hSslDll2->Init();
m_hSslDll2->Init();
return true;
}
21. 리팩토링 검증
• 리팩토링 과정에서 버그가 생길 수 있음
• 자동화된 리팩토링 도구에 버그가 있을 수 있음
• 리팩토링 후 동작을 변경시키지 않는지 검증해야
함
22. 리팩토링 예제
public class A{ public class A{
private int alpha = 0; private int alpha = 0;
private int getValue(){ private int getValue(){
alpha++; alpha++;
return 12; return 12;
} }
public void doSomething(){ public void doSomething(){
int v = getValue(); int total = 0;
int total = 0; for(int n=0; n<10; n++){
for(int n=0; n<10; n++){ total += getValue();
total += v; v를 제거하라!! }
} }
} }
}
23. 리팩토링 예제
public class A{ public class A{
private int alpha = 0; private int alpha = 0;
private int getValue(){ private int getValue(){
alpha++; // alpha 1 증가 alpha++; // alpha 10 증가
return 12; return 12;
} }
public void doSomething(){ public void doSomething(){
int v = getValue(); int total = 0;
int total = 0; for(int n=0; n<10; n++){
for(int n=0; n<10; n++){ total += getValue();
total += v; 리팩토링 후 }
} 동작이 변경됨 }
} }
}
테스트 루틴을 두어 리팩토링 후 수행!!
ex) alpha 값 검증
25. xUnit 단위 테스트 프레임워크
• 소프트웨어의 함수나 클래스 같은 서로 다른 구성
원소(단위)를 테스트 하는 프레임워크
• 같은 테스트 코드를 여러번 작성하지 않음
• Java 단위 테스트는 jUnit
C++ 단위 테스트는 CppUnit
.NET 단위 테스트는 Nunit
• 오픈소스로 사용 가능
27. import junit.framework.*;
public class FormulaTest extends TestCase{
// testXXX() 형식의 메소드
public void testEmpty(){ // 테스트 하려는 내용(빈 경우 테스트)
// 확인코드 // 코드포함가능(새로운 객체 생성, value 메소드 이용)
assertEquals(0, new Formula("").value());
}
public void testDigit(){
// 값이 일치하면 테스트 통과, 아니면 테스트 실패
assertEquals(1, new Formula("1").value());
}
}
메소드 별로 서로 영향을 주지 않기 위해
각 테스트 메소드 용으로 완전히 분리된 객체 생성
28. public class EmployeeTest extends TestCase{
private Employee employee;
//테스트 메소드가 실행되기 전에 각 테스트 객체에서 실행됨
protected void setUp(){
//각 테스트에서 사용할 객체 생성
employee = new Employee("Fred", 0, 10);
TDate cardDate = new TDate(10, 10, 2000);
employee.addTimeCard(new TimeCard(cardDate, 40));
}
public void testNormalPay(){
//setUp에서 생성된 하나의 employee가
한번만 시간카드의 봉급 계산하는지 검사
assertEquals(400, employee.getPay());
}
public void testOvertime(){
TDate newCardDate = new TDate(11, 10, 2000);
employee.addTimeCard(new TimeCard(newCardDate, 50));
//setUp에서 생성된 하나의 employee가
초과 근무 조건을 발생시키는지 검사
assertTrue(employee.hasOvertimeFor(newCardDate));
}
}
36. 정리가 안되는 맞는 얘기들
• 재사용 가능하도록 작은 조각들로 쪼개 프로그램
을 작성하는 것이 좋음
• 자주 독립적으로 재사용되는 모듈화는 어려운 일
• 테스트하면 코드를 다른 각도에서 볼 수 있게 됨
• 테스트 루틴을 작성하려 할 때서야 기존의 코드가
얼마나 엉성하게 짜여져 있는지 알게 됨
37. 비트 경제(?)와 공짜 테스트
나는 개발자
개발 해서 돈을 벌지~
그런데 내가 왜 개발하면서
테스트 코드를 만들어야지?
테스트는 QA가 알아서 할텐데
뭣하러 공짜로?
38. 공짜가 아니야~
개발 단계에서 작성하는 테스트 코드는
QA가 진행하는 테스트보다
비용과 시간이 절감되지
기획과 합심하면 QA쯤이야
그 화폐를 우리 손으로~