'소스코드'에 해당되는 글 4건

  1. 2007.10.18 자주 리펙토링을 하라.(3)
  2. 2007.10.16 자주 리펙토링을 하라.(2) (1)
  3. 2007.10.13 자주 리펙토링을 하라.(1)
  4. 2007.09.27 프로젝트 관리 어떻게 시작할까요?

자주 리펙토링을 하라.(3)

|



리펙토링을 실제로 어떻게 수행하는지.. 마틴 파울러(Martin Fowler)의 리펙토링 책에 나온 내용을 요약합니다.

여기에 정리한 내용은 인덱스 정도로 활용하시고.. 실제 리펙토링을 위한 예제나 자세한 설명은 책을 참고하시기 바랍니다.

1. 메소드 정리 (Composing Methods)

Extract Method (136)
그룹으로 함께 묶을 수 있는 코드 조각이 있으면, 코드의 목적이 잘 드러나도록 메소드의 이름을 지어 별도의 메소드로 뽑아낸다.

Inline Method (144)
메소드 몸체가 메소드의 이름 만큼이나 명확할 때는, 호출하는 곳에 메소드의 몸체를 넣고 메소드를 삭제하라

Inline Temp (146)
간단한 수식의 결과값을 가지는 임시변수가 있고, 그 임시변수가 다른 리펙토링을 하는데 방해가 된다면, 이 임시변수를 참조하는 부분을 모두 원래의 수식으로 바꾸라

Replace Temp with Query (147)
어떤 수식의 결과값을 저장하기 위해서 임시변수를 사용하고 있다면, 수식을 뽑아내서 메소드로 만들고 임시변수를 참조하는 곳을 찾아 모두 메소드 호출로 바꾼다. 새로 만든 메소드는 다른 메소드에서도 사용될 수 있다.

Introduce Explaining Variable (151)
복잡한 수식이 있는 경우에는, 수식의 결과나 또는 수식의 일부에 자신의 목적을 잘 설명하는 이름으로 된 임시변수를 사용하라.

Split Temporary Variable (155)
루프 안에 있는 변수나 collecting temporary variable도 아닌 임시변수에 값을 여러 번 대입하는 경우에는, 각각의 대입에 대해서 따로따로 임시변수를 만들어라.

Remove Assignments to Parameters (159)
파라미터에 값을 대입하는 코드가 있으면, 대신 임시변수를 사용하도록 하라.

Replace Method with Method Object (163)
긴 메소드가 있는데 지역변수 때문에 Extract Method를 적용할 수 없는 경우에는, 메소드를 그 자신을 위한 객체로 바꿔서 모든 지역변수가 그 객체의 필드가 되도록 한다. 이렇게 하면 메소드를 같은 객체 안의 여러 메소드로 분해할 수 있다.

Substitute Algorithm (167)
알고리즘을 보다 명확한 것으로 바꾸고 싶을 때는, 메소드의 몸체를 새로운 알고리즘으로 바꾼다.

2. 객체간의 기능 이동

Move Method (170)
메소드가 자신이 정의된 클래스보다 다른 클래스의 기능을 더 많이 사용하고 있다면, 이 메소드를 가장 많이 사용하고 있는 클래스에 비슷한 몸체를 가진 새로운 메소드를 만들어라. 그리고 이전 메소드는 간단한 위임으로 바꾸거나 완전히 제거하라.

Move Field (175)
필드가 자신이 정의된 클래스보다 다른 클래스에 의해서 더 많이 사용되고 있다면, 타켓 클래스에 새로운 필드를 만들고 기존 필드를 사용하고 있는 모든 부분을 변경하라.

Extract Class (179)
두 개의 클래스가 해야 할 일을 하나의 클래스가 하고 있는 경우, 새로운 클래스를 만들어서 관련 있는 필드와 메소드를 예전 클래스에서 새로운 클래스로 옮겨라.

Inline Class (184)
클래스가 하는 일이 많지 않은 경우에는, 그 클래스에 있는 모든 변수와 메소드를 다른 클래스로 옮기고 그 클래스를 제거하라.

Hide Delegate (187)
클래스가 객체의 위임 클래스를 직접 호출하고 있는 경우, 서버에 메소드를 만들어서 대리객체를 숨겨라.

Remove Middle Man (191)
클래스가 간단한 위임을 너무 많이 하고 있는 경우에는, 클라이언트가 대리객체를 직접 호출하도록 하라.

Introduce Foreign Method (194)
사용하고 있는 서버 클래스에 부가적인 메소드가 필요하지만 클래스를 수정할 수 없는 경우에는, 첫 번째 인자로 서버 클래스의 인스턴스를 받는 메소드를 클라이언트에 만들어라.

Introduce Local Extension (196)
사용하고 있는 서버 클래스에 여러 개의 메소드를 추가할 필요가 있지만 서버 클래스를 수정할 수 없는 경우, 필요한 추가 메소드를 포함하는 새로운 클래스를 만들어라. 이 확장 클래스를 원래 클래스의 서브클래스 또는 래퍼 클래스로 만들어라.

3. 데이터 구성 (Organizing Data)

Self Encapsulate Field (205)
필드에 직접 접근하고 있는 필드에 대한 결합이 이상해지면, 그 필드에 대한 get/set 메소드를 만들고 항상 이 메소드를 사용하여 필드에 접근하라.

Replace Data Value with Object (209)
추가적인 데이터나 동작을 필요로 하는 데이터 아이템이 있을 때는, 데이터 아이템을 객체로 바꾸어라.

Change Value to Reference (213)
동일한 인스턴스를 여러 개 가지고 있는 클래스가 있고 여러 개의 동일한 인스턴스를 하나의 객체로 바꾸고 싶으면, 그 객체를 참조 객체로 바꾸어라.

Change Reference to Value (217)
직고, 불변성(immutable)이고 관리하기 어려운 참조 객체가 있는 경우, 그것을 값 객체로 바꾸어라.

Replace Array with Object (220)
배열의 특정 요소가 다른 뜻을 가지고 있다면, 배열을 각각의 요소에 대한 필드를 가지는 객체로 바꿔라.

Duplicate Observed Data (224)
GUI 컨트롤에서만 사용 가능한 도메인 데이터가 있고 도메인 메소드에서 접근이 필요한 경우, 그 데이터를 도메인 객체로 복사하고 옵저버를 두어 두 데이터를 동기화하라.

Change Unidirectional Association to Bidirectional (232)
각각 서로의 기능을 필요로 하는 클래스가 있는데, 링크가 한쪽 방향으로만 되어 있는 경우, 반대 방향으로 포인터를 추가하고 수정자(modifier)가 양쪽 세트를 모두 업데이트 하게 변경하라.

Change Bidirectional Association to Unidirectional (236)
서로 링크를 가지는 두 개의 클래스에서 한 쪽이 다른 한쪽을 더 이상 필요로 하지 않을 때는 불필요한 링크를 제거하라.

Replace Magic Number with Symbolic Constant (240)
특별한 의미를 가지는 숫자 리터럴이 있으면, 상수를 만들고 의미를 잘 나타내도록 이름을 지은 다음 숫자를 상수로 바꾸어라.

Encapsulate Field (242)
public 필드가 있는 경우, 그 필드를 private으로 만들고 접근자를 제공하라.

Encapsulate Collection (244)
컬렉션(collection)을 리턴하는 메소드가 있으면, 그 메소드가 읽기 전용 뷰를 리턴하도록 만들고 add/remove 메소드를 제공하라.

Replace Record with Data Class (254)
전통적인 프로그래밍 환경에서 레코드 구조에 대한 인터페이스가 필요한 경우, 그 레코드를 위한 데이터 객체를 만들어라.

Replace Type Code with Class (255)
클래스의 동작에 영향을 미치지 않는 숫자로 된 타입 코드가 있으면 숫자를 클래스로 바꾸어라.

Replace Type Code with Subclass (261)
클래스의 동작에 영향을 미치는 변경 불가능하는 타입코드가 있다면, 타입 코드를 서브클래스로 바꾸어라.

Replace Type Code with State/Strategy (265)
클래스의 동작에 영향을 미치는 타입 코드가 있지만 서브클래싱을 할 수 없을 때는 타입 코드를 스테이트(state) 객체로 바꾸어라.

Replace Subclass with Fields (270)
상수 데이터를 리턴하는 메소드만 다른 서브클래스가 있으면, 그 메소드를 수퍼클래스의 필드로 바꾸고 서브클래스를 제거하라.

4. 조건문의 단순화

Decompos Conditional (276)
복잡한 조건문 (if-then-else)이 있는 경우, 조건 then 부분 그리고 else 부분에서 메소드를 추출하라.

Consolidate Conditional Expression (278)
같은 결과를 초래하는 일련의 조건 테스트가 있는 경우, 그것을 하나의 조건식으로 결합하여 뽑아라.

Consolidate Duplicate Conditional Fragments (281)
동일한 코드 조각이 조건문의 모든 분기 안에 있는 경우, 동일한 코드를 조건문 밖으로 옮겨라.

Remove Control Flag (283)
일련의 boolean 식에서 컨트롤 플래그 역할을하는 변수가 있는 경우, break 또는 return을 대신 사용하라.

Replace Nested Conditional with Guard Clauses (288)
메소드가 정상적인 실행 경로를 불명확하게 하는 조건 동작을 가지고 있는 경우, 모든 특별한 경우에 대해서 보호절을 사용하라.

Replace Conditional with Polymorphism (293)
객체의 타입에 따라 다른 동작을 선택하는 조건문을 가지고 있는 경우, 조건문의 각 부분을 서브클래스에 있는 오버라이딩 메소드로 옮겨라. 그리고 원래 메소드를 abstract로 만들어라.

Introduce Null Object (298)
null 체크를 반복적으로 하고 있다면, null 값을 null 객체로 대체하라.

Introduce Assertion (306)
코드의 한 부분이 프로그램의 상태에 대하여 어떤 것을 가정하고 있으면, assertion을 써서 가정을 명시되게 만들어라.

5. 메소드 호출의 단순화

Rename Method (313)
메소드의 이름이 그 목적을 드러내지 못하고 있다면, 메소드의 이름을 바꿔라.

Add Parameter (316)
어떤 메소드가 그 메소드를 호출하는 부분에서 더 많은 정보를 필요로 한다면, 이 정보를 넘길 수 있는 객체에 대한 파라미터를 추가하라.

Remove Parameter (318)
파라미터가 메소드 몸체에서 더 이상 사용되지 않는다면, 그 파라미터를 제거하라.

Separate Query from Modifier (320)
값을 리턴할 뿐만 아니라 객체의 상태도 변경하는 메소드를 가지고 있는 경우, 두 개의 메소드를 만들어서 하나는 값을 리턴하는 역할을 하고, 하나는 객체의 상태를 변경하는 역할을 하게 하라.

Parameterize Method (325)
몇몇 메소드가 메소드 몸체에 다른 값을 포함하고 있는 것을 제외하고는 비슷한 일을 하고 있다면, 다른 값을 파라미터로 넘겨 받는 하나의 메소드를 만들어라.

Replace Parameter with Explicit Methods (327)
파라미터의 값에 따라서 다른 코드를 실행하는 메소드가 있다면, 각각의 파라미터 값에 대한 별도의 메소드를 만들어라.

Preserve Whole Object (331)
어떤 객체에서 여러 개의 값을 얻은 다음 메소드를 호출하면서 파라미터로 넘기고 있다면, 대신 그 객체를 파라미터로 넘겨라.

Replace Parameter with Method (335)
객체가 메소드를 호출한 다음, 결과를 다른 메소드에 대한 파라미터로 넘기고 있다. 수신자 또한 이 메소드를 호출할 수 있다면 그 파라미터를 제거하고 수신자가 그 메소드를 호출하도록 하라.

Introduce Parameter Object (339)
자연스럽게 몰려다니는 파라미터 그룹을 가지고 있다면, 그것들을 객체로 바꾸어라.

Remove Setting Method (344)
어떤 필드가 객체 생성시에 값이 정해지고 그 이후에는 변경되지 않아야 한다면, 그 필드 값을 설정하는 모든 메소드를 제거하라.

Hide Method (348)
메소드가 다른 클래스에서 사용되지 않는다면, 그 메소드를 private로 만들어라.

Replace Constructor with Factory Method (350)
객체를 생성할 때 단순히 생성하는 것 이외에 다른 작업도 하고 있다면, 생성자를 팩토리 메소드로 대체하라.

Encapsulate Downcast (355)
메소드가 그 호출부에서 다운캐스트 될 필요가 있는 객체를 리턴하고 있다면 다운캐스트 하는 것을 메소드 안으로 옮겨라.

Replace Error Code with Exception (357)
메소드가 에러를 나타내는 특별한 코드를 가지고 있다면, 대신 예외를 던져라.

Replace Exception with Test (363)
호출부에서 먼저 검사할 수 있는 조건에 대해 예외를 던지고 있다면, 호출부가 먼저 검사하도록 바꿔라.

6. 일반화 다루기

Pull Up Field (368)
두 서브클래스가 동일한 필드를 가지고 있다면, 그 필드를 수퍼클래스로 옮겨라.

Pull Up Method (370)
동일한 일을 하는 메소드를 여러 서브클래스에서 가지고 있다면, 이 메소드를 수퍼클래스로 옮겨라.

Pull Up Constructor Body (373)
서브크래스들이 대부분 동일한 몸체를 가진 생성자를 가지고 있다면, 수퍼클래스에 생성자를 만들고 서브클래스 메소드에서 이것을 호출하라.

Push Down Method (376)
수퍼클래스에 있는 동작이 서브클래스 중 일부에만 관련되어 있다면, 그 동작을 관련된 서브클래스로 옮겨라.

Push Down Field (377)
어떤 필드가 일부 서브클래스에 의해서만 사용되고 있다면, 그 필드를 관련된 서브클래스로 옮겨라.

Extract Subclass (378)
어떤 클래스가 일부 인스턴스에 의해서만 사용되는 기능을 가지고 있다면, 기능의 부분집합을 담당하는 서브클래스를 만들어라.

Extract Superclass (384)
비슷한 메소드와 필드를 가진 두 개의 클래스가 있다면, 수퍼클래스를 만들어서 공통된 메소드와 필드를 수퍼클래스로 옮겨라.

Extract Interface (389)
여러 클라이언트가 한 클래스 인터페이스와 동일한 부분 집합을 사용하고 있거나, 두 클래스가 공통된 인터페이스를 가지는 부분이 있다면, 그 부분 집합을 인터페이스로 뽑아내라.

Collapse Hierarchy (392)
수퍼클래스와 서브클래스가 별로 다르지 않다면, 그것들을 하나로 합쳐라.

Form Template Method (393)
각각의 서브클래스에 동일한 순서로 비슷한 단계를 행하지만 단계가 완전히 같지는 않은 두 메소드가 있다면, 그 단계를 동일한 시그니처를 가진 메소드로 만들어라. 이렇게 하면 원래의 두 메소드는 서로 같아지므로, 수퍼클래스로 올릴 수 있다.

Replace Inheritance with Delegation (401)
서브클래스가 수퍼클래스 인터페이스의 일부분만 사용하거나 또는 데이터를 상속 받고 싶지 않은 경우, 수퍼클래스를 위한 필드를 만들고 메소드들이 수퍼클래스에 위임하도록 변경한 후 상속 관계를 제거한다.

Replace Delegation with Inheritance (404)
위임을 사용하고 있는데 전체 인터페이스에 대해 간단한 위임을 자주 작성하고 있다면, 위임하는 클래스를 대리객체의 서브클래스로 만들어라.




Trackback 0 And Comment 0

자주 리펙토링을 하라.(2)

|



리펙토링을 하려면 소스 코드 속의 나쁜 냄새를 맡을 수 있어야 한다고 합니다.

"리펙토링"이란 책에서 켄트 벡(Kent Beck)과 마틴 파울러(Martin Fowler)가 이야기한 코드 속의 나쁜 냄새에 대해 정리해 보려고 합니다.

사용자 삽입 이미지


중복된 코드 (Duplicated Code)
- 동일한 소스가 여기 저기 사용된다면 반드시 리펙토링을 해야 한다고 합니다.
Extract Method (136), Extract Class (179), Pull Up Method (370), Form template Method (393)

긴 메소드 (Long Method)
- C 프로그래밍부터 시작해서인지 절차적 프로그래밍에 익숙한 경우, 하나의 메소드에서 모든 일을 처리하는 경우가 종종 있습니다. 긴 메소드는 쪼개야 한다고 하네요~
Extract Method (136), Replace Temp with Query (147), Replace method with Method Object (163), Decompose Conditional (276)

거대한 클래스 (Large Class)
- 클래스가 너무 많은 일을 하면 변수도 많아지고, 중복된 코드도 많아질 가능성이 높다고 합니다.
Extract Class (179), Extract Subclass (378), Extract Interface (389), Replace Data Value with Object (209)

긴 파라미터 리스트 (Long Parameter List)
- 메소드에 전달되는 파라미터가 길면 소스를 이해하는 것이 어렵기 때문에 수정하는 것이 낫다고 합니다.
Replace Parameter with Method (335), Introduce Parameter Object (339), Preserve Whole Object (331)

확산적 변경 (Divergent Change)
- 말이 좀 어려운데요..  A라는 클래스를 "가" 이유 때문에  3개의 메소드를 수정해야 하고, 또 "나" 이유 때문에 4개의 메소드를 수정해야 한다면.. 차라리 "A가", "A나"와 같이 두개의 객체로 만드는 것이 바람직하다는 것인데요.. 대략적으로는 알겠는데 정말 확 와닿지는 않네요..
Extract Class (179)

산타총 수술 (Shotgun Sugery)
- 역시 어려운 말입니다. -.- 자주 수정하는 부분인데.. 한번 수정할 때마다 여러개의 클래스를 수정해야 한다면 이를 하나의 클래스만 수정하도록 변경해야 한다는 겁니다. 요건 가끔 있을 것 같네요..
Move Method (170), Move Field (175), Inline Class (184)

기능에 대한 욕심 (Feature Envy)
- 메소드가 자신이 속한 클래스보다 다른 클래스를 더 많이 활용하고 있다면, 옮겨야 겠죠..
Move Method (170), Move Field (175), Extract Method (136)

데이터 덩어리 (Data Clump)
- 한 클래스와 관련없는 여려 데이터들이 모여있는 경우입니다. 각각의 역할에 맞는 여러개의 객체로 쪼개야 한다고 하네요..
Extract Class (179), Introduce Parameter Object (339), Preserve Whole Object (331)

기본 타입에 대한 강박관념 (Primitive Obsession)
- 기본 타입만을 고집하지 말고 Money 클래스, Range 클래스, 전화번호 클래스, 우편번호 클래스등 특정한 작업을 위한 작은 객체를 충분히 활용하라고 합니다.
Replace Data Value with Object (209), Extract Class (179), Introduce Parameter Object (339), Replace Array with Object (220), Replace Type Code with Class (255), Replace Type Code with Subclasses (261), Replace Type Code with State/Strategy (265)

Switch 문 (Switch Statements)
- Switch 문은 객체지향 코드에서는 다형성을 이용해 수정해 주어야 한다고 합니다. 기본적으로 Switch문이 중복성을 가지고 있기 때문이라고 하네요~
Replace Conditional with Polymorphism (293), Replace type with Subclasses (261), Replace Type Code with State/Strategy (265), Replace Parameter with Explicit Method (327), Introduce Null Object (298)

게으른 클래스 (Lazy Class)
- 클래스가 충분한 일을 하지 않을 경우, 제거해야 한다는 겁니다.
Inline Class (184), Collapse Hierarchy (392)

추측성 일반화 (Speculative Generality)
- 앞으로 필요할 것 같아서 미리 추가한 기능과 관련된 코드중 실제로 사용되지 않는 것은 삭제하라는 거네요
Collapse Hierarchy (392), Inline Class (184), Remove Parameter (318), Rename Method (313)

임시 필드 (Temporary Field)
- 객체 안의 인스턴스 변수가 특정 상황에서만 사용된다면, 이해하기 어렵게 되므로 변경해야 한다고 하네요.
Extract Class (179), Introduce Null Object (298)

메시지 체인 (Message Chains)
- 어떤 객체를 사용하기 위해 다른 객체에 물어보고, 다른 객체는 다시 또 다른 객체에 물어보고, 그 객체는 다시 다른 객체에 물어보고.. 이런 경우가 메시지 체인이라고 하네요~~
Hide Delegate (187)

미들 맨 (Middle Man)
- 클래스 메소드의 대부분이 다른 클래스로 위임하고 있다면.. 지나친 캡슐화를 사용한고 있다는 것인데요.. 리펙토링을 적용해야 한다고 하네요~
Remove Middle Man (191), Inline Method (144), Replace Delegation with Inheritance (404)

부적절한 친밀 (Inappropriate Intimacy)
- 지나치게 친밀한 클래스는 서로 갈라 놓아야 한다고 하네요..
Move Method (170), Move Field (175), Change Bidirectional Association to Unidirectional (236), Replace Inheritance with Delegation (401), Hide Delegate (187)

다른 인터페이스를 가진 대체 클래스 (Alternative Classes with Different Interface)
- 같은 작업을 하지만 다른 시그너처를 가진 메소드에 대해서 리펙토링 하라는 거네요..
Rename Method (313), Move Method (170)

불완전한 라이브러리 클래스 (Incomplete Library Class)
- 기존의 라이브러리 클래스가 가지고 있었으면 하는 메소드가 있다면 리펙토링을 통해 보완하라는 겁니다.
Introduce Foreign Method (194), Introduce Local Extension (196)

데이터 클래스 (Data Class)
- get / set 메소드만 가진 클래스.. 실제로 많이 만드는 데요~ 이런 경우 적절한 리펙토링을 하라는 거네요~
Move Method (170), Encapsulate Field (242), Encapsulate Collection (244)

거부된 유산 (Refused Bequest)
- 상속구조가 잘못된 경우, 새로운 형제 클래스를 만들고 리펙토링해야 한다는 이야기 입니다.
Replace Inheritance with Delegation (401)

주석 (Comments)
- 주석을 써야 할 것 같다면 먼저 코드를 리펙토링 하여 주석이 불필요하도록 하라는 거네요..
Extract Method (136), Introduce Assertion (306)

리펙토링은 최적화의 개념이 아니라.. 소스 코드를 이해하기 쉽게 만드는 겁니다.
소스 코드 속의 나쁜 냄새를 잘 파악할 수 있도록 위의 내용을 참고하시기 바랍니다.




Trackback 0 And Comment 1
  1. 쭌이 2008.01.25 13:41 address edit & del reply

    좋은내용이라 네이버 블로그로 자료 퍼갈깨요
    출처는 이곳으로 써놓았습니다

자주 리펙토링을 하라.(1)

|



프로그래머들은 한번쯤 리펙토링이라는 것을 들어봤을 겁니다.
리펙토링이 좋다는 것은 익히 들어 알겠는데 실제로 못하는 경우가 대부분입니다.

왜 그럴까요?

우선, 리펙토링이 무엇이고 어떻게 하는 것인지 모르기 때문인 것 같습니다.
솔직히 저도 리펙토링 관련 책을 이번에 읽어보기는 했지만,
아직도 어떤 경우에 리펙토링을 해야 하는지 느낌이 확 오지는 않습니다. -.-

A->B로 변경하는 것이 설명되어 있으면, 바로 B->A로 바꾸는 것도 설명되어 있습니다.
즉, 경우에 따라 적용하는 리펙토링이 다르다는 것인데.. 이건 경험이 필요한 것 같습니다.~
끊임없이 생각해보고 변경하다보면 어떤 것이 올바른 리펙토링인지 알수 있지 않을까 합니다.

다음으로는 리펙토링을 하고 있으면, 윗분들은  아무것도 하지 않고 있다고 생각하는 경우가 많을 것 같습니다.
열심히 뭔가 코드를 고치고는 있는데, 프로그램 결과물이 바뀐게 없으니까요..
리펙토링은 기능개선이나 디버깅과 달리 프로그램을 현재 상태 그대로 두고 소스코드만 이해하기 쉽게 바꾸는 것이니까요..

하지만 이 작업의 중요성을 충분히 설명해 주어야 한다고 생각합니다.
프로젝트가 대규모가 될수록.. 추후 유지보수를 위해서도 리펙토링은 반드시 필요하거든요.

방법론에 따른 산출물이 있지 않느냐? 하고 반문할 수도 있지만..
글쎄요~~ 산출물은 끊임없이 바뀌는 프로그램을 모두 반영할 수 있을지 솔직히 의문이거든요
특히, 산출물에 기반하는 개발이 아닌, 개발후 형식적으로 만드는 산출물은 더욱 문제겠지요..
리펙토링을 통해 소스 자체가 훌륭한 산출물이 된다면 더할 나위 없지 않을까 합니다. ^^

사용자 삽입 이미지



마틴파울러(Martin Fowler)의 다음 이야기가 떠오르네요..
"컴퓨터가 이해할 수 있는 코드는 어느 바보나 다 짤 수 있다. 좋은 프로그래머는 사람이 이해할 수 있는 코드를 짠다."
그렇다면, 리펙토링은 언제 해야 할까요?
자주.. 생각날 때마다 하는 것이 따로 일정을 잡아서 하는 것보다는 수월하다고 하네요..

그리고 리펙토링을 하려면 잘못됐을 때 소스를 이전 버전을 바꿀 수 있는 버전관리와..
현재 프로그램 전체를 테스트할 수 있는 테스트코드 또한 중요한 요소라고 합니다.

리펙토링을 통해서 잘 디자인된 소스코드를 만드시기 바랍니다.




Trackback 0 And Comment 0

프로젝트 관리 어떻게 시작할까요?

|



프로젝트를 진행할 때, 현업에서 사용하는 방법론은 여러가지가 있습니다.
방법론!! 몇몇 사람들 특히 개발자들은 방법론은 쓸데없는 것이고 개발에 전혀 도움이 되지 않는다고 이야기 합니다.
저 역시도 RUP, 마르미, 이노베이터 등의 방법론을 토대로 프로젝트를 진행해 본 경험이 있습니다만,
솔직히 방법론이 무용지물이라는 생각을 해본 적이 꽤 있습니다.

이유는 바로 방법론에 맞추어 개발하고 산출물을 만드는 것이 아니라, 프로젝트 완료 시점에 방법론의 산출물을 한꺼번에 작성하거나 초기에 대충 작성해 놓고 나중에 한꺼번에 변경하는 것이 문제가 되는 것이었습니다.
그러다보니 오히려 방법론이 개발팀에 있어서는 짐이 되는 것이죠..

또, 방법론은 모든 프로젝트를 염두에 두고 만들어 놓은 것이므로.. 프로젝트의 특성에 따라 다시 재구성해서 진행할 필요가 있는데도 불구하고... 그냥 지난번에도 이런이런 것을 적용했으니 이번 산출물에도 이것들은 넣어야 해.. 하는 식으로 사용하므로 문제가 되는 것 같습니다.

일단, 제가 현재 사용하고 있는 제 나름대로의 방법론이 아닌 프로젝트 관리를 나열해 보고자 합니다.
물론 SI 프로젝트로서 고객에게 산출물을 제출해야 하는 경우에는 어쩔 수 없이 협의를 통해 방법론에 따른 산출물을 정의하지만.. 이것은 회사 내부 개발이나 저 혼자 개발할 경우.. 주로 사용하는 것입니다.

첫째, CVS와 같은 소스코드 관리는 필수입니다. 이게 없으면.. 소스에 대한 백업이나 통합등 여러가지를 수동으로 처리해야 하는 문제가 발생합니다. 먼저 CVS를 세팅하고 개발팀 전체가 사용할 수 있어야 합니다.
매일 CVS에 업데이터를 해야 하구요.. 프로젝트 관리자의 입장에서 수시로 들어가서 현재 진행상태를 눈으로 확인해 보는 겁니다.
소스코드의 버전관리는 이전 글(http://xmlmanager.tistory.com/6)을 참고하시기 바랍니다.
또한, CVS와 ANT를 이용해 서버에 배치하는 스크립트를 짜서 활용하기도 합니다.

둘째, 간트차트를 이용한 프로젝트 일정관리를 초기부터 합니다. 툴로는 MS Project를 사용하는데요.
여기서 중요한 점은 간트차트를 통한 일정관리를 1주일 단위로 초기에 전체적으로 잡아 놓습니다.
그리고 매주 업데이트 한다는 것입니다.
일정이라는 것이 늦어지는 경우가 많기 때문에 초기 계획시 늦어질 경우에 대한 버퍼도 마련해 두고요..
하지만, 개발팀에 절대 일정을 다그쳐서는 안됩니다. 매일 야근에 날새면서 개발한 것 치고 제대로 된 것이 없거든요.. 다만, 긴장이 풀어졌다는 느낌이 들지 않도록 유지하는게 중요하다고 봅니다. (이게 정말 어려워요.. -.-)

셋째, DB 설계입니다. DB 설계에서는 ER-Win으로 ER 다이어그램을 만들고요.. (logical, physical 두개 다 만듭니다.) CVS에 함께 공유합니다. 개발중에 DB 필드가 변경되는 경우가 종종 있는데요.. 그때는 공유된 다이어그램도 함께 변경하도록 해서.. 다이어그램과 실제 DB와 똑같이 유지시킵니다.
그리고 DB에서 사용하는 상태값들이 있습니다. 이건 메모형태로 ERD에 포함시켜 둡니다.
ER 다이어그램을 그려 놓으면 나중에 DB 관련 문서들을 만들기 편리합니다.

넷째, MiniSpecification이라는 문서를 하나 만듭니다.(MS-Word를 사용하고, 스타일을 적용함다) 초기에는 여기에 구성도, 전체 흐름, 기본 요구사항등을 자유형식으로 정리합니다. 프로젝트 진행 중에는 각 부분에서 비즈니스 로직이 들어갈 경우.. 해당 로직을 여기에도 정리해 놓습니다.
저는 이 스펙 문서를 꽤 중요하게 생각합니다. 추후 유지보수나 여러 측면에서 활용하려고 하는데요..
만약 이것이 없다면 소스코드를 추적해야 하니.. 시간이 더 걸리겠죠..
하지만, 개발자들은 이걸 그리 최신으로 유지하려고 하지 않습니다. 아무래도 소스코드 바꾸고 잊어버리는 경우가 많은 것 같습니다. 그래서 저는 소스를 확인할 때, 제가 직접 이부분을 정리하는 방향으로 하고 있습니다.
어차피 코딩을 안할 경우, 간트챠트 보고.. DB 확인하고.. 스펙 문서 다듬는 것이 기본 작업이 되니까요..

다섯째, 마지막으로 버그나 기능개선을 위한 엑셀 문서를 하나 만듭니다. 개발완료후, 사용할 것인데요..
Debug와 Enhancement 탭으로 나누고요..
우선순위, 수정여부, 수정일, 기록일, 버그재현단계, 예상수행결과, 실제수행결과, 수정처리자, 비고
의 형식으로 정리합니다.
이것 또한 CVS에 올려놓고 누구나 추가, 수정할 수 있도록 하지만.. 역시 제가 주기적으로 내용을 점검합니다.
(버그질라와 같은 것도 생각해 봤는데, 아직 적용하지는 않고 있슴다.)
이상이 프로젝트 관리만 할 때, 제가 하는 방법입니다. 문서는 MS-Project 파일, ERD 파일, Word 파일, Excel 파일 1개가 만들어집니다.
이렇게만 해도 프로젝트 진행을 관리하는데 바쁩니다. ㅋㅋ 그리고 산출물도 운영하는데 전혀 지장이 없을 만큼 충분히 나오지요..

앞으로 해보고 싶은 것은 개발자들에거 본인이 만든 로직에 대한 테스트코드를 생성하라는 주문을 하고 싶습니다. 어떤 프로젝트에서 개발자 부담을 덜어주려고 제가 직접 JUnit을 이용해 해봤는데요.. 거기까지는 힘들더라구요.. 시간이 너무 많이 걸리고.. 해당 개발자가 인터페이스나 메소드를 변경하면.. 따라서 고쳐줘야 하는데.. 관리자가 할 몫은 아니더군요..

아~ 그리고 최근에는 칠판을 하나 추가했습니다.
프로젝트별 "계획", "완료", "이번주"의 내용을 박스안에 간단하게 기록하는데요..
위 문서들을 CVS에 접속해서 직접확인하지 않는 윗사람들을 위해서.. 한눈에 볼 수 있도록 항목만 정리해 놓은 겁니다. XP 책에 있길래 해봤는데.. 나름 괜찮은 것 같더라구요..  *^^*




Trackback 0 And Comment 0
prev | 1 | next