주말에 Python 배우기: 시작부터 완료된 프로젝트까지
우리는 어떻게 새로운 프로그래밍 언어를 빠르게 배울 수 있을까요? 이 기사에서는 Python을 배우며 완성된 프로젝트를 구축하는 주말 경험을 공유할 예정입니다.
소개
Logto는 ID 서비스로서 다양한 프로그래밍 언어와 프레임워크 간에 원활한 경험을 제공하는 것이 중요합니다. 이는 종종 소프트웨어 개발 키트(SDK)를 만드는 것을 포함하지만, 프로그래밍 언어가 우리의 기술 스택 외에 있고, 팀이 친숙하지 않다면 탄탄한 SDK를 제작하는 것은 도전이 됩니다.
Python은 우리에게 그런 도전이었습니다. Python 사용자가 많음에도 불구하고 Python SDK가 부족했고, 이는 지속적으로 걱정거리였습니다. 이 문제를 해결하기 위해, 저는 이 격차를 메우기 위한 여정을 시작했습니다.
비록 제가 다년간의 프로그래밍 경험을 가지고 있지만, Python은 저에게 상대적으로 미지의 영역이었습니다. 몇 년 전 간단한 스크립트를 위해 잠깐 Python 2를 사용해 본 적은 있지만, 제 지식은 이미 오래되었습니다. 그럼에도 불구하고 이제 물에 뛰어들어야 할 때였습니다!
1일차: 기초 다지기
목표 설정하기
제 경험상 새로운 프로그래밍 언어를 배우는 가장 효과적인 방법은 완료된 프로젝트를 구축하는 것입니다. 다행스럽게도 우리의 목표는 명확했습니다: 웹 애플리케이션을 위한 Logto Python SDK를 구축하기.
바로 코딩에 뛰어들기보다는, 먼저 이를 나누어 봅시다. 다음은 할 일 목록입니다:
- 로그인, 로그아웃, 사용자 정보 및 토큰 관리를 위한 Logto 클라이언트를 생성합니다.
- SDK 사용 방법을 보여주는 튜토리얼과 샘플 프로젝트를 제공합니다.
- SDK를 사용자들이 쉽게 설치할 수 있도록 배포합니다.
첫 번째 작업이 가장 많은 작업을 필요로 할 것 같으므로, 범위를 확정하고 더 세부적으로 나누는 것이 중요합니다. 이 단계는 프로젝트의 경계를 보호하고, 범위의 확장 및 과도한 엔지니어링을 방지하기 위해 필수적입니다.
우리 팀의 이전 작업이 저의 시간을 크게 절약했습니다:
- SDK 규약은 SDK의 구조와 API 디자인을 개략적으로 설명했습니다.
- 다양한 언어용 기존 SDK는 패턴과 Python에 대한 잠재적 개선 사항에 대한 통찰력을 제공했습니다.
이 자원을 참고하여, 해야 할 일이 명확하게 보였습니다. 비록 구체적인 사항은 이 기사의 범위를 벗어나 있지만, 앞으로 나아가 봅시다.
환경 설정하기
저는 맥을 사용 중이어서 Python이 이미 설치되어 있습니다. 하지만, Python 버전을 관리하는 더 좋은 방법이 있을지 궁금했습니다(Node.js의 nvm
처럼 버전 호환성의 고통을 들어본 적이 있습니다). 빠르게 pyenv를 발견하고 바로 설치하기 시작했습니다.
다음 일정은 패키지 및 의존성 관리자를 선택하는 것입니다. 일반적으로 이 둘은 결합되어 있습니다. 그래서 Python 기본 관리자인 pip
를 사용하지 않는 이유가 뭘까요? requirements.txt
를 살펴보면, 단지 버전이 지정된 패키지 목록만 볼 수 있습니다. 이는 다른 프로젝트에서 사용될 수 있는 SDK에는 충분하지 않습니다. 예를 들어, 개발을 위해 일부 패키지를 추가해야 할 수도 있지만, 최종 SDK에는 포함하고 싶지 않습니다. requirements.txt
는 이를 처리하기에 너무 단순합니다.
기술 스택에 다른 프로그래밍 언어가 포함되면, 이를 찾을 때 "Python 등가"를 검색할 수 있는 이점이 있습니다. 그래서 저는 "package.json Python 등가"를 검색했고 Poetry라는 훌륭한 후보를 발견했습니다:
- 이 도구는 패키지 매니저, 의존성 매니저 및 가상 환경 매니저로 기능합니다.
- 이 도구는 Node.js의
package.json
에 해당하는pyproject.toml
파일을 사용합니다. - 이 도구는 정밀한 의존성 버전을 로그하는 락 파일을 사용합니다.
현대적인 CLI는 종종 새로운 프로젝트를 위해 init
명령을 포함합니다. Poetry도 마찬가지입니다. 명령을 실행하여 저에게 pyproject.toml
파일을 생성했습니다.
첫 줄의 코드
드디어 코드 작성을 시작할 순간이 다가왔습니다. 클래식한 "Hello, World!" 프로그램으로 시작하는 것은 항상 좋은 선택입니다. 프로그래밍 언어를 배울 때, 풀 기능의 IDE는 항상 필수는 아닙니다. 강력한 커뮤니티를 가진 에디터, 예를 들어 VS Code는 충분히 적합합니다.
우리 SDK의 초점이 웹 애플리케이션이므로, 인기 있는 프레임워크인 Flask를 사용하여 간단한 웹 서버로 시작했습니다.
Poetry 기능을 활용하여 Flask를 설치하는 것은 poetry add flask
명령을 실행함으로써 쉽게 가능했습니다. 그런 다음, Flask의 공식 빠른 시작 가이드를 따라 'hello.py' 파일을 다음 코드 스니펫으로 작성했습니다:
flask --app hello run
명령을 통해 서버를 실행하고, 브라우저에서 http://localhost:5000 를 열자 원하는 결과가 나왔습니다. 성공했습니다!
초보자로서, 더 많은 코드를 작성하는 것에 서두르지 않았습니다. 대신, 코드 스니펫에서 배울 정보가 많이 있습니다:
from x import y
를 사용하여 모듈이나 클래스를 가져올 수 있습니다.- 줄을 종료할 때 세미콜론이 필요 없습니다(오 맙소사).
- 임의의 이름으로 새 변수를 정의하고 해당 값으로 할당할 수 있습니다.
new
키워드 없이 클래스 인스턴스를 생성할 수 있습니다.- Python은 데코레이터를 지원하며,
@app.route
는 함수를 라우트 핸들러로 등록하는 데코레이터 역할을 합니다.- 함수의 반환 값은 응답 본문으로 해석됩니다.
def
키워드를 사용하여 함수를 정의할 수 있습니다.
보시다시피, 코드를 단지 "작동하게 하기"보다는, 코드의 각 줄을 이해하려고 시도하면 많은 것을 배울 수 있습니다. 동시에, Flask의 공식 문서는 스니펫을 더 자세히 설명해주었습니다.
프로젝트 시작하기
이제 프로젝트를 시작할 시간입니다. 곧 LogtoClient
클래스를 정의하고, 언어를 느끼기 위해 몇 가지 속성과 메서드를 추가해 보았습니다:
그런 다음, Flask와 클래스를 통합해 보았습니다:
이제 진짜 프로젝트 같은 느낌이 들기 시작했습니다. 하지만 뭔가 부족한 느낌이 들었습니다: 타입 시스템.
타입 시스템
SDK이기 때문에, 타입 시스템을 포함하면 API를 이해하고 개발 중에 오류 가능성을 줄이는 데 도움이 됩니다.
Python은 버전 3.5에서 타입 힌트를 도입했습니다. 이것은 TypeScript만큼 강력하진 않지만, 없는 것보단 낫죠. LogtoClient
클래스에 몇 가지 타입 힌트를 추가했습니다:
이제 훨씬 더 나아졌습니다. 하지만 사전 정의된 키를 가진 객체와 같은 복잡한 타입으로 오면 문제가 발생할 수 있습니다. 예를 들어, 구성 객체를 나타내기 위해 LogtoConfig
클래스를 정의해야 합니다:
이제 괜찮아 보이지만, 곧 JSON에서 객체를 인코딩, 디코딩 및 검증하는 문제를 마주하게 될 것입니다.
조사 후 저는 pydantic을 솔루션으로 선택했습니다. 이 라이브러리는 타입 힌트와 함께 작동하는 데이터 유효성 검사 라이브러리입니다. 복잡한 boilerplate 코드를 따르지 않고도 다양한 JSON 기능을 지원합니다.
따라서 LogtoConfig
클래스는 다음과 같이 다시 작성될 수 있습니다:
이 또한 클래스 상속에 대해 Python에서 클래스 이름 뒤에 괄호를 추가해야 한다는 사실을 가르쳐주었습니다.
비동기 작업
Logto SDK 내에서, 우리는 Logto 서버로 HTTP 요청을 해야 합니다. JavaScript 경험이 있다면, "콜백 지옥"이라는 문구가 익숙할 것입니다. 비동기 작업을 처리할 때 흔히 발생하는 문제입니다. 현대 프로그래밍 언어는 Promise
나 coroutine
과 같은 유사한 솔루션을 제시합니다.
다행히도, Python에는 async
와 await
라는 내장 솔루션이 있습니다. 이를 사용하기 전에, 인기 있는 프레임워크와의 호환성을 보장해야 합니다. Flask에서는 async
옵션을 설치하고 def
대신 async def
를 사용하여 이를 수행할 수 있습니다:
그런 다음 await
를 사용하여 비동기 작업의 결과를 기다릴 수 있습니다.
HTTP 요청
HTTP 요청은 흥미로운 주제입니다. 거의 모든 프로그래밍 언어에는 네이티브 솔루션이 있지만, 개발자들은 보통 사용하기 쉬운 서드파티 라이브러리를 사용합니다. 몇 가지 예시:
- JavaScript:
XMLHttpRequest
vs.fetch
vs.axios
- Swift:
URLSession
vs.Alamofire
- Java:
HttpURLConnection
vs.OkHttp
Python도 마찬가지입니다. 저는 async
와 await
을 지원하는 aiohttp를 사용하기로 결정했습니다.
Copilot의 마법
Copilot 이전이라면, 이제 비즈니스 로직을 작성해야 하는 지루한 단계에 와야 합니다. SDK 규약과 다른 SDK의 도움으로, 코드 작성 전에 각 메서드에 대해 설명적인 주석을 달 수 있습니다.
이것은 더 많은 코드 가독성을 추가하고, 개발자들이 코드 인텔리전스를 통해 IDE나 에디터에서 바로 API를 이해하는 데 도움이 됩니다.
예를 들어, generateCodeChallenge
메서드를 고려해보면, 주석은 다음과 같이 작성할 수 있습니다:
이것은 대형 언어 모델(LLM)의 훌륭한 프롬프트를 제공했습니다. 그리고 Copilot은 실망시키지 않았습니다:
몇 가지 수정이 필요할 수도 있지만, 그것은 큰 문제가 아닙니다. 게임이 이미 바뀌었습니다.
마무리
첫날 도달한 진행 상황은 이 정도입니다. 긴 하루였지만, 현대 도구와 기술 덕분 에 예상보다 훨씬 더 나았습니다.
2일차: 기준을 높이기
첫날 작업을 기반으로, 비즈니스 로직은 빠르게 완성되었습니다. 하지만 SDK로서 여전히 충분하지 않습니다. 2일차의 작업 목록은 다음과 같습니다:
- 유닛 테스트 추가.
- 코드 포맷팅 강제.
- Python 버전 호환성 확인.
- 지속적인 통합 추가.
- SDK 배포.
유닛 테스트
유닛 테스트는 수차례 우리를 구해주었기 때문에, 건너뛰지 않겠습니다. 유닛 테스트 작성 시 일반적으로 고려할 사항은 다음과 같습니다:
- 테스트를 어떻게 구성하고 실행할 것인가?
- 결과를 어떻게 단언할 것인가?
- 비동기 테스트를 어떻게 실행할 것인가? (당연해 보이지만, 일부 언어에서는 가끔 문제를 일으킬 수도 있습니다.)
- 종속성을 어떻게 모킹할 것인가? (이 주제에 너무 깊이 들어가면 토끼구멍을 발견할 수 있으니, 불가피할 때까지는 피하세요.)
- 코드 커버리지 보고서를 어떻게 생성할 것인가?
이 질문들을 염두에 두고, 내장된 unittest
모듈이 일부 경우에는 부족하다는 것을 발견했습니다. 그래서 저는 pytest를 테스트 프레임워크로 선택했습니다. 비동기 테스트를 지원하고 충분히 성숙해 보였습니다.
이 여정에서 기능
과 같은 흥미로운 새로운 개념을 발견했습니다. 이는 다른 언어로 코드를 작성할 때 사고방식에도 도움이 될 수 있습니다.
코드 포맷팅
각 언어는 자체 코드 포맷팅 스타일을 가지고 있습니다. 개인적으로 일관된 포맷팅은 저를 행복하고 편안하게 만들며, 코드 리뷰와 협업에 유리합니다.
"최고"의 스타일을 논쟁하는 대신, 의견이 강한 포맷터를 선택하고 그것을 따르기로 결정했습니다.
Black은 좋은 선택처럼 보였습니다. 유일한 불만은 수정할 수 없는 탭 크기였습니다. 그러나 큰 문제는 아니었고, 저는 그것을 수용하기로 했습니다.
Python 버전 호환성
SDK로서, 널리 사용되는 Python 버전에서 호환 가능해야 합니다. "python version usage statistics"를 검색하여 Python 3.8을 최소 버전으로 결정했습니다.
이제 환경 관리자의 장점이 나타납니다. pyenv local 3.8
및 poetry env use 3.8
명령을 실행하여 Python 버전을 쉽게 전환할 수 있습니다. 그런 다음 테스트를 실행하여 호환성 문제를 발견할 수 있습니다.
지속적인 통합
지속적인 통합은 모든 코드 변경의 품질을 보장합니다. 우리의 리포지토리가 GitHub에 호스팅되었기 때문에, GitHub Actions가 자연스러운 선택이었습니다.
핵심 워크플로우는 간단한 원칙을 따릅니다:
- 환경을 설정합니다.
- 종속성을 설치합니다.
- 프로젝트를 빌드합니다.(Python은 필요 없습니다.)
- 테스트를 실행합니다.
GitHub Actions는 좋은 커뮤니티를 가지고 있어, 워크플로우를 구성하는 데 몇 분밖에 걸리지 않았습니다.
매트릭스 전략을 사용하여 서로 다른 Python 버전, 심지어 서로 다른 운영 체제에서도 워크플로우를 실행할 수 있습니다.
SDK 배포
마지막 단계는 SDK를 배포하는 것입니다. 공개 패키지의 경우, 이는 보통 공식 언어별 패키지 레지스트리에 제출하여 이루어집니다. 예를 들어 Node.js의 npm, Python의 PyPI, Flutter의 CocoaPods이 있습니다.
Poetry는 저의 안내서 역할을 합니다. poetry publish
를 실행하기만 하면 패키지를 PyPI에 배포할 수 있습니다. 간단하죠.
마무리 생각
정말로 몰입적인 여정이었습니다. 오픈 소스 커뮤니티의 도움 없이는 훨씬 어려웠을 것입니다. 모든 기여자들에게 박수를 보냅니다!
몇 가지 일반적인 교훈이 있습니다:
- 목표를 정확히 정의하고 세분화하며, 항상 목표를 염두에 둡니다.
- 안정적이고 재현 가능한 개발 환경을 설정합니다.
- 가능한 한 (좋은) 도구를 사용합니다.
- 기본적으로 내장된 솔루션 또는 기존 솔루션을 우선시합니다.
- 언어 관습과 작성한 모든 코드를 이해합니다.
- 그러나 미세한 부분에 집착하지 마세요.
- 명확하고 설명적인 작업에 Copilot을 사용하세요.
이 리포지토리에서 최종 결과물을 찾을 수 있습니다. 같은 전략으로 Logto PHP SDK도 빠르게 만들었습니다. 제안 사항이 있으시면 주저하지 말고 알려주세요.
이 기사가 새로운 프로그래밍 언어를 배우는 데 도움이 되기를 바랍니다. 해킹을 즐기세요!