39
+ 소프트웨어 설계 악취: 기술 부채 관리 방법 엑셈 CTO I 박재호([email protected])

소프트웨어 설계 악취: 기술 부채 관리 방법

Embed Size (px)

Citation preview

Page 1: 소프트웨어 설계 악취: 기술 부채 관리 방법

+

소프트웨어 설계 악취: 기술 부채 관리 방법

엑셈 CTO I 박재호([email protected])

Page 2: 소프트웨어 설계 악취: 기술 부채 관리 방법

+목차

n 기술 부채

n 설계 악취

n 설계 원칙

n 악취에 대한 사례 연구: 추상화, 캡슐화, 모듈화, 계층화

n 깨끗한 코드

Page 3: 소프트웨어 설계 악취: 기술 부채 관리 방법

+프로그램이 진화함에 따라 유지보수 작업을 행하거나 복잡도를 줄이지 않는 이상 프로그램의 복잡도는 증가한다.

- 늘어나는 복잡도에 대한 레만의 법칙

Page 4: 소프트웨어 설계 악취: 기술 부채 관리 방법

+부채

n 부채 n  미래의 부를 현재로 할인해서 당겨오는 행위로 인해 발생 n  부의 확장, 편의성 추구, 생존을 위한 지렛대로 사용할 수 있지만 기본적으로는 최대한 작게 유지(risk!)

n  이자 발생

n  상환 기간

n  복리 n  변동 금리

n  인플레이션

Page 5: 소프트웨어 설계 악취: 기술 부채 관리 방법

+설계 악취와 기술 부채

n 설계 악취의 정의 n  설계 품질에 부정적인 영향을 미치고 기본 설계 원칙을 위반하는 설계상의 특정 구조

n  설계 구조에서 잠재적인 문제

n 기술 부채의 정의 n  잘못되거나 최적화되지 않은 설계 결정을 의식적이거나 무의식적으로 내릴 경우 축적되는 부채다

n  워드 커닝햄(1992)이 처음으로 사용 n  누적된 이자를 갚지 못하면 파산 à 기술 부채를 해소하지 못하면 제품 파산

n  코드 부채, 설계 부채, 테스트 부채, 문서 부채

Page 6: 소프트웨어 설계 악취: 기술 부채 관리 방법

+기술 부채가 등장하는 이유?

n 빨라진 제품 주기 n  경쟁사에 비해 더 빨리 더 저렴하게 시장에 신제품 출시 요구 n  설계 결정의 영향력을 적절히 평가할 기회나 시간적 여유 부족

n  지역적인 설계 결정의 집합이 구조적인 품질을 떨어뜨림 à 설계 부채 축적

n  문제는 유지보수!

n 기술 부채가 눈에 보이지 않는 이유? n  결함은 최종 사용자에게 직접 보임 n  기술 부채는 소프트웨어 시스템의 내부 품질에 영향을 미침 à 보이지 않으므로 무시됨

Page 7: 소프트웨어 설계 악취: 기술 부채 관리 방법

+기술 부채가 미치는 영향

n 기술 부채의 구성 요소 n  원금(꼼수나 지름길)과 이자(상환하지 않을 경우 치뤄야 할 대가)

n 기술 부채에서 복리로 붙는 이자 문제 n  소프트웨어에 가해지는 새로운 변경이 부채에 허덕이는 설계 구조와 결합해 부채를 더 늘이기 때문 à 더 많은 꼼수 à 더 많은 부채

n  변경 비용이 기술 부채에 따라 기하급수적으로 증가함 à 기술 파산

n 개발팀의 사기 저하 n  부채를 짊어진 3류 제품을 개발하고픈 개발자는 아무도 없다!

n  단기간에 부채를 갚기란 쉽지 않기 때문 n  소프트웨어 변경을 시도할 경우 발생하는 불확실성과 위험에 직접 노출

Page 8: 소프트웨어 설계 악취: 기술 부채 관리 방법

+

Page 9: 소프트웨어 설계 악취: 기술 부채 관리 방법

+기술 부채를 초래하는 원인

n 관리자, 아키텍트, 개발자들이 내린 엉뚱한 결정의 원인 n  일정 압력: 복사해붙이기 n  좋은/숙달된 설계자 부족: 악화(나쁜 관례)가 양화를 구축

n  설계 원칙의 응용 부족: 경험/인식 부족 n  설계 악취와 리펙터링에 대한 인식 부족

Programming == Googling stackoverflow?

Page 10: 소프트웨어 설계 악취: 기술 부채 관리 방법

+기술 부채를 관리하는 방법

n 기술 부채에 대한 점진적인 자각

n 기술 부채의 감지와 상환

n 기술 부채의 누적 방지

Page 11: 소프트웨어 설계 악취: 기술 부채 관리 방법

+설계 악취란?

n 설계가 잘못되었음을 알려주는 징표

n 악취에 신경을 써야 하는 이유? n  소프트웨어 이해 가능성에 치명적인 문제를 일으킴 n  결함 수정과 개선을 위한 변경이 끊이지 않고 유지 보수 시간이 늘어남

n  논리적인 재사용이 불가함 n  안정성과 테스트 가능성이 점점 나빠짐

n 소프트웨어 설계가 소프트웨어 품질에 영향을 미침 n  설계가 잘못되면 악취가 발생!

Page 12: 소프트웨어 설계 악취: 기술 부채 관리 방법

+악취가 영향을 미치는 품질 속성

n 소프트웨어 비기능 측면 n  이해 가능성 n  변경 가능성

n  확장 가능성 n  재사용 가능성

n  테스트 가능성

n  안정성

n 주의: 비기능은 소프트웨어의 내재된 속성이므로 개발자가 보증해야 한다!

Page 13: 소프트웨어 설계 악취: 기술 부채 관리 방법

+설계 악취를 일으키는 요인

n 설계 원칙 위반

n 부적절한 패턴 사용

n 언어 제약

n 객체지향에서 절차적인 사고 방식

n 점성

n 우수 관계와 우수 프로세스의 미준수

Page 14: 소프트웨어 설계 악취: 기술 부채 관리 방법

+설계 악취를 일으키는 요인

n  java.util 패키지 일부인 Calendar 클래스 n  실세계의 달력 기능을 추상화 n  날짜와 관련된 기능을 제공

n  하지만 시간 관련 기능도 제공

n 여기서 위반된 설계 원칙 n  추상화는 유일한 책임만 맡아야 함 à 추상화 원칙 위반

n  다면적인 추상화 악취 발생

사례(설계 원칙 위반)

Page 15: 소프트웨어 설계 악취: 기술 부채 관리 방법

+설계 악취를 일으키는 요인

n  JDK의 AbstractQueuedSynchronizer와 AbstractQueuedLongSynchronizer 클래스 n  두 클래스는 AbstractOwnableSynchronizer 에서 파생 n  원시 타입의 차이뿐!

n 여기서 위반된 설계 원칙 n  펙터링이 안 된 설계 계층 악취 n  문제) 자바에서는 제네릭에서 원시 타입을 지원하지 않음! à 필연적인 코드 중첩 발생

사례(언어 제약)

Page 16: 소프트웨어 설계 악취: 기술 부채 관리 방법

+설계 악취를 일으키는 요인

n 소프트웨어 점성이란? n  올바른 해법을 문제에 적용하는 과정에서 반드시 직면하는 저항(늘어나는 노력과 시간)

n  꼼수는 시간과 노력을 적게 요구(낮은 저항)

n 환경 점성이란? n  우수 관례를 따르기 위해 반드시 극복해야 할 소프트웨어 개발 환경으로 인한 ‘저항’

n  우수 관계를 따를 때 시간이 더 많이 걸리면 나쁜 관례를 선택! n  개발 프로세스, 재사용 프로세스, 조직 요구 사항, 법적인 제약

사례(점성)

Page 17: 소프트웨어 설계 악취: 기술 부채 관리 방법

+악취 분류에 기반한 설계 원칙

n 악취 맥락에서 위반이 일어난 설계 원칙을 인식할 필요가 있음 n  추상화

n  단순화와 일반화 기법을 사용해 엔티티의 단순화를 옹호함

n  단순화는 불필요한 세부 사항을 제거하며, 일반화는 공통적이며 중요한 특성을 파악하고 명세함

n  캡슐화

n  추상화의 세부 구현과 변형을 숨기는 기법을 사용해 관심사 분리와 정보 은닉을 옹호 n  모듈화

n  지역화와 분해 기법을 사용해 응집력은 높고 결합력은 낮은 추상화 생성을 옹호 n  계층 구조

n  분류, 일반화, 대체, 배치와 같은 기법을 사용해 계층적인 추상화 구조 생성을 옹호

Page 18: 소프트웨어 설계 악취: 기술 부채 관리 방법

+몇 가지 추가적인 설계 원칙(1)

n OCP(Open/Close Principle) n  모듈은 확장에 대해 열려야 하지만 변경에 대해 닫혀야 마땅하다 n  모듈은 코드 변경 없이 새로운 요구 사항을 지원할 수 있어야 마땅하다

n 단일 책임 원칙(SRP, Single Responsibility Principle) n  클래스가 변경되어야 하는 이유가 결코 둘 이상 있어서는 안 된다 n  각 책임은 변경 축이되므로, 각 변경은 단일 책임에만 영향을 미쳐야 마땅하다

n  LSP(LISKOV’S SUBSTITUTION PRINCIPLE) n  상속 받은 클래스는 사용자가 차이점을 알 필요 없이 기초 클래스 인터페이스를 통해 사용 가능해야만 한다

Page 19: 소프트웨어 설계 악취: 기술 부채 관리 방법

+몇 가지 추가적인 설계 원칙(2)

n  KISS(KEEP IT SIMPLE SILLY) 원칙 n  소프트웨어 설계 구성에는 두 가지 방법이 있다. 하나는 아주 단순하게 만들어 명백하게 의존성이 하나도 없게 만드는 방법이며, 다른 하나는 아주 복잡하게 만들어 명백한 의존성이 하나도 없게 만드는 방법이다

n  정보 은닉(Information Hiding) 원칙 n  어렵거나 변경되기 쉬운 설계 결정을 파악하고 적절한 모듈이나 타입을 생성해 다른 모듈이나 타입으로부터 이런 결정을 감추는 방식

n  DRY(Don’t Repeat Yourself) 원칙 n  모든 지식은 시스템 내부에서 단일하고 모호하지 않고 권위 있는 표현이 되어야만 한다

n  비순환 의존성 원칙(ADP, Acyclic Dependencies Principle) n  패키지 사이의 의존성은 순환을 형성해서는 안 된다

Page 20: 소프트웨어 설계 악취: 기술 부채 관리 방법

+

Page 21: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 중복된 추상화 악취란? n  이름이 같거나 구현이 동일하거나 이름도 같고 구현도 동일할 때 발생하는 악취

n  동일한 이름: 추상화 이름이 동일(우연히 이름이 동일할 가능성에 주의!)

n  동일한 구현: 의미상으로 동일한 멤버 정의가 있는 경우

n  문제의 원인: DRY, 중복 방지 원칙을 어김(예: 복붙) n  여파: 코드 중복으로 인한 유지보수가 어려워짐

추상화 악취 중 중복된 추상화

Page 22: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 예제: JDK에 존재하는 이름이 동일한 클래스 n  자바 7에서 4005개 타입 중 135개 타입이 중복(3.3%)! n  예: java.util.Date와 여기서 파생된 java.sql.Date 클래스

n 컴파일러가 문제 삼지 않는 이유 n  패키지가 다르다

n 사용자 입장에서 문제가 되는 이유 n  두 클래스를 동시에 import할 경우 명시적으로 한정해야 한다 à 모호성 문제를 수동으로 해소

추상화 악취 중 중복된 추상화

Page 23: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 리펙터링 제안 n  java.sql.Date JavaDoc 문서: “SQL DATE 정의에 순응하기 위해, java.sql.Date 인스턴스가 감싼 밀리초 값은 관련된 인스턴스가 위치한 특정 시간대에 맞춰 시, 분, 초, 밀리초를 0으로 설정하는 방식으로 ‘정규화되어야’만 한다.”

n  더 나은 설계안

n  java.sql.Date에서 java.util.Date 인스턴스를 감싸기 n  상속을 위임으로 변환

n  또한 java.sql.SQLDate로 이름 변경

추상화 악취 중 중복된 추상화

Page 24: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 누락된 캡슐화 악취란? n  구현 변형을 계층 내부나 추상화 내부에서 캡슐화하지 않을 경우 발생하는 악취

n  문제의 원인: OCP 위반(타입의 행동 양식은 변경이 아니라 확장에 의해 바꿔야 함)

n  여파: 계층에 새로운 변형을 지원하려고 시도할 때마다 불필요한 클래스 ‘폭발’ 발생

캡슐화 악취 중 누락된 캡슐화

Page 25: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 예제(1) n  데이터 암호화를 위한 Encryption 클래스: DES (Data Encryption Standard), AES (Advanced Encryption Standard), TDES (Triple Data Encryption Standard)를 포함해 알고리즘에 대한 다양한 선택이 가능

n  초보 개발자는 Encryption 클래스 내부에 EncryptUsingDES(), EncryptiUsingAES(), …와 같은 수많은 메소드를 추가

n 문제점 n  Encryption 클래스가 알고리즘 추가에 따라 점점 커짐(한번에 알고리즘을 하나만 사용하더라도 덩치 큰 클래스를 가져와야 함)

n  새로운 알고리즘 추가가 어려움

n  특정 알고리즘 하나만 재사용하기가 불가능

캡슐화 악취 중 누락된 캡슐화

Page 26: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 예제(2) n  데이터 암호화를 위한 알고리즘 뿐만 아니라 다양한 유형의 데이터를 암호화

n  내용 유형과 암호화 알고리즘 유형의 두 가지 변형이 존재 n  DESImageEncryption, AESTextEncryption, …

n 문제점 n  구현에서 변형이 서로 뒤섞이며, 독자적으로 캡슐화되지 못함

n  클래스 폭발로 마무리

캡슐화 악취 중 누락된 캡슐화

Page 27: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 리펙터링 제안 n  예제(1)

n  EncryptionAlgorithm 인터페이스를 생성 n  DESEncryptionAlgorithm와 AESEncryptionAlgorithm는 EncryptionAlgorithm 인터페이스를 구현하고 각각 DES와 AES 알고리즘을 정의

n  Encryption 클래스는 EncryptionAlgorithm 인터페이스에 대한 참조를 유지

n  장점 n  Encryption 객체는 실행 시간에 특정 암호화 알고리즘으로 구성 가능 n  EncryptionAlgorithm 계층에 정의된 알고리즘은 다른 맥락에서 재사용 가능

n  새로운 알고리즘 추가 용이

캡슐화 악취 중 누락된 캡슐화

Page 28: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구 캡슐화 악취 중 누락된 캡슐화

깨진 계층화 악취

다른 맥락에서 알고리즘 재사용 불가

Page 29: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 리펙터링 제안 n  예제(2)

n  두 가지 직교적인 관심사에 대해 독자적으로 변형을 캡슐화

캡슐화 악취 중 누락된 캡슐화

Page 30: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 불충분한 모듈화 악취란? n  완벽하게 분해되지 않은 추상화 à 추가로 분해할 경우 크기/구현 복잡도 해소 가능

n  부풀어로은 인터페이스: 추상화의 공개 인터페이스에 엄청나게 많은 멤버 존재

n  부풀어오른 구현: 구현에 엄청나게 많은 메소드 존재/구현 복잡도가 과도하게 높은 메소드가 하나 이상 존재

n  문제의 원인: 추상화를 관리 가능한 크기로 유지하지 못함

n  ‘연산과 클래스는 조화로운 크기가 되어야 마땅하다. 다시 말해, 크기는 양극단을 피해야 마땅하다.”

n  주의: SRP와 혼동 à 책임이 하나인 추상화면서도 여전히 크고 복잡할 수 있다. 유사하게, 작은 추상화면서도 여전히 책임이 여럿일 수 있다

모듈화 악취 중 불충분한 모듈화

Page 31: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 불충분한 모듈화 악취란? n  완벽하게 분해되지 않은 추상화 à 추가로 분해할 경우 크기/구현 복잡도 해소 가능

n  부풀어로은 인터페이스: 추상화의 공개 인터페이스에 엄청나게 많은 멤버 존재

n  부풀어오른 구현: 구현에 엄청나게 많은 메소드 존재/구현 복잡도가 과도하게 높은 메소드가 하나 이상 존재

n  문제의 원인: 추상화를 관리 가능한 크기로 유지하지 못함

n  ‘연산과 클래스는 조화로운 크기가 되어야 마땅하다. 다시 말해, 크기는 양극단을 피해야 마땅하다.”

n  주의: SRP와 혼동 à 책임이 하나인 추상화면서도 여전히 크고 복잡할 수 있다. 유사하게, 작은 추상화면서도 여전히 책임이 여럿일 수 있다.

모듈화 악취 중 불충분한 모듈화

Page 32: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 예제: JDK에 존재하는 java.awt.Component 클래스 n  메소드가 332개(그 중 259개가 public으로 선언!) n  중첩된 내부 클래스가 11개, 필드가 107개(상수 포함)

n  원시 코드: 10,102행

n 문제점 n  분석, 유지보수, 기능 추가 과정에서 이 클래스를 이해하기가 너무 복잡하다!

추상화 악취 중 중복된 추상화

Page 33: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n  리펙터링 방안 n  부풀어오른 인터페이스

n  공개 인터페이스의 부분 집합이 밀접히 연관된 (응집력이 높은) 멤버를 포함하면, 부분 집합을 독자적인 추상화로 추출

n  클래스가 멤버로 구성된 부분 집합을 둘 이상 포함하며 각 부분 집합의 응집력이 높으면, 이런 부분 집합을 독자적인 클래스로 나눔

n  클래스 인터페이스가 클라이언트에 밀접한 메소드를 사용해 여러 클라이언트를 서비스하면, 원본 인터페이스를 클라이언트에 밀접한 여러 인터페이스로 분리하기 위해 ISP(Interface Segregation Principle)를 적용

n  부풀어오른 구현 n  메소드 논리가 복잡하면, 해당 메소드에 있는 코드를 단순하게 만들기 위해 사적인 도우미 메소드를 도입

n  불충분한 모듈화 악취와 함께 다면적인 추상화 악취까지 포함하는 추상화라면, 각 책임을 분리된 (새로 만들거나 기존에 존재하는) 추상화에 캡슐화

추상화 악취 중 중복된 추상화

Page 34: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 넓은 계층 악취란? n  중간 타입이 빠졌을지도 모른다는 사실을 암시하는 ‘너무’ 넓은 상속 관계가 존재하는 악취

n  문제의 원인: ‘의미있는 일반화 적용’이라는 요소 기술을 위반 n  빠진 중간 타입은 계층에 있는 클라이언트가 하위 타입을 직접 참조하게 강제할지도 모른다. 이런 의존성은 계층의 변경 가능성과 확장 가능성에 영향을 미친다.

n  타입 내부에 불필요한 중복이 있을지도 모른다(중간 타입의 부족으로 인해 공통성을 적절히 추상화할 수 없다)

n  영향: 동일 층에 하위 타입 수가 너무 많으면(9개를 넘길 경우), 계층을 이해하거나 사용하기가 더 어려워짐

계층 악취 중 넓은 계층

Page 35: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 예제 n  JDK 7에서 바로 아래 하위 클래스 36개를 거느리는 java.util.EventObject 클래스

n 문제점 n  형제자매 클래스가 엄청나게 많아서 이해가 어려움

계층 악취 중 넓은 계층

Page 36: 소프트웨어 설계 악취: 기술 부채 관리 방법

+사례 연구

n 리펙터링 제안 n  중간 타입을 도입 n  예: TreeEvent

계층 악취 중 넓은 계층

Page 37: 소프트웨어 설계 악취: 기술 부채 관리 방법

+설계에서 코드로

n 설계 리펙터링은 코드 리펙터링과 밀접한 관련이 있다! n  깨끗한 설계를 유지하는 동시에 깨끗한 코드를 유지해야 한다

Page 38: 소프트웨어 설계 악취: 기술 부채 관리 방법

+참고 자료

Page 39: 소프트웨어 설계 악취: 기술 부채 관리 방법

+