/Flask-Large-Application-Example

This is how I structure my large Flask applications.

Primary LanguagePythonMIT LicenseMIT

Flask-Large-Application-Example

Scrutinizer Code Quality Codacy BadgeCode style: black

This is how I structure my large Flask applications.

About

마이크로 웹 프레임워크인 Flask는 항상 개발자에게 구조에 대한 고민을 하게 만듭니다. 이 저장소는 제가 Flask를 배우기 시작했던 고등학교 1학년 때부터 지금까지의 시간동안 Flask 어플리케이션의 구조에 대해 고민한 흔적입니다. 근데 뭐 계속 개선하다 보니까 Flask에게만 특별히 적용할 수 있는 구조라기 보단 다른 웹 프레임워크들에서도 써먹을 수 있는 기반이 될 수도 있을 것 같네요.

구조가 막 빡세다고 좋아지는 건 아닌 것 같아서, 조금 편하려고 복잡도를 높여버리는 모습은 지양했습니다. 이 레포의 '최신 버전'은 항상 제 기준에선 가장 편한 구조인데, 모두에게 그렇지도 않고 저도 자주 마음이 바뀝니다. 별거 아닌 코드에 커밋이 백단위인 게 이런 이유니까, 그냥 이거 가져가서 본인한테 맞게 커스텀하시면 좋을 것 같습니당 ㅎㅎ

컨셉

application factory가 필요하다.(app/__init__.py)

local에서 실행해보는 용도, 테스트 클라이언트를 얻는 용도, 배포 단에서 사용하는 용도 등으로 app 객체가 필요한데, 그들은 모두 extension 초기화 - view들 라우팅 - hook 달아주는 것은 똑같고, 단지 주입되는 config가 다른 것밖에 차이가 없습니다. create_app에서 config class들을 받도록 했습니다.

extension들은 lazy하게 초기화한다.(app/extensions.py, app/__init__.py의 register_extensions)

어떤 config를 주입할지는 create_app 함수가 호출된 후 정해지므로, config에 의해 초기화가 진행되는 extension들은 lazy하게 초기화하도록 했습니다.

config를 따로 패키지화해서, 선택지를 두어 관리한다.(config/)

  1. Flask에서 config는 class로 다루는 게 가장 좋다고 생각합니다.
  2. Config는 정적이어야 합니다. Config class 내에서 if절이 있는 형태는 좋지 않다고 생각합니다. 환경 변수에 따라 서로 다른 config를 주입해야 한다면, 각각에 맞게 class를 나누어 준비한 후 create_app을 호출하는 단에서 config를 상황에 맞게 전달하도록 만드는 게 좋다고 봅니다.
  3. 선택지마다 모듈을 만들어 두었습니다. 예를 들어, Local DB를 바라보도록 하는 config/Remote DB를 바라보도록 하는 config를 db_config라는 모듈에 LocalDBConfig, RemoteDBConfig 클래스로 준비한다.

상수 config는 따로 관리되어야 한다.(constants/)

DRY한 코드를 작성하기 위해 리터럴을 지양해야 합니다. 게시글 목록 API에서 반환해주는 게시글 기본 갯수나, 특정 API의 사용 가능 시간같은 것들을 예로 들 수 있습니다. 이런 상수 config들은 따로 관리해야 하는 것은 맞지만, 굳이 app 객체에 주입할 필요가 없습니다. 따로 모듈만 만들어 두면 됨.

blueprint와 flask_restful이 필요하다.(app/views/_init_.py)

다른 복잡한 이유가 아니라, 더 구조적인 라우팅을 위해 blueprint의 url prefix, flask_restful의 MethodView 확장이 도움을 주기 때문입니다.

context-dependent한 데이터는 따로 property class화 시킨다.(app/context.py)

request, g 처럼 contenxt-dependent한 객체는 attribute가 dynamic하기 때문에, known attribute를 가지는 객체를 만들어 중계해주는 게 좋습니다. 휴먼 에러 예방에 도움이 되더라구요.

request context를 hook하는 친구들은 hook 패키지에 따로 관리한다.(app/hooks/)

view function이 호출되기 전의 전처리는 view decorator가 하는 것이 맞다.(app/decorators/)

I Referred

People

정겨울님

Repository

Website

Explore Flask - Explore Flask 1.0 documentation
Organizing your project - Explore Flask 1.0 documentation
Patterns of Flask - Flask Documentation (0.12)
Larger Applications - Flask Documentation (0.12)
Application Structure | Flask(A Python Microframework)

How To Structure Large Flask Applications | DigitalOcean
How to Structure a Flask Application
Flask Large App How to - GitBook
Flask Project 구조 예제 - /usr/lib/libsora.so
StackOverflow - Common folder/file structure in Flask app

Presentation

Flask Hacks and Best Practices