1. 프로젝트 소개
1-1. Co-Labor : 외국인 근로자 서포트 플랫폼
- 외국인 근로자들이 한국에서 안정적으로 정착하고 적응할 수 있도록 돕는 플랫폼
- 일자리, 정보 부족, 법률 등 외국인 근로자들이 겪을 수 있는 다양한 문제 해결에 도움을 줌
- 프로젝트 인원 : 4명 ( 백엔드 3명, 프론트 1명)
- 개발기간: 2024.07.01 ~ 2024.07.22 / 2024.07.30 ~ 2024.08.02 / 2024.10.03 ~ 2024.10.18
이 프로젝트는 사회적 약자 지원에 대한 주제에서 외국인 근로자도 사회적 약자에 포함되지 않을까? 에서 시작된 프로젝트이다. 우리나라는 아시아 최초로 다민족 국가로 지정될 정도로 외국인이 많이 거주하고 있다. 사회는 점차 저출산을 향해가며, 이에 따라 일손은 부족해지고 점점 외국인 채용을 늘리는 추세로서 외국인 근로자가 점점 많아지는데 이에 대한 서비스는 부족하다는 점이 핵심적인 개발 동기이다.
Co-Labor프로젝트는 노동자(labor)와 함께(co)한다는 의미에서 지어졌다.
Co-Labor에는 여러 기능이 존재하는데, 첫 번째로 외국인 근로자를 위한 기업 정보와 채용공고를 볼 수 있다.
두번째로는 법률 챗봇이다. 한국에서 발생할 수 있는 취업 시장과 근무 중 발생할 수 있는 법적 문제들을 법률 챗봇을 통해 조언을 구할 수 있다.
마지막으로는 지원센터&병원 지도이다. 근무 중 발생할 수 있는 문제들을 해결할 때 도움이 될 수 있는 외국인 노동자 지원센터의 위치와 근처 가까운 병원의 위치를 확인할 수 있다.
1-2. Co-Labor 기능 소개 및 시연영상
1-3. 아키텍처와 기술스택
2. 프로젝트 진행 과정
2-1. 프로젝트 협업
같이 프로젝트를 진행한 팀원들은 충북대 Nestnet 동아리에 속해있는 동기들로 회의나 협업이 필요한 과정에서는 학교 동아리방에서 모여서 협업을 진행했다. 같은 학교 동기들이기 때문에 다른 프로젝트에 비해 소통에 있어서는 편했던 것 같다.
우리 팀의 이름이 펠리컨인 이유는 일단 시도해 보는 성격이 매우 잘 어울렸기에 선택했다.
무모한 것인지 어려운 것인지 힘든 것인지 시도를 해봐야 알 수 있고, 배울 수 있는 것이라 생각한 우리 팀에 찰떡같은 상징이다.
Co-labor프로젝트를 진행하면서 여러 공모전에 참가하면서 진행되었는데, 여러 개 공모전을 함께 관리하기 위해서 노션에서 각 프로젝트별 페이지를 따로 만들어 프로젝트 단위로 관리하고, 칸반보드를 통해 협업을 진행했다.
나뿐만 아니라 팀원들 모두 학교에서 진행하는 프로젝트는 여러 번 했었지만, 제대로 구실을 갖추고 팀컨벤션과 Git을 체계적으로 사용한 경험은 없었다.
그렇기에 이번 프로젝트에서는 "GitHub가 서툴더라도 최대한 팀컨벤션에 맞게 잘 사용해 보자"에 모두 동의하였다.
백엔드와 프론트엔드의 레포지를 분리하여 시작하다. 각 레포지에서는 Pr템플릿, 이슈템플릿, 커밋 컨벤션을 지켜서 작업을 하였다.
GitFlow방식을 채택하여 main과 develop에서만 작업하는 것이 아니라, 현재는 남아있지 않지만 각 이슈에 맞게 기능별로 브랜치를 만들어서 작업하고 develop으로 올리고, 이후 재 배포할 버전이 완료되면 main에 Pr하여 올리는 방식으로 수행하였다. 오류가 생기면 hotFix, fix 브랜치를 별도로 분리하여 변경이 있더라도 기능에 최대한 영향이 없도록 진행하였다.
아래는 백엔드와 프론트엔드에서 각 작업마다 이슈를 작성하여 작업한 내용이다.
2-2. 도전과제와 해결과정
- 도전과제
새싹 해커톤은 React를 배운 후 처음 도전한 공모전이었다. 프로젝트 자체가 나에게는 도전과제였고 Front-end 파트를 혼자 담당하다 보니 막히는 부분이 있어도 조언을 구할 곳이 없었다. 내가 가는 방향이 옳은지 확신이 없는 상태로 일단 달렸던 것 같다.
프로젝트를 진행할 때에는 거의 XP(Extreme programing) 방식으로 진행되었다.
사실 실질적인 해커톤 또는 공모전에 계획중심 개발방법을 도입하는 것은 매우 어렵고, 애자일 또는 XP방식으로 진행되는 것이 맞다고 생각한다. 하지만 이번 프로젝트에서는 나뿐만 아니라 팀원들이 경험이 많지 않은 상태로 부딪히게 되니 기획에 관하여 같이 회의를 진행할 때 디테일 하게 정하지 못했던 부분들이 있었다.
Co-Labor 프로젝트의 초기 기획은 "이런 기능이 있으면 좋겠다", "이런 참고 사이트의 이런 부분을 활용하면 좋겠다" 정도의 간단한 수준에 그쳤다. 이로 인해 인원 분배가 불명확했고 각 기능의 완료 시점을 픽스하는 데 어려움이 있었다. 또한 백엔드에 요청하여 받는 response도 백앤드 팀원마다 결과 코드와 key값의 이름이 달라 혼란스럽고 잦은 변동이 있었다.
프론트에서는 컴포넌트의 구조를 구상하지 않고 분리를 하다 보니 복잡해졌으며, 하나의 state를 여러 컴포넌트를 거쳐 사용하기에 props drilling 문제점이 존재하였다.
이러한 상황이 맞물려 백에서 전해주는 response에서 key값이 변동하게 되면, props drilling과 함께 변수 이름 수정지옥에 빠져버렸다.
또한 기본적인 FE레포지는 react가 vite환경에서 작동하고, 웹앱을 추가적으로 만들고 싶어 레포지를 따로 만들었다. 이 과정에서 기존에 웹앱을 시도하던 webpack환경을 그대로 가져오다 보니, vite환경과 webpack환경 레포지를 혼자서 왔다 갔다 하면서 작업하게 되는 것이다. 사실 환경이 그렇게 크게 중요하지 않지만, vite프로젝트 부분을 웹앱으로 webpack에 이식하는 과정에서 이미지 경로 이슈, env를 불러오는 방식 그리고 배포되었을 때 이미지를 불러오는 방식이 각 환경마다 다른 것이 혼란스러워 골머리를 앓았다.
그뿐만 아니라 가장 큰 문제점은 관리되지 않는 CSS와 설계되지 않는 React 프로젝트 구조였다.
아래는 React 폴더 구조와 CSS파일 상황이다.
PS C:\Users\@@@> tree /f Co-Labor-FE/src
Folder PATH listing
Volume serial number is EE2D-C31D
C:\USERS\@@@\CO-LABOR-FE\SRC
│ App.css
│ App.jsx
│ index.css
│ main.jsx
│
├───assets
│ Ai_Icon.png
│ banner.jpg
│ Co-labor.png
│ cross_icon.png
│ current_location_icon.png
│ icon8.png
│ legalAdvice_ex.png
│ search_icon.png
│ supportCenter.jpg
│ supportCenterIcon.png
│ web-Title.svg
│
├───components
│ │ BarGraph.jsx
│ │ CompanyDetailsCenter.jsx
│ │ CompanyItem.jsx
│ │ CompanyList.jsx
│ │ EnterpriseApplyCenter.jsx
│ │ FilterBox.jsx
│ │ FilterOption.jsx
│ │ Footer.jsx
│ │ Header.jsx
│ │ IegalAdviceCenter.jsx
│ │ JobNoticeApplyCenter.jsx
│ │ JobNoticeDetailsCenter.jsx
│ │ JobNoticeList.jsx
│ │ JobNotieItem.jsx
│ │ QuickMenu.jsx
│ │ RadarChart.jsx
│ │ RecentReviewItem.jsx
│ │ RecentReviewList.jsx
│ │ SearchOutput.jsx
│ │ SingInCenter.jsx
│ │ StarRate.jsx
│ │ SupportCenterItem.jsx
│ │ SupportCenterMap.jsx
│ │
│ └───css
│ common.css
│ CompanyDetailsCenter.css
│ CompanyItem.css
│ CompanyList.css
│ EnterpriseApplyCenter.css
│ FilterBox.css
│ Footer.css
│ Header.css
│ IegalAdviceCenter.css
│ JobNoticeApplyCenter.css
│ JobNoticeDetailsCenter.css
│ JobNoticeItem.css
│ JobNoticeList.css
│ QuickMenu.css
│ RecentReviewItem.css
│ RecentReviewList.css
│ SearchOutput.css
│ SingInCenter.css
│ SupportCenterItem.css
│ SupportCenterMap.css
│
├───hooks
│ fade_in.jsx
│ useBarGraph.jsx
│ useEmpty.jsx
│ useStarRate.jsx
│
└───pages
CompanyDetails.jsx
CompanyInfo.jsx
EnterpriseApply.jsx
Home.jsx
IegalAdvice.jsx
JobNotice.jsx
JobNoticeApply.jsx
JobNoticeDetails.jsx
Notfound.jsx
Search.jsx
SingIn.jsx
Support.jsx
수많은 CSS파일이 도배되어 있고, 심지어 vite환경에서의 css를 사용하다 보면 css파일이 공유되는 경우도 있다. 예를 들어 SingINCenter.css를 import 하여 사용하게 되면, SearchOutput.css파일에 있는 css까지 적용이 된다.
.CompanyDetailsCenterCompanyBasicInfo {
display: flex;
align-items: center;
margin-top: 20px;
margin: 0 auto;
justify-content: center;
}
.CompanyDetailsCenterCompanyImg {
width: 150px;
height: 150px;
}
CSS가 공유되면서 원하는 클래스에 스타일을 적용하기 위해 구분하다 보니, 위와 같이 복잡하고 가독성이 떨어지는 클래스명이 만들어지게 된다.
지금 보니 매우 끔찍하다.🤦♂️
- 해결과정
1. styled-components
첫 프로젝트 이후 시간이 지남에 따라 CSS의 전역 범위(Global Scope) 이슈를 알게 되고, 해결방법인 SingINCenter.moudle.css와 같이 module을 사용하면 된다는 것을 알게 되었다.
하지만 module로 분리한다고 해서 위의 CSS지옥을 해결하기 어려울 것이라 판단하였다.
그렇기에 CSS관리 문제를 해결하기 위해 styled-components를 채택하였다.
styled-components의 장점인 "styled-components의 장점이 CSS관리를 잘할 수 있다~"를 처음 접하게 되었을 때와 다르게, 내가 직접 싼 똥들을 치울 때에 느껴지는 깨달음은 격이 다르다는 것을 느꼈다.
직접 부딪혔을 때에 느끼는 후회는 굉장히 큰 깨달음을 안겨주는 것 같다.
2. 프로젝트 구조 변경
├───assets
├───components
│ └───css
├───hooks
└───pages
이전의 src폴더 아래 구조는 위와 같다. pages안에는 페이지에 해당하는 jsx파일이 1개씩만 존재하고, components 안에 page에 들어가는 모든 컴포넌트와 이에 해당하는 CSS에 관한 모든 코드가 존재했다.
CSS관리를 위해 아래와 같이 src파일 구조로 변경하면서 1번에서 말했듯이 styled-components를 채용하여 한 파일 안에서 해당 CSS를 관리할 수 있게 되었다. 추가적으로 폴더 구조를 apis, assets, components, hook, page로 분리하고 page안에는 각 page에 해당하는 컴포넌트와 page내용을 따로 관리함으로써 어떤 파일이 무슨 역할을 하는지 이전보다 명료하게 알 수 있게 되었다.
추후에도 프로젝트 상황에 맞게 더 효율적인 프로젝트 구조가 있는지 고민하면서 프로젝트를 설계하려고 노력해보려 한다.
\\---src
| App.css
| App.jsx
| index.css
| main.jsx
|
+---apis
| apply.jsx
| Login.jsx
| Notice.jsx
| review.jsx
| search.jsx
|
+---assets
| | Building.jpg
| | jobInfo.gif
| | legalChat.gif
| | logo.jpg
| | mainBackground.jpg
| | suuportMap.gif
| |
| +---icon
| | arrow-down-grey-filter.svg
| | BuildingChoose.png
| | BuildingLocation.png
| | cross_icon.png
| | currentLocation.png
| | filter.svg
| | HospitalChoose.png
| | HospitalLocation.png
| | search_icon.png
| |
| \\---profile
| DoHyun.jpg
| HanUl.jpg
| JunHwa.jpg
| MoonKi.jpg
|
+---components
| BarGraph.jsx
| CommonStyled.jsx
| FadeIn.jsx
| FilterBar.jsx
| FilterOption.jsx
| Header.jsx
| MainTitle.jsx
| MainTitleFilter.jsx
| RadarChart.jsx
| StarRate.jsx
| TranslateCountry.jsx
| TranslateList.jsx
|
+---hooks
| fade_in.jsx
| useBarGraph.jsx
| useEmpty.jsx
| useStarRate.jsx
|
\\---pages
| Notfound.jsx
|
+---Apply
| EnterpriseApply.jsx
| NoticeApply.jsx
|
+---Enterprises
| | EnterpriseParticular.jsx
| | Enterprises.jsx
| |
| \\---components
| BasicInfo.jsx
| EnterprisesItem.jsx
| EnterprisesList.jsx
| JobPreview.jsx
| ReviewAddContainer.jsx
| ReviewAddStar.jsx
| ReviewAverage.jsx
| ReviewItem.jsx
| ReviewList.jsx
|
+---Home
| | Home.jsx
| |
| \\---components
| Arrow.jsx
| Contact.jsx
| GoToButton.jsx
| JobInfo.jsx
| LegalChatInfo.jsx
| MainIntroduce.jsx
| MainTitle.jsx
| MapInfo.jsx
|
+---Jobs
| | JobNotice.jsx
| | JobNoticeParticular.jsx
| |
| \\---components
| JobNoticeList.jsx
| JobNotieItem.jsx
|
+---LegalChat
| | LegalChat.jsx
| |
| \\---components
| InitalMessage.jsx
| Message.jsx
| MessageSend.jsx
|
+---Login
| | SingIn.jsx
| |
| \\---components
| SingInCenter.css
| SingInCenter.jsx
|
+---Map
| | Support.jsx
| | SupportCenterMap.jsx
| |
| \\---components
| ChooseMode.jsx
| SidePage.jsx
| SupportCenterItem.jsx
|
\\---Search
Search.jsx
SearchOutput.jsx
3. Context도입
props drilling를 막기 위해 Context를 도입하였다.
import { createContext, useContext } from 'react';
기업정보면 기업 정보 관련 컴포넌트들은 백에게 fetch 해서 받아온 기업 정보를 Context로 전달해 주고, 채용공고면 채용공고 데이터를 Context로 전달해 주었다.
추후에 다른 프로젝트에서는 Context Api에서 생기는 Context.Provider와 Context.Consumer과 같은 보일러 플레이트를 줄 일 수 있는 Zustand를 사용해서 상태관리를 해보려고 한다.
- 도착지
순서대로 첫 번째 Co-Labor 버전과 이전 문제들을 해결하고 전반적인 디자인들을 리팩토링 버전이다.
기존 프로젝트는 부차적인 기능들을 과감히 제거하고, 보다 효율적이고 체계적인 구조를 도입하였다. 파일 구조를 개선하고 styled-components를 활용하여 CSS 관리 문제를 해결했으며, Context API를 적극적으로 도입하여 props drilling 문제를 해결한 것을 확인할 수 있다.
프로젝트 소개에서 아키텍처를 보면 왼쪽과 같은 배포 구조를 확인할 수 있다.
기존 첫 Co-Labor버전에서는 S3만 사용하여 Ec2 백엔드와 연결만 되어있는 상태였는데, 공개 SW 개발자 대회 멘토링 과정에서 https 배포는 어떠겠냐는 의견을 듣고 SSL인증서를 통해 https배포를 마치게 되었다.
이 과정에서도 백엔드 팀원과 나 모두 배포에 아는 지식이 많지 않았기에, https 첫 연결에서 많은 어려움이 존재했다. 배포가 연결이 안 되는 상황에서 CloudFront가 문제 인지, Nginx가 문제인지 알 수 없었기 때문에 팀원과 거의 하루 종일 붙어서 문제를 해결했던 기억이 있다. 결론적으로는 Nginx의 CORS문제였지만, 덕분에 Nginx와 CloudFront가 어떻게 동작할 수 있는지 파악할 수 있게 되었다.
https배포를 완료했을 뿐만 아니라, 오픈소스로서도 가치 있는 결과물을 만들어 냈다.
프로젝트의 접근성을 높이기 위해 README를 한글과 영어 두 버전으로 제공하고, Docker를 활용한 Quickstart 환경까지 구축하여 누구나 쉽게 시작할 수 있도록 했습니다. 그리고 Apache License 2.0으로 오픈소스 등록까지 완료하여, React를 처음 배운 이후 프로젝트를 시작했을 때 상상도 못 했던 결과를 이뤄냈다는 점에서 많은 성취를 느낄 수 있었다.
3. 결과 및 성과
- 2024 새싹 해커톤 본선 진출
- AI메이커톤 경진대회 최우수상
- 2024 공개 SW 개발자대회 본선 진출 및 우수작 선정
- 2024년 스마트 & 디지털 페스티벌 VIP초청
4. 후기 및 배운 점
- 기획의 중요성
앞서 프로젝트 진행과정에서 말했듯이 초반 기획이 제대로 되어있지 않아 방황을 많이 했던 것 같다.
큰 틀에서의 필요한 기획들은 먼저 잡고 나갔으면 많은 시간을 절약할 수 있었을 텐데 라는 아쉬움이 남았던 프로젝트이기도 하다. 원래 기존의 학교에서 배우는 소프트웨어 설계나 문서에서는 별로 중요하다는 것을 느끼지 못했지만, 오히려 이 프로젝트를 통해 어느 부분까지 기획이 영향을 끼칠 수 있는지 느낄 수 있어서 좋은 경험이었던 것 같다.
개발에서 요구하는 협업은 사실 팀원들과의 원활한 소통뿐만 아니라, 기획과 같은 틀을 잡는 작업들도 포함되는 것이라고 느꼈다.
- 부딪히고 얻는 깨달음
부딪히고 얻는 깨달음과 그저 글로 배우는 지식은 큰 차이가 있다는 것을 느꼈다.
이번에 CSS 관리지옥에서 느낀 것은 styled-components와 Tailwind CSS가 왜 사용되는지는 확실하게 알 수 있었다. 글로벌 적으로 관리하는 것보다는 조금의 중복이 있더라도 해당 요소 근처에 css가 존재함으로 써 얻어가는 이점이 너무 크기 때문에, 앞으로도 styled-components와 Tailwind CSS 중 하나를 채택해서 사용할 것 같다.
기존에도 상태관리가 어떤 것인지 기본적인 개념은 알고 있었지만, "왜 써야 하는가?"에 대한 개념은 부족했던 것 같다.
internal state관련 느낀 점은 props drilling이 무엇인지 변수명 한번 바뀌면 30분 동안 붙잡고 변수명을 바꾸면서 몸소 체험하였다. 이후 Context를 통해 문제를 해결하였고, 상태관리 라이브러리를 왜 사용하는지를 깨닫고 이후에 Zustand를 사용하려 한다.
external state로 첫 Co-Labor버전에서는 fetch에서 사용하고 두 번째 Co-Labor버전에서는 fetch를 사용하여 데이터를 불러올 때 에러처리를 추가적으로 해줘야 한다는 불편함을 해결할 수 있는 axios를 사용하여 https요청을 했다.
하지만 Client state는 페이지가 새로 고침 되었을 때 새로 useEffect를 통해 불러와서 해결할 수 있었지만, Server state변경에 맞게 Client state의 낡은 데이터를 지속적으로 갱신할 수 없다는 문제점이 있다는 것을 파악하였다.
이러한 문제점을 경험한 이후에는 React qurry를 왜 사용하는지 비로소 이해할 수 있었다.
이러한 상태관리와 CSS관리뿐만 아니라 React의 프로젝트 구조 등을 이론적으로만 공부하는 것이 아닌, 직접 경험하면서 그 필요성을 깨달아 가는 과정이 뜻깊은 경험이었던 것 같다.
- 기록의 중요성
2024년도에서 학교생활을 제외하고는 대부분 Co-labor프로젝트와 새로운 지식을 배워나갔다.
1년의 과정을 지금 돌이켜 보면, "더 열심히 했어야 했나?", "아, 이렇게 하지 말걸.", "다른 것을 했어야 했나?"와 같은 아쉬움은 없지만, 단 하나 아쉬운 점이 있다면 프로젝트를 진행하거나 새로운 지식을 배워나갈 때의 기록 부족이다.
기존에 노션도 사용하고 옵시디언 앱을 사용한다. 하지만 프로젝트가 마감에 가까워지면 질수록 마무리에만 급급하여 주먹구구식 개발만 하게 되고 개발하는 과정을 기록으로 남겨두지 않았다.
프로젝트 진행 중에 나는 무수히 많은 어려움들을 겪었었지만, 지금 현재 회고를 작성하는데도 학기가 끝난 후 너무 오래된 나머지 기억이 조금 휘발되어 어려움들이 자세히 기억이 나지 않는 문제가 있다.
이전 프로젝트에서 어려움 또는 개발 과정을 기록을 해야 다음 프로젝트에서 같은 실수를 하지 않거나 더 발전 가능성이 있고 도움이 된다고 생각한다.
기록의 중요성을 깨달은 만큼 앞으로 기록하는 습관을 더욱 체계적으로 만들어가려 한다.
- 마무리
Co-Labor 프로젝트는 단순히 기능 개발에 그치지 않고, 실제 문제점을 인식하고 이를 해결해 나가는 과정에서 의미 있는 성과를 이룰 수 있었던 프로젝트였다.
특히 오픈소스 라이센스 등록과 HTTPS 배포 과정은 처음 경험해 보는 영역이라 많은 어려움이 있었다. 하지만 HTTPS 배포를 위한 SSL 인증서 적용, Cloud Front, Nginx 설정 문제를 해결하며 배포와 보안에 대한 이해도를 높일 수 있었다.
또한, styled-components 도입, Context API 활용, React 프로젝트 구조 개선 등 개발 중 발생한 문제들을 해결하는 과정에서 다양한 최신 기술들을 도입할 수 있었다. 이 과정에서 단순히 '신기술 도입'을 목표로 한 것이 아니라, 실제 문제 상황에서 느껴지는 불편함과 한계를 극복하기 위한 도구로 신기술을 활용했다는 점에서 의미가 컸다.
공모전과 해커톤 참가를 통해 프로젝트를 발표하고, 실질적인 성과를 거두면서 성취감을 느낄 수 있었다. 특히 '2024 새싹 해커톤 본선 진출', 'AI 메이커톤 경진대회 최우수상', '공개 SW 개발자대회 본선 진출 및 우수작 선정', '스마트 & 디지털 페스티벌 VIP 초청' 등 여러 대회에서의 성과는 팀원들의 노력과 프로젝트의 가치를 입증하고 뿌듯함을 느낄 수 있었다.
이번 프로젝트를 통해 기획의 중요성과 체계적인 협업의 필요성을 느낄 수 있었으며, 문제 해결 능력과 새로운 기술을 습득하는 과정을 경험할 수 있었다. 앞으로도 이러한 경험을 바탕으로 더 나은 프로젝트를 만들고, 기록과 회고를 통해 지속적으로 성장해 나가보려 한다.
5. 관련 포스팅
'Retrospect' 카테고리의 다른 글
[공모전 회고] 2024 공개SW 개발자대회 본선 진출 및 우수작 후기 (과학기술정보통신부x정보통신산업진흥원) (2) | 2025.01.03 |
---|---|
[공모전 회고] 2024 +AI메이커톤 경진대회 최우수상 후기(충북대학교 산업인공지능센터 주관) (0) | 2025.01.03 |
[공모전 회고] 2024 새싹 해커톤 본선진출 후기 (서울경제진흥원 x 스마트 CMS x 데이콘|동대문DDP) (1) | 2025.01.03 |