파이썬 프로젝트 구조화 작업
해당 포스트는..
프로젝트 구조화는 프로젝트의 성공과 지속 가능성을 위한 핵심 요소입니다. 특히 여러 개발자가 협업하거나 장기간 유지보수가 필요한 프로젝트에서는 더욱 중요합니다. 프로젝트 구조화란 무엇이며 어떻게 해야할지 고민해보았습니다.
5월의 어느날
[구조화] python_process 구조화
라는 약간은 부담스러운 티켓이 생성되었습니다.
매출 정산을 위한 크롤링 소스만 존재하던 기존 파이썬 프로젝트를 구조화하는 작업을 맡게 되어버린 것이었습니다… 기존 코드베이스에 추가하여 다양한 프로세스를 파이썬으로 실행하기 위해서 포괄적인 프로젝트 구조를 설계해야 했습니다. 코드와 로직만 고민하면 되는 업무들과 다르게 프로젝트의 전반적인 방향성을 결정하는 작업이다보니 마음대로 하기 망설여졌습니다. 그래서 구조화가 무엇이고 보통 어떻게 해야 하는지부터 공부하기 시작했습니다. 먼저 구조화는 왜 중요하고 해야만 할까요?
프로젝트 구조화의 중요성
먼저, 한 명의 개발자가 단일 폴더 안에 몇 가지 코드 파일만 작성하여 시작된 작은 프로젝트를 상상해봅시다. 이 코드들은 각각 하나의 역할만을 하면서 문제없이 운영되고 있습니다. 또한, 개발자 혼자 모든 코드를 작성했으므로, 문제가 발생했을 때 어느 파일을 봐야 하는지, 기능을 추가할 때 어떤 부분을 수정해야 하는지, 새로운 코드를 어떻게 작성해야 하는지 모두 잘 알고 있습니다.
하지만 시간이 흐르고 프로젝트가 성장하면서 함께 일하는 개발자들이 추가되고, 요구되는 기능들이 늘어난다면 상황은 달라집니다. 프로젝트가 커지고 코드의 양이 많아지며, 팀원들이 추가되고 기능이 복잡해지면, 무작위로 파일을 쌓아 두는 방식은 여러 가지 문제를 일으킬 수 있습니다.
-
파일 관리의 어려움
하나의 폴더에 모든 코드를 넣어두면, 코드가 많아질수록 파일을 찾고 관리하는 데 어려움이 발생합니다. 필요한 코드가 어디에 있는지 파악하기 어려워지며, 프로젝트의 구조가 혼란스러워질 수 있습니다. 특정 기능이나 모듈을 찾는 데 시간이 걸리며 코드의 흐름을 이해하기 어려워질 수 있습니다. 특히 새로운 팀원들이 프로젝트에 합류할 때, 코드의 위치와 역할을 이해하는 데 어려움을 겪을 수 있습니다.
-
협업과 의사소통의 비효율
코드 구조가 일관되지 않으면 팀원들이 서로의 작업을 이해하고 협력하는 데 시간이 더 걸리며, 중복 작업이나 충돌이 발생할 위험이 증가합니다. 각 팀원이 코드의 위치와 역할을 명확히 알기 어려워져 협업과 의사소통의 효율이 떨어질 수 있습니다. 일관성 없는 코드 구조는 팀 전체의 작업을 복잡하게 만들어 프로젝트 진행 속도를 늦출 수밖에 없습니다.
-
유지보수와 확장성의 어려움
코드의 변경이나 기능 추가가 필요할 때, 모든 파일을 일일이 점검하고 수정해야 하는 상황이 발생할 수 있습니다. 이는 작업을 복잡하게 만들고 오류를 발생시킬 위험을 증가시킵니다. 잘못된 수정이 다른 부분에 영향을 미치거나 버그를 유발할 수 있기 때문에, 코드의 구조를 명확히 하고 변경 사항이 최소한으로 영향을 미치도록 하는 것이 중요합니다.
-
중복 코드 문제
구조화되지 않은 프로젝트에서는 중복된 코드가 발생할 위험이 커집니다. 중복된 코드는 유지보수를 복잡하게 만들고, 동일한 기능이 여러 곳에서 변경되어야 할 때 일관성을 유지하기 어려워집니다.
이런 문제들이 발생하기 전에, 잘 구조화된 프로젝트를 만들어두는 것이 좋습니다. 100개의 코드를 나중에 구조화하는 것보다는, 10개의 파일을 구조화 한 뒤 그 틀을 바탕으로 프로젝트를 성장시켜나가는 것이 더 효욜적이기 때문입니다. 잘 구조화를 한다는 것은 파일을 적당한 폴더에 잘 분류하는 작업이라고 할 수 있습니다. 이 문장만 보면 구조화 작업이 간단해 보일 수도 있지만, ‘적당히’와 ‘잘’이라는 애매한 부사는 중요한 동시에 까다롭게 만듭니다. 적절한 폴더에 잘 나눠진 프로젝트는 높은 응집도와 낮은 결합도를 갖게 됩니다. 높은 응집도란 모듈이나 클래스가 명확한 책임이나 기능을 가지고 있어 관련된 코드가 한 곳에 집중되는 상태를 의미하고, 낮은 결합도는 모듈 간의 의존성이 최소화된 상태를 의미합니다. 높은 응집도와 낮은 결합도를 가진 프로젝트는 각 모듈이 독립적으로 작동할 수 있도록 하며, 이로 인해 다음과 같은 다섯 가지 주요 장점이 있습니다.
-
가독성
높은 응집도 덕분에 프로젝트가 체계적으로 정리되면, 코드와 폴더 구조가 명확해져 개발자들이 프로젝트를 쉽게 이해하고 적용할 수 있습니다. 각 모듈이 하나의 책임을 가지고 있어서 코드의 기능과 흐름을 쉽게 파악할 수 있습니다. 예를 들어, 서비스 계층에서 비즈니스 로직을 확인하고, 컨트롤러 계층에서 HTTP 요청 처리를 확인함으로써 프로젝트의 전체적인 구조를 빠르게 이해할 수 있습니다.
-
유지보수성
응집도가 높고 결합도가 낮은 코드는 변경 사항이 특정 부분에만 영향을 미치기 때문에 유지보수가 용이합니다. 관련 기능이 하나의 모듈에 집중되어 있어 이해하고 수정하기 쉬워집니다. 또한, 독립적으로 수정하고 테스트할 수 있는 구조 덕분에 전체 코드의 안정성과 유지보수성이 높아집니다. 예를 들어, 하나의 모듈을 수정할 때 다른 모듈에 미치는 영향을 최소화할 수 있습니다.
-
재사용성
높은 응집도와 낮은 결합도는 특정 기능이나 유틸리티를 독립적인 모듈로 분리하여, 프로젝트 내에서 쉽게 재사용할 수 있도록 합니다. 잘 분리된 모듈은 동일한 기능을 여러 곳에서 재사용하거나 새로운 기능을 추가하는 것이 용이하게 합니다. 반대로, 응집도가 낮고 결합도가 높은 경우에는 코드 중복이 발생할 수 있으며, 이는 유지보수를 복잡하게 만들 수 있습니다.
-
협업 효율성
명확한 구조는 팀 내 역할 분담과 소통을 원활하게 합니다. 각 기능이나 모듈이 명확히 정의되어 있어 개발자들이 각자의 역할에 집중할 수 있고, 필요한 정보나 기능을 쉽게 찾아 활용할 수 있습니다. 이렇게 하면 팀 전체의 협업 효율성이 향상됩니다.
-
테스트 용이성
높은 응집도와 낮은 결합도는 테스트 코드를 작성하고 관리하는 데 유리합니다. 각 기능이나 모듈이 독립적으로 구성되어 있어, 테스트를 별도로 작성하고 실행하기가 용이합니다. 이로 인해 버그를 조기에 발견하고 해결할 수 있어 전체 프로젝트의 안정성을 높이는 데 기여합니다.
Package by Layer vs Package by Feature
그럼 프로젝트 구조화에 대표적인 방식은 어떤 것들이 있을까요? 프로젝트 구조화를 위해 패키지를 구성하는 방법은 크게 계층별 패키지
와 기능별 패키지
로 나눠집니다. 각각의 접근 방식은 프로젝트의 특성과 요구사항에 따라 선택할 수 있으며, 장단점이 명확히 구분됩니다.
Package by Layer(계층별 패키지)
계층별 패키지는 프로젝트를 아키텍처적 계층에 따라 패키지화하여 분리하는 방식입니다. 이 방식은 주로 소프트웨어의 아키텍처를 분리하고 각 계층별로 책임을 명확히 할 수 있도록 도와줍니다.
예시:
-
장점:
-
각 계층이 명확하게 분리되어 있어 프로젝트에 대한 이해도가 상대적으로 낮더라도 코드의 기능과 전체 프로젝트의 흐름을 쉽게 이해할 수 있습니다. 예를 들어, 비즈니스 로직은 서비스 계층에서, HTTP 요청 처리는 컨트롤러 계층을 확인하여 파악이 가능합니다.
-
각 계층의 역할이 명확히 정의되어 있어, 협업 시 코드베이스를 이해하고 유지보수하는 데 도움이 됩니다. 각 계층의 책임이 분명하게 나뉘어 있으므로, 특정 계층의 수정이 다른 계층에 미치는 영향을 쉽게 추적할 수 있습니다.
-
-
단점:
- 기능을 추가하거나 수정할 때 코드베이스 전체를 돌아다녀야 할 수 있습니다. 예를 들어, 새로운 회원 기능을 추가할 때는 컨트롤러, 서비스, 모델 계층 모두를 수정해야 할 수 있습니다. 이러한 전방위적인 수정은 작업을 복잡하게 만들고 시간이 더 소요될 수 있습니다.
계층별 패키지 구조는 프로젝트의 구조적 명확성을 제공하지만, 기능 추가나 수정 시 코드베이스 전체를 수정해야 하는 단점이 있습니다. 따라서 계층별 패키지 구조를 효과적으로 활용하기 위해서는 객체지향 설계 원칙과 단일 책임 원칙을 철저히 준수해야 합니다. 각 계층의 역할과 책임을 명확히 해야만 낮은 결합도와 높은 응집도를 유지할 수 있으며, 코드 변경의 영향을 최소화하고 시스템의 유연성과 유지보수성을 높일 수 있습니다.
Package by Feature(기능별 패키지)
기능별 패키지 구조는 프로젝트의 기능 또는 모듈을 기준으로 패키지를 구성하는 방식입니다. 이러한 구조는 각 기능이 독립적으로 동작할 수 있도록 합니다.
예시 :
-
장점:
-
각 기능이 독립적으로 동작하도록 구성되어 있어 모듈화가 잘 이루어집니다. 이는 코드의 이해도와 유지보수성을 높이는 데 도움이 됩니다.
-
관련된 클래스와 인터페이스가 한 곳에 모여 있어 응집도가 높아지고, 특정 기능을 찾고 수정하는 데 걸리는 시간을 줄여줍니다.
-
각 기능이 독립적으로 개발되고 유지보수될 수 있어 결합도가 낮아집니다. 한 기능의 변경이 다른 기능에 미치는 영향을 최소화할 수 있습니다.
-
-
단점:
-
유사한 기능이나 유틸리티 코드가 여러 패키지에 중복될 가능성이 있습니다. 이로 인해 코드 유지보수가 복잡해질 수 있습니다.
-
프로젝트 전반의 흐름을 파악하기 어려울 수 있습니다. 기능별로 나누어져 있기 때문에 전체적인 코드 흐름을 이해하는 데 시간이 더 걸릴 수 있습니다.
-
패키지 간에 순환참조가 발생할 수 있습니다. 이는 코드 의존성을 복잡하게 만들고, 문제 해결을 더 어렵게 만들 수 있습니다.
-
기능별 패키지 구조는 모듈화된 코드베이스를 제공하여 높은 응집도와 낮은 결합도를 유지하는 데 도움이 됩니다. 그러나 코드 중복과 초기 설계의 복잡성 등 몇 가지 단점도 존재합니다. 이러한 구조를 효과적으로 활용하기 위해서는 기능 간의 공통 요소를 잘 관리하고, 초기 설계를 신중하게 수행하는 것이 중요합니다. 기능별 패키지 구조는 특히 대규모 프로젝트나 마이크로서비스 아키텍처에서 유용하게 활용될 수 있습니다.
정석적인 파이썬 프로젝트 구조란?
파이썬은 매우 유연한 언어이기 때문에 프로젝트 구조에 대한 정해진 규칙이 없습니다. 이러한 패키지 구분 방식을 고려하여 파이썬 프로젝트에도 유사한 접근 방식을 적용할 수 있었습니다. 몇 가지 원칙을 세우고, 계층별 패키지 방식과 기능별 패키지 방식을 적절히 혼합하여 프로젝트 구조를 설계했습니다.
-
공통 함수 구성
프로젝트의 코드를 가능한 작은 모듈로 나누어 관리합니다. 공통 기능을 가진 파일은 _lib/ 디렉토리에 모아 클래스로 구성합니다.
-
폴더링된 소스 코드
프로젝트의 핵심 기능이 동작하는 코드는 src/ 디렉토리 아래 기능별로 분류합니다. 이렇게 하면 각 기능을 쉽게 찾고 관리할 수 있습니다.
-
모듈화된 함수 구성
필요한 코드는 각각의 기능을 수행하는 함수로 작성하고 modules/ 디렉토리에 넣습니다. 이렇게 하면 코드 재사용성이 높아지고 유지보수도 쉬워집니다. 또한 modules 아래 긴으별로 패키지를 나누어 각 기능에 대한 모듈을 한 폴더에서 관리하기 쉽게했습니다.
-
명확한 파일 이름
모듈 파일 이름은 해당 모듈이 어떤 기능을 수행하는지 명확하게 드러나도록 지어야 합니다. 이는 다른 개발자가 프로젝트를 이해하고 사용할 때 도움이 됩니다.
-
데코레이터 활용
파이썬의 강력한 기능 중 하나인 데코레이터를 적극적으로 활용하여 코드의 효율성을 높이고 중복을 줄입니다. 예를 들어, 로깅, 인증, 성능 측정 등 여러 측면에서 유용하게 활용할 수 있습니다.
유연한 구조화: 부스터스 테크팀의 파이썬 프로젝트 접근법
이번 파이썬 프로젝트 구조화에서 가장 중점적으로 고려했던 부분은 바로 유지보수의 용이성과 코드의 재사용성이었습니다. 부스터스 테크팀에서는 지속적이고 빠른 개발이 동시에 이루어져야 하기 때문에, 이러한 요소들은 프로젝트의 성공과 효율적인 운영을 위해 필수적인 조건입니다.
구조화 작업을 진행하면서 “유연한 구조화”라는 다소 모순된 개념에 집중하게 되었습니다. 구조화라는 단어는 자칫하면 변경될 수 없는 고정된 규칙을 의미하는 것처럼 보일 수 있지만, 실제로는 프로젝트의 진행 상황과 팀의 요구사항이 끊임없이 변화합니다. 이에 발맞추어 유연하게 대응할 수 있는 구조화가 필요하다고 생각했습니다. 정해진 틀에 얽매이지 않고 필요에 따라 구조를 수정하고 개선해나가는 접근 방식이 중요하다고 보았습니다.
이를 통해 부스터스 테크팀은 변화하는 요구사항에 유연하게 대응하면서도 명확하고 효율적인 프로젝트 구조를 유지하려 합니다. 이는 단순히 프로젝트의 성공뿐만 아니라 지속적인 성장을 위한 견고한 기반을 마련하는 데에도 큰 도움이 될 것입니다.