Post

토이프로젝트 회고

1
2
docker, WSL2, linux OS, Cloud Server(NCP), nginx, Spring boot, JPA,
Spring data JPA, QueryDSL, AWS S3

https://okky.kr 에 토이프로젝트 구인글을 올렸고, 뜻대로 프론트개발자 2명, 서버개발자 1명을 모집하여

총 구성인원은 프론트개발자 2명, 서버개발자 본인포함 2명, 웹 디자이너까지 5명이었다.

프로젝트 리딩이 이토록 조원 컨트롤이 안될줄은 몰랐다. 게다가 접점이 있는 사람들이 아니었다보니 더욱 힘들었던 것 같다.

기획단계

기획단계에선 조원들의 여러 의견과 아이디어를 조합하여 최종적으로 중고책거래 웹 어플리케이션이 뽑혔다. 요구사항 등을 적절히 분석하지 못했는지, 기획단계에선 부족한점이 많았다고 생각한다. 협업툴의 중요성을 실감하게 된 계기가 되지 않았나 싶다. 노션 무료버전은 너무나 스토리지가 작았다.

설계단계

프로젝트 기간이 충분하다고 생각하지 않았는데도 불구하고 많은 기능을 구현하려 했다. 돌이켜보면 기능을 줄이고, 기능을 구현하는데 집중했어야 했는데, 그렇지 못했다.

기술스택

FE 언어는 typescript를 적용해보고 싶다 하여 승인하였다. 처음 개발에 적용해봐서 그런지 프론트엔트 개발 속도가 나질 않았다. BE 언어는 java 11버전을 사용하였으며, 람다와 스트림을 사용해보려 노력해보았다.

자잘한 얘기

국비지원학원 프로젝트 이후 다시 한번 깨달은 점은, 토이프로젝트에서 책임감이 결여된 조원과의 커뮤니케이션은 상당히 어렵다는 것이었다. 그래서 나는 최대한 많이 조원들과 얘기 나누고, 시간을 같이 보내려 노력했었다. 클라우드 서버를 이용해서 배포를 처음 해보았는데, 배포하며 리눅스, 정적웹서버(프록시서버), ssl(https) 등을 적용하며 서버 관련하여 많이 깨달았다. docker로 centOS 이미지를 조원들에게 배포하였는데, 클라우드 서버 환경과 동일하게 구성하며 개발 환경을 조성하였다. 도커를 사용해보지 않았던 조원들에게 사용법을 공유하고 서버 환경등을 설명하느라 시간을 많이 잡아먹었다. 리눅스 CLI에 조금은 익숙해져 너무 좋았다.

무중단 배포, jenkins등을 공부해보고 싶은 계기가 되었다. 일일히 빌드된 파일을 서버에 전송하였는데, 상당히 번거로운 일이었다. 여기서 구글드라이브를 사용하였고, gdown이라는 라이브러리를 사용하였다.

처음 DB 설계 후 JPA 설계를 하였고, 연관관계 중 @ManyToOne 등의 default FetchTypeEager이었으므로, 원치않는 쿼리가 자꾸 나가 모든 전략을 LAZY로 설정하여 작업 하였다. 스스로 N + 1 쿼리를 짜지 않도록 유의하여 개발하였다. 알라딘 api를 적용하여 책 카테고리 등을 받아왔는데, 프록시서버 구성으로 cors 문제는 발생하지 않도록 설계하였다. 게시물 필터링 적용이 필요하여, jpql 로 개발하였는데, 개발하다 querydsl을 알게되어 querydsl 사용하여 동적쿼리를 구성하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
select(new QArticleDTO(
                    articleDAO.article_id,
                    articleDAO.countDAO,
                    articleDAO.title,
                    articleDAO.tprice,
                    articleDAO.progress,
                    articleDAO.category,
                    articleDAO.member.nickname,
                    articleDAO.write_date,
                    articleDAO.imageInfo.image1))
            .from(articleDAO)
            .join(articleDAO.member, memberDAO)
            .join(articleDAO.countDAO, countDAO)
            .join(articleDAO.category, book_CategoryDAO)
            .join(articleDAO.imageInfo, image_infoDAO)
            .where(
                    articleLatGoe(member),
                    articleLatLoe(member),
                    articleLngGoe(member),
                    articleLngLoe(member),
                    titleLike(articleSearchCondition.getTitle()),
                    articleIdLt(articleSearchCondition.getLastId()),
                    divisionEq(division),
                    articleDAO.market.isNull(),
                    articleDAO.category.cid.in(
                            JPAExpressions
                                    .select(book_CategoryDAO.cid)
                                    .from(book_CategoryDAO)
                                    .where(
                                            one_depthEq(categoryList[0]),
                                            two_depthEq(categoryList[1]),
                                            three_depthEq(categoryList[2]),
                                            four_depthEq(categoryList[3]),
                                            five_depthEq(categoryList[4]))),
                    articleDAO.progress.eq(Progress.POSTING).or(articleDAO.progress.eq(Progress.TRADING))
            )
            .limit(10)
            .orderBy(articleDAO.article_id.desc())
            .fetch(); 

=> 이 쿼리는 문제가 있는데, 페이징 처리시에 모든 데이터를 가져와서 메모리에 올리고, 그 후에 애플리케이션 레벨에서 페이징 처리를 하게 된다. 이는 성능에 좋지 않다. 해결하기 위해선, Join을 하지 않고, 가져오려는 데이터만 가져와서 페이징 처리를 애플리케이션 레벨에서 하지 않고 DBMS 레벨에서 처리하도록 하고, 필요한 데이터들의 ID를 이용해서 다시 한번 쿼리를 날려서 데이터를 가져오는 방법이 있다.

토이프로젝트가 끝난 후 결심

  • gradle build tool에 대해서도 공부할 예정이다.
  • 특히 기초가 부족하기 때문에 cs와 알고리즘, 자료구조 등을 지속적으로 공부할 예정이다.

여러모로 우리에게 벅찬 프로젝트

채팅까지 구현하고 싶었으나,(백엔드 개발은 거의 완료된 상태) 프로젝트 조원의 탈주로 인해 프로젝트를 연장은 하되, 일단락 짓기로 마음을 먹은 상태이다.

협업툴과 일정관리가 정말 중요하다는 생각이 들었고, 똑같은 실수를 반복하지 않을 것이라 굳게 다짐하였다.

This post is licensed under CC BY 4.0 by the author.