프로그래밍 공부
작성일
2024. 1. 23. 15:44
작성자
WDmil
728x90

4.5.3 코드 재사용 전략

라이브러리, 프레임워크, 동료가 작성한 코드, 본인이 작성한 코드, 어느 경우든 코드를 재사용 할 때는 따라야 할 몇가지 원칙이 있다.


4.5.3.1 기능과 한계의 이해

사용할 코드가 어떤 기능을 제공하고 제약 사항은 무엇인지 시간을 들여서 잘 파악하는 것이 중요하다.

이때 가장 먼저 할 일은 관련 문서를 읽어보고 공개된 인터페이스와 API를 살펴보는 것이다. 이상적으로는 이것만으로 코드의 사용법을 이해하는 데 충분해야 하지만 그렇지 않으면 직접 소스코드를 뒤져보어야 한다.

 

만약 주변에 해당 코드를 이용해본 적이 있거나 관련 된 내부 동작 방식을 설명해줄 수 있는 사람이 있다면 도움을 구하는 것도 좋은 방법이다. 코드의 사용법을 익힐 떄는 가장 기본적인 것부터 이해하는 것이 좋다. 재사용 대상이 라이브러리라면, 어떤 함수들을 지원하는지?, 프레임워크라면, 프레임워크에 맞춰서 코드를 짜려면 어떻게 해야 하는지? 상속받아야 하는 클래스 들은 무엇이고 직접 개발해야 하는 부분은 무엇인지? 같은 답을 구한다. 그리고 코드의 유형에 따라 특별히 고려해야할 이슈도 있다.

 

  • 멀티스레드 프로그램에서 사용해도 안전한가?
  • 라이브러리가 그것을 사용하는 코드에 특정 컴파일러 세팅을 필요로 하는가? 만약 그렇다면 전체 프로젝트에서 수용할 수 있는가?
  • 라이브러리나 프레임워크가 초기화를 요구하는가? 종료시 수행해야 할 작업이 있는가?
  • 라이브러리나 프레임워크가 또 다른 라이브러리에 의존하는가?
  • 클래스를 상속받는다면 어떤 생성자를 호출하고 어떤 버추얼 메서드(가상 메서드)를 오버라이딩 하는가?
  • 함수가 메모리 포인터를 리턴한다면 그 메모리의 해제는 누가 해야 하는가? 호출자가 하는가, 라이브러리가 하는가? 만약 라이브러리에서 한다면 언제 메모리에서 해제되는가? 라이브러리에서 할당하는 메모리 포인터는 스마트 포인터로 감싸서 이용하는 것이 바람직하다.
  • 라이브러리 함수 호출 시 체크되는 에러 조건은 무엇이고, 기본적으로 가정되는 조건은 무엇인가? 에러를 어떻게 처리하나? 라이브러리를 사용하는 클라이언트 프로그램에 에러 발생을 어떤 방법으로 알려주나? 팝업 메시지 박스를 띄우거나, 표준출력 STDERR/CERR 또는 stdout/cout으로 에러 메세지를 내보내거나, 프로그램을 종료시켜버리는 라이브러리는 가능하면 피하는 것이 좋다.
  • 값이든 참조든 함수가 리턴하는 것은 무엇인가?
  • 함수 호출로 발생할 수 있는 익셉션은 어떤 것 들이 있는가?

4.5.3.2 성능에 대한 이해

라이브러리나 제공된 코드가 어떤 수준의 성능을 보증하는지 알아야 한다. 개발하려는 프로그램이 성능에 민감하지 않더라도 재사용할 코드가 특정 사용 시나리오에서 문제가 될 만한 동작 성능을 보이지 않는지 파악해야 한다.

 

Big-O 표기법

프로그래머들은 알고리즘이나 코드가 어떤 성능을 가지는지 설명할 때 Big-O 표기법 을 이용한다. 이번에는 가능한 수학을 사용하지 않으면서 알고리즘 복잡도 분석과 Big-O 표기법에 대해 설명한다.

 

Big-O표기법은 절대적인 성능이 아니라 상대적인 성능을 나타낸다. 예를들어 이 함수는 300밀리초 안에 작업을 완료한다고 하지 않고, 작업 대상 데이터 크기가 커질 때 소요시간에 따라서 커지는 비율이 어떻게 달라지는지 이야깋 ㅏㄴ다.

 

작업대상 데이터란 정렬할 숫자의 개수, 해시 맵에서 항목을 찾을 때 해시에 이미 들어있는 데이터의 개수, 파일으 ㄹ복사할 때 파일의 개수 따위를 말한다.

 

Big-O 표기법은 입력 데이터가 존재하고 그 크기가 가변적인 알고리즘을 대상으로 한다. 입력 데이터가 없거나 실행 소요 시간이 무작위(random) 알고리즘은 Big-O 표기법을 적용할 수 없다.

 

좀더 형식적으로 말하면 Big-O 표기법은 알고리즘의 실행 소요 시간을 입력 데이터의 크기에 대한 함수로 나타낸 것으로 알고리즘 복자볻 라고도 한다. 어려워 보이지만 실상은 그렇지 않다. 예를들어 어떤 정렬 알고리즘이 500개 항목을 정력하는데 2초가 소요되고 1,000개 항목을 정렬하는 데는 4초가 소요된다고 하자, 데이터가 두 배로 늘어날 때 소요시간도 두배로 늘어났다.

 

따라서 실행시간은 입력크기에 선형으로 비례하는 함수라고 할 수 있다. 성능과 입력 데이터 크기를 각각 축으로 하여 그래프를 그리면 기울어진 일직선이 나온다.

 

이러한 경우를 Big-O표기법으로 나타내면 O(n)과 같이 표현된다. 여기서 O는 Big-O 표기법 이라는 것을 나타내고, n은 입력 데이터 크기를 나타낸다. O(n)은 알고리즘의 실행 소요 시간이 입력 데이터의 크기에 정비례하는 함수임을 표현한다.

 

만약 모든 알고리즘이 위에서처럼 입력 데이터 크기에 비례하는 실행시간을 보여준다면, 컴퓨터 프로그램이 지금보다 훨씬 더 빨가질 것 이다. O(n)은 사실 달성하기 쉽지 않은 성능이다.

 

알고리즘 복잡도 Big-O표기볍 설명 알고리즘 예
상수
(Constant)
O(1) 대상 데이터 크기와 관계없이 항상 수행시간이 동일 배열 항목 하나에 인덱스 값으로 접근
로그
(Logarithmic)
O(log n) 입력 데이터 크기에 따라 실행 시간이 지수 2의 로그 함수에 비례 이미 정렬된 리스트에서 바이너리 탐색으로 특정 항목 탐색
선형
(Linear Logarithmic)
O(n log n) 실행 시간이 입력 데이터 크기의 로그값의 선형 곱에 비례 병합 정렬
제곱
(Quadratic)
O(n^2) 실행 시간이 입력 데이터 크기의 제곱에 비례 선택 정렬과 같이 성능이 낮은 알고리즘
지수
(Exponential)
O(2^n) 실행 시간이 입력 데이터 크기의 승수에 비례 외판원 문제 의 최적화

 

절대적인 숫자 대신 입력크기에 대한 상대적인 값으로 성능을 표기하면 다음과 같은 두가지 장점이 있다.

  1. 플랫폼에 독립적이다.
    특정 컴퓨터에서 200밀리초의 소요 시간을 가진다는 정보로는 다른 컴퓨터에서 어떻게 나타날지 짐작하는데 별 도움이 안된다. 같은 컴퓨터에서 비교하더라도 부하 상황과 데이터 크기를 완전히 동일하게 맞추어야 의미가 있다. 반면 입력 데이터의 크기 변화에 따른 성능 변화 정보가 있으면 플랫폼과 독립적으로 알고리즘 간 성능을 비교할 수 있다.
  2. 성능이 입력 데이터 크기에 대한 함수로 표현되면 모든 종류의 입력 데이터 크기에 대해 실행 성능을 알 수 있다.
    반면 특정 데이터 크기에 대한 실행 시간 측정치는 다른 데이터 크기에서 실행 시간이 어떻게 될지 알려주지 못한다.

어떤 때는 Big-O표기법에 통계적인 기댓값을 반영하기도 한다. 이 경우 Big-O 수식은 기대 시간을 나타낸다. 예를 들어 선형 탐색 알고리즘은 종종 O(n/2)이라고 표기된다. 왜냐하면 확률적으로 전체 항목의 절반 정도를 탐색하면 목적하는 항목이 발견되지 떄문이다. O(n/2)보다 더 빨리 찾아지는 경우는 O(n/2)보다 더 오래 걸리는 경우와 서로 상쇄되어 없어진다.


4.5.3.3 플랫폼 제약 사항의 이해

사용하려는 라이브러리가 어느 플랫폼에서 구동되는지 미리 확인해야 한다. 너무 당연한 이야기 같지만 크로스 플랫폼을 지원하는 라이브러리 조차도 플랫폼마다 미묘한 차이가 있을 때가 많다.

 

플랫폼은 서로 다른 종류의 운영체제 뿐만 아니라 서로 다른 버전의 같은 운영체제도 포함한다.

애플리케이션이 솔라리스 8, 솔라리스 9, 솔라리스 10 에서 모두 구동되어야 한다면, 라이브러리도 세 버전의 솔라리스 운영체제를 모두 지원하는 것으로 선택해야 한다. 

 

모든 버전의 운영체제가 하위 또는 상위 호환성을 가진다고 가정해서는 안 된다. 즉, 어떤 라이브러리가 솔라리스 9에서 구동된다고 해서 솔라리스 10이나 솔라리스 8에서 구동되는 것이 보증되는 것은 아니다.


4.5.3.4 라이선스와 기줄 지원에 대한 이해

외부 업체( 보통 제 3자라는 의미에서 서드파티 라고 한다) 의 라이브러리를 이용하게 되면 복잡한 라이선스 문제에 부딛힌다. 어떤 경우 라이브러리 사용 대가(라이선스 사용료)를 개발사에 지급해야 한다. 그리고 라이브러리의  2차 사용에 대한 제한 같은 별도의 제약 사항이 따라오기도 한다. 오픈 소스 라이브러리라면 해당 라이브러리와 링크된 모든 코드를 오픈소스화 하여 배포하라고 요구한다.

 

서드파티 라이브러리는 기술 지원 문제도 있다. 라이브러리를 이용하기 전에 버그 리포트 절차가 어떻게 되고 수정본을 받기까지 시간이 얼마나 걸리는지 확인해두는 것이 좋다. 가능하다면 기술 지원을 받을 수 있는 기간을 확인하여 그에 맞추어 프로그램 개발 일정을 짠다.

 

심지어 같은 조직 내의 라이브러리를 이용할 때도 기술 지원 문제가 있다. 동료에게 버그 수정 요청을 하는 것이 서드파티에 하는 것만큼이나 어려울 수 있다. 사실 내부 동료가 서드 파티보다 더 어렵다. 왜냐하면 서드파티는 계약 관계로 돈을 지급한 고객이지만 내부 동료는 그렇지 않기 때문이다. 조직 내부의 라이브러리를 이용할 때는 조직 내정책이나 역학 관계 따위를 잘 이해해야 한다.


4.5.3.5 도움요청 방법 알기

  1. 라이브러리와 관련된 문서를 살펴본다.
    STL이나 MFC같이 널리 사용되는 코드라면 좋은 문헌이 많이 있을 수 있다.
  2. 문서에서 찾을 수 없다면, 인터넷 검색엔진 또는 관련 포럼을 확인해본다.

4.5.3.6 프로토타입

새로운 라이브러리나 프레임워크를 이용할 때 가장 먼저 할 일은 간단한 프로토타입을 구현해 보는 것이다.

단순한것이라도 직접 이용해보면 가장 빨리 라이브러리의 기능에 친숙해질 수 있다. 프로그램 디자인에 라이브러리를 적용해보기 전에 라이브러리의 기능과 제약 사항에 먼저 익숙해지도록 여러 가지를 시험해보아야 한다. 이렇게 직접 시험해보면 라이브러리의 성능과 관련된 특성도 알 수 있게 된다.

 

프로토타입이 실제 개발할 애플리케이션과는 거리가 멀어 보여도 프로토타입에 투자된 시간은 전혀 낭비가 아니다. 실제 개발할 애플리케이션 수준으로 프로토타입을 만들고 싶은 유혹이 있겠지만 피하는것 이 좋다. 가상 프로그램은 단지 사용할 라이브러리를 시험해보고 친숙해지는것을 목적으로 한다.

728x90