🌆
Sunset Archive
GitHubLinkedInBlog
  • litsynp
  • Archives
    • Projects
      • Let's Parking!
      • 맛집몬스터 (JMT Monster)
      • spring-x-demo Projects
    • Articles
      • My Thoughts on GitBook
      • Wake-on-LAN & RDP Setup
    • Learning
      • Languages
        • Rust
          • Useful Links
          • Syntax
          • Pointers
          • Dependencies
          • Logging
          • Phantom Types
          • Iterable
            • Optional Skip
        • Go
          • Useful Links
          • Structures
          • Zero Values
          • Error Handling
          • Dependency Injection
          • Project Layout
        • JavaScript/TypeScript
          • Basics
            • Types
              • [JS] Falsy Values
              • [TS] Types - unknown, any, never
            • Rest Parameters (...)
            • Spread Syntax (...)
            • Destructuing Assignment
            • CJS, AMD, UMD, ESM
          • Advanced
            • Conditional Destructuring Assignment
            • Type Guards
          • Miscellaneous
            • Dependency Injection in JS?
            • ESLint, Prettier, TypeScript
          • Node
            • Useful Links
            • General
              • V8 Engine
              • Version Management: NVM
              • Environment Variables
            • Database
              • Knex
        • C
          • Dynamic Multi-dimensional Arrays
        • Spring
          • General
            • @Import v.s. @ContextConfiguration
            • MessageSource
          • Kotlin+Spring
            • Kotlin Annotations (Use-Site Targets)
            • Handling Null in Request DTO
            • Handling Null in URL
          • Reactive Stack
            • Reactive API with Spring WebFlux
          • Spring Security
            • Google OAuth Setup
          • Spring Batch
            • Bulk Insert
        • Kotlin
          • val/var in Constructor
          • Initializer Blocks
          • Inheritance Modifiers (final, open, abstract)
          • Delegate Pattern
        • Java
          • Serialization
          • Random Number Generation
            • (1) Math.random() v.s. Random
            • (2) Random v.s. ThreadLocalRandom
        • Python
          • Version Management
        • Ruby
          • Installation
          • Getters & Setters
        • Elixir
        • Erlang
        • Flutter
        • AWS
          • AWS CLI
        • Terraform
          • Installation
          • Basics
      • Code
        • OOP
          • The 4 Basic Concepts of OOP
          • The SOLID Principles
          • GRASP
          • Spring POJO
          • Others
        • Functional Programming
          • Currying
          • Higher-Order Function
          • Closure
          • Monad
        • 공변성, 반공변성, 무공변성
        • Others
          • UUID
          • GraphQL
          • Multimedia
            • Streaming
          • Geography
            • 위도 (Latitude), 경도 (Longitude)
      • Tools
        • Nix
        • Mermaid
          • Flowchart
          • Sequence Diagram
          • Class Diagram
          • Entity Relationship Diagrams
        • VSCode
          • VSCode CLI
          • VSCode Extensions
        • JetBrains
          • IntelliJ - Open Projects in Tabs
          • Delete Leftover IDE Directories
        • vim
          • Commands
      • Books
        • 다재다능 코틀린 프로그래밍 (Programming Kotlin)
          • Pt 01. 코틀린으로 스크립팅 하기
            • Ch 01. 코틀린 시작하기
            • Ch 02. Java 개발자를 위한 코틀린 필수 사항
            • Ch 03. 함수를 사용하자
            • Ch 05. 콜렉션 사용하기
        • 오브젝트 (Object)
          • Ch.0 들어가며 - 프로그래밍 패러다임
          • Ch.1 객체, 설계
          • Ch.2 객체지향 프로그래밍
          • Ch.3 역할, 책임, 협력
          • Ch.4 설계 품질과 트레이드오프
          • Ch.5 책임 할당하기
          • Ch.6 메시지와 인터페이스
          • Ch.7 유연한 설계
          • Ch.8 의존성 관리하기
          • Ch.9 유연한 설계
          • Ch.10 상속과 코드 재사용
          • Ch.11 합성과 유연한 설계
          • Ch.12 다형성
          • Ch.13 서브클래싱과 서브타이핑
          • Ch.14 일관성 있는 협력
          • Ch.15 디자인 패턴과 프레임워크
          • End. 마치며 - 나아가기
          • 후기
        • 헤드 퍼스트 디자인 패턴 (Head First Design Patterns)
          • Ch.1 디자인 패턴 소개와 전략 패턴
          • Ch.2 옵저버 패턴
          • Ch.3 데코레이터 패턴
          • Ch.4 팩토리 패턴
          • Ch.5 싱글턴 패턴
          • Ch.6 커맨드 패턴
          • Ch.7 어댑터 패턴과 퍼사드 패턴
          • Ch.8 템플릿 메소드 패턴
          • Ch.9 반복자 패턴과 컴포지트 패턴
          • Ch.10 상태 패턴
          • Ch.11 프록시 패턴
          • Ch.12 복합 패턴
        • 이펙티브 타입스크립트 (Effective TypeScript)
          • Ch.1 타입스크립트 알아보기
            • Item 1 타입스크립트와 자바스크립트의 관계 이해하기
            • Item 2 타입스크립트 설정 이해하기
            • Item 3 코드 생성과 타입이 관계없음을 이해하기
            • Item 4 구조적 타이핑에 익숙해지기
            • Item 5 any 타입 지양하기
          • Ch.2 타입스크립트의 타입 시스템
            • Item 6 편집기를 사용하여 타입 시스템 탐색하기
            • Item 7 타입이 값들의 집합이라고 생각하기
            • Item 1-7 Study Summary
            • Item 8 타입 공간과 값 공간의 심벌 구분하기
            • Item 9 타입 단언보다는 타입 선언을 사용하기
            • Item 10 객체 래퍼 타입 피하기
            • Item 11 잉여 속성 체크의 한계 인지하기
            • Item 12 함수 표현식에 타입 적용하기
            • Item 13 타입과 인터페이스의 차이점 알기
            • Item 14 타입 연산과 제너릭 사용으로 반복 줄이기
            • Item 15 동적 데이터에 인덱스 시그니처 사용하기
            • Item 16 number 인덱스 시그니처보다는 Array, 튜플, ArrayLike를 사용하기
            • Item 17 변경 관련된 오류 방지를 위해 readonly 사용하기
            • Item 18 매핑된 타입을 사용하여 값을 동기화하기
          • Ch.3 타입 추론
            • Item 19 추론 가능한 타입을 사용해 장황한 코드 방지하기
            • Item 20 다른 타입에는 다른 변수 사용하기
            • Item 21 타입 넓히기
            • Item 22 타입 좁히기
            • Item 23 한꺼번에 객체 생성하기
            • Item 24 일관성 있는 별칭 사용하기
            • Item 25 비동기 코드에는 콜백 대신 async 함수 사용하기
            • Item 26 타입 추론에 문맥이 어떻게 사용되는지 이해하기
            • Item 27 함수형 기법과 라이브러리로 타입 흐름 유지하기
          • Ch.4 타입 설계
            • Item 28 유효한 상태만 표현하는 타입을 지향하기
            • Item 29 사용할 때는 너그럽게, 생성할 때는 엄격하게
            • Item 30 문서에 타입 정보를 쓰지 않기
            • Item 31 타입 주변에 null 값 배치하기
            • Item 32 유니온의 인터페이스보다는 인터페이스의 유니온을 사용하기
            • Item 33 string 타입보다 더 구체적인 타입 사용하기
            • Item 34 부정확한 타입보다는 미완성 타입을 사용하기
            • Item 35 데이터가 아닌, API와 명세를 보고 타입 만들기
            • Item 36 해당 분야의 용어로 타입 이름 짓기
            • Item 37 공식 명칭에는 상표를 붙이기
          • Ch.5 any 다루기
            • Item 38 any 타입은 가능한 한 좁은 범위에서만 사용하기
            • Item 39 any를 구체적으로 변형해서 사용하기
            • Item 40 함수 안으로 타입 단언문 감추기
            • Item 41 any의 진화를 이해하기
            • Item 42 모르는 타입의 값에는 any 대신 unknown을 사용하기
            • Item 43 몽키 패치보다는 안전한 타입을 사용하기
            • Item 44 타입 커버리지를 추적하여 타입 안전성 유지하기
          • Ch.6 타입 선언과 @types
            • Item 45 devDependencies에 typescript와 @types 추가하기
            • Item 46 타입 선언과 관련된 세 가지 버전 이해하기
            • Item 47 공개 API에 등장하는 모든 타입을 익스포트하기
            • Item 48 API 주석에 TSDoc 사용하기
            • Item 49 콜백에서 this에 대한 타입 제공하기
            • Item 50 오버로딩 타입보다는 조건부 타입을 사용하기
            • Item 51 의존성 분리를 위해 미러 타입 사용하기
            • Item 52 테스팅 타입의 함정에 주의하기
          • Ch.7 코드를 작성하고 실행하기
            • Item 53 타입스크립트 기능보다는 ECMAScript 기능을 사용하기
            • Item 54 객체를 순회하는 노하우
            • Item 55 DOM 계층 구조 이해하기
            • Item 56 정보를 감추는 목적으로 private 사용하지 않기
            • Item 57 소스맵을 사용하여 타입스크립트 디버깅하기
          • Ch.8 타입스크립트로 마이그레이션하기
            • Item 58 모던 자바스크립트로 작성하기
            • Item 59 타입스크립트 도입 전에 @ts-check와 JSDoc으로 시험해 보기
            • Item 60 allowJS로 타입스크립트와 자바스크립트 같이 사용하기
            • Item 61 의존성 관계에 따라 모듈 단위로 전환하기
            • Item 62 마이그레이션의 완성을 위해 noImplicitAny 설정하기
        • Dive Into Design Patterns
          • 디자인 패턴 소개
          • 소프트웨어 디자인 원칙들
          • 디자인 패턴 목록
          • 유용한 링크
        • 가상 면접 사례로 배우는 대규모 시스템 설계 기초 (System Design Interview)
          • Key Points
          • Real Life Systems
          • Engineering Blogs
        • Node.js 디자인 패턴 바이블 (Node.js Design Patterns 3rd Edition)
        • 리팩터링 2판 (Refactoring: 2nd Ed.)
          • 1장 리팩터링: 첫 번째 예시
          • 2장 리팩터링 원칙
          • 3장 코드에서 나는 악취
          • 4장 테스트 구축하기
Powered by GitBook
On this page
  • About
  • Splitting Up Tasks
  • Project Architecture
  • Sequence Diagram
  • OAuth
  • Email Domain Filtering
  • Collaboration
  • Final Product
  • But there's still a room for an improvement...
  • My Thoughts
  • REF
  • Teammates

Was this helpful?

Edit on GitHub
  1. Archives
  2. Projects

Let's Parking!

(Dec 2022) Let's Parking!

PreviousProjectsNext맛집몬스터 (JMT Monster)

Last updated 9 months ago

Was this helpful?

About

최근 테커(Techeer)라는 개발자 그룹에 속한 친구 의빈, 동현과 함께 렛츠파킹 (Let's Parking!)이라는 주차 예약 프로젝트를 진행하게 되었습니다.

회사마다 주차 예약을 하는 시스템이 다르겠지만 이 프로젝트의 경우 Google Form을 이용해 주차 신청을 넣어야 하는 것이 주요 구현 포인트였습니다.

주차할 때마다 Google Form에 들어가는 내용은 매번 같으니 이 부분은 사용자를 식별하고 사용자마다 양식에 넣을 데이터를 저장해뒀다가 날짜마다 신청을 누를 때마다 주차 예약을 할 수 있도록 하였습니다.

이 과정에서 Google Form 입력을 자동화할 수 있도록 Selenium을 이용하도록 하고, 이 작업을 주기적으로 돌리기 위해 Spring Batch를 활용하기로 했습니다.

프로젝트 진행 기간은 2022-12-16 ~ 2022-12-26으로, 약 열 흘 가량입니다.

Splitting Up Tasks

같은 부분의 코드를 동시에 개발하고 변경하게 되면 아무래도 버전 관리 측면에서 매끄럽지 않게 진행될 거라 판단하여 팀원과 역할 분담을 하는 것도 중요했는데요. 사실 규모가 많이 큰(?) 프로젝트는 아니라서 3명이서 역할을 나누기엔 적합했다고 생각합니다.

각각 맡은 파트는 다음과 같습니다.

  • 김의빈: Back End, Infrastructure

  • 장동현: Front End

  • 이승준(나): Back End

이 중에 저는 OAuth 구글 로그인 기능과 API 개발을 담당했습니다.

Project Architecture

상단의 다이어그램은 프로젝트 아키텍처입니다. (의빈이가 수고해주었어요.)

백엔드로 Spring MVC와 ORM인 Spring Data JPA를 사용했으며, 인증에는 Spring Security를, 주차 예약 및 배치 태스크 스케줄링에는 Spring Batch, Quartz와 Selenium을 이용했습니다.

Sequence Diagram

Sequence diagram을 통해 전반적인 앱의 흐름을 구조화해보도록 했습니다. (마찬가지로 의빈이가 수고해주었어요.)

로그인 후 주차 양식을 만들고, 만든 주차 양식을 이용해 주차 신청할 날짜를 고르면 배치 스케줄링이 되어 주차 예약이 되는 시스템입니다.

OAuth

Kakao, Naver 등 다른 소셜 로그인은 괜찮지만 무엇보다 Google 로그인을 지원해야 해서 Spring Security를 이용해 Google 로그인을 지원하기로 했습니다.

이전에도 프로젝트를 몇 번 진행하면서 Spring Security를 이용한 OAuth 인증을 구현하곤 했지만 구현할 때마다 항상 어떻게 했는지 까먹게 되곤 했습니다. 로그인/인증이 아무래도 한 번 구현해두면 그 뒤로는 다른 기능보다 많이 건드리지는 않게 되어서 그런 듯 합니다.

매번 구글링하면서 같은 내용을 찾을 바에는 차라리 여기에 문서를 남겨서 다음에 구현할 때도 참고하기 위해 Google OAuth Setup 페이지를 따로 분리하여 정리하였습니다.

Email Domain Filtering

또한, 사내에서만 사용하는 프로젝트이다보니 특정 이메일 도메인을 제외하고는 가입/인증을 금지해야 했습니다.

개발 단계에서 초안으로 넣은 부분이기도 하고 이해를 위해 코드를 바꿔서 지금과는 코드가 상이합니다. 코드의 질이 높지 않더라도 양해 바랍니다. 😅

public abstract class AuthorizedEmailDomains {

    abstract List<String> getAuthorizedDomains();

    public boolean isAuthorizedEmail(String email) {
        String domain = email.substring(email.indexOf("@") + 1);
        for (String authorizedDomain : getAuthorizedDomains()) {
            if (authorizedDomain.contains(domain)) {
                return true;
            }
        }
        return false;
    }
}
@Component
public class AuthorizedLitsynpEmailDomains extends AuthorizedEmailDomains {

    private final List<String> authorizedDomains = List.of(
            "litsynp.com"
    );

    @Override
    List<String> getAuthorizedDomains() {
        return authorizedDomains;
    }
}

AuthorizedEmailDomains 이라는 이메일로부터 도메인을 추출해 필터링할 수 있는 인터페이스를 만들고, AuthorizedLitsynpEmailDomains (예시)와 같은 컴포넌트를 구현하였습니다. 이제 이 구현체를 인증이 필요한 곳에서 DI를 통해 주입하여 이메일의 도메인이 @litsynp.com 일 때만 인증에 성공하도록 만들었습니다.

좀 더 확장성을 높이자면 STRATEGY PATTERN 등의 디자인패턴을 활용해 strict한 domain matching 방식이 아닌 다른 인증 알고리즘을 사용할 수 있도록 할 수도 있겠네요.

물론 DB나 OAuth 앱 쪽에서 관리하는 방법도 있겠지만 일단 가장 빠르게 구현할 수 있는 방법으로 소스 코드 쪽에서 막는 방식을 택했습니다.

Collaboration

프로젝트는 항상 처음에 구상 단계에서 떠올렸던 크기보다 항상 커지더라구요. 렛츠파킹도 마찬가지로 생각보다 볼륨이 커지게 되었습니다. 실 개발은 사실 일주일 남짓인데 PR도 32개가 머지가 되었네요.

Final Product

아직 1차 배포이긴 하지만 결과물은 다음과 같습니다. 예쁘게 프론트를 디자인해준 동현이에게 박수를... 👏

But there's still a room for an improvement...

위에서 언급했던 부분 외에도 조금 더 개선할 부분이 있곤 합니다. 아무래도 빠르게 MVP를 만드는 것이 목적이었기 때문에 리팩토링이나 API 에러핸들링에서 미흡한 부분이 있습니다.

이 부분은 실 사용자분들의 QA 진행 후 진행하는 게 좋을 것 같다고 생각합니다. 👍

My Thoughts

제 인생의 멘토이신 Palo Alto Networks의 Andrew 멘토님께서 말씀하시길, 인간 관계에서 'fit'이라는 것이 굉장히 중요하고, 사람마다 'fit'이 맞는 사람들이 모두 다르다고 합니다.

'fit'이 완벽히 맞는 사람을 만나는 것이 쉬운 세상은 아니라고 생각했습니다. 마음이 맞더라도 프로젝트 진행이 잘 되는 건 별개의 일이 되기도 하구요.

그런데 운좋게 이번에 마음도 잘 맞고 실력도 좋은 친구들과 함께 프로젝트 진행을 할 수 있어서 매우 즐거웠습니다.

다음에도 재밌는 프로젝트 많이 만들 수 있으면 좋겠어요!

REF

Teammates

litsynp - OverviewGitHub
My GitHub
의빈 (Joe's) GitHub
JoeCP17 - OverviewGitHub
Let's Parking 주차장 프로젝트 회고
Let's Parking! - Retrospectives by Ruben
ww8007 - OverviewGitHub
동현 (Ruben's) GitHub
Logo
Logo
Logo
프로젝트 회고 : Let's Parking!열정과다 개발자의 공부방
Let's Parking! - Retrospectives by Joe
Logo
Let's Parking! - Project Architecture - Made by Joe
Let's Parking! - Sequence Diagram - Made by Joe
Let's Parking! - GitHub Pull Requess
로그인 및 인증
주차 신청 에러 핸들링
주차 신청 (성공)
주차 신청 (실패)
Logo