[Python, Flask] 간단한 쇼핑몰 웹 앱 예제

0

프로젝트

목록 보기
8/14

😎 소개

최근에 학부 1학년 수업에서 팀 단위로 파이썬 프로젝트를 기말 평가로 진행을 한다고 합니다. 그래서 제가 멘토? 까지는 아니더라도 좋은 성적을 받고 싶어하는 지인에게 만들어준 간단한 쇼핑몰 웹 앱 입니다.

당부의 말씀,,

이 게시글을 읽는 분들에게 말씀드리자면 전 어떤 기술적인 부분들을 소개하고자 하는 것이 아닙니다. 저학년 학생들이 또는 프로젝트 개발 경험이 적은 분들끼리 팀 프로젝트를 진행할 때 소프트웨어 공학적인 단계들을 간접적으로 거치는 방식을 소개하고자 합니다. 저는 막연하게 IDE를 켜서 "~하는법"을 검색해서 코딩을 하는 것은 지양합니다.

환경 설정

  1. Python 3.8 이상에서 개발되었습니다.
  2. flask, flask-cors, mysql-connector-python 패키지를 필수로 설치해야합니다.
  3. MySQL은 5.x 버전을 사용합니다.

구현할 기능들

먼저, 테마를 쇼핑몰로 정했으면 큼직큼직하게 어떤 도메인 지식들이 필요할까 구상할 필요가 있습니다.

  1. 사용자 관련 서비스: 사용자 계정 관리를 수행하는 서비스로 로그인, 로그아웃, 회원가입, 회원 정보 수정과 같은 구체적인 기능들이 포함될 수 있습니다.
  2. 주문 관련 서비스: 상품 주문과 관련된 요청을 처리하는 서비스로 상품 주문, 주문 내역 보기, 주문 내역 상세 보기와 같은 기능들이 포함될 수 있습니다.
  3. 장바구니 서비스: 장바구니와 관련된 요청을 처리하는 서비스로 장바구니에 상품 담기, 장바구니에 상품 제거하기, 장바구니에 담긴 상품 수량 변경하기와 같은 기능들이 포함될 수 있습니다.
  4. 상품 서비스: 상품과 관련된 요청을 처리하는 서비스로 상품 조회와 같은 기능들이 포함될 수 있습니다.

    이렇게 어떤 서비스들이 필요할지 정리가 끝났다면 프로젝트의 디렉토리 구조를 아래와 같이 구성할 수 있습니다. 또 이를 기반으로 각자 특정 서비스에 해당하는 기능들을 구현하는 식으로 역할을 분담한다면 서로 겹치는 부분을 건드리지 않고 개발을 진행할 수 있으므로 깃과 같은 형상관리 시스템에서 충돌을 일으키지 않고 수월하게 개발할 수 있습니다.

Your project
├── User
├── Order
├── Cart
└── Product

어떤가요?
훨씬 보기좋지 않나요? 이렇게 구조화되어 개발된 경우, 추후 기능을 수정하거나 추가할 일이 발생하더라도 해당 기능이 속한 서비스 내부적으로만 수정될 가능성이 높기 때문에 유지 보수 차원에서도 도움이 많이 될 수 있습니다.

DB 설계하기

앞서서 간략하게 어떤 기능들이 필요한지 추출하였으니 DB를 설계하면 됩니다. 사용자 정보에는 어떤 속성들이 담겨있어야 하는지, 주문 정보에는 어떤 속성들이 필요한지,, 와 같은 고민들을 함으로써 DB 설계를 완료할 수 있습니다. 아래에는 개발된 쇼핑몰의 ER 다이어그램을 보여주고 있습니다. 정답이 아닐 뿐더러 완벽하다고 할 수도 없지만 참고가 되었으면 합니다.


MySQL은 관계형 데이터베이스이므로 테이블 내의 컬럼들이 어떤 정보를 담고 있는지에 주목하기보단 왜 저런 관계가 필요한지에 대해서 설명을 하도록 하겠습니다.

  1. user -> role
    사용자는 역할의 번호 또는 아이디 값만 가지고 있고, 실제 역할에 대한 정보는 role 테이블에서 관리됩니다. 현재는 간단한 쇼핑몰이기 때문에 역할이 어드민, 일반 회원 정도로 구분되지만 추후 세부적인 역할들이 생겨나면서 추가를 해야할 필요가 있을 때 사용자는 role 테이블의 id 값만 가지고 있으면 되므로 일관성있게 데이터를 관리하기 편합니다.
  2. product -> category
    이것 역시 user와 role 사이의 관계와 비슷합니다. 쇼핑몰의 카테고리가 세분화되는 경우를 생각하여 product는 category의 id 값만 가지고 있도록 설계하였습니다.
  3. order_sequence -> user
    order_sequence 테이블은 사용자가 주문을 생성하면 데이터 (row)가 하나 생성됩니다. 어떤 사용자가 주문한 것인지 명백해야하기 때문에 user 테이블을 참조하고 있습니다. 쇼핑몰의 사용자가 아닌 사람의 데이터가 들어갈 수 없습니다.
  4. order_detail -> order_sequence
    사용자는 한번 주문을 수행할 때, 한 가지의 상품을 사는 것이 아닙니다. 여러 개의 상품들을 구매할 수 있습니다. 따라서 하나의 order_sequence에 대해서 여러 개의 order_detail들이 존재할 수 있습니다. 이 order_detail들을 결국 한번의 주문에 구매된 상품들이기 때문에 내가 어떤 order_sequence에서 구매된 상품들인지를 알고 있어야합니다.
  5. order_detail -> product
    order_detail에 저장된 주문된 상품들은 쇼핑몰에 등록된 상품들이어야 합니다. 따라서 product 테이블을 참고하고 있으며 일종의 제약조건이라고 볼 수 있습니다.

클래스 다이어그램 그리기

저는 자바 언어를 다루는 사람이라 객체 지향 설계에 근접하다고 할 수 있습니다. 물론 디자인 패턴을 자유자재로 다루지는 못합니다. 또 저는 자바 웹 앱에 대한 연구를 수행하고 있기 때문에 MVC 패턴에 익숙합니다. 그러나 Flask 웹 앱인 경우 MVC 패턴으로 개발하기에 적합한 것 같지는 않습니다. 그렇지만 비슷하게 흉내를 낼 수 있었습니다.
실제 클래스 다이어그램의 경우 객체의 정보를 세세하게 나타낼 수도 있습니다만 제가 한 방식은 쇼핑몰 웹 앱에서 필요한 개체들을 식별하는 정도라고 생각하면 됩니다. 이러한 방식이 실제 팀 프로젝트에서는 더 사용하기 편할 수 있습니다. 너무 완벽한 설계에 집착하다보면 개발 속도를 지연시키게 됩니다.

여기서 짚고 넘어갈 부분은 세 가지 정도가 있습니다. 먼저 DBConnect에 그려진 싱글톤 패턴, 왜 서비스들이 Model, 즉 도메인 정보를 담은 객체들을 사용하고 있는지, 그리고 왜 컨트롤러들은 클래스가 아니라 모듈인지 입니다.

  1. 싱글톤 패턴: 이것은 DBConnect의 특성과 연관이 깊습니다. DBConnect는 데이터베이스와의 커넥션들을 가지고 있습니다. 해당 클래스를 사용하는 DAO들은 데이터베이스에 접근해야할 일이 있을 때, DBConnect로부터 커넥션을 가지고 와서 사용하고 다시 반납합니다. 그러나 이 DBConnect는 프로그램의 동작 중에 한 개만 필요합니다.
    ProductDAO와 OrderDAO가 각각 1개씩 가지고 있을 필요가 없습니다. 또 어떤 로직이 수행될 때마다 이 DBConnect 객체가 생성되었다가 소멸하는 것을 반복한다면 불필요할 수 있습니다. 따라서 우리는 이것을 예방하기 위해 싱글톤 패턴을 사용할 수 있습니다. 이는 클래스로부터 단 하나의 객체만 인스턴스화 된다고 볼 수 있습니다. 그리고 다른 곳에서 이 객체를 생성하려고 할 때, 이미 생성된 객체를 사용하도록 반환합니다. 이를 통해서 모든 클래스들은 단 하나의 DBConnect 객체를 사용하는 것이 가능합니다.

  2. User, Product, Sequence, Order, Cart, CartProduct 와 같은 객체들을 DTO라고 얘기할 수 있습니다. DTO라 하면 데이터를 주고받을 때 사용되는 객체입니다. DTO를 사용하게 되면 어떤 클래스가 다른 클래스를 호출할 때 함수의 파라미터로 정보들을 나열하는 것보다 훨씬 더 규격화된 데이터를 주고받게 됩니다. 우리는 이를 통해서 시각적으로도 아 이 둘 간에 이런 정보를 주고받는구나 라고 쉽게 이해할 수도 있습니다.
    안타깝게도 이 DTO를 컨트롤러가 html로 렌더링하는 과정에 전달해줄 수가 없었습니다. 자바에서는 직렬화를 통해서 객체를 요청에 담아 전달하는 것이 가능한데 Flask에서는 딕셔너리 형식으로 전달하는 것이 가능했습니다. 따라서 각각의 DTO에는 toDict()라는 함수를 구현하여 자기 자신의 정보를 딕셔너리 형태로 나타낼 수 있도록 하였습니다.

  3. Flask에서는 모든 요청을 받는 프론트 컨트롤러와 같은 녀석이 있습니다. 여기서는 main.py입니다. 프론트 컨트롤러에서 요청을 전부 받은 뒤, 억지로 컨트롤러 클래스를 만들어서 경우에 따라 특정 컨트롤러를 호출하도록 할 수도 있습니다. 이렇게 하지 않은 이유는 프론트 컨트롤러의 코드 길이가 너무 길어지기 때문입니다. 따라서 저는 Flask의 기능을 활용해 라우팅을 각각의 모듈 단위로 관리할 수 있도록 하였습니다. 이렇게 하면 프론트 컨트롤러에는 이 라우터모듈들을 등록하는 코드들만 들어가고 실제로 각 서비스별 요청을 실제 서비스 컨트롤러 모듈에서 관리할 수 있습니다.

순서도 그리기

객체 식별이 완료되었기 때문에 저희는 특정 기능에 대한 흐름도를 작성할 수 있습니다. 이것은 실제 흐름도라기 보다는 구현을 위해 직전에 만드는 설계도라고 할 수 있습니다. 여기에는 객체들간에 상호작용이 나타나있으며, 어떤 순서로 진행되는지를 알 수 있습니다.
저는 로그인 관련 흐름도만 첨부하도록 하겠습니다. 나머지 각 기능들에 대해서 다음과 같이 나타내고 구현을 한다면 빠지는 부분 없이 코드로 개발하는 것이 가능할 것입니다.

여기서 세션에 정보를 담는 이유는 로그인 여부를 계속 유지해야하기 때문입니다. 저희는 실제 웹 사이트를 사용할 때 페이지를 이동할 때마다 로그인을 하지 않습니다. 왜냐하면 로그인을 한번 한 순간부터 계속 로그인 상태가 유지되기 때문입니다. 이것을 구현하기 위해 로그인이 성공하면 세션에 사용자 정보를 담고, 페이지가 이동할 때마다 이 세션에 사용자 정보가 담겼는지를 확인하여 로그인이 된 상태인지 아닌지를 판단할 수 있습니다.

코드 보러 가기

https://github.com/1876070677/FlaskWebapp

데이터베이스에 접근을 어떻게 해요?

  • ~DAO 클래스를 참고하세요

세션에 정보를 어떻게 담나요?

  • ~Controller 클래스의 코드를 참고하세요

Demo

https://shop.shbox.kr/

profile
최악의 환경에서 최선을 다하기

0개의 댓글