[브랜디인턴쉽] 회고록 volume 1

김기용·2021년 1월 18일
0
post-thumbnail
post-custom-banner
(브랜디 인턴쉽을 진행하면서 그 과정에서 배운것 그리고 기억에 남는 것들을 모아 작성했다.)

서비스되고 있는 브랜디의 admin 과 service 페이지를 실무에 맞춰 모델링 설계부터 배포까지 재개발하는 과정을 진행하였고, 모델링, API 문서제작, 프로젝트초기세팅 에 참여하였으며 주로 초기세팅 팀장으로써 팀의 적응성을 고려해 디자인패턴의 선택, sql driver의 선택 등 팀의 적응성을 고려한 프레임워크 구조를 책임지고 설계하는 역할을 수행하였다.


⚡️ 초기세팅

플라스크로 초기세팅을 진행하게되면서 많은 고민에 빠졌다.🥺 모든 프레임워크는 비슷하다고 생각하였는데 막상 플라스크의 뚜껑을 열고 보니깐 "아무것도 존재하지 않았다" 문자 그대로 아무것도 없었다. 디렉토리 구조는 꿈도 꿀수 없었으며 변수를 만들어 그안에 플라스크 객체를 할당해 주는것부터 시작을 했었어야했다.🤯

from flask import Flask

app = Flask(__name__)

🎯 목표

데이터 모델링팀과 API 팀이 각자 역할에 집중하고 있는 동안 초기세팅팀은 팀의 적응성을 고려해 디자인패턴의 선택, sql driver의 선택 등 팀의 적응성을 고려한 프레임워크 구조를 책임지고 설계하는 것에 있었다.


🤔 1. 디자인 패턴 선택

"어떤 디자인 패턴을 우리 조직이 가장 익숙하게 받아 드릴까?"

PROBLEM

첫번째로 했던 생각은 디자인 패턴에 대한 고민이였다. FLASK 는 micro framework 가볍고 자유로운 환경을 제공해준다. 하지만 가볍고 자유롭다라는 말은 "아무것도 지원해주지 않는다" 라는 말과 일맥상통한다😭.

대부분의 팀원들은 개발을 2개월동안 배운 비전공자로 이루어져 있었으며 장고라는 프레임워크에 익숙해져 있었다. 이 때문에 디렉터리 구조를 처음부터 만들어야된다는 부담감을 가지게 되었다.🥺

SOLUTION

"어떤 디자인 패턴을 우리 조직이 가장 익숙하게 받아 드릴수 있을가?"🤔 라는 생각을 가지고 리서치를 진행하였다. 클라이언트-서버, MVC, layered Pattern(계층화패턴) 등 여러 아키텍쳐 패턴의 선택지가 있었다.

리서치 결과 앱어플리케이션에서 제일 널리적용되는 mvc 모델과함께 layerd 패턴을 이용하기로 하였다. 검색도 용이하며, MVC 같은경우 비슷한 패턴인 MVT 모델은 장고에서도 쓰이고 있었고 layered Pattern 의 계층이라는 직관적인 모델 개념또한 받아드리기 어렵지 않은것 같아 팀의 적응성을 고려했을때 최적이라고 생각이들어 선택하게 되었다.


🤔 2. 파라미터 유효성 검사

PROBLEM

두번째로 했던 고민은 파라미터들의 유효성 검사이다. 서비스부터 어드민 페이지까지 만드는 작업은 많은 API를 필요로한다. 즉, 우리팀은 많은 양의 파라미터들의 유효성을 검사해야하며 누락된 값은 없는지 체크하여야했다. 일일이 받아서 validate 함수를 구현해 체크한다는것은 시간낭비가 될것이다.

또한 regular expression(정규표현식)을 사용해 보다 정확한 유효성 검사를 하고 싶었고, API 팀 문서팀과 상의를 한 결과 폼 데이터의 처리가 필요한 사실 또한 알게되었다.

def reserved_values():
    return ['today', 'tomorrow']

class MyRule(AbstractRule):
    def validate(self, value):
        errors = []
        if value in reserved_values():
            errors.append('Value %s is reserved' % value)

        # other errors...
        errors.append('One more error')

        return value, errors


@app.route('/')
@validate_params(
    Param('day', GET, str, False, rules=[MyRule()])
)
def hi(day):
    return day
reference - https://github.com/d-ganchar/flask_request_validator

SOLUTION

json schema와 flask-request-validator 둘중에 고민을 하였지만 폼데이터 처리의 필요성에 의해 flask-request-validator가 더 좋은 선택지라고 생각하였고 AbstractRule 클래스를 상속받아 커스터마이징 한다면 정규표현식도 문제없이 사용할수 있다는 점이 장점으로 생각되어 선택하였다.


🤔 3. SQL 드라이버의 선택

reference - https://wiki.openstack.org/wiki/PyMySQL_evaluation

PROBLEM

브랜디 인턴쉽에서 프로젝트를 진행할때 ORM을 사용하지 않고 raw query를 사용해야한다는 제약조건이 있었다.

SOLUTION

솔직히 말하자면 sql 드라이버의 개념을 잘 이해하지 못해서 리서치하는데 시간이 많이 걸렸다. 처음에 쓰고 싶은 드라이버는 sqlalchemy 였다. 하지만 ORM의 불필요하다는 점때문에 다른 드라이버를 찾아보기로 하였다.

두번째로 눈에 들어온건 MYSQL-Connector 라고 oracle에서 공식적으로 지원 받고 있는 드라이버였지만 팀의 적응성을 고려했을때 pyMYSQL의 간결한 문법과 강력한 커뮤니티가 더 큰 장점으로 보였다. 또한 pypi에서 공식적으로 호스트를 해주었고, eventlet(비동기)지원, 파이썬3 호환성이란 옵션도 좋은 장점으로 생각되어 PyMYSQL 을 선택하게 되었다.


🤔 4. View에 대한고민..

PROBLEM

웹 API는 HTTP method 와 매우 밀접하게 작동됨으로, "view 가 직관적이였으면 좋겠다" 라는 생각으로 리서치를 진행하게 되었다.

Flask 0.7 introduces pluggable views inspired by the generic views from Django which are based on classes instead of functions. The main intention is that you can replace parts of the implementations and this way have customizable pluggable views.

reference - https://flask.palletsprojects.com/en/1.1.x/views/

SOLUTION

선택지는 플라스크에서 기본으로 제공해주는 router viewclass-based-view 가 있었다. router view 는 Url 별로 보여줘야 하는 페이지가 증가하는 경우, 하나의 파이썬 파일에 계속 쌓인다는 점과 직관적이지 못하다는 점이 단점으로 생각되었다. 그러던중 클래스뷰 기반에 methodView라는것을 알게 되었는데 flask 0.7 부터 장고의 generic view 에서 영감받아 만들어진 view 라고한다. 무엇보다도 장고와 비슷하다는 점이 큰 장점으로 다가왔기때문에 router view 대신 methodView 를 상속받아 view를 구현하는 방식으로 정하였다.


🤔 5. 예외처리 구조

PROBLEM

12명의 작업자가 한 프로젝트를 작업해야 되는 상황이였고 많은양의 에러메세지가 발생할것을 예상하였다. 통일성 있는 에러메세지를 위해 예외처리 구조를 잘 만들어야 했다.

SOLUTION


class CustomError(Exception):
    def __init__(self, status_code, message, error_message):
        self.status_code = status_code
        self.message = message
        self.error_message = error_message

class InvalidUserId(CustomError):
    def __init__(self, error_message:
        self.status_code = 400
        self.message = 'Invalid User'
        self.error_message = error_message
        super().__init__(status_code, message, error_messag)
        
@error_handler(CustomError)
def handle_errors(e):
    return jsonify({'message': e.message, 'error_message': e.error_message}), status_code

기본 Exception 클래스를 상속받아 사용자정의 예외처리 클래스(CustomError)를 만들어준다음 CustomError 클래스를 다시 상속받은 상세 예외처리 클래스를 만들어주었다. 이렇게 계층 구조로 만들어준 이유는 flask 에서 제공해주는 error_handler 데코레이터를 사용해 모든 예외처리를 한번에 처리할수 있도록 만들어주기 위해서이다.

이런 구조로 만들어진 예외처리 구조는 어느 계층에서 여러개의 raise로 예외처리가 발생시켜도 일관성 있는 메세지와 하나의 error_handler 데코레이터를 통해 처리할 수 있다는 장점이있다.


profile
매일 새로운 배움을 통해 꾸준히 성장하는 것을 목표를 두고 있습니다. 논리적인 사고로 문제해결 하는것에 희열을 느끼고 언젠가 제가 만든 결과물들이 사람들에게 편이를 제공하며 사용되는 날을 간절히 소망하고 있습니다. 🙏
post-custom-banner

0개의 댓글