메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

[진지한 파이써니스타 인터뷰] 파이썬 코어 개발자, 더그 헬먼

한빛미디어

|

2021-02-04

|

by 쥘리앵 당주

10,768

 
파이썬 작동 원리에서 확장, 테스트, 배포, 최적화까지
『진지한 파이썬』 중
 

더그 헬먼Doug Hellmann은 드림호스트의 수석 개발자이자 오픈스택 프로젝트에 기여한 개발자입니다. 그는 웹 사이트(http://www.pymotw.com)를 운영하고, 『The Python Standard Library by Example 한국어판』(에이콘출판사, 2012)이라는 훌륭한 책도 썼습니다. 그리고 파이썬 코어 개발자이기도 합니다. 더그에게 표준 라이브러리, 라이브러리 설계, 애플리케이션에 대해서 몇 가지 질문을 했습니다.
· · ·
Q. 파이썬으로 애플리케이션을 만들 때 가장 먼저 해야 하는 것은 무엇일까요?
애플리케이션을 처음부터 만들 때는 기존에 있는 애플리케이션을 해킹하듯이 진행하고 세부 사항을 변경하면 됩니다.
기존 코드를 변경할 때는 코드가 어떻게 작동하는지 먼저 확인하고, 변경할 위치를 파악하는 것으로 시작합니다. 로깅 또는 print 문을 추가하거나, pdb를 사용해서 테스트 데이터로 애플리케이션을 실행하여 수행하는 작업을 이해하도록 하는 몇 가지 디버깅 기술을 사용합니다. 보통 직접 수정하고 테스트한 후 다음 패치에 적용하기 전에 자동화된 테스트를 추가합니다.
저는 새로운 애플리케이션을 만들 때 동일한 접근 방식으로 작업을 시작합니다. 직접 코드를 만들고 실행하여 기본적인 기능이 작동하면, 모든 에지 케이스edge case를 해결했는지 확인하기 위해 테스트를 만듭니다. 테스트를 만들고 나면 코드가 더 잘 작동하도록 리팩터링을 하기도 합니다.
애플리케이션을 만들기 전에 사용하지 않는 몇 개의 스크립트를 이용해서 파이썬의 추적 API를 실험했습니다. 원래는 실행 중인 다른 애플리케이션에서 데이터를 수집하고, 네트워크를 통해 전송된 데이터를 수집하여 저장해둘 계획이었습니다. 보고 기능을 몇 가지 추가하면서 수집된 데이터를 재생하는 과정이 처음 데이터를 수집하는 과정과 거의 동일하다는 것을 깨달았습니다. 몇 가지 클래스를 리팩터링하여 데이터 수집, 데이터베이스 접근 및 보고서 생성기를 위한 기본 클래스를 만들 수 있었습니다. 클래스를 동일한 API에 부합하도록 해서 네트워크를 통해 정보를 보내는 대신 데이터베이스에 직접 작성한 데이터 수집 애플리케이션 버전을 쉽게 만들었습니다.
smiley9라는 툴을 만든 방식이 바로 이와 같습니다. 제가 애플리케이션을 설계할 때는 사용자 인터페이스의 작동 방식에 대해 생각하지만 라이브러리를 설계할 때는 개발자가 API를 사용하는 방법에 중점을 둡니다. 프로그램에서 사용할 새로운 라이브러리에 대한 테스트를 작성한 다음 라이브러리 코드를 작성하는 것이 더 쉬울 수 있습니다. 저는 보통 일련의 예제 프로그램을 테스트 형식으로 만들고 라이브러리를 빌드하여 작동합니다.
또한 코드를 작성하기 전에 라이브러리에 대한 설명서를 작성하면 라이브러리 사용자가 세부 사항에 신경 쓰지 않고, 기능과 워크플로에 집중할 수 있게 도울 수 있습니다. 설명서를 먼저 작성하면 라이브러리를 설계할 때 의도하고 선택했던 사항을 기록해 사용자가 라이브러리의 사용 방법을 쉽게 이해할 수 있을 뿐 아니라, 라이브러리 개발 시 의도했던 바를 이해하게 할 수 있습니다.
사람들이 더 잘 알았으면 하는 표준 라이브러리 모듈 세 개를 꼽아볼 수 있나요?
표준 라이브러리에서 정말 유용한 도구는 abc 모듈입니다. 저는 abc 모듈을 동적으로 로드 된 확장을 위한 API를 추상 기본 클래스로 정의하기 위해 사용합니다. 이는 확장 설계자들이 API의 모듈, 라이브러리, 프레임워크 메서드는 필수이고, 어떤 것은 선택 사항으로 넣을 수 있는지 이해할 수 있게 돕습니다. 추상 기본 클래스는 다른 객체 지향 프로그래밍object-oriented programming(OOP) 언어에 내장되어 있지만 많은 파이썬 개발자가 우리가 가지고 있다는 것을 알지 못합니다.
bisect 모듈의 이진 검색 알고리즘은 유용한 기능이지만 종종 잘못 구현되곤 합니다. bisect 모듈은 표준 라이브러리에 적합합니다. 특히 검색값이 데이터에 포함되지 않을 수 있는 희소한 리스트를 검색할 수 있어서 좋아합니다.
collections 모듈에는 자주 사용되지 않는 몇 가지 유용한 자료구조가 있습니다. 저는 관련 논리 없이 데이터를 보유해야 하는 작은 클래스와 같은 자료구조를 만들기 위해 namedtuple을 사용하는 것을 좋아합니다. namedtuple은 이름으로 속성에 접근하는 것을 지원하므로 나 중에 논리를 추가해야 할 때 namedtuple에서 일반 클래스로 변환하는 것이 매우 쉽습니다. 모듈의 또 다른 흥미로운 자료구조는 ChainMap으로, 이는 스택이 가능한 stackable 네임스페이스를 잘 만듭니다. ChainMap은 명확하게 정의된 우선 순위를 가진 다른 소스에서 템플릿을 렌더링하거나 구성 설정을 관리하기 위한 콘텍스트를 만드는 데 사용할 수 있습니다.
Q. 오픈스택과 외부 라이브러리를 포함한 많은 프로젝트는 날짜/시간 처리와 같은 표준 라이브러리 위에 자체 추상화를 가져옵니다. 개발자가 표준 라이브러리에 충실해야 하나요 아니면 자체 기능을 사용하거나, 외부 라이브러리로 전환하거나, 파이썬에 패치를 보내야 할까요?
모두 해야죠! 저는 시간 낭비하는 걸 싫어합니다. 디펜던시로 사용할 수 있는 프로젝트에 업 스트림upstream하여 수정과 개선 사항에 기여하면 좋겠습니다. 상황에 따라서는 다른 추상화 abstraction을 만들고, 애플리케이션 내부 또는 새 라이브러리에 해당 코드를 별도로 유지 관리하는 것이 합리적일 수도 있습니다.
예제에서 사용되는 timeutils 모듈은 파이썬의 datetime 모듈을 감싸는 간단한 래퍼입니다. 대부분의 함수는 상황에 따라 짧고 간단하지만 가장 일반적인 방법으로 모듈을 만들면 모든 프로젝트에서 일관되게 처리될 수 있습니다. 함수는 애플리케이션에 따라 다르게 사용됩니다. 따라서 파이썬 라이브러리에 패치를 적용하거나 범용 라이브러리로 릴리스되어 다른 프로젝트에서 사용되면, 타임스탬프 형식 문자열이나 now가 의미하는 것을 일방적으로 적용해야 하기 때문에 좋지 않습니다.
저는 프로젝트 초기에 만들어진 웹 서버 게이트웨이 인터페이스Web Server Gateway Interface(WSGI) 프레임워크에서 오픈스택의 API 서비스를 타사 웹 개발 프레임워크로 이동하기 위해 노력해왔습니다. 파이썬에는 WSGI 애플리케이션을 만들기 위한 많은 옵션이 있습니다. 오픈스택의 API 서버에 완전히 적합하도록 WSGI 애플리케이션을 향상시켜야 할 수도 있지만, 재사용이 가능한 변경 사항을 업스트림에 제공하는 것이 ‘비공개’ 프레임워크를 유지하는 것보다 좋습니다.
설계, 우선 계획, 마이그레이션 등의 측면에서 애플리케이션에서 라이브러리로 코드를 분기 하는 가장 좋은 방법은 무엇입니까?
애플리케이션은 특정 목적을 위해 라이브러리를 함께 보관하는 글루코드gluecode의 모음입니다. 라이브러리의 기능을 사용하여 애플리케이션을 설계하고 빌드하면, 코드가 논리적 단위로 적절하게 구성되어 테스트가 더 간단해집니다. 이 과정은 라이브러리를 통해 애플리케이션 기능에 접근할 수 있게 하고, 다른 애플리케이션을 만들 때 재사용할 수도 있게 합니다. 이 방법을 사용하지 않으면 애플리케이션의 기능이 사용자 인터페이스에 밀접하게 연결되어 수정하고 재사용하는 것이 더 어렵게 됩니다.
자신의 파이썬 라이브러리를 설계하려는 사람들에게 어떤 조언을 해주겠습니까?
항상 각 계층에 단일 책임 원칙single responsibility principle(SRP)과 같은 설계 기준을 적용하여 위에서 아래로 라이브러리와 API를 설계하는 것이 좋습니다. 라이브러리로 수행할 작업을 생각하여 호출자를 만들고, 이러한 기능을 지원하는 API를 만듭니다. 어떤 값이 인스턴스에 저장되고 어떤 값이 메서드에서 사용되는지, 각 메서드에 매번 전달해야 하는 값을 생각해보세요. 마지막으로 구현해야 하는 것과 기본 코드를 공용 API의 코드와 다르게 구성해야 하는지를 생각해보세요.
SQLAlchemy는 이러한 지침을 적용하는 훌륭한 예입니다. 선언적 객체 관계 매핑object relational mapping(ORM), 데이터 매핑 및 표현식 생성 레이어는 모두 분리되어 있습니다. 개발자는 라이브러리 설계에 의해 조건이 제한되지 않고 API를 입력하며, 필요에 따라서는 라이브러리를 사용하기 위한 적절한 추상화 수준을 결정할 수도 있습니다.
Q. 파이썬 개발자가 코드를 읽으며 범하는 가장 일반적인 프로그래밍 오류는 무엇입니까?
파이썬이 다른 언어와 크게 다른 한 영역은 루프와 이터레이션iteration입니다. 예를 들어 가장 일반적인 안티 패턴은 for 문을 사용하여 처음의 항목을 새 리스트에 추가한 다음 두 번째 반복(아마도 함수에 리스트를 인수로 전달한 후)에서 결과를 처리하여 리스트를 필터링하는 것입니다. 저는 항상 이러한 필터링 반복을 효율적이고 이해하기 쉬운 제너레이터 표현식로 변환하기를 제안합니다. 또한 itertools.chain()을 사용하기보다는 리스트가 결합되어 내용을 함께 처리할 수 있도록 하는 것이 일반적입니다.
저는 긴 if:then:else 블록 대신 dict()를 조회 테이블로 사용하는 것처럼 코드 검토에서 자주 제안하는 것이 있습니다. 예를 들어 함수가 항상 같은 유형의 객체(예를 들어 ‘없음’ 대신 ‘빈 리스트’)를 반환하도록 하는 것, 튜플 또는 새로운 클래스가 있는 객체에 관련 값을 결합하여 함수에 필요한 인수를 줄이는 것, 사전에 의존하지 않고 공용 API에서 사용할 클래스를 정의하는 것입니다.
프레임워크를 사용할 때 가장 주의할 점은 무엇입니까?
프레임워크도 다른 종류의 도구와 같습니다. 프레임워크는 유용하지만 작업에 맞는 것을 선택하기 위해 매우 신중해야 합니다.
애플리케이션의 공통 부분을 프레임워크로 작업하면 애플리케이션의 고유한 부분을 개발하는 데 집중할 수 있습니다. 또한 프레임워크는 개발 모드에서 실행하거나 테스트 도구 모음을 작성하는 많은 부트스트래핑 코드를 제공합니다. 이는 애플리케이션을 신속하게 유용한 상태로 만드는 데 도움을 줍니다. 추가적으로 프레임워크를 사용하면 애플리케이션을 일관성 있게 구현하여, 이해하기 쉽고 재사용이 가능한 코드를 작성할 수 있습니다.
몇 가지 함정도 있습니다. 특정한 프레임워크는 일반적으로 애플리케이션에서 자체적으로 설계할 수 있는 부분을 포함하기도 합니다. 프레임워크를 잘못 선택하면 이러한 설계 제약 조건이 애플리케이션의 요구 사항에 맞지 않아 애플리케이션을 구현하기가 더 어려워질 수도 있습니다. 그래서 프레임워크가 권장하는 것과 다른 패턴이나 코드를 사용하려고 하면 문제가 될 수 있습니다.
· · ·
댓글 입력
자료실