20년 된 파이썬(Python) 라이브러리, 리팩토링(Refactoring)으로 다시 태어나다!
20년 된 파이썬(Python) 라이브러리 akismet의 리팩토링(Refactoring) 배경과 과정을 상세히 설명함
비동기(Async) 지원을 위해 동기(Sync) 및 비동기(Async) 클라이언트(Client) 클래스를 분리하는 설계를 채택함
테스트(Testing) 용이성을 위해 httpx 라이브러리를 활용하고, pytest 플러그인을 개발하여 테스트 환경을 개선함
API 디자인(API Design) 개선을 통해 Akismet API의 세 가지 응답 상태를 지원하도록 구현함
비동기(Async) 지원을 위한 아키텍처(Architecture) 설계
리팩토링(Refactoring)의 주요 목표 중 하나는 비동기(Async) 프로그래밍 지원이었다. 이를 위해 기존의 단일 Akismet 클래스를 akismet.SyncClient와 akismet.AsyncClient 두 개의 클래스로 분리했다. 특히, 비동기(Async) 클라이언트(Client)의 초기화 과정에서 API 키 검증을 처리하기 위해 validated_client()라는 대체 생성자(Alternate Constructor)와 async with 구문을 활용하여, 비동기(Async) 환경에서도 안전하게 API 키를 검증할 수 있도록 설계했다. 이러한 설계는 동기(Sync) 및 비동기(Async) 코드의 공통 부분을 추출하여 코드 중복을 최소화하는 방식으로 구현되었다.
테스트(Testing) 환경 개선
라이브러리(Library)의 테스트(Testing) 용이성을 높이기 위해 httpx 라이브러리를 활용하여 HTTP 요청을 추상화하고, MockTransport를 통해 가짜 응답을 제공하는 방식을 채택했다. 이를 통해 실제 Akismet API에 의존하지 않고도 테스트(Testing)를 수행할 수 있게 되었다. 또한, pytest 기반의 테스트 프레임워크(Framework)를 도입하고, akismet_client라는 사용자 정의 pytest 마크(Mark)를 개발하여 테스트(Testing) 코드의 간결성을 높였다. 이러한 접근 방식은 라이브러리(Library) 사용자들이 쉽게 테스트(Testing) 코드를 작성하고, 다양한 테스트 시나리오를 구성할 수 있도록 지원한다.
API 디자인(API Design) 개선 및 enum 활용
기존의 boolean 기반의 응답 방식 대신, Akismet API의 세 가지 응답 상태를 정확하게 표현하기 위해 enum.IntEnum을 활용한 CheckResponse enum을 도입했다. 이를 통해, 'spam', 'ham', 'discard'와 같은 세 가지 상태를 명확하게 구분하고, 개발자가 각 상태에 맞는 로직을 구현할 수 있도록 지원한다. 특히, 'discard' 상태는 X-Akismet-Pro-Tip 헤더를 통해 전달되는 정보를 활용하여, 개발자가 추가적인 검토 없이 콘텐츠를 폐기할 수 있도록 한다. 이러한 API 디자인(API Design) 개선은 Akismet API의 기능을 보다 정확하고 효율적으로 활용할 수 있도록 돕는다.
HTTP 클라이언트(Client) 교체 및 확장성 확보
기존의 requests 라이브러리 대신 httpx 라이브러리를 도입하여, 동기(Sync) 및 비동기(Async) HTTP 요청을 모두 지원하도록 했다. 또한, Akismet 클라이언트(Client) 클래스의 생성자(Constructor)에서 HTTP 클라이언트(Client) 객체를 주입받을 수 있도록 설계하여, 프록시(Proxy) 설정과 같은 다양한 환경 설정을 유연하게 지원한다. 이러한 설계는 개발자가 특정 환경에 맞게 HTTP 클라이언트(Client)를 커스터마이징(Customizing)할 수 있도록 하여, 라이브러리(Library)의 확장성을 높인다.