기록

[ICT 인턴십] 회고록 5 - 세 번째 프로젝트

라임온조 2023. 2. 26. 16:15

세 번째 프로젝트이자 마지막 프로젝트는 스프링과 vue를 사용하는 내부 프로젝트였다. 

 

1. 프로젝트 시작하기 전 나의 마음가짐

스프링을 사용하는 프로젝트를 꼭 해보고 싶었는데 드디어 하게 되어서 기뻤다. 스프링을 어떻게 사용하는지 많이 배워야 겠다는 다짐을 가지고 프로젝트에 임했었다.

하지만, vue로 프론트엔드도 해야했기에 걱정이 되는 것도 있었다. 자바스크립트를 거의 써 보지 않았었고, 웹 프론트를 예전에 해봤지만 나와는 너무 안 맞는다는 생각을 가졌었기 때문...

 

2. 프로젝트를 진행하며 배운 지식적 내용

1) 테이블 설계

데이터베이스 과목을 막 듣고 있을 때는 테이블 설계가 엄청 어렵게 느껴졌다. 그냥 테이블 하나를 다루는 거는 괜찮았는데, 외래키를 가지고 막 연관을 지어야 하는 경우에는 머릿속에서 딱 설계되지 않고 시간도 많이 걸리고 종이에 써봐야 하는.. 

하지만 앞선 2개의 프로젝트와 이번 프로젝트를 통해 다양한 테이블 설계를 보고, 프로젝트를 진행하며 테이블 설계를 직접 하다보니 이런 기능이 필요하면 이런 테이블이 필요하고, 이렇게 테이블 설계를 하면 되겠다는 직관이 생기게 되었다. 엄청난 시간이 별로 필요하지 않고 딱딱 머릿속에서 테이블 설계를 생각할 수 있게 되었다고나 할까? 

예를 들어, 사용자가 본인이 가지고 있는 기술 스택 여러 개를 골랐을 때 고른 데이터를 테이블에 저장해야 된다고 할 때, 유저 테이블과 기술 스택 테이블을 따로 만들고, 기술 스택 테이블에는 유저아이디와 유저아이디가 고른 기술 스택을 담아 테이블을 설계하면 된다. 

2) 선택사항들을 담고 있는 테이블 설계

이 부분은 엄청 신선했던 부분이었다. 예전에 진행했던 프로젝트에서는 긴 목록 중에서 선택해야 되는 일이 없어서 이 부분을 생각하지 못했었다. 여기서 목록 중 선택해야 한다는 것은 예를 들어 사용자가 본인의 기술 스택을 골라야 할 경우, 기술 스택으로 자바, 파이썬, 스프링 등등 수백가지의 기술 스택이 목록 형식으로 화면에 떠야하는 상황을 의미한다.

만약 사용자가 긴 목록 중에서 어떤 항목을 선택하여야 할 때, 그 목록을 프론트엔드가 모두 가지고 있다면 여러모로 효율적이지 않다. 먼저, 그 많은 항목을 프론트엔드가 매번 본인의 데이터 코드에 삽입할 경우 쓸데없이 코드가 길어지게 된다. 또한, 다른 화면에서 또 그 목록을 사용해야 할 경우 쓸데없이 코드를 반복해야 한다. 그리고, 만약 기술 스택의 종류 변화가 발생할 경우 변화한 부분을 모두 찾아서 일일이 바꿔줘야 하는 상황이 발생한다.

따라서, 이러한 목록을 테이블로 보관하는 것이 효율적이다. 그러면 프론트엔드는 매번 목록을 작성하지 않고 api를 불러오는 형식으로 쉽고 간편하게 데이터 목록을 사용할 수 있기 때문이다.

 

이때, 목록을 테이블로 보관할 때는 컬럼으로 id, parent_id, name, value, ranking, status, created_date, last_modified_date를 생성하한다. 각 컬럼의 의미는 다음과 같다.

 

id: 해당 항목의 고유 id

parent_id: 해당 항목이 속하는 상위 카테고리의 id

name: 해당 항목이 겉으로 보일 때 사용될 이름

value: 해당 항목이 저장될 때 사용될 값

ranking: 해당 항목이 나열될 순서 값

status: 해당 항목의 상태(보여질 상태인지 안 보여질 상태인지 등)

id parent_id name value ranking status
013   최종학력     T
01301 013 고등학교 졸업   1 T
01302 013 대학(4년제)   2 T

그리고 프론트엔드가 값을 불러서 쓸 때는 해당 목록을 불러오는 api를 사용하여 parent_id와 sort 조건을 줘서 불러오면 된다.

3) 데이터 묶어서 프론트엔드에 넘겨주기

사용자가 본인의 기술 스택을 선택하고, 그 선택들을 테이블에 담았다고 하자. 그 사용자가 선택한 것들을 골라서 사용자 정보에 덧붙여서 프론트엔드에 보내줘야 할 일이 있을 수 있다. 이때는 다음과 같은 sql을 사용할 수 있다.

SELECT
     ps.person_id,
     GROUP_CONCAT(IFNULL(`ps`.`skill`, '\\N') ORDER BY `ps`.`person_id` SEPARATOR '#') AS `person_skill_group`,
FROM
     `tb_person_skill` `ps`
INNER JOIN 
      `tb_code` `skill`
ON 
       `ps`.`skill` = `skill`.`id`
GROUP BY
        `ps`.`person_id`

GROUP_CONCAT

특정 컬럼의 한 값이 가지고 있는 다른 컬럼의 모든 값을 묶어서 보여주는 것

위에서는 person_id별로 해당 person_id가 가지고 있는 skill의 모든 값을 묶어서 보여준다.

근데 이때 separator에 의해 해당 값들을 '#'으로 묶는다.

 

IFNULL

IFNULL(column명, "null일 경우 대체 값")

 

INNER JOIN

조인은 두 개의 테이블을 서로 묶어서 하나의 결과를 만들어 내는 것을 말한다.

INNER JOIN(내부 조인)은 두 테이블을 조인할 때, 두 테이블에 모두 지정한 열의 데이터가 있어야 한다.

 SELECT <열 목록>
 FROM <첫 번째 테이블>
          INNER JOIN <두 번째 테이블>
          ON <조인될 조건>
 [WHERE 검색 조건]

 * INNER JOIN을 JOIN이라고만 써도 INNER JOIN으로 인식한다

4) @Transient 어노테이션

jpa를 사용할 때 @Entity 어노테이션을 사용해서 엔티티라고 등록한 부분은 테이블과 연동되어 테이블에 있는 컬럼들만을 가지고 있는 것이 보통이다. 하지만, 개발을 하다 보면 테이블에는 필요 없는데 프론트엔드에게 특정 데이터들을 보내 줘야 할 때가 있다. 이때 @Transient를 사용하면 해당 필드는 영속화되지 않기 때문에 테이블 컬럼과 상관없이 객체로써 프론트엔드에게 보내 줄 수 있다.

5) 임시저장 로직

내가 가장 먼저 생각했던 방법은 원래 테이블과 임시저장 테이블을 따로 만드는 것이었다. 그래서, 임시저장 버튼을 누르면 임시저장 테이블의 내용이 영향을 받고, 저장 버튼을 누르면 원래 테이블의 내용이 영향을 받도록 했다.

이 방법의 장점은 원래 내용과 임시저장 내용을 따로 저장해서 직관적으로 데이터를 살펴볼 수 있다는 것. 하지만 단점은 테이블 개수가 늘어난다는 것. 특히, 임시저장 할 내용 외적으로 테이블이 존재한다면, 해당 테이블 역시 임시저장 테이블로 만들어 줘야 한다는 점이다. 예를 들어, 게시글을 저장한다고 할 때, 해당 게시글 테이블 뿐만 아니라 만약 게시글의 카테고리를 따로 담는 테이블이 있다면 그 테이블의 임시저장 테이블도 따로 만들어 줘야 한다는 것.

 

또 다른 방법은 본 테이블만 만들어 두고, 해당 테이블에 글의 상태를 담는 컬럼을 추가하는 것이다. 임시저장이면 T, 실제저장이면 S와 같은 상태로 저장을 하는 것. 이때, 임시저장 row와 진짜 저장 row가 각각 저장될 수도 있다.

이 방법의 장점은 테이블 개수가 늘어나지 않는다는 것이다. 하지만 단점은 임시저장과 실제 내용을 한 테이블에 담다 보니 명확한 구분이 되지 않는다는 것..

 

하나의 테이블만 임시저장하면 어렵지 않을 것 같은데 그 테이블과 연관된 다른 테이블도 임시저장 로직에 고려해야하다보니 복잡하게 느껴졌었다. 사실, 아직 어떤 것이 더 적합하고 좋은 방법인지 모르겠다. 구현하다가 계속 오류가 나기도 했고. 추후로 임시저장 로직에 관해 살펴봐야 할 것 같다.

 

3. 프로젝트를 하면서 배운 지식 외적 내용

1) 본인의 역할이 아닌 부분에 접근할 필요가 있을 때는 미리 소통하자

역할을 나눠서 진행하더라도 다른 사람이 개발하는 부분을 내가 개발할 필요가 있을 수 있다. 이럴 때는 미리 팀원에게 현재 어떤 상태인지와 내가 그 코드를 건드려도 되는지 등을 먼저 물어봐야 한다. 만약 내가 진행하려던 일을 다른 팀원이 미리 했다면 나는 그 일을 할 필요가 없는데 물어보지 않으면 불필요한 일을 반복하게 될 수 있다. 또한, 나 혼자 알아서 진행하다가 오류를 발생시킬 수도 있다. 이러면 나 때문에 팀원이 혼란스러움을 겪게 될 수도 있다...

2) 개발하는 서비스에 대한 이해

개발하는 서비스에 대한 전체적인 이해를 하고 개발을 해야 서비스의 색에 맞는 개발을 진행할 수 있고, 이상한 부분을 더 빠르게 캐치해서 기획자에게 알릴 수 있다.

4. 프로젝트를 마친 후 소감

백엔드를 맡아서 진행해 볼 수 있어서 좋았다. 특히, 추후에 활용할 수 있을 것 같은 다양한 백엔드 기술적 코드를 배울 수 있어서 보람찼다.

스프링 jpa를 제대로 사용하지 못한 점은 아쉬웠지만, 스프링을 계속 사용하다보니 스프링 전체적인 구조를 자연스럽게 이해할 수 있게 되었고, 기본적인 스프링 코드를 이해할 수 있게 되었다.

5. 인턴십을 마친 후 소감

생각하지 못했던 기술 스택을 접하면서 나의 능력적인 한계를 뛰어넘을 수 있었다. 못할 것 같다고 생각했던 부분이 있었는데, 열심히 공부하고, 열심히 알아보면서 프로젝트를 진행하다보니 어느새 가능하게 되어있었다.

배우고 싶었던 기술 스택을 접하면서 나의 진로를 명확히 할 수 있었다. 스프링을 접하고, 스프링으로 프로젝트를 진행하면서 나의 부족한 부분을 확인할 수 있었고, 이를 더 공부해야겠다는 다짐을 하게 되었다.

또한, 사람들과 함께 일하면서 회사에서 동료와 함께 일하는 방법을 배울 수 있었다. 먼저 다가가기도 하고, 다가오는 동료들을 밀어내지 않으며 어느 정도의 친목을 쌓아야 효율적이고 효과적으로 소통하며 일 할 수 있게 만든다는 것을 느낄 수 있었다.

특히, 백엔드 개발자의 경우 기획, 프론트엔드와 끊임없이 소통을 해야 함을 느낄 수 있었다. 위에서 형성한 친함을 바탕으로 서로를 배려하며 소통해야 효과적으로 소통이 이루어질 수 있고 이것이 효과적인 개발 과정으로 이어지게 되는 것 같다.