Final project 회고록

들어가며

2022-04-15 시작된 국비교육이 2022-11-22을 끝으로 모두 마무리되었다.

7개월이라는 시간 동안 정신없이 달려온 최종 종착지인 Final Project의 회고록을

작성하며 다음 목표로 나아가기 위해 지금까지 달려온 시간들을 정리해 보고자 한다.

 


 

1. 프로젝트의 시작 ( 2022 - 10 - 03 )

 

세 번의 작은 프로젝트 후 드디어 마지막 프로젝트가 10월 3일을 기점으로 시작되었다.

우리 팀은 5명의 팀원으로 구성되었으며, NBW(No Book Is Worthless)라는 프로젝트명으로 도서 이커머스 사이트를 주제로 개발을 진행하였다.

 

 

팀원 소개

 

주제 선정의 기준은 특별한 기획보다는 일상에서 쉽게 접할 수 있는 주제를 선정하여 최대한 실제 서비스되고 있는 부분들을 구현해 보는 것에 초점을 맞추자는 의견이 모여 교보문고의 기능 및 디자인을 모델로 삼아 개발을 시작하였다.

 

우리 팀은 모두 백엔드를 지망하는 팀원들만 있었기 때문에 각자 기능에 해당하는 ui는 개별로 개발하였고, 클라이언트 페이지와 관리자 페이지의 공통 컴포넌트는 몇몇 개씩 나누어 제작하였다.

 

전체 프로젝트의 템플릿은 나의 담당으로 미리 필요한 의존성을 pom파일에 추가하고 xml세팅을 한 후 깃을 만들어 콜라보를 걸어 프로젝트를 진행하였다.

 

 


2. 프로젝트 설계 및 관리

 

프로젝트는 Spring Legacy 기반으로 하고 빌드 툴은 Maven을 사용하여 진행하였다.

대부분의 시간은 DB 및 화면 설계, 기능 정의 등에 많은 시간을 투자하였다.

 

 

2-1. 프로젝트 관리 -  폭포수 방법론

 

 

폭포수 방법론

 

 

개발 방법론으로는 폭포수 방법론을 따르려고 노력했다.

전체적인 프로젝트의 개발 흐름은 그림과 같이 요구사항 분석 → 설계 → 구현 → 검증 → 유지보수 순으로  진행하였다.

폭포수 방법론은 완벽하게 요구사항이 반영되어 설계가 되었다는 가정하에 다음 단계로 넘어가는 것을 전제로 한다.

우리 입장에서는 완벽하게  설계를 했다고 생각을 했지만 구현을 하던 중 잦은 수정사항이 발생했기에 이 방법론을 100% 따랐다고 보기엔 힘들 것 같다.

그래도 전체적인 흐름상 실제 개발현장에서 가장 많이 따르는 개발 방법론을 경험해 볼 수 있는 좋은 기회였다.

 

 

2-2. ERD

 

DB는 오라클 11g를 사용하였고 테이블은 총 23개, 컬럼은 총 151개로 구성되어 있다.

ERD

 

테이블을 그리면서 까다로웠던 부분은 n:n의 관계를 풀어내는 것과 복합 키 사용의 여부였다.

이론적으로 이런 것들을 제대로 알고 있다고 생각했기에 때문에 테이블을 그리기 전까지는 별문제 없이 그릴 수 있을 거 같았지만 실제 세계를 반영하여 여러 가상의 시나리오들을 고려해 보니 여간 까다로운 일이 아니었다.

 

이러한 문제들은 구글링을 통해 개념을 확실시하고 팀원들과 관계도를 그려보며 의논을 통해 해결해 나갔다.

 

 

2-3. 폴더 구조 -  Domain Directory

 

프로젝트의 폴더 구조는 기존에 사용하던 계층형 방식이 아닌 도메인 디렉터리 기준으로 폴더를 구성하였다.

각 기능 별로 Controller - dao - domain(dto) - repository - service 폴더를 형성하였다.

 

폴더 구조

 

 

이렇게 코드를 관리하면서 느꼈던 장점은 기존 계층형 디렉터리는 하나의 Controller, Service 폴더에 너무 많은 클래스들이 응집해 있었지만 도메인 디렉터리에서는 각 기능 별로 폴더가 나눠져 있기 때문에 이러한 복잡도를 줄일 수 있었다.

추가로 각 기능 별로 팀원들과 역할을 분배하였기에 각자의 작업 영역이 확실히 나누어진다는 장점도 있었다.

 

하지만 단점은 프로젝트에 대한 이해도가 낮은 경우 전체적인 구조를 파악하기 어렵다는 측면이 존재했다.

또한, 디렉터리 안에 하나의 클래스만 있는데도 불구하고 각 디렉터리를 모두 구성하기 때문에 다른 시각으로 봤을 때 더 복잡해 보이거나 비효율적이다라는 부분도 존재했다.

 

 

2-4. 스케줄러 ( 매달 정기 쿠폰 지급 )

 

해당 프로젝트에서는 총 구매 가격을 기준으로 회원의 등급이 존재한다.

등급은 브론즈, 실버, 골드, VIP로 구성되어 매월 해당 등급에 맞는 정기 쿠폰을 금액에 차등을 두어 지급하자고 계획하였다.

오라클에서는 이러한 정기적으로 일어나야 하는 일을 프로시저를 생성하여 job으로 등록하고, 스케줄러 설정을 통해 쿼리 문의 실행 주기를 설정해 줄 수 있었다.

 

아래는  위의 내용에 해당하는 쿼리문이다.

 

------ 회원 정기쿠폰 프로시저--------
CREATE OR REPLACE PROCEDURE NBW.memCouponProc AS
BEGIN
        DELETE FROM tb_couponzip
            where cp_no IN (
            'aaa058c6-5743-48fd',
            'b530a22c-8ea4-47f5',
            'dd6dd214-24c6-42c2',
            '3dc784f9-e8f6-4090'
            );
       INSERT INTO tb_couponzip(cp_no, mem_id)
            SELECT 
            CASE WHEN g_grade = 'bronze' THEN 1
            WHEN g_grade = 'silver' THEN 2
            WHEN g_grade = 'gold' THEN 3
            WHEN g_grade = 'vip' Then 4 
            END AS cp_no
            ,mem_id
            FROM tb_member;
END;
/


// 쿠폰 스케줄러(매달 회원 정기쿠폰 발행하는 스케줄러)
DECLARE
  X NUMBER;
BEGIN
  SYS.DBMS_JOB.SUBMIT
    (
      job        => X
     ,what       => 'NBW.MEMCOUPONPROC;'
     ,next_date  => to_date('10-31-2022 16:06:57','mm/dd/yyyy hh24:mi:ss')
     ,interval   => 'TRUNC(SYSDATE+30)'
     ,no_parse   => FALSE
    );
commit;
END;
/

 


3. Git

 

형상관리 툴로는 GitHub를 사용하였다.

이전 세미프로젝트와 토이 프로젝트로 깃 사용은 어느 정도 익숙해져 있었지만 충돌을 해결하거나 merge 또한 Fast-Forward merge만 주로 사용하였기 때문에 다른 merge 방식은 미숙했다.

그래서 이번에는 다섯 명에서 효율적으로 깃을 사용하기 위해 3-way merge 방식을 익히고 주로 이 방법으로 merge를 진행하였다.

 

깃 사용 일부 이미지

 

 

다른 팀원들 몇몇은 제대로 깃을 사용해본 경험이 전무하다고 하여 코드 리뷰 및 request 수락은 내가 전담하여 merge를 진행하였다.

 

그리고 추가로 프로젝트 시작 전 커밋 메시지의 규칙을 정하였다.

커밋 메시지의 접두어로 Feat(새로운 기능 추가), Design(디자인 관련), Fix(수정 및 버그 해결), Test(테스트 코드) 등 작업 단위가 끝날 때마다 커밋 메시지 앞에 접두어를 달아 본인이 작업한 내용을 좀 더 명확하게 팀원들에게 보여줄 수 있도록 하였다.

 


4. JUNIT4를 활용한 TDD

 

JUNIT 4

 

 

테스트 코드는 JUNIT4를 활용하여 작성하였다.

개발 순서는 DB와 가까운 순인 Persistence Layer → Business Logic Layer → Control Layer 순으로 개발을 진행하였다.

 

우선 구현하려는 기능들의 Sql문을 미리 작성하여 mapper와 Dao를 작성 후 테스트 코드를 작성하여 테스트 진행 후 이상이 없을 경우 Service 단 코드를 작성하고 테스트하는 방식으로 진행하였다.

 

단순 CRUD만 테스트하는 것이 아닌 몇몇 가상의 시나리오를 세워 예외상황이 발생했을 때 rollback이 잘 일어나는지 확인하였다.

 

테스트 코드 일부

 

 


5.  프로젝트 발표( 2022 - 11 - 16 )

프로젝트 발표는 비대면 수업으로 인해 영상을 제작하여 제출하고 수업시간에 각 팀의 영상을 보는 방식으로 진행되었다.

근 한달이라는 시간 동안 팀원들과 고생하면서 만든 프로젝트를 보면서 뿌듯하면서도 아쉬움이 많이 남았다.

 

특히 발표 시간상 조금 더 세부적인 기능을 보여주지 못한 점과 트러블 슈팅에 대해서 말하지 못한 것이 아쉬웠다.

프로젝트가 끝나고 나면 홀가분할 줄 알았는데.. 뭔가 허전한 마음이 들었다.

7개월이라는 시간이 너무 순식간에 지나갔다.. 

 

그렇게 11월 16일 마지막 프로젝트 발표를 기점으로 7개월의 국비 생활의 종점을 찍으며 학원을 수료하게 되었다.

 


6.  프로젝트를 진행하며 잘되거나 배운 점

 

🟠 6-1. 주석의 생활화

 

처음 프로젝트를 시작할 때부터 팀원들과 가장 중요시 얘기했던 부분이다. 내가 작성한 코드도 주석이 없을 경우 시간이 지나면 한참을 들여다보아야 무슨 코드인지 알 수 있다.

 

그렇다면 남이 작성한 코드는??

 

아마 주석이 없다면 처다도 안 볼 것이다.

 

더욱이 리팩토링 하려고 할 때 이렇게 상세히 주석이 없다면...

코드를 열어보고 IDE창을 바로 닫아 버릴 수 도..

 

이전 프로젝트를 통해 이러한 주석의 중요성을 느꼈기 때문에 팀원들과 주석은 꼭 생활화하자고 하였다.

그렇기 때문에 주석은 그때그때 문서화했으며 나중에 코드를 열어봐도 알아보기 쉽도록 잘 작성한 것이 가장 잘한 부분인 것 같다.

 

 

🟠 6-2. 공통 코드 개발

 

각자 기능을 구현하는 데 있어 공통으로 사용되는 관심사는 따로 분리하여 공통 코드로 만들어 오류를 줄이고 유지보수에 용이하게 하고자 하였다.

 

그렇게 처음에 공통 관심사를 뽑은 부분은 메일 관련 클래스, 페이징 처리 클래스, 파일 업로드 및 다운로드 클래스 이렇게 얘기가 나왔다.

 

그렇게 서로 의논하고 공통 코드로 뽑아 놓으니 확실히 중복되는 코드도 없을 뿐 아니라 유지보수 측면에 큰 기여를 할 수 있었다.

 

이후 앞단에서는 메일 서버를 연결하거나 결제를 할 때 시간이 오래 걸리기 때문에 사용자가 그 시간 동안 다른 탭을 클릭하여 오류가 발생하지 않도록 하기 위해 로딩 창을 띄우는 것이 필요해졌고 로딩 함수를 공통으로 만들어 각자 필요한 곳에서 사용하였다.

 

추가로 등록 삭제 시 알림음과 메시지를 출력하는 함수 등 여러 방면에서 공통 코드로 만들어 개발을 진행하였다. 

 

🟠 6-3. 깃 활용

 

깃을 실무에서 다루는 것처럼 깊게 다룬 것은 아니지만 collabolation을 걸고 권한을 설정하고 pull-request를 보내어 merge 하는 방식으로 최대한 활용하고자 하였다.

 

위에서 본 바와 같이 3-way merge를 주로 하여 merge를 진행하였으며 충돌이 일어났을 때는 해결하기 위해 한 번씩 진땀을 빼기도 했지만 그러한 덕분에 더 많은 것을 배우고 이 merge방식이 얼마나 좋은지 알 수 있었다.

 

 

🟠 6-4. 코드 리뷰

 

우리 팀은 매주 금요일을 코드 리뷰하는 날로 정하여 프로젝트 시작일부터 테스트 기간 전까지 코드 리뷰를 진행하였다.

한주 동안 각자 구현한 기능에 대해서 발표하고 코드를 보며 개선 부분이 있는지 의논하였다.

팀원에게 본인의 코드를 설명하기 위해서는 주석 및 문서화가 잘 되어있어야 했기 때문에 일석이조였던 것 같다.

 

코드 리뷰 시간을 통해 얻을 수 있었던 장점 중 가장 큰 장점은 다각적인 시선으로 문제에 접근할 수 있다는 것이 가장 큰 장점이었다.

 

여러 사람의 접근법을 통해 '이런 방법으로도 구현할 수도 있구나'라는 생각을 많이 들었고, 여러 방법으로 접근하여 구현할 수 있다는 것이 정말 흥미로웠다.

 

 

🟠 6-5. 의사소통

 

 

노션 회의록 일부 발췌

 

 

주말 빼고는 거의 매일같이 만나서 회의를 진행하였고 비대면으로 회의를 진행할 경우는 디스코드 및 게더 타운을 주로 활용하여 회의를 진행하였다.

회의록은 노션을 활용하여 문서화해 두었다.

팀원 모두 수동적인 자세가 아닌 능동적인 자세로 본인의 의견을 활발히 얘기하면서 회의가 이루어졌다.

프로젝트를 진행하면서 항상 느끼지만 의사소통 시 말하는 방식과 상대방을 존중하고 경청하는 자세가 무엇보다 중요하다고 여겨졌다.

 

일을 굉장히 잘하더라도 남의 의견을 무시하거나 본인의 할 말만 한다면 누가 같이 일을 하고 싶겠는가?

 

내가 생각하는 실력 있는 개발자란 실력이 좋은 것은 물론이고 남의 말을 잘 경청하고 남들이 같이 일하고 싶다고 이구동성으로 말하는 개발자가 정말 실력 있는 개발자가 아닐까 라는 생각이 든다.

 

그런 측면에서 우리 팀은 자신의 의견을 활발히 말하면서도  서로의 의견을 존중하고 의견 조율을 통해 조금 더 나은 방향으로 나고자 한 부분이 정말 잘 이루어졌다고 생각하고 어떻게 팀원과 의사소통해야 하는지 많이 배울 수 있는 기회였다.

 

🟠 6-6. Ajax 활용

 

요즘은 보통 리액트를 많이 활용하여 싱글 페이지 애플리케이션을 많이 접하게 되는데, 우리 팀원 모두 백엔드를 지망하였기 때문에 jsp와 ui설루션은 부트스트랩을 채택하여 개발을 진행하였다.

 

그러므로 기본적인 렌더링 방식이 서버사이드 렌더링이므로 불필요하게 모든 페이지가 렌더링 되는 부분들은 비용적인 측면을 고려하여 Ajax로 처리를 해야 할 필요성을 느꼈다.

 

예를 들어 공지글에 댓글 및 답글을 달 때 현재 공지글은 렌더링 된 상태로 두고 새로 입력된 댓글 부분만 렌더링 한다거나 리뷰를 등록할 때 해당 새로운 리뷰 건에 대해서만 렌더링 한다거나 쿠폰을 다운로드할 때 다운로드한 쿠폰만 지급된 쿠폰으로 상태를 바꾸는 등 다양한 곳에 Ajax를 적용시켰다.

 

SPA(Single Page Application)처럼 완벽하게 상태 관리를 할 수는 없었지만  최대한 Ajax를 활용하여 UX 측면에서 편의성 및 사용감을 높이려 하였고 렌더링 비용도 줄이려고 노력하였다.

 

🟠 6-7. Spring의 양면성

 

파이널 프로젝트를 진행하기 전 나를 포함한 세 명의 인원에서 공부 차원으로 pojo방식의 쇼핑몰 프로젝트를 진행했었다.

DispatcherServlet 및 HandlerMapping, Model 객체를 직접 구현하고 HandlerMapping에서는 DispatcherServlet에서 전달받은 업무 내용에 맞게 Controller인터페이스의 구현체를 인스턴스화하여 분기하는 방식으로 최대한 스프링을 따라 해 보며 연습했었다.

pojo를 spring으로 이관하는 작업도 해보았지만 프로젝트의 규모가 작았기 때문에 스프링의 편리성을 그때는 크게 느끼지 못했었다.

 

하지만 이번 파이널 프로젝트를 통해 스프링이 개발 속도에 있어서 엄청 큰 기여를 했다는 것과 얼마나 편리한지 알 수 있었다. POJO방식에서는 파라미터로 전달된 값을 일일이 꺼내어 형변환 시켰어야 했고 혹여나 같은 name값으로 전달된 값을 배열로 변환하여 service 단으로 전달할 때는 정말 코드가 길어지고 여간 귀찮은 작업이 아니었다.

하지만 스프링을 사용하니 파라미터 값을 DTO로 받을 수 도 있고, 원하는 데이터 타입만 명시해 주면 자동으로 형변환까지 해주는 것이 정말 놀라울 정도로 편리했다.

막바지에 어느 정도 익숙해졌을 때는 개발을 하고 있는 게 맞는지 싶을 정도로 개발 속도가 빨라졌다.

 

하지만 나중에는 나 같은 초보자에게는 편한 것이 독이 될 수 있겠다는 것을 직감했다.

스프링의 기능을 사용한 것은 극히 일부지만 스프링 사용에 점점 익숙해지다 보니 고민하는 시간이 줄어들었다. 

POJO 방식으로 개발을 진행할 때는 손으로 코딩하는 시간보다 생각하는 시간이 압도적으로 많았다.

어떻게 값을 전달받을 것인지. 전달받은 값을 외부 클래스로 넘겨 처리 후 들고 와 코드의 가독성을 높일 것인지 등 정말 많은 고민을 했었지만 스프링을 사용하니 그러한 고민을 전혀 하지 않게 된 것이다.

개발을 한단 느낌보다는 정말 잘 만들어 놓은 기성 상품의 사용법을 익히고 사용하면서 "우와... 이 제품 너무 좋다" 하는 꼴이 아닌가 싶었다.

 

지금까지 들었던 프레임워크의 단점 즉 개발의 자유도가 떨어진다는 것이 확 와닿는 계기가 되었다.

물론 장점 측면도 정말 많고 앞으로도 스프링을 지속적으로 공부하면서 사용 실력을 늘려야겠지만  내가 바라는 실력 있는 개발자가 되기 위해서는 스프링을 사용하지 않고도 원하는 서비스를 개발할 수 있도록 프레임워크 없이 개발하는 훈련도 해야겠다고 다짐하는 계기가 되었다.

 

(Pojo 기반 토이 프로젝트 주소입니다)

https://github.com/odong2/Toy-Project_POJO/tree/main/toyprj/src/main/java/com/shopping/toyprj

 


7.  아쉬운 점

 

🟣 7-1. 못다 한 기능 구현

 

프로젝트 초반에  여러 기능을 구현하고자 하였다.

시간적인 문제로 구현하지 못한 기능은 챗봇, 커뮤니티, 채팅이 있다.

1차 프로젝트로 Java Socket을 활용하여 채팅 프로그램을 했던 터라 이번에는 Spring Web Socket을 활용하여

양방향 통신에 대해서 공부하고 개발해 보고 싶은 욕심이 있었다.

 

하지만 예상보다 설계에서 더 많은 시간을 투자하면서 토크온처럼 만드려고 했던 채팅 기능은 단시간에 할 수 없게다라는 판단이 서서 구현하지 않게 되었다.

 

이후 Spring Web Socket 및 Sockjs에 대해서 차근차근 공부해 보며 이 기능은 추가적으로 만들어 보고자 한다.

 

 

🟣 7-2.  TDD

 

테스트 코드를 본인이 맡은 기능인 공지글, 댓글 대댓글, 결제에 적용해 보긴 하였지만 모든 케이스에 대해서 작성하지 못한 부분이 아쉽게 다가왔다.

여러 가상의 시나리오를 작성하고 테스트를 더 많이 해봤어야 한다는 아쉬움이 있다.

 

프로젝트 시작 단계에서는 Persistence Layer부터 Business Logic Layer까지 코드를 완성하면 바로 테스트 코드를 작성하여 테스트를 진행하였는데 시간이 지남에 따라 이 과정이 생략되기 시작했다...

 

테스트 주도 개발이 추후 리팩토링과 유지보수에서 많은 이점을 가져온다는 것을 알기 때문에 진행하였지만 한정된 개발 시간 안에 테스트 코드를 작성하며 개발한다는 것은 시간적인 비용이 많이 든다는 점을 깨달았다.

 

이런 단점이 있음에도 불구하고 나는 TDD의 이점이 더 많다고 생각이 들기 때문에 다음 프로젝트에서는 mockito와 함께 좀 더 적극적으로 사용해보고자 한다.

 

 

🟣 7-3. DB의 잦은 수정사항

 

기능 구현을 할 때 생각보다 DB의 수정사항이 많았다.

중간중간 추가 기능으로 인해 수정사항이 생긴 부분도 있었지만 예기치 못하게 기존 기능에서 설계가 조금 잘 못된 부분들이 몇몇 있었다.

 

아래에 한 가지 예를 통해 확인해 보자.

 

비회원 결제 테이블(TB_UNMEMPAYMENT)에서는 비회원 주문 상세(TB_UNMEMPAYMENTDETAIL) 테이블에서 주문 번호(order_no)를 FK로 받아와 사용한다.

 

설계 단계에서 비회원 결제 테이블에 PK를 시퀀스로 생성한 이유는 오라클을 사용하였기 때문에 PK 생성 시 인덱스가 생성되고 옵티마이저가 인덱스를 활용하여 좀 더 빠른 실행계획을 세울 수 있다고 판단하여 생성했었다.

 

하지만 mybatis를 사용하여 INSERT ALL을 할 때 PK로 시퀀스를 지정한 컬럼은 nextval이 되지 않는다는 이슈가 존재했다.

 

비회원이 여러 상품을 주문할 때 비회원 결제 테이블에 여러 건의 데이터가 INSERT ALL이 되어야 했기 때문에 결국 PK값을 삭제하게 되었다.

 

다음 토이 프로젝트를 혼자 진행해 볼 때는 조금 더 DB 부분을 세밀하게 짜 볼 계획이며, SQL 튜닝에 대해서도 공부해 보고자 한다.

 

 


https://github.com/odong2/NBW  (Final Project GitHub)

https://www.youtube.com/watch?v=Z4p-AV51g2k (시연 영상)

 

 

마치며

 

7개월의 과정을 거치면서 나란 사람이 새로운 것을 배우는 데 거리낌이 없고

'문제를 고민하고 해결해 나가는 과정을 좋아하는 사람이구나'란

것을 알 수 있는 뜻깊은 시간이었다.

앞으로 개발자로 살아감에 있어 배우는 것을 게을리하지 않고

지금처럼 부단히 노력하고 비단 실력뿐 아니라 인성도 갖추어 

남들에게 인정받는 개발자가 되길 간절히 소망한다.

 

 

 

 

 

 

'회고록' 카테고리의 다른 글

퍼피캣 프로젝트 개선 사례 및 경험한 것 들  (0) 2024.03.24