<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>develup.log</title>
        <link>https://velog.io/</link>
        <description>지속 가능한 개발과 꾸준한 성장을 목표로 하는 Web Developer 박성용입니다</description>
        <lastBuildDate>Sun, 06 Jul 2025 23:29:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>develup.log</title>
            <url>https://velog.velcdn.com/images/low_level_v99/profile/b0de5e35-a09f-47ba-8e7f-95c4c4350929/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. develup.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/low_level_v99" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[한화시스템 15기 24주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-15%EA%B8%B0-24%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-15%EA%B8%B0-24%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 06 Jul 2025 23:29:16 GMT</pubDate>
            <description><![CDATA[<h3 id="24주차에-대하여">24주차에 대하여</h3>
<p>이번 주는 파이널 프로젝트에만 몰입한 한 주였습니다. 코딩 테스트나 자기소개서를 준비할 시간은 사실상 없었고 이제는 현실적으로 그럴 여유조차 없다는 걸 인정하게 된 것 같습니다. </p>
<p>최근들어 자주 방황하고 있습니다. 몇 주 전부터 뭔가 ‘개발을 즐긴다’는 느낌보다는, 그냥 주어진 기능을 &#39;막 찍어내는 느낌&#39;을 강하게 느낍니다. 그냥 &quot;기능 구현하고 끝 그리고 다음&quot;의 반복 속에서 방향 없이 달리고 있다는 생각이 너무 많이 들고 내가 하고 싶었던 것은 과연 뭐였을까에 대한 반문을 계속들어 하게됩니다. </p>
<p>그런데 신기하게도 주말동안 약간의 휴식을 취했는데 아무런 생각과 스트레스에서 벗어나 휴식을 즐기는 것에 행복을 느꼈고 어느순간 &quot;나는 지금 잘 할 수 있고, 잘 하고 있으며 이 자체로 만족해&quot;라는 생각이 들면서 여유를 찾게 되었고 이로하여금 개발의 재미를 조금씩 되찾게 되었습니다. 그렇게 에너지를 찾고 기능 하나를 구현하더라도 ‘내가 생각하는 원칙’을 세우고 그것을 지켜가면서 개발하다 보니, 어느 순간 &#39;만드는 재미&#39;도 다시 살아났습니다. </p>
<p>이제는 남은 2주가 아닌 앞으로의 인생에 대한 고민을 한층 더 해봐야되는 순간이 온 것 같고 부트캠프를 벗어나서 여기 있을 때 처럼 부지런하게 준비하고 노력할 수 있는 환경을 마련하는 것이 이번주의 숙제인 것 같습니다. 
날도 덥고 점점 지치는 것은 사실이지만 이럴 때일수록 더 굳건하게 앞으로 나아가는 모습 보여드리도록 하겠습니다. 파이팅!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 15기 23주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-15%EA%B8%B0-23%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-15%EA%B8%B0-23%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 29 Jun 2025 23:26:27 GMT</pubDate>
            <description><![CDATA[<h3 id="23주차에-대하여">23주차에 대하여</h3>
<p>요즘들어 방황하는 느낌이 많이듭니다. 이전엔 개발 공부 하나만 하면 됐었는데 요즘엔 자기소개서도 써야되고 코테도 준비해야되고 영어 공부도 해야되고 대회도 준비해야하다 보니 뭔가 하는건 많지만 하나하나 비중을 높게 가져가지 못하다보니 뭔가 한듯한 느낌이 안들고 매일 매일 불안한것 같습니다.</p>
<p>이럴 때일수록 시간관리의 중요성은 더욱 커지고 저를 잡아줄 무언가가 필요한 것 같습니다. 지금엔 주변에 의지될 동기분들도 계시고 강사님도 멘토님도 계시지만 부트캠프가 끝나면 지금의 생활을 지속하지 못할 수도 있기에 남은 20일 동안은 시간관리 및 자기계발 템플릿 및 도구를 만들고자 합니다.</p>
<h3 id="느낀점-및-배운점">느낀점 및 배운점</h3>
<p>개발은 정말 뿌듯하거나 화가 나거나 둘 중 하나인 것 같습니다. 생각한 흐름대로 실행되면 무엇보다 기쁜데 무조건 되어야 하는데 안 될 때는 너무 지치고 힘든 것 같습니다. 이번 개발하면서도 계속 그 감정을 느꼈고 그래서 이번엔 모든 흐름에 AOP로 로그를 찍었고 대부분은 로그를 찍으면 문제를 발견했는데 그래도 발견못한 문제는 대부분 캐시를 비우거나 인테리제이를 초기화하거나 컴퓨터를 껐다켜야 문제가 해결되는 모습을 확인 할 수 있었습니다. 
지독한 문제를 해결하는 과정에서 추상화된 흐름을 보다 구체화되게 인식할 수 있는 좋은 기회이기도 하지만 그 당시에는 정말 당황스럽습니다... 그래서 개발자는 개인적인 능력 뿐만 아니라 인내와 참을성이 높아야되는 것 같습니다..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW CAMP 15기 22주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-22%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-22%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 22 Jun 2025 23:46:14 GMT</pubDate>
            <description><![CDATA[<h3 id="22주차에-대하여">22주차에 대하여</h3>
<p>이번주차엔 새롭게 시작하는 일이 많아진 한주입니다. 해커톤 기획도 시작하고 개발자로서의 첫 이력서를 작성해보기도 하고 코테도 이제 드디어 단순 구현이 아닌 알고리즘 문제를 내손으로 풀기 시작했습니다.</p>
<p>또한 파이널 프로젝트에선 AI 연결을 위해 다양한 모델을 직접 써보고 파이썬 서버도 구축해보는 중입니다. openAI는 사용해본 경험이 있어 이번엔 일부로 허깅페이스에서 제공하는 모델을 사용해보고 있는데 제가 익숙치 못한 탓인지 구현에 어려움을 겪고 있습니다. 
그래도 여러 모델들의 종류 및 특징과 사용법을 하나씩 익히고 있어서 언젠가 AI 연결이 필요한 경우를 대비하여 미리 공부해볼 수 있는 좋은 경험인 것 같습니다. </p>
<p>최적의 프롬프트를 찾아가는 것부터 학습시키는 과정까지 나름 재미를 느끼고 있고 이번에 참여하는 해커톤에서 잘 사용하기 위해서 최대한 많은 공부를 해볼 예정입니다!</p>
<p>그리고 이력서를 작성하다보니 고가용성, 성능, 장애율 등을 구현 및 개선한 경험을 해봐야겠단 생각을 하게되면서 최대한 파이널에서 경험 해보고 안되면 이전 프로젝트를 리팩토링 해볼 예정입니다.</p>
<h3 id="느낀점-및-배운점">느낀점 및 배운점</h3>
<p>요즘들어 해야할게 너무 많아지다 보니 내 일정을 관리해주고 피드백을 주는 시스템이 필요하단 생각이 들어 요즘 어차피 ai를 연결하고 있기도 해서 나만의 시간관리 웹 앱을 만들어 봐야겠단 생각을 하고 있습니다.</p>
<p>그리고 감사하게도 주변분들이 좋은 평가를 해주셔서 조금씩 자신감을 갖고 있는데 아직은 스스로에 대한 자신감과 믿음이 많지 않다고니 매순간 기분이 오락가락 하는것 같습니다. 언젠간 잘하겠지 믿으면서 그냥 헬스장 가는 마음으로 일단 실행에 옮기고 생각은 나중에 하는 편이긴 한데 그런 마음으로 하다보니 이미 벌여놓은 일들이 꽤나 많게 되서 생각을 조금하고 실행해야되나 라는 생각이 듭니다 🤣...</p>
<p>어쨋든 항상 용기주시는 모든 분들 감사드리고 저도 용기와 좋은 기운을 줄 수 있는 사람이 되겠습니다!! 
그저 정진!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW CAMP 15기 21주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-21%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-21%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 15 Jun 2025 23:48:22 GMT</pubDate>
            <description><![CDATA[<h3 id="21주차에-대하여">21주차에 대하여</h3>
<p>21주는 성장의 시작이라고 할 수 있는 주인 것 같습니다. 매주 버거웠던 시기가 지나고 하나씩 익숙해지다 보니 요즘들어 약간의 정체기를 느끼고 나태해지고 있었는데 갑자기 등장한 대회 준비와 취업 준비를 하다보니 다시금 부족함을 느끼고 성장할 수 있다는 두근거림에 활력을 찾게 되었습니다.</p>
<p>그리고 파이널 프로젝트에서 인공지능 관련 기능을 담당하게 되어 요즘 자료조사를 하고 있고 여러 api들을 시도해보면서 새로운 기술을 공부하고 적용해 보는 것에 대해 부담이 줄게 되었습니다.</p>
<p>또한 기능으로서 인공지능을 연결하는것 뿐만 아니라 피그마 페이지를 구현하거나 깃허브 코드를 직접 수정해주고 PR을 작성해주는것 까지 다양한 분야에서 인공지능을 사용할 수있게다는 것을 알게되고 하나씩 시도해보고 있는데 이제는 인공지능을 정말 잘 사용하는것이 좋은 개발자의 척도가 될 수 있다는것이 체감되는 것 같습니다.</p>
<p>그래서 요즘 chat gpt와의 대화중 좋은 결과물이 나올때마다 그 결과물이 다시 나올 수 있도록 프롬프트를 정리해서 폴더링 및 버전관리 하고 있고 팀원과 동기분들께 공유드려서 직접 적용해 보신 분들이 모두다 프롬프트에 의한 결과물 차이를 인정해주셨습니다.</p>
<p>앞으로 한 달 정도라는 시간이 남았고 지금은 오직 스스로 모든 시간들을 관리해야 하기 때문에 시간 관리가 무엇보다 주요한 때이고 저는 보다 체계적으로 시간 관리를 하기 위해서 이제는 템플릿을 넘어 저만의 시간관리 웹페이지를 만들어서 노션 api와 인공지능을 연결해서 저만의 시간관리 비서를 생성해보고자 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW CAMP 15기 20주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-20%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-20%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 08 Jun 2025 15:23:08 GMT</pubDate>
            <description><![CDATA[<h3 id="20주차에-대하여">20주차에 대하여</h3>
<p>이번 주는 부트캠프에서 수행했던 모든 프로젝트의 회고를 마무리한 의미 있는 시간이었습니다.<br>그 중 파이널을 제외하면 마지막이었던 <strong><a href="https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BE15-%EB%8D%B0%EB%B8%8C%EC%98%B5%EC%8A%A4-%EC%BA%A3%EC%B9%98-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0">데브옵스 프로젝트 회고</a></strong>를 작성하면서 지금까지의 경험과 고민들을 다시 떠올리고, 다시 공부하고 다시 한번 제 것으로 만들 수 있었던 점이 참 뜻깊은것 같습니다. </p>
<p>회고를 작성한다는 것은 단순히 내가 무엇을 했는지를 정리하는 것을 넘어서, 왜 그렇게 했는지를 스스로에게 되묻고, 그것이 어떤 의미였는지를 복기하는 과정이라고 생각합니다.<br>그러한 과정 속에서 배운 내용들은 더 오래 기억에 남고, 경험이 더 단단하게 쌓이는 것 같습니다.</p>
<p>이번 주가 특히 뜻깊었던 이유는 데브옵스 회고를 끝으로 파이널 프로젝트를 제외한 모든 프로젝트 회고를 마무리했다는 점입니다.<br>그리고 부트캠프에서 제가 가장 크게 얻은 것이 있다면, ‘회고’ 그 자체였던 것 같습니다.<br>회고를 통해 제가 무엇을 했고, 무엇을 고민했으며, 어떤 선택을 했는지를 진지하게 되돌아보는 시간이 있었기에 그 순간의 감정과 사고가 그냥 사라지지 않고 오래 남아 있는 것 같습니다. </p>
<p>그리고 회고를 작성하다보니 저에게도 뜻밖의 기회가 왔습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/4b86cad3-f00f-4ffc-a410-297f4ad64861/image.png" alt=""></p>
<p>클래스101에서 강의 제안을 받았고, 아마도 제가 작성해온 블로그 글이나 회고들을 보고 연락을 주신 것 같습니다. 아직은 강의를 시작할 생각은 없지만 제가 기록해온 것들이 누군가에게 긍정적으로 다가갔다는 사실이 너무 기뻤습니다.</p>
<p>이 경험을 통해 ‘내가 쓰는 회고를 누군가는 보고 있다’는 사실을 더 진지하게 받아들이게 되었고, 앞으로는 회고를 더 잘 써야겠다는 책임감도 생겼습니다. </p>
<p>또한 블로그뿐만 아니라 평소에 하는 다양한 활동들도 계속 공유하다 보면 언젠가는 더 큰 기회로 연결될 수 있을 거란 기대감이 들었고 그 생각만으로도 뭔가 마음속에 많은 길들이 열리는 듯한 느낌을 받게되어 앞으로도 제가 노력한 내용들을 기록하고 공유하는 활동은 꾸준히 하지 않을까 싶습니다.</p>
<h3 id="데브옵스-프로젝트에서-배운-점-요약">데브옵스 프로젝트에서 배운 점 요약</h3>
<p>데브옵스 프로젝트에서는 처음부터 실무 중심의 효율적인 흐름을 목표로 삼았습니다.<br>불필요한 문서는 과감히 생략하고, 정말 필요한 정보만 담은 문서들로 협업 환경을 구성했으며, 그 결과 협업 속도와 커뮤니케이션 품질이 눈에 띄게 높아졌습니다.</p>
<p>특히 컨벤션은 제가 가장 애정을 가지고 정리했던 부분입니다.<br>백엔드, 프론트엔드, UI에 이르기까지 구체적인 기준을 정의했고, 그 덕분에 제가 직접 구현하지 않은 영역에서도 일관된 품질과 예측 가능한 구조가 유지될 수 있었습니다.</p>
<p>CI/CD는 Jenkins와 ArgoCD를 기반으로 구성하였고, Webhook, Docker multi-stage build, 무중단 배포, Presigned URL 기반 S3 업로드, Prometheus + Grafana 모니터링, Discord 알림 연동 등 다양한 DevOps 도구들을 하나하나 직접 연동해보았습니다.</p>
<p>물론 Redis 기반 좋아요 기능은 시간 부족으로 인해 끝내 구현하지 못했고, Kubernetes 환경에서 ELK 스택까지 연동하는 데에도 어려움이 있었지만, 이러한 실패 경험들 역시 다음 프로젝트를 위한 좋은 실험이 되었다고 생각합니다.</p>
<p>개인적으로 가장 크게 느낀 점은, DevOps란 단순한 자동화나 기술 집합이 아니라 <strong>신뢰와 협업을 어떻게 설계할 것인가</strong>에 대한 고민이라는 것이었습니다.<br>기술을 넘어서 시스템 자체를 설계했다는 감각, 그것이 이번 프로젝트의 가장 큰 성과였습니다.</p>
<h3 id="파이널-프로젝트-기획의-시작">파이널 프로젝트 기획의 시작</h3>
<p>이번 주부터는 파이널 프로젝트 기획에도 본격적으로 착수하였습니다.<br>초기에는 ‘직무 중심 인사관리 시스템’을 구상했지만, 직무 중심이라는 개념 자체가 급여, 성과, 등급, 직무 평가 등과 얽히면서 기준을 설정하기가 매우 어려웠습니다.</p>
<p>추상적인 단어에 실질적인 기능을 붙이기 위해 관련 논문을 20편 이상 읽고, 선행 시스템들을 조사하며 가능한 정의를 찾아보았지만, 그 한계가 분명하게 느껴졌습니다.<br>그래서 강사님의 피드백을 반영하여 급여 기능은 제외하고, KPI/OKR 기반의 성과 관리에 집중하기로 방향을 수정했습니다.</p>
<p>하지만 멘토님과의 미팅을 통해 ‘우리가 정말 해결하고 싶은 문제는 무엇인가?’라는 질문을 다시 던지게 되었고, 그 결과 단순한 평가 시스템이 아닌 <strong>기술 중심의 인재 추천 및 성과 관리 시스템</strong>으로 방향을 선회하게 되었습니다.</p>
<p>실제로 SI 기업에서 개발자를 채용할 때, 프로젝트 이력이나 기술 스택만으로는 실무 역량을 평가하기 어렵고, 결국 추천을 통해 채용하는 경우가 많은데, 저희는 이 문제를 정면으로 해결하고자 했습니다.<br>AI를 통해 기업 요구사항에 적합한 인재를 추천하고, 피드백, 프로젝트 이력, 기술 점수 등을 기반으로 <strong>객관적인 근거가 있는 추천 시스템</strong>을 만드는 것을 목표로 하였습니다.</p>
<p>그렇게 저희는 ‘<strong>기술 중심 인재풀 기반 SI 인력 추천 및 성과관리 시스템</strong>’이라는 명확한 목표에 도달할 수 있었습니다.  </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/9e08380b-141f-46a4-bad6-e327ef985f4c/image.png" alt=""></p>
<p>요구사항은 네 번 이상 갈아엎었고, 수십 개의 시나리오를 작성하고 폐기했지만, 그 과정을 통해 더욱 탄탄한 기준을 세울 수 있었고, 저 역시 기획자로서 방향을 명확히 세울 수 있었기에 매우 보람 있는 경험이었습니다.</p>
<h3 id="코딩-테스트-준비-시작">코딩 테스트 준비 시작</h3>
<p>이번 주에는 코딩 테스트와 CS 정리도 병행하여 시작하였습니다.<br>목표는 두 달 안에 백준 기준 플래티넘 등급을 달성하는 것이고, 이를 위해 매주 어떤 알고리즘을 학습할지, 어떤 문제를 풀고 어떻게 복습할지를 포함한 <strong>구체적인 학습 계획</strong>을 수립해두었습니다.</p>
<p>단순히 많은 문제를 푸는 것이 아니라, 실력을 체계적으로 끌어올리기 위한 로드맵을 기반으로 학습을 진행하고 있으며, 실제로 성과가 생긴다면 그 학습 방식도 따로 정리하여 공유할 계획입니다.</p>
<h3 id="리듬-회복과-시간-사용에-대한-고민">리듬 회복과 시간 사용에 대한 고민</h3>
<p>이번 주에는 부산을 다녀오면서 약 3일 정도 쉬게 되었고, 처음에는 리듬이 끊긴 느낌이 있었지만 결과적으로는 스트레스가 풀리고 에너지를 재정비할 수 있었던 좋은 계기가 되었습니다.</p>
<p>지금은 다시 학습 루틴과 프로젝트 흐름을 회복한 상태이며, 남은 시간을 어떻게 효율적으로 사용할 수 있을지에 대해 진지하게 고민하고 있습니다.<br>이제는 시간이 무한하지 않다는 것을 실감하고 있고, 짧게 남은 기간을 가장 밀도 있게 활용하기 위한 계획을 세워야겠다는 생각이 들었습니다.</p>
<h3 id="다음-주-목표">다음 주 목표</h3>
<ul>
<li>파이널 프로젝트 화면 정의서 v1 완성  </li>
<li>인재풀 및 추천 로직 아키텍처 설계  </li>
<li>코딩 테스트 매일 2문제 + 주간 복습  </li>
<li>슬럼프 방지를 위한 주간 회고 시간 확보  </li>
<li>기획·개발·학습 루틴 유지</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BE15 데브옵스 캣치 프로젝트 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BE15-%EB%8D%B0%EB%B8%8C%EC%98%B5%EC%8A%A4-%EC%BA%A3%EC%B9%98-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BE15-%EB%8D%B0%EB%B8%8C%EC%98%B5%EC%8A%A4-%EC%BA%A3%EC%B9%98-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 03 Jun 2025 11:34:14 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프로젝트-개요">1. 프로젝트 개요</h2>
<h3 id="프로젝트-기획-및-설계">프로젝트 기획 및 설계</h3>
<p>이번 프로젝트의 목표는 짧은 시간 내에 기획부터 DevOps까지 효율적으로 구현하는 것이었습니다. 이를 위해 저는 어떻게 하면 업무를 효율적으로 처리할 수 있을지 깊이 고민했습니다.</p>
<p>새로운 팀을 구성한 직후 제가 팀원들에게 가장 먼저 요청한 두 가지는 첫째, 정말 필요한 것들만 진행하자는 것이었고 둘째, 회의 시간을 길게 가지지 말자는 것이었습니다.</p>
<p>이번 프로젝트까지 포함하면 총 네 번의 프로젝트를 수행했는데, 그동안 부트캠프에서 제공한 가이드라인을 따르는 것이 일종의 관습처럼 굳어져 있었습니다. 그러나 그 안에는 이번 프로젝트에서 불필요하거나 다소 부담스러운 요소들이 있었습니다.</p>
<p>예를 들어, 그라운드 룰을 작성할 때도 필요하면 좋겠지만, 이전 프로젝트들에서 실제로 지켜지지 않았던 이상적인 내용들은 제외했습니다. 또한 유사 프로젝트 분석, 프로젝트 기획서 작성, UML 작성, 화면 설계서 작성 같은 문서들도 이번에는 과감히 생략했습니다.</p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/17fa9d44-676f-4be3-8b32-bc60e985bb63/image.png" alt=""></p>
<p>결국 이번 프로젝트에서 남긴 핵심 문서는 다음과 같습니다.</p>
<ol>
<li>컨벤션</li>
<li>회의록</li>
<li>안건함</li>
<li>그라운드룰</li>
<li>서비스 기능 정의서</li>
<li>요구사항 명세서</li>
<li>피그마 UI</li>
<li>플로우 차트</li>
<li>물리/논리 ERD</li>
<li>REST API 명세서</li>
</ol>
<p>이 문서들은 기획부터 구현까지 팀원들 간 최소한의 생각과 기능을 공유하고 구현 계획을 세우는 데 필수적이라고 판단했습니다. 각 기능이 무엇이며 어떻게 동작하고 어떤 경로와 과정을 거치는지 공유할 수 있는 최소한의 뼈대였습니다. 오히려 실효성 없는 정보들은 노션 페이지에서 과감히 배제하면서 정보 접근성이 높아져 매우 효율적이었다고 생각합니다.</p>
<p>특히 이번 프로젝트에서 제가 가장 의미 있게 느낀 점은 컨벤션을 최대한 구체적이고 다양한 분야에 걸쳐 정의한 것이었습니다.</p>
<p>이전 DB, 백엔드, 프론트엔드 프로젝트들을 진행하면서 각자의 구현 방식이 다를 수밖에 없다는 것을 절실히 느꼈습니다. 하지만 제가 알고 있는 지식과 노하우를 컨벤션으로 정리해 공유하자, 팀원들이 그것이 효율적이고 효과적이라 판단될 경우 그에 맞춰 구현해 주었습니다. 그 결과 내가 직접 구현하지 않아도 의도한 방식으로 작업이 진행되었고, 자연스럽게 분업이 원활히 돌아가며 맡은 역할에 더 집중할 수 있는 좋은 협업 환경이 만들어졌다고 생각합니다.</p>
<p>이번 프로젝트 기획 단계에서 저는 노션 페이지 설계를 맡았습니다. 이전 백엔드 프로젝트에서 설계했던 템플릿이 충분히 효율적이고 효과적이라고 판단하여 기존 템플릿을 유지하되 몇 가지를 추가했습니다.</p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/57863301-2d2d-4844-9f35-e02fe19c859b/image.png" alt=""></p>
<p>우선 회의록 템플릿을 적용하여, 안건함과 진행할 일 공유, 공통 과제 등을 매 회의록에 포함하도록 구성했습니다. 또한 이번에는 최대한 역할을 나눠서 일을 처리하기로 했기에 위에서 제공한 이미지와 같이 회의에서 나온 액션 아이템을 담당자별로 구분하고 진행 상황을 한눈에 볼 수 있는 액션 아이템 리스트를 중앙에 배치했습니다.</p>
<p>비록 이미 좋은 템플릿이었지만, 회의록-안건함-각각의 DB(예: 프로젝트 기획서, 서비스 기능 명세서, 컨벤션 등) 간 연결성이 부족하다는 점은 아쉬웠습니다. 현재 노션을 일종의 레포지토리처럼 사용하고 있는데 앞으로는 프로젝트 관리에 더 초점을 맞춘 노션 페이지 구성이 필요하다고 느꼈습니다.</p>
<p>아직 사실 여부를 직접 확인한 것은 아니지만, 제가 가장 먼저 페이지를 구성한 뒤 다른 팀들도 동일한 템플릿을 적용하는 모습을 보았을 때, 제가 만든 페이지를 다른 팀원들도 긍정적으로 평가해주었다고 생각해 뿌듯함을 느꼈습니다 ㅎㅎ.</p>
<p>이번 협업에서 새롭게 시도한 점은 지라(Jira) 툴을 사용한 것이었습니다.</p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/ef8f86c1-7942-482d-b05f-175fe09068eb/image.png" alt=""></p>
<p>지라를 사용하면서 좋았던 점은 도메인별로 처리해야 할 이슈들을 관리할 수 있었고, 다른 팀원들이 어디까지 구현했는지 확인할 수 있었다는 것입니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/986d63a0-5918-4047-ba0f-89a8ab09d01a/image.png" alt=""></p>
<p>지라에는 일정 및 업무 처리 분석 기능도 있는 것으로 알고 있지만, 이번 프로젝트에서는 해당 기능들을 충분히 활용하지 못했습니다. 주로 개인 일정 관리, 전체 업무 달성 확인, 브랜치 생성 측면에서 특히 효과적이었습니다. 다음 프로젝트에서는 새로운 협업 툴을 시도해 보거나, 지라의 다양한 기능들을 더 깊이 탐색해보는 것도 좋을 것 같습니다.</p>
<h3 id="2-하고싶었던-것-및-아쉬운-점">2. 하고싶었던 것 및 아쉬운 점</h3>
<p>이번 프로젝트에서 제가 시도해보고자 했던 목표는 다음과 같습니다.</p>
<ol>
<li>패키징 및 번들링<ul>
<li>Vite와 Webpack 각각의 빌드 결과를 분석</li>
<li>컴포넌트 분리 및 Lazy Loading 설정</li>
<li>Multi-Stage Dockerfile 구성</li>
<li>Docker 이미지 사이즈 최소화</li>
<li>캐시 최적화</li>
</ul>
</li>
<li>릴스 업로드 기능 구현<ul>
<li>Presinged URL로 프론트에서 S3로 직접 요청</li>
<li>썸네일 이미지 자동 추출</li>
<li>영상 길이 검증</li>
</ul>
</li>
<li>로그/메트릭 수집 및 알림<ul>
<li>장애 대응, 자동 알림, SLA 분석</li>
<li>메트릭 수집 후 자동 스케일링 기준 (HPA 등) → CPU 70% 이상이면 Pod 증가</li>
<li>퍼포먼스 모니터링 및 알람 조건 지정</li>
<li>DB 병목 탐지, 인덱스 개선 유도</li>
</ul>
</li>
<li>대용량 처리 예약<ul>
<li>릴스 변환, 통계 집계, 알림 발송, 오래된 로그 삭제 등 반복 작업 백그라운드로 처리</li>
</ul>
</li>
<li>인메모리 DB(Redis) 사용<ul>
<li>좋아요 기능에 적용</li>
</ul>
</li>
<li>Web Hook 사용해보기<ul>
<li>Github Webhook</li>
<li>Discrod Webhook</li>
</ul>
</li>
<li>테스트코드 자동화</li>
<li>무중단 배포 전략 적용</li>
</ol>
<p>짧은 시간 안에 위의 모든 목표를 달성하려고 했지만, 역시 모든 것을 구현하기에는 시간이 부족했습니다. 그중 릴스 업로드 기능은 완벽히 구현했고, 로그 및 메트릭 수집과 알림은 Docker Compose 환경에서 ELK 스택과 Prometheus + Grafana 연동에 성공했으나, 쿠버네티스 환경에서는 한계에 부딪혔습니다. ELK 스택과 Prometheus, Grafana는 쿠버네티스 환경에서 매우 무거웠고, 로그 출력 및 actuator 추가 후 이미지를 다시 빌드하고 컨테이너로 실행하는 과정이 노트북 환경에서 상당히 부담스러웠습니다. 이로 인해 쿠버네티스 환경에서는 결국 구현에 실패했습니다.</p>
<p>GitHub Webhook은 Jenkins 파이프라인을 구성하여 CI/CD 자동화를 구현하는 데 활용했고, Discord Webhook은 파이프라인 마지막 단계에서 빌드 성공 여부를 Discord 알림으로 전달하는 데 적용했습니다.</p>
<p>이미지 빌드 과정에서는 테스트 코드까지 포함해 빌드하는 데 성공했고, 롤링 업데이트 방식의 무중단 배포도 구현했습니다.</p>
<p>다만 아쉬웠던 점은, 팀원 중 한 분이 Redis를 적용해 RefreshToken을 저장 및 관리하는 기능은 성공적으로 구현했지만, 좋아요 기능을 Redis로 전환하려던 계획은 끝내 실행하지 못한 채 프로젝트가 종료되었다는 점입니다. 처음에는 DB에 저장된 좋아요 데이터를 Redis로 이관하려 했으나, 배포까지 완료하고 남은 시간이 부족해 해당 부분은 다음으로 미루게 되었습니다.</p>
<p>또한 패키징 및 번들링 측면에서도 멀티 스테이지로 빌드 스테이지와 실행 스테이지를 분리해 이미지를 빌드하는 데는 성공했지만, Docker 이미지 사이즈 최소화나 캐시 최적화는 구현하지 못했습니다. 프론트엔드에서 Vite와 Webpack 빌드 결과를 분석하는 작업 역시 시도하지 못했습니다.</p>
<p>따라서 파이널 프로젝트에서는 이러한 미완성된 목표들을 차근차근 하나씩 테스트하고, 최대한 많은 실험과 성능 개선, 테스트 최적화에 초점을 맞춰 개발 역량을 한층 더 향상시켜볼 계획입니다.</p>
<h2 id="3-내가-한-것">3. 내가 한 것</h2>
<p>우선 위에서 컨벤션을 언급했었는데 제가 담당했던 컨벤션은 백엔드, UI, 서비스 레이어 컨벤션을 맡아서 구조를 작성했었습니다. </p>
<h3 id="컨벤션-설계">컨벤션 설계</h3>
<p><strong>백엔드 컨벤션</strong></p>
<p><a href="https://chemical-printer-c99.notion.site/1-1ee2fdb14148803c96d6f23f10bbea44">백엔드 컨벤션</a></p>
<p>우선 프로젝트 구조에 대한 컨벤션을 작성했는데요. 위의 게시한 링크를 확인해보시면 확인할 수 있는 내용입니다. </p>
<pre><code class="language-java">src/main/java/com/project
├── command
│       ├── application
│       │   ├── controller
│       │   ├── dto
│       │   │   ├── request
│       │   │   ├── internal
│       │   │   └── response
│       │   └── service
│       └── domain
│           ├── aggregate
│           ├── repository
│           ├── service
│           └── constants
├── query
│       ├── application
│       │   ├── controller
│       │   ├── dto
│       │   │   ├── request
│       │   │   ├── internal
│       │   │   └── response
│       │   └── service
│       └── domain
│           ├── aggregate (command와 공유)
│           ├── repository (command와 공유)
│           └── constants
├── common
│   ├── dto
│   │   ├── ApiResponse.java
│   │   └── PageResponse.java
│   ├── aggregate
│   ├── util
├── config
│   │   ├── AppConfig.java
│   │   ├── JavaConfig.java
│   │   ├── AppConfig.java
│   │   ├── ModelMapperConfig.java
│   │   ├── SecurityConfig.java
│   │   └── PageResponse.java
├── exception
│   ├── GlobalExceptionHandler
│   ├── Errorcode
│   ├── ErrorResponse
│   └── BusinessException.java
├── security
│   ├── filter
│   │   └── JwtAuthenticationFilter.java
│   ├── handler
│   │   ├── RestAccessDeninedHandler.java
│   │   └── RestAuthenticationEntryPoint.java
│   └── jwt
│   │   └── JwtTokenProvider.java
└── Application.java</code></pre>
<p>이전 백엔드 프로젝트에서의 프로젝트 구조와 동일하게 도메인 기준의 CQRS 구조 패턴으로 설계하였고 처음에는 Mybatis 없이 JPA로만 프로젝트를 구현하려고 했는데 Mybatis가 없다보니 복잡한 SQL 구문을 작성하는 것이 매우 번거로웠고 쿼리용과 커맨드용 엔티티가 많아지면서 오히려 좋지 않은 프로젝트 구조를 형성하게 되면서 이전 프로젝트와 동일하게 조회의 경우엔 Mybatis를 사용하고 명령의 경우엔 JPA를 사용하여 처리했습니다. </p>
<p>하지만 저의 경우엔 Mybatis를 사용하는 것이 다소 꺼리는 이유가 Mybatis를 사용하면 ORM이 아닌 SQL 구문 그 자체를 작성해서 실행하기 때문에 휴먼 에러가 발생할 여지가 높고 컴파일 시점에 에러를 확인할 수 없으므로 개발 용이성이 다소 떨어진다는 문제가 있어 해당 문제를 해결해줄 수 있는 jooq를 적용해보려고 했지만 역시 시간이 많은 것이 아니였기 때문에 새로운 스택을 추가하는 것이 다소 어렵다는 결론에 도달하였고 이번 프로젝트에선 Mybatis와 PageHelper 라이브러리를 사용하여 Mybatis로 조회 및 페이지네이션을 구현했지만 다음에는 jooq를 적용하여 조회를 처리해보는 것을 시도해보고자 합니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/49d180f0-895a-43ca-894c-8ef123b56388/image.png" alt=""></p>
<p>위의 링크로 이동하여 확인해보시면 아시겠지만 각각의 레이어에서의 역할이나 해야할 일들을 정리하였고 구현체와 인터페이스의 구분에 대해서도 정리하긴 했는데 그냥 이렇게 막연하게 정리하면 보시는 분들도 있으시고 안보시는 분들도 계신 것 같아서 다음에는 특히 필수적으로 확인을 했으면 하는 것들은 따로 요약용 버전도 만들어서 제공해야 할 것 같단 생각을 하게 되었습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/210e933a-8b72-4c7f-a14b-90f3429627e7/image.png" alt=""></p>
<p>ErrorCode도 이전 프로젝트에서 하나의 파일로 관리하다보니 매번 병합시 사라지는 일이 발생하여 도메인별로 에러코드 Enum을 관리하자는 안건을 냈지만 이번 팀원분들은 깃 관리에 자신있다고 하셔서 하나의 파일로 관리하는 것으로 합의를 봤고 다행히도 모두가 깃 관리를 잘해주셔서 하나의 파일로 관리해도 문제가 없었습니다. </p>
<p>그리고 HTTP 상태 코드 뿐만 아니라 에러 코드도 Enum에 추가하자는 의견이 있어 추가하게 되었는데 하나의 페이지에서 다양한 API를 호출하는 것이 아니다 보니 에러 코드가 그렇게 의미가 있었던 것은 아니여서 최대한 활용할 수 있는 방법들에 대해 더 고민할 필요가 있을 것 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/559b3cd8-bede-44f8-8bf3-f93ff7cd37c4/image.png" alt=""></p>
<p>GlobalExceptionHandler에 대한 컨벤션도 미리 정리하고 함께 공유하다보니 이번 프로젝트에선 모두 예외 처리를 동일하게 한 것이 매우 의미가 있었던 것 같습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/8d38fdf6-f237-483d-9a7d-8f5e151d710d/image.png" alt=""></p>
<p>그리고 통합 ApiResponse도 컨벤션을 정리하여 공유하다보니 내가 직접 구현한 API가 아니여도 예상 가능한 Response를 받을 수 있어 다른 사람들이 만든 API를 사용하기 매우 쉬었고 코드 리뷰하는 것 역시 어려움이 없었던 것 같습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/04c815b7-aff7-4e30-abf3-7b3a242c735b/image.png" alt="">
그리고 페이지네이션의 경우에 수업에서 배운 방식이 아닌 PageResponse로 감싸서 PageHelper 라이브러리를 사용해서 페이지네이션을 처리해주는 것 역시 동일하게 구현해주셔서 통일성 있는 프로젝트를 진행한 것 같아 컨벤션을 정리해야 하는 이유에 대해 다시 한번 중요성을 인식할 수 있었습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/3431ee51-8b5d-4caf-a2c4-f8d9ee8c6531/image.png" alt=""></p>
<p>다만 제가 위와 같이 SpringSecurity에 대한 설계를 하고 실제로 제가 프로젝트 구현은 다음과 같이 CustomUserDetails를 Authentication으로 관리하는 것이 아니라 userId를 관리하는 것으로 구현하여 컨트롤러 단에서 @AuthenPrincipal로 접근하는 값들이 무엇인지에 대한 혼란이 있었습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/0513c6fe-946d-45fe-aac6-e61598e76c48/image.png" alt=""></p>
<p>이를 통해 컨벤션을 설계해놓고 잘못 구현해놓으면 저 혼자만 실수하는 것이 아닌 모든 팀원들의 실책으로 이어져 큰 문제가 발생 할 수 있음을 이번 프로젝트에서 경험하게 되었습니다. 물론 저도 userId만 Authentication으로 관리하는 이유가 이번에는 role이 필요없다 보니 String 타입의 userId만 관리하면 될 것 같아서 변경을 한 것인데 변경을 했으면 컨벤션도 수정을 했어야 했는데 그러지 못해서 문제가 있었고 이번에는 작은 문제이지만 회사에선 큰 문제를 발생할 수도 있단 생각을 하게 되어 컨벤션 설계에서 끝나지 않고 업데이트 역시 중요하단 것을 이번 경험을 통해 알게 되었습니다. </p>
<p><strong>UI 컨벤션</strong></p>
<p><a href="https://chemical-printer-c99.notion.site/3-UI-1ee2fdb1414880fd8602c0a9f66817ed?pvs=73">UI 컨벤션</a></p>
<p>이번 디자인 시스템은 실제로 모두가 적용하고 이해할 수 있도록 UI 컨벤션을 정리했고 그 결과는 위의 링크를 따라가시면 확인하실 수 있습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/5507740f-7b4d-4925-ab06-375eb12f67a8/image.png" alt=""></p>
<p>그 결과 위와 같이 모든 페이지가 통일성과 일관성을 유지한 프로젝트를 설계할 수 있게 되었고 디자인 시스템에 대한 컨벤션을 한번 정리하다보니 유지보수하는 것이 매우 쉬웠습니다. </p>
<p>다소 아쉬운 점은 실제 프로젝트 구현에선 미리 컴포넌트 단위로 구현하지 않고 각자 맡은 도메인에 따른 페이지를 구현하다보니 재사용성이 높은 컴포넌트가 있는 반면 재사용성이 떨어지는 컴포넌트도 있고 하나의 페이지에 많은 요소들이 포함되서 디버깅이 어려울 뿐만 아니라 유지보수하는 것이 매우 어려웠습니다. </p>
<p>그래서 다음에는 처음에 무조건 컴포넌트부터 구현한 뒤에 페이지를 구현하는 단계로 넘어가야겠단 생각을 하게 되었고 프론트엔드에서 주로 사용하는 패턴중 하나인 Atomic 패턴에 따라 구현해보고자 합니다. </p>
<h3 id="초기-프로젝트-세팅">초기 프로젝트 세팅</h3>
<p><strong>백엔드 프로젝트 세팅</strong></p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/090fa5bd-3872-48c4-9a9a-6e8083986db7/image.png" alt="">
이번 프로젝트에서 가장 중요시 한 것이 효율적인 개발 환경이었기 때문에 서로 코드 개발에 대한 내용은 모두 PR로 공유하는 것으로 하기로 했고 남들의 코드 리뷰 시간을 최소한 줄이기 위해 PR을 최대한 구체적으로 잘 작성하기로 했고 위의 예시처럼 최대한 구체적으로 코드나 예시 위주로 작성하는데 중점을 두어 작성했습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/03b3a0d7-e412-4348-a381-73e787369922/image.png" alt="">
그리고 저 뿐만이 아니라 초기 세팅에서 가장 도움이 되었던 것은 바로 테스트 로그인 코드입니다. 제가 이전 프로젝트에서 인증과 사용자 관련된 모든 것들을 담당해서 구현했었기 때문에 SpringSecurity, JWT 인증 필터, 로그인과 관련된 코드들을 빠르게 작성할 수 있는 상황이었고 저는 이번에 백엔드와 프론트를 동시에 구현하는 것을 목표로 했고 프론트엔드에서 api 호출 시에 accessToken을 request에 담아서 받아서 서버로 전송하는 것들을 초기 세팅에서 구현해놨기 때문에 Vue 프로젝트 초기화 시점에 테스트 로그인 api를 호출해서 accessToken은 응답의 body로 받고 refreshToken은 HttpOnly 쿠키에 저장하도록 구현하는 코드가 필요했습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/d3801928-afe3-421a-a7cc-62cd61612b92/image.png" alt=""></p>
<p>그래서 저는 빠르게 해당 기능만 구현하는 코드를 구현했고 추가적으로 로그인 시에 필요한 유효성 검사나 refreshToken을 Redis에서 관리하는 코드는 모두 빼고 accessToken과 refreshToken을 생성하고 refreshToken은 body에 넣고 refreshToken은 헤더에 넣어서 HttpOnly 쿠키에 저장하도록 하는 것만 구현해서 초기부터 로그인 했을 땡와 동일한 환경을 구축했고 userId가 필요한 api를 구현할 때 테스트 로그인을 사용해서 다른 팀원분들도 빠르게 api를 구현할 수 있으셔서 참 뿌듯했던 것 같습니다. </p>
<p><strong>프론트엔드 프로젝트 세팅</strong></p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/4f9453ef-dd19-4bdc-bc87-0494e6f7b525/image.png" alt=""></p>
<p>프론트엔드 프로젝트 세팅에 대한 PR역시 자세하게 작성하기 위해 노력했고 이전 프로젝트에서 TaiwlindCSS를 사용해본 팀원분들이 많으셨고 클래스 기반의 스타일 적용 방식의 편의성을 모두 좋게 생각하셔서 tailwindCSS를 적용하기로 했고 다른 팀원분들의 경우에 tailwind.config.js 파일로 스타일 시스템을 확장 할 수 있다는 것을 모르셨다고 하셔서 피그마에서 적용한 스타일 시스템과 동일하게 tailwindCSS에서 구현에서 사용할 수 있는 시스템을 확장했습니다. </p>
<p>그리고 위에서 언급한 바와 같이 초기화 시점에 loginUserTest api를 호출하여 token값을 가져와서 Pinia에서 관리하고 axios 인터셉터로 api 호출 시점에 header에 Authorizaiton에 token을 포함해서 전달하도록 모두 세팅을 해두었습니다. 이를 통해 대략적인 프론트-백엔드 프로세스를 구축하였고 이를 기반으로 매우 빠르게 프론트엔드와 백엔드를 동시에 구현할 수 있게 되어 백엔드와 프론트엔드 프로젝트에 대한 초기 프로젝트는 템플릿으로 남겨놔야 할 것 같습니다. </p>
<h3 id="주요-기능-구현">주요 기능 구현</h3>
<p><strong>동영상 업로드 기능 및 썸네일 자동 추출 기능 구현</strong>
<img src="https://velog.velcdn.com/images/low_level_v99/post/875e0781-81f9-41b0-b094-aa54c49b4544/image.gif" alt=""></p>
<p>동영상 업로드에서 중요한 것은 동영상의 경우엔 최소 10MB부터 크게는 아주 큰 크기의 데이터가 서버로 전달되어야 하기 때문에 대용량 트래픽 처리 문제가 발생하게 되고 어차피 서버에 전달되었다가 서버에서 S3로 다시 동영상을 전달해야 하는 것이라면 프론트엔드에서 바로 S3로 동영상을 업로드하는 것이 좋겠다고 판단했습니다. </p>
<p>그래서 서버에서 Presigned URL을 발급한 뒤 발급한 URL로 프론트엔드에서 S3로 PUT 요청으로 동영상을 업로드하는 방법을 사용했고 해당 과정이 가능하도록 S3 버킷 정책을 설정하고 DB에는 파일키와 caption만 저장하고 실제 조회시에는 파일키와 버킷명과 지역의 조합으로 조회할 수 있도록 설정하였고 이 역시 버킷 정책에서 AllowPublicRead가 가능하도록 설정을 해주었습니다. </p>
<p>또한 업로드한 동영상에서 1프레임을 기준으로 썸네일을 자동으로 추출하는 기능도 구현했고 이는 HtmlCanvas 기능을 사용하여 구현했습니다. </p>
<p>그런데 썸네일 이미지의 경우엔 이미지다 보니 동영상보단 용량이 크지 않고 최대 용량을 10MB로 제한했기 때문에 서버로 전달해도 되겠다고 판단했고 서버에선 전달받은 파일 이미지를 S3에 저장하고 프론트에는 접근할 수 있는 CloudFront Domain을 제공하여 조회할 수 있도록 구현했습니다. </p>
<p><strong>고양이 카드 맞추기 게임</strong></p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/bbd2231b-3cd3-4757-86df-d6257c38b8e0/image.gif" alt=""></p>
<p>해당 게임은 우리 팀이 시연 1등으로 만들어주는데 일등공신을 해주는 기능이라고 개인적으로 생각하는 아주 귀여운 기능입니다. 사용자가 직접 자기 고양이 이미지를 선택하여 카드 맞추게 게임을 할 수 있는데요. 백엔드는 어려울 것이 없었지만 프론트 구현에서 다소 어려움이 있었고 시간에 따라 타이머바가 자연스럽게 채워지는 애니메이션을 적용하기 위해 requestAnimationFrame을 적용했습니다. </p>
<p>또한 카카오 공유 API를 연결하여 게인 랭킹을 공유하는 기능도 구현했습니다. </p>
<h3 id="cicd-자동화-구현">CI/CD 자동화 구현</h3>
<p><strong>CI/CD 자동화 시연</strong>
<img src="https://velog.velcdn.com/images/low_level_v99/post/b7426698-6e82-41dd-a0a3-bacba8e99a88/image.gif" alt=""></p>
<p><strong>아키텍처 설계</strong></p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/3ee9596e-fbd2-4e66-bc1d-2bb43a68d492/image.png" alt=""></p>
<p>이번 프로젝트의 CI/CD 자동화 구현은 최신 DevOps 트렌드와 실전 환경을 고려하여 효율성, 자동화, 확장성을 중심으로 설계하였으며, Jenkins 기반의 CI/CD 파이프라인과 ArgoCD 기반의 GitOps 배포 자동화를 연계하여 완전 자동화된 배포 체계를 구축했습니다.</p>
<p><strong>Jenkins 파이프라인 구축</strong></p>
<p>이번 파이프라인은 Groovy 기반 Jenkins Declarative Pipeline으로 작성되었으며, 주요 설계 포인트는 다음과 같습니다.</p>
<ol>
<li>변경 감지 기반 빌드</li>
</ol>
<ul>
<li>GitHub main 브랜치에서 Webhook으로 변경 사항이 들어오면, git diff를 통해 백엔드(backend/), 프론트엔드(frontend/) 변경 여부를 감지하여 <strong>변경된 부분만 선택적으로 빌드하여 불필요한 작업을 방지</strong>하고 빌드 효율을 극대화하고자 노력했습니다. </li>
</ul>
<ol start="2">
<li>Manifests 업데이트 자동화</li>
</ol>
<ul>
<li>Kubernetes manifests를 별도의 GitHub 리포지토리로 관리하고, Jenkins가 sed 명령어로 배포 YAML 파일 내 이미지 태그를 최신 상태로 갱신한 후 commit &amp; push까지 자동화했습니다.</li>
<li>이를 통해 GitOps 방식의 소스 중심 배포 자동화가 실현되었고, ArgoCD가 해당 변경을 감지하여 Kubernetes 클러스터에 자동 배포하도록 연계했습니다. </li>
</ul>
<ol start="3">
<li>Discord Webook 연동을 통한 알림 기능 구현</li>
</ol>
<ul>
<li>빌드 성공/실패 시 어떤 부분이 변경되었는지와 결과, 실행 시간, Jenkins 링크를 Discord로 전송하여 팀원들이 실시간으로 파이프라인 상태를 확인할 수 있도록 구현했습니다. </li>
</ul>
<ol start="4">
<li>Credential 보안 처리</li>
</ol>
<ul>
<li>DockerHub, GitHub, Kakao API 키, Discord Webhook 등 민감 정보는 enkins Credentials Manager로 관리하여 보안성 확보를 위한 노력을 했습니다. </li>
</ul>
<p>설계에서 중점을 둔 부분에 대해 얘기해보자면 Jenkins가 단순히 Docker 이미지 빌드 및 Push만 하는것이 아니라 manifests 리포지토리까지 자동으로 업데이트하고 ArgoCD가 이를 감지해 배포까지 이어지도록 설계하여 GitOps 완전 자동화를 달성하였습니다.</p>
<p>또한 parallel stage로 백엔드, 프론트엔드를 동시에 처리해 빌드 속도를 최적화하고자 한 부분도 성능 개선에 있어 힘쓴 부분입니다. </p>
<p><strong>Docker 빌드 및 Docker hub에 push</strong>
위에서 언급했듯이 Jenkins가 Webhook을 통해 이벤트를 감지하는데 이때 Git 변경 감지를 통해 변경된 영역별 조건부 빌드로 변경된 프로젝트만 빌드하도록 설정하였습니다. </p>
<p>Backend용 멀티 스테이지 Dockerfile을 활용해 Gradle 빌드용 레이어와 실행 환경 레이어를 분리하였고 최종 이미지는 Gradle 기반 JAR 파일만 포함하도록 경량화하여 이미지 최적화를 실현하고자 노력했습니다. 또한 빌드된 이미지는 latest, 빌드 번호, 커밋 해시 3개의 태그로 Docker Hub에 Push하여 버전 관리를 할 수 있도록 구현했습니다. </p>
<p>또한 Frontend용 Dockerfile은 Node 빌드 스테이지와 Ngnix 서빙 스테이지를 분리하여 관리했고 Vite 기반 정적 파일 처리 및 Ngnix 설정 적용을 명확히 하여 구현했고 최종적으론 용량 최적화를 시도한 이미지를 Docker Hub에 push하여 외부 K8s에서 바로 Pull 가능하도록 구현했습니다. </p>
<p><strong>Ingress 및 Nginx 구축</strong></p>
<p>또한 이번 프로젝트에서 Ingress 및 Nginx 구축은 Kubernetes 환경에서 서비스 라우팅을 효율적으로 구성하고 Vue 프론트엔드의 정적 파일을 안정적으로 서빙하는 것을 핵심 목표로 삼았습니다
이 설계는 서비스 접근성을 높이고 라우팅 및 자원 관리를 체계화하며 실전 운영 환경에서 발생할 수 있는 문제를 사전에 탐색하기 위한 실험적이자 실용적인 시도라고 생각합니다. </p>
<p>특히 Kubernetes 환경에서는 LoadBalancer 방식보다 Ingress Controller를 도입해 경로 기반 및 호스트 기반 라우팅을 설계하는 것이 관리와 확장성 측면에서 훨씬 유리하고 이번 프로젝트처럼 프론트엔드와 백엔드가 독립적으로 배포되고, 클러스터 내부에서 여러 서비스가 협력하는 구조에서는 Ingress 기반 경로 분리 설계가 필수적이라는 판단하에 다음과 같은 주요 내용들을 구현했습니다. </p>
<ol>
<li>Ingress로 서비스 라우팅 관리</li>
</ol>
<ul>
<li>프론트엔드(Vue)와 백엔드(Spring Boot)를 경로 기반으로 분리 라우팅을 구현했고 &#39;/&#39;는 프론트엔드, &#39;/boot&#39;는 백엔드로 트래픽을 전달하도록 설정했습니다. </li>
<li>또한 rewrite-target 및 proxy-body-size 같은 annotation을 통해 경로 해석과 대용량 요청 지원을 구축했습니다. </li>
</ul>
<ol start="2">
<li>Kubernetes Service로 내부 서비스 정의</li>
</ol>
<ul>
<li>클러스터 내부에서 통신하면 되기 때문에 ClusterIP로 프론트엔드, 백엔드 각각 내부 서비스 노출하고 포트 매핑을 통해 외부 요청과 컨테이너 내부 포트를 연결하였습니다. </li>
</ul>
<ol start="3">
<li>Nginx로 정적 자산 서빙 및 특수 프록시 구성</li>
</ol>
<ul>
<li>Vue 프로젝트 내의 Dockerfile에서 Nginx Alpine 기반 경량 이미지를 사용하여 Nginx 컨테이너를 실행하고 빌드된 정적 파일을 복사하고 Nginx 설정(nginx.conf)을 적용하여 정적 파일을 Nginx로 서빙하는 것을 구현하였습니다. </li>
<li>Nginx 설정에선 존재하지 않는 경로 접근시 /index.html로 fallback하도록 처리했고 /s3/ 경로 요청은 AWS S3 버킷으로 프록시 처리했으며 최대 30MB까지 요청을 처리할 수 있도록 설정하였습니다.</li>
</ul>
<p>동영상 처리를 위해 Presigned URL을 사용해 브라우저에서 S3로 직접 파일을 업로드할 때, CORS(Cross-Origin Resource Sharing) 문제가 발생했고 이를 해결하기 위해 Nginx 설정에서 Access-Control-Allow-* 헤더를 강제로 추가하여 클라이언트가 브라우저 환경에서 S3로 직접 접근할 수 있도록 조치하였습니다. </p>
<p>다만 현재 Ingress에는 TLS가 적용되지 않아 HTTPS로 운영하지 못하는 한계가 있고 추후 cert-manager 등을 연동해 TLS 인증서를 자동 관리하고, 보안성을 강화할 계획입니다. </p>
<p>또한 Helm Chart나 Kustomize를 도입해 환경별로 설정을 동적으로 관리하는 개선 방안도 반영하여 다음 파이널 프로젝트에서 시도해볼 예정입니다. </p>
<p><strong>무중단 배포 전략</strong>
이번 프로젝트에서 무중단 배포 전략은 Kubernetes의 Deployment 리소스를 중심으로 구현했습니다. 서비스 가용성을 유지하면서도 안정적으로 신규 버전을 배포하는 것을 목표로 하였고 이를 통해 운영 중에도 사용자가 서비스 중단을 느끼지 않게 하는 경험을 구현하고자 노력했습니다. 주요 구현 내용은 다음과 같습니다. </p>
<p>Deployment에서 strategy type을 RollingUpdate를 설정하여 기존 애플리케이션의 버전을 점진적으로 업데이트 하는 방식을 사용하여 무중단 배포를 구현하였습니다. 배포 시 추가 생성 가능한 최대 Pod 수와 배포 중 사용할 수 없는 최대 Pod 수를 1개로 설정하여 배포 중 최소한의 서비스 장애만 허용하고 항상 일정 수의 정상 Pod가 서비스 요청으 처리하도록 보장하였습니다. </p>
<p>이렇게 설정한 이유는 현실적인 테스트 환경제약 때문입니다. 
로컬 환경에선리소스 한계로 동시에 3개 이상의 Pod를 안정적으로 띄울 수 없었기 때문에 결국 테스트용 배포에선 최대 2개의 Pod까지만 운영할 수 있도록 구현했고 이로 인해 실제 운영 환경의 완전한 무중단 배포 시뮬레이션은 어려웠지만 구조 설계 및 파이프라인 연계 실험에선 충분한 학습 효과를 거둘 수 있었고 추후 AWS 배포 과정에선 더 많은 테스트를 해보길 기대하고 있습니다. </p>
<p><strong>PV 및 PVC 설정</strong>
저희 프로젝트에서는 데이터베이스로 MariaDB, 인메모리 캐시로 Redis를 사용했습니다. 이 두 컴포넌트 모두 Kubernetes 클러스터에서 운영될 때 단순히 컨테이너 레벨에서만 관리해서는 안 되며 특히 MariaDB는 데이터 영속성, Redis는 상태 데이터 유지 측면에서도 별도의 스토리지 설계가 필수적이라고 판단했습니다. </p>
<p>컨테이너는 언제든 재시작되거나 교체될 수 있기 때문에 컨테이너 내부의 디스크에 의존하면 데이터 손실 위험이 있고 때문에 K8S의 PV와 PVC 리소스를 활용했습니다. 해당 내용은 다음과 같습니다. </p>
<p>MariaDB의 경우 클러스터 내에서 독립된 스토리지 자원(PV)에 연결되어 컨테이너가 교체되더라도 임의로 지정한 /var/lib/mysql 경로에 저장된 데이터가 안전하게 보존되도록 설계했습니다. </p>
<p>PVC를 통해 Deployment가 필요한 스토리지 용량, 액세스 모드 등을 선언했고 PVC는 사전에 정의된 PV와 바인딩되어 컨테이너와 물리적 스토리지를 연결하는 역할을 수행하였습니다. </p>
<p><strong>ConfigMap과 Secret을 통한 환경 변수 설정</strong></p>
<p>저희는 프로젝트 구현때부터 외부 환경에 따라 달라질 수 있는 설정 값이나 민감 정보는 깃허브로 관리되면 보안상 취약하기 때문에 환경변수로 관리했었고 쿠버네티스 환경에서도 이미지로 하드코딩하면 관리 측면에서 보안상 큰 위협 요소가 될 수 있기 때문에 Kubernetes의 ConfigMap과 Secret을 활용하여 민감 정보와 비민감 정보를 구분하여 관리하였습니다.</p>
<p>우선 ConfigMap에선 ConfigMap(catchy-config)에는 비민감성 환경 설정 값들을 집중적으로 관리했습니다. 주요 항목은 다음과 같습니다. </p>
<ul>
<li>데이터베이스 접속 정보: DB_HOST, DB_PORT, DB_NAME, DB_USERNAME</li>
<li>JWT 관련 만료 시간: JWT_ACCESS_EXPIRATION, JWT_REFRESH_EXPIRATION</li>
<li>Redis 연결 정보: REDIS_HOST, REDIS_PORT</li>
<li>AWS, CloudFront, 프론트엔드 리다이렉트 URL, OAuth 클라이언트 ID</li>
</ul>
<p>이 값들은 서비스 실행 시 컨테이너 환경 변수로 주입되어 환경별로 손쉽게 교체 가능하며 코드나 이미지 변경 없이도 동적으로 반영될 수 있도록 설정을 했습니다. </p>
<p>Secret에는 외부에 노출되면 치명적인 민감 정보만을 관리했습니다. 주요 항목은 다음과 같습니다. </p>
<ul>
<li>데이터베이스 비밀번호: DB_PASSWORD, ROOT_PASSWORD</li>
<li>JWT 암호화 시크릿: JWT_SECRET</li>
<li>Redis 비밀번호: REDIS_PASSWORD</li>
<li>AWS Access/Secret Key, 각종 OAuth Client Secret</li>
</ul>
<p>Secret은 Kubernetes 내부에서 base64로 인코딩되어 저장되며,
RBAC(권한 관리) 및 Secret 마운팅 정책을 통해 외부 노출 위험을 최소화 했습니다. </p>
<p>이를 통해 운영 및 유지보수 효율성을 높이면서 민감 정보 노출 경로를 최소화 할 수 있었습니다. </p>
<p><strong>ArgoCD를 통한 K8S 클러스터 배포 자동화 구축</strong></p>
<p>위에서 언급한 바와 같이 ArgoCD를 활용한 GitOps 기반 배포 자동화 체계를 구축했고 이는 단순히 CI/CD 파이프라인으로 끝내는 것이 아닌 배포의 최종 단계인 K8S 클러스터 적용까지 모든 배포 프로세스를 Git을 통해 관리하도록 설계 및 구현하였습니다. </p>
<p>해당 과정은 Jenkins가 새로운 버전의 Docker 이미지를 빌드하고 Docker Hub로 푸시하는 동시에 K8S manifests GitHub 리포지토리도 함께 업데이트하는 작업을 진행했고 ArgoCD는 주기적으로 Git을 Pull해서 변경사항을 감지하고 만약 불일치가 감지되면 자동 동기화 설정을 통해 K8S 클러스터를 업데이트하도록 구현했습니다. </p>
<p>물론 ArgoCD의 자동 동기화는 휴먼 에러를 줄일 수 있고 편의성이 높은 기능이긴 하지만 잘못된 manifest가 커밋되면 실시간으로 클러스터에 문제가 전파될 수 있는 위험성도 내포하고 있어 ArgoCD를 통한 배포 자동화를 일부러 지원하지 않는 기업들도 많다고 들었습니다. 따라서 젠킨스 파이프라인에서 manifests 수정 전 체계적인 사전 Ling, 테스트, 검증 단계를 반드시 거쳐야 하며 안전하게 서비스가 업데이트가 될 수 있는 방안들을 고민해봐야 겠단 생각을 했습니다.</p>
<h2 id="배운점-및-느낀점">배운점 및 느낀점</h2>
<p>이번 프로젝트에선 저는 CI/CD 영역을 다루면서 Docker, Kubernetes, Ingress, Nginx, ArgoCD, Jenkins, GitHub Webhook, Discord Webhook, ELK 스택, Prometheus, Grafana, Spring Actuator 등 실로 다양한 DevOps 도구들을 한꺼번에 접하고 연동하는 경험을 했습니다. </p>
<p>처음에는 단순히 도구들을 연결해보자는 마음으로 시작했지만 이 과정이 결코 간단하진 않았습니다. 
예로들어 ArgoCD를 GitHub와 연동할 때, 처음에는 최신 인증 방식인 Fine-grained Personal Access Token(PTA)을 사용했지만 의외로 이 방식은 ArgoCD와의 호환성 문제를 일으켜 결국 Classic 버전의 Token으로 변경하자 문제가 해결되었는데 이는 모든 블로그들을 모두 찾아본 뒤에 알게된 방법이고 문제 해결 과정이 다소 허무하지만 최신 기능이 항상 호환성을 보장하지는 않는다는 중요한 교훈을 얻게 되어 다음에는 동일 문제가 발생하면 호환성 문제는 없는지 부터 확인해볼 것 같습니다. </p>
<p>그래도 CI/CD 자동화 및 배포 구현 경험을 통해 릴리즈 자동화의 전체 그림을 이해할 수 있었고 단순히 Jenkins에서 빌드 후 Docker 이미지 푸쉬에서 끝나는 것이 아니라 ArgoCD가 manifests 리포지토리를 감지해 배포까지 연동되는 End-to-End GitOps 흐름을 직접 설계해보니 CI/CD의 전체 흐름과 각 단계의 역할을 명확히 이해할 수 있게 된 것 같습니다. </p>
<p>그리고 K8S에 연결하진 못했지만 Docker Compose에서 Prometheus, Grafana, Actuator로 성능 모니터링을 붙이고, ELK 스택을 연계해 로그 수집 및 분석까지 시도하면서 각 도구의 역할과 실행 과정에 대한 대략적인 과정을 이해할 수 있게 되었습니다.</p>
<p>이제는 ArgoCD나 Jenkins 외에도 Tekton, Spinnaker, GitLab CI, CircleCI, Flux 등 다른 CI/CD 및 GitOps 툴들을 더 많이 직접 경험해보고 각각의 철학과 강점, 단점을 비교하여 저만의 DevOps 설계 역량을 넓히고 싶다는 열망이 강하게 생겼고 이를 통해 보안, 확장성, 멀티 클러스터 관리, Secret 관리, Canary/Blue-Green 배포 같은 운영 환경 수준의 고급 설계로 확장하여 웹 개발과 관련된 모든 프로세스를 이해하고 실제 구현할 수 있는 전문가가 될 수 있겠단 생각이 들어 매우 뿌듯하고 의미있던 프로젝트였던 것 같습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW CAMP 15기 19주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-19%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-19%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 01 Jun 2025 07:59:11 GMT</pubDate>
            <description><![CDATA[<h3 id="지나간-4개월-남은-기간-2개월">지나간 4개월, 남은 기간 2개월</h3>
<p>부트캠프 수료까지 이제 2개월도 채 남지 않았습니다. 지난 4개월을 되돌아보면 제 개인적인 기준에서는 결코 완벽하지 않았지만, 그동안 수많은 변화를 시도하며 크고 작은 성취를 일궈냈다고 생각합니다.</p>
<p>저는 학습의 본질을 ‘왜’, ‘무엇을’, ‘어떻게’로 구분합니다. 지난 4개월 동안 저는 그중에서도 특히 ‘왜’와 ‘무엇을’에 대한 이해를 깊이 확장할 수 있었습니다.</p>
<h3 id="왜와-무엇을을-학습한-과정">‘왜’와 ‘무엇을’을 학습한 과정</h3>
<p>저는 어떤 개념을 배울 때 반드시 ‘왜 중요한가’를 고민합니다. 물론 이유를 모른다고 해서 학습을 멈추는 것은 아니지만, 명확한 목표와 목적이 있을 때 몰입도와 학습 효과가 비약적으로 높아진다는 점을 깨달았습니다.</p>
<p>그래서 저는 평소 일부러 특정 개념이나 행동의 중요성을 정의해보고, 그 이유를 직접 만들어내려 노력합니다. 만약 이유를 도출하기 어렵다면 관련 맥락이나 역사적 배경을 조사해보며 자연스럽게 흥미를 붙입니다. 이 습관은 부트캠프에서 존경하는 양하 형님을 보며 배우게 되었고, 하루하루 따라하다 보니 어느새 저의 일상적인 학습 방식으로 자리 잡게 되었습니다(감사합니다, 형님 ㅎㅎ).</p>
<p>특히 클린코드 스터디에 참여한 것은 지금까지 선택한 것들 중에서도 손꼽히는 최고의 결정 중 하나였습니다. 혼자였다면 절대 읽지 않았을 로버트 마틴의 『Clean Code』를 정독하고, 발표 준비를 통해 내용을 소화했던 경험은 부트캠프의 어떤 경험과 비교해도 뒤처지지 않을 만큼 값진 배움이었습니다.</p>
<p>이 과정을 통해 왜 아키텍처를 고민해야 하는지, 왜 객체지향적인 설계가 중요한지, 왜 테스트 코드와 유지보수성을 고민해야 하는지 그 근본적인 이유를 이해할 수 있었습니다. 앞으로 남은 2개월 동안 욕심 같아서는 또 한 권의 책을 완독하고 싶지만, 설령 그럴 시간이 부족하더라도 이 경험만으로도 이미 충분히 값진 자산을 얻었다고 생각합니다.</p>
<p>저는 저희 15기 강사님을 만날 수 있었던 것이 큰 행운이었다고 생각합니다. 강사님은 수업 자체의 만족도를 넘어서 최대한 다양한 기술 스택과 방법론을 전달해주시려 노력해주셨고, 덕분에 제가 무엇을 배우고 익혀야 하는지에 대한 폭을 크게 넓힐 수 있었습니다.</p>
<p>자료구조와 알고리즘도 유형별로 체계적으로 정리해주셔서, 코딩 테스트를 어떻게 준비해야 할지 명확한 틀을 가질 수 있었고, 매일 채용 공고를 보며 어떤 기술을 추가 학습해야 할지 점검하고 프로젝트에 적용해보려 시도했던 경험 역시 중요한 성장의 발판이 되었습니다. 앞으로 남은 2개월 동안은 이전 프로젝트에서 미처 시도하지 못했던 기술들을 최대한 실험하며, 더 많은 경험을 쌓는 데 주력할 계획입니다.</p>
<h3 id="프로젝트-경험이-준-교훈">프로젝트 경험이 준 교훈</h3>
<p>저희 부트캠프는 다른 부트캠프들보다 프로젝트 수가 많고 학습 범위도 넓어, 특정 분야를 깊게 파고들기는 다소 어렵다는 단점이 있지만, 저에게는 오히려 이 점이 큰 장점으로 다가왔습니다.</p>
<ul>
<li>Web Application의 전반적인 생태계에 대한 이해</li>
<li>프로젝트를 통해 주요 개념의 의미와 중요성에 대한 인식</li>
<li>반복 프로젝트에서 자연스럽게 고안한 효율적인 작업 방식</li>
</ul>
<p>처음 부트캠프에 입소했을 당시, 저는 프론트엔드를 제외한 DB, 백엔드, 배포 개념에 대해 전무했습니다. 매일같이 쏟아지는 새로운 개념들 앞에서 벅참을 느꼈고, ‘내가 과연 이 길이 맞는가’ 하는 의문을 반복해서 품곤 했습니다. 그럼에도 불구하고 이미 선택한 길이니 부트캠프에서만큼은 의문을 잠시 접어두고 하나하나 차근히 배워나갔으며, 매일 전력을 다해 몰입했습니다. 그렇게 할 수 있었던 큰 이유 중 하나는 매달 주어지는 프로젝트 덕분이었습니다.</p>
<p>혼자 공부했다면 조금만 벽에 부딪혀도 포기했을지 모르지만, 팀원들의 포트폴리오에 들어갈 프로젝트를 함께 만들어야 했기에 ‘내가 맡은 부분만큼은 반드시 완수하자’는 마음으로 정신없이 달려왔고, 그 결과 이제는 팀원들에게도 실질적인 도움을 줄 수 있는 수준까지 성장할 수 있었습니다.</p>
<p>반복된 프로젝트 경험은 효율성을 높이는 것뿐 아니라 팀원들과 함께 컨벤션을 정의하고 그것을 따르며 개발해보는 협업의 과정을 배우게 해주었습니다. 이는 저에게 매우 뜻깊은 경험이었고, 앞으로도 제가 개발자로서 성장하는 데 중요한 밑거름이 될 것이라 확신합니다.</p>
<h3 id="인생을-계획하기">인생을 계획하기</h3>
<p>학습이라는 범주에서는 의미 있는 성과를 거둔 4개월이었지만, 가장 개선하지 못한 부분은 단연 시간 관리였습니다. 제 시간을 온전히 제어하는 데 매일 실패했고, 매일 세우는 계획은 많았지만 정작 그중 60%도 채 실행하지 못했습니다.</p>
<p>가장 큰 문제는 제 욕심이 지나쳤다는 점이며, 여전히 자기 분석이 부족하다는 사실을 인정해야 할 것 같습니다. 최근에는 체력이 점점 떨어지는 것을 실감하면서 운동의 필요성을 절실히 느끼게 되었고, 이제 남은 기간 동안에는 시간을 더 세분화하고 치밀하게 관리하는 것이 무엇보다 중요하다고 생각합니다.</p>
<p>잠자는 시간, 운동하는 시간, 공부하는 시간, 코딩 테스트 준비, 이력서 작성까지 모든 활동을 명확한 계획 아래에서 움직이고자 합니다. 거창한 계획보다는 오늘부터 실천할 수 있는 작은 실행들을 하나씩 이어가는 방식으로 가려고 합니다.</p>
<p>이를 위해, 제가 애정하던 시간 관리 템플릿을 V2로 리팩토링할 예정입니다. 현재의 템플릿은 자동 일정 추가 버튼, 퀘스트, 목표, 메모장 등 많은 기능을 사실상 활용하지 않고, 새로 알게 된 내용을 단순히 적어두는 용도로만 쓰고 있기에 앞으로는 체크리스트 중심의 WBS 관리와 최종 학습 정리용으로 개선하려 합니다. 리팩토링이 완료되면 꼭 공유드리겠습니다.</p>
<h3 id="앞으로의-계획">앞으로의 계획</h3>
<p>남은 2개월 동안은 ‘어떻게’를 채워가는 시간이 될 것 같습니다. 이제 코딩 테스트 준비도 어떤 유형을 공부해야 할지, 기술 스택도 어떤 부분을 확장해야 할지 감이 잡혔으니, 앞으로는 문제 풀이 및 실전 적용, 그리고 취업 준비에 집중할 생각입니다.</p>
<p>취업 스터디도 시작해 함께 코딩 테스트를 풀고, 이력서를 작성하며, 면접을 준비하고, 필요하다면 필요한 기술 스택이나 정보들을 서로 공유하며 학습할 계획입니다.</p>
<p>긴 글 읽어주셔서 진심으로 감사드리고 남은 시간 저도, 그리고 이 글을 읽는 여러분도 끝까지 힘내며 한 걸음씩 나아가길 응원합니다. 감사합니다!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BE15 프론트엔드 링크업 프로젝트 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BE15-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A7%81%ED%81%AC%EC%97%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BE15-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A7%81%ED%81%AC%EC%97%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 25 May 2025 01:48:25 GMT</pubDate>
            <description><![CDATA[<h2 id="프로젝트-회고">프로젝트 회고</h2>
<h3 id="1-프로젝트-개요">1. 프로젝트 개요</h3>
<p>이번 프로젝트는 제가 발표를 진행했고 해당 내용은 유튜브에 업로드했습니다. 관심 있으신 분들은 아래 링크 참고하셔서 시청 부탁드리겠습니다.</p>
<p><a href="https://youtu.be/Mdms5gXJTPc">BE15 프론트엔드 링크업 프로젝트 발표영상</a></p>
<p>이번 프로젝트는 프론트엔드 프로젝트다보니 화면을 어떻게 설계했는지와 관련하여 짧게 소개해드리겠습니다. </p>
<p>우선 이번 프로젝트에서 사용한 기술스택은 다음과 같습니다. </p>
<p><strong>기술스택</strong></p>
<table>
<thead>
<tr>
<th>구분</th>
<th>사용한 기술</th>
</tr>
</thead>
<tbody><tr>
<td>💻 Backend</td>
<td>Java, Gradle, SpringBoot, Spring Security, JPA, MyBatis, JWT, JUnit5, Swagger</td>
</tr>
<tr>
<td>🎨 Frontend</td>
<td>HTML5, CSS3, JavaScript, Vue.js, Bootstrap, Pinia</td>
</tr>
<tr>
<td>📦 Database</td>
<td>MariaDB, Amazon S3</td>
</tr>
<tr>
<td>🛠️ Tool</td>
<td>Git, GitHub, Postman, Notion, Figma, Miro, Google Sheets, Discord</td>
</tr>
</tbody></table>
<p>발표 영상을 보시면 아시겠지만 저희 링크업은 기획부터 화면설계, 그리고 구현까지 프론트엔드 개발에 필요한 모든 단계들을 설계하고 실행했습니다. </p>
<p>다음은 저희가 피그마 툴을 사용해서 직접 디자인하고 설계한 화면 설계서입니다. </p>
<p><strong>피그마 화면 설계서</strong>
<img src="https://velog.velcdn.com/images/low_level_v99/post/ab6141b2-e0fd-4dee-9468-55f3d1012e60/image.png" alt=""></p>
<p>화면 설계 기간을 1주 정도로 잡았는데 저희가 디자인해야 하는 페이지는 70 페이지가 넘었습니다. 그래서 저희는 백엔드 프로젝트에서 담당한 도메인별 페이지를 제작하게 되었고 최대한 효율적이고 유지보수성이 높으면서 디자인 통일성을 줄 수 있는 컴포넌트를 설계했습니다. </p>
<p><strong>컴포넌트 설계</strong>
<img src="https://velog.velcdn.com/images/low_level_v99/post/058fd899-7cfa-4dcd-a245-300a7985a6a6/image.png" alt=""><img src="https://velog.velcdn.com/images/low_level_v99/post/86bc8f30-a74a-449f-8c9e-bc431a3d6418/image.png" alt=""></p>
<p>또한 디자인을 각자 진행하다보니 서로 사용하는 색이 다르고 요소와 요소간의 여백이나 사용하는 폰트나 둥글기나 그림자 같은것이 다르다는 것을 깨닫고 이러한 디자인과 관련된 컨벤션을 정리할 필요성을 깨닫고 팀원분들이 보고 참고할 수 있도록 디자인 시스템을 설계했고 그 결과물은 다음과 같습니다. 피그마 스타일에도 적용하여 페이지 제작시에 필요한 색상이나 폰트들을 사용할 수 있도록 설정도 하였습니다. </p>
<p><strong>디자인 시스템 설계</strong>
<img src="https://velog.velcdn.com/images/low_level_v99/post/78681298-8dce-4073-a3dc-e765a3b066a7/image.png" alt=""><img src="https://velog.velcdn.com/images/low_level_v99/post/ca465ac6-6dda-464e-813f-349782e40666/image.png" alt=""><img src="https://velog.velcdn.com/images/low_level_v99/post/3621bbec-088c-41d1-945b-3f8c6b44c79b/image.png" alt=""><img src="https://velog.velcdn.com/images/low_level_v99/post/36f1c895-ea9c-4753-b680-d285fff2a3cf/image.png" alt=""></p>
<h3 id="2-하고-싶었던-것-및-아쉬운점">2. 하고 싶었던 것 및 아쉬운점</h3>
<p>저는 원래 미디어커뮤니케이션 전공하면서 프론트엔드 개발을 공부했었고 이전 기획 회사에서 일했을 때 프로모션 페이지를 제작하고 배포했던 경험이 있기 때문에 시도해보고 싶었던 것이 많았는데 저번 백엔드 프로젝트와 동일하게 역시 해보고 싶었던 것을 모두 해내지 못해 아쉬운 마음이 큽니다. </p>
<p>우선 저는 다음과 같은 것들을 해보고 싶었습니다.</p>
<ul>
<li>디자인 시스템 설계</li>
<li>컴포넌트 및 레이아웃 설계</li>
<li>Git Webhook 및 Husky 적용</li>
<li>반응형 레이아웃 구현</li>
<li>Typescript를 사용하지 못하는 상황에서 타입 안정성 챙기기</li>
<li>API 타입 동기화</li>
<li>SEO 향상을 위한 SPA 페이지에서의 메타 태그 정보 설정하기</li>
<li>성능 측정: LAI(Loading And Intersection) 및 개선하기</li>
<li>예외 처리 설계</li>
<li>로그인 상태 유지</li>
<li>무한 스크롤</li>
<li>자동 응답 캐싱 및 상태 관리</li>
<li>컨벤션 유지를 위한 ESLint 적용</li>
</ul>
<p>위에서 제가 이번 프로젝트에서 진행해본 것은 디자인 시스템 및 컴포넌트를 설계해보거나 예외 처리 및 로그인 상태 유지, 무한 스크롤 등만 적용해보고 그 외에는 시도해보지 못했습니다. </p>
<p>제가 우연찮게 <a href="https://www.youtube.com/watch?v=cpE1dwJgS4c&amp;t=1146s">네이버 테크 콘서트</a>를 보면서 성능을 개선하는 것에 대한 큰 갈망을 느끼면서 이번 프로젝트에 꼭 적용해보고 싶었는데 시도해보지 못했다는 것에 매우 큰 아쉬움을 느끼고 SPA의 문제점 중 하나인 SEO 개선에 대하여 시멘틱 태그를 사용하거나 접근성을 높이는 등의 시도는 했지만 결국에는 가장 중요한 페이지별 메타 정보를 설정하지 못해 이것역시 너무나 아쉬움이 큽니다.</p>
<p>다음 데브옵스 프로젝트에선 해당 내용들을 적용해볼 시간은 없겠지만 꼭 최종때는 적용해 볼 것을 다짐하며 이번 아쉬움은 다음의 성공을 위한 발판이라고 생각하며 아쉬운 마음을 가라앉치고 다음은 제가 무엇을 했는지에 대해 작성해보고자 합니다. </p>
<h3 id="3-내가-한-것">3. 내가 한 것</h3>
<p>우선 제가 이번 프로젝트에서 한 것에 대해 정리한 것은 다음과 같습니다.</p>
<ul>
<li>Vue 프로젝트 구조 설계</li>
<li>컴포넌트 및 레이아웃 설계</li>
<li>피그마 스타일 시스템과 tailwind 연결</li>
<li>전역 인증 상태 관리 및 네비게이션 가드 설정</li>
<li>axios 인터셉터를 통한 전역 요청 및 응답 관리</li>
<li>무한 스크롤 상태관리 로직 구현</li>
</ul>
<p>우선 저희 프로젝트 구조는 다음과 같습니다.</p>
<p><strong>프로젝트 구조</strong></p>
<pre><code>📦 LinkUp
├── 📁 linkup.src
│   ├── 📁 api
│   │   ├── 📄 admin.js
│   │   ├── 📄 axios.js
│   │   ├── 📄 user.js
│   │   ├── 📄 place.js
│   │   ├── 📄 community.js
│   │   └── 📄 meeting.js
│   │   
│   ├── 📁 assets
│   │   ├── 📁 css
│   │   ├── 📁 icons
│   │   └── 📁 images.js
│   │   
│   ├── 📁 components
│   │   ├── 📁 command
│   │   └── 📁 layout
│   │   
│   ├── 📁 composables
│   │   ├── 📄 useLoadingBar.js
│   │   └── 📄 usePaginaition.js
│   ├── 📁 features
│   │   ├── 📁 admin
│   │   ├── 📁 auth
│   │   ├── 📁 community
│   │   ├── 📁 meeting
│   │   ├── 📁 place
│   │   ├── 📁 point
│   │   └── 📁 user
│   │   │    ├── 📁 views
│   │   │    ├── 📄 router.js
│   │   │    └── 📁 components
│   ├── 📁 router
│   │   ├── 📄 index.js
│   ├── 📁 stores
│   │   ├── 📄 auth.js
│   ├── 📁 util
│   │   ├── 📄 toast.js
│   ├── 📁 tokens
│   │   └── 📄 design-tokens.json
│   ├── 📄 App.vue
│   └── 📄 main.js
</code></pre><p>feature 기반의 아키텍처를 설계했고 DDD 설계에서 나눈 도메인과 동일하게 기능을 나눈뒤 각각의 기능에 views, router, components를 관리했고 각각의 도메인에서 사용하는 api들은 한눈에 보기 쉽게 상단에 api 디렉토리 안에서 관리했습니다. </p>
<p>재사용되는 컴포넌트나 레이아웃은 최상단 components 디렉토리에서 관리했고 특정 도메인에 종속된 컴포넌트와 페이지만 각각의 도메인에서 관리하도록 역할을 분리했고 모든 도메인에서 재사용되는 컴포넌트의 경우엔 최대한 재사용할 수 있도록 도메인별 종속성을 없애는데 초점을 맞춰 구현하였습니다. </p>
<p><strong>컴포넌트 및 레이아웃 설계</strong></p>
<p>화면 설계 및 컴포넌트 설계는 위에 개요에서 설명드린 내용과 동일하고 추가적으로 저는 화면을 설계하다보니 공통되는 레이아웃의 종류가 총 3개라는 것을 알게되었습니다.</p>
<p>그 종류는 크게 다음과 같습니다</p>
<ul>
<li>SidebarMainLayout</li>
<li>FullCenterMainLayout</li>
<li>DefaultMainLayout</li>
</ul>
<p>SidebarMainLayout은 회원쪽 페이지와 모임 및 장소 조회 페이지에서 사용되는 레이아웃입니다. </p>
<p>FullCenterMainLayout은 모든 모달 및 로그인과 같이 수직-수평 가운데 정렬이 필요한 레이아웃입니다. </p>
<p>DefaultMainLayout은 수평으로만 가운데 정렬되는 기본적인 레이아웃입니다. </p>
<p>각각의 레이아웃에 대해서 width, height, paddin 등을 설정했고 공통 레이아웃이기 때문에 특정 도메인에 종속되지 않도록 필요하면 호출하는 쪽에서 class를 전달하여 적용될 수 있도록 구현하였습니다. </p>
<p>그리고 팀원분들이 쉽게 사용할 수 있도록 아래와 같이 컨벤션을 정리하여 공유한 내용은 다음과 같습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/df8ae2e2-a44b-4a03-8989-7fa992506a94/image.png" alt=""></p>
<p><strong>피그마 스타일 시스템과 tailwindCSS 연결</strong></p>
<p>저희는 이번 프로젝트에서 tailwindCSS 프레임워크를 사용하여 효율적으로 CSS를 적용할 수 있도록 했습니다.  </p>
<p>위의 개요에서 피그마 스타일을 설정하여 화면 설계부터 컬러 팔레트나 폰트 같은 것들을 맞춘바 있다고 했는데요, 피그마에서 설계한 스타일 시스템을 tailwindCSS로 가져오는 것이 디자인 통일성과 화면 설계와 구현을 일치하는데 무엇보다 중요했습니다. </p>
<p>따라서 처음에는 자동화를 위해 Style Dictionary 라이브러리를 사용하여 피그마 디자인 토큰 스튜디오 플러그인에서 추출한 JSON 파일을 TailwindCSS 버전으로 변환하는 자동화 과정을 구현했으나 마음처럼 되지는 못했고 어쩔 수 없이 수동으로 tailwind.config.js 파일을 피그마 스타일 시스템과 동일하게 맞춰 화면 설계와 구현의 일관성을 맞추는데 성공하게 되었습니다. </p>
<p>다만 아직 자동화를 하지 못했기 때문에 화면 설계가 모두 맞치지 못한 상태에서 디자인과 개발이 동시에 일어나야 하는 상황이라면 유지보수가 어렵다는 문제가 아직 남아 있기 때문에 다소 아쉬운 구현이라고 할 수 있습니다. </p>
<p>따라서 다음 최종 프로젝트에선 꼭 피그마 -&gt; tailwind.config.js 변환을 자동화하는 시스템을 구축하는 것을 목표로 하고자 합니다. </p>
<p><strong>전역 인증 상태 관리 및 네비게이션 가드 설정</strong></p>
<p>저는 백엔드 프로젝트때도 회원 및 인증 및 인가 상태 관리 전체를 담당했었기 때문에 프론트엔드 개발에 있어서도 해당 도메인을 주로 맡아 담당했습니다. </p>
<p>우선 기존 Postman에서 api 테스트를 진행했을땐 CORS 정책에 대한 고민을 안했었는데 Vue 호스팅 도메인에서 axios로 api를 연결할 땐 다른 도메인에서 호출을 하게되므로 CROS 문제가 발생하였고 저희는 Spring Gateway에서 모든 인증을 처리했기 때문에 Spring Gateway의 application.yml에서 다음과 같이 CORS 설정을 추가하게 되었습니다.  </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/a10e94ec-d003-423f-9916-5abfeaa8605a/image.png" alt=""></p>
<p>그리고 기존에는 로그인을 성공하게 되면 응답으로 body에 accessToken과 refreshToken을 담아서 보냈는데 그렇게 되면 accessToken과 refreshToken 모두 localStorage나 인메모리나 세션등에 저장해야 하는데 accessToken은 유효시간이 짧기 때문에 문제가 될 여지가 적지만 refreshToken을 localStorage나 인메모리에 저장하는 것은 스크립트 구문 실행을 통해 탈취될 여지가 있기 때문에 스크립트로 접근할 수 없는 HttpOnly 쿠키에 담아서 보내는 것으로 수정하였고 accessToken은 접근성과 짧은 유효시간을 고려하여 인메모리, 즉 Pinia 전역 상태에서 관리하는 것으로 결정하였습니다. </p>
<p>이와 관련하여 추가한 메서드는 다음과 같습니다. 
<img src="https://velog.velcdn.com/images/low_level_v99/post/471c6042-ef6b-4ada-87df-7f03d38680ed/image.png" alt=""></p>
<p>쿠키 설정에 대한 소스코드들은 유틸 클래스로 관리하도록 구현했습니다. 
<img src="https://velog.velcdn.com/images/low_level_v99/post/04a8147a-7e01-4662-8255-d67131bd41ba/image.png" alt=""></p>
<p>그리고 Vue에서 login api를 호출하여 전달받는 accessToken뿐만 아니라 페이지내에서 빈번하게 재사용되는 값들은 로그인시에 body에 추가적으로 포함하여 전달하고 이것들을 모두 useAuthStore에서 관리했습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/a8ed4e87-c89c-4069-a527-f5e7d25f7305/image.png" alt=""></p>
<p>인증과 관련한 모든 코드들 예로들어 login, logout, refresh, clearAuth 메서드는 모두 useAuthStore에서 집중 관리하도록 하였고 필요시에 가져다 사용할 수 있도록 구현했습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/ec11360f-4a21-4bb9-ae5c-12bc2f54d86e/image.png" alt=""></p>
<p>그리고 새로고침 시에 accessToken이 초기화가 되면서 인증 상태게 해제되는 문제가 있는데 해당 문제는 main.js에서 초기화와 관련된 코드들을 함수로 묶어서 마운트 시점에 호출될 수 있도록 하였고 매번 초기화 될 때마다 authStore에서 관리하는 refresh 메서드를 호출하여 현재 HttpOnly 쿠키에 저장된 refreshToken으로 서버에 전달하여 refreshToken이 DB에서 관리되고 있는 값이 맞다면 새로운 accessToken과 refreshToken을 다시 전달하여 인증 상태를 유지할 수 있도록 구현하였습니다.</p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/34f23fd3-b9ed-46da-83b5-b43c954ae1ac/image.png" alt=""></p>
<p>그리고 저희는 총 3개의 권한이 있습니다. user, business, admin인데요. 페이지별로 접근 권한이 각기 달랐기 때문에 도메인으로 접속하지 못하도록 네비게이션 가드를 설정해야 했고 인증이 필요한 페이지의 경우에는 설정한 라우터 메타 정보로 판별했고 권한의 경우엔 useAuthStore에서 관리하는 role로 접근 여부를 판별하여 권한별 가드를 설계했습니다. </p>
<p>그리고 인증이 필요한 페이지의 경우에는 로그인 리다이렉트 하도록 설정했는데 이때 사용자 경험을 향상하기 위해 로그인 성공을 하게 되면 원래 이동하려고 했던 도메인으로 이동 할 수 있도록 query에 리다이렉트 정보를 포함하고 다음 페이지 이동시에 해당 정보를 추출하여 해당 페이지로 이동할 수 있도록 구현하였습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/beb6c811-2b18-4d09-8a23-2a820b0aedda/image.png" alt=""></p>
<p><strong>axios 인터셉터를 통한 전역 요청 및 응답 관리</strong></p>
<p>저는 저번 백엔드 프로젝트부터 응답에 대한 통일성을 무엇보다 중요시했고 예외처리도 모두 동일한 ErrorResponse를 사용하도록 구조를 설계했습니다. </p>
<p>그래서 프론트에서도 axios 인터셉터를 설정하여 성공 응답의 경우엔 성공 toast 알림이 뜨도록 설정하고 에러 응답의 경우엔 ErrorCode에 따라 응답 자체가 없으면 네트워크 에러로 판별하였고 만약에 refresh token에 대한 요청중 401 에러가 나면 토큰이나 인증에 문제가 있는 것이기 때문에 바로 로그아웃 처리가 되도록 하였고 그 외의 api 호출에 401 에러가 발생했고 만약에 그것이 2번 이상 동일한 api 호출의 경우라면 로그아웃 처리하도록 하였습니다. </p>
<p>왜냐하면 api 호출에 있어서 401 에러가 발생할 수 있는 가능성은 JWT 토큰의 유효시간이 만료된 것으로만 한정을 했고 그런 경우에는 refresh 메서드를 호출하여 accessToken과 refreshToken을 새로 발급받아서 기존 api 연결을 다시 보내도록 설정했는데 만약에 2번 호출했는데도 401에러가 발생하면 토큰에 문제가 있다는 것이기 때문에 무조건 로그아웃 처리하도록 하였습니다. </p>
<p>그리고 추가적으로 저희는 ErrorCode를 명확하게 분기했기 때문에 403 에러가 나면 권한이 없다는 Toast 알림을 날리도록 했고 기타 500 에러면 서버에 문제가 있다는 알림을 전송하도록 하였습니다. </p>
<p>그리고 요청시에도 Pinia 전역 상태에서 관리하는 JWT 토큰을 Header의 Authorization에 넣어 보낼 수 있도록 요청 시 인터셉터를 설정하기도 했습니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/af2684a4-61e9-4bfa-8ee6-b55a1e22eb17/image.png" alt=""></p>
<h3 id="4-배운점-및-느낀점">4. 배운점 및 느낀점</h3>
<p>프론트엔드 프로젝트를 3주 정도 진행한 것 같은데 3개월은 한 것만큼 치열하게 준비하긴 했지만 욕심이 많았던 탓에 아쉬움이 크게 남는 것 같습니다. </p>
<p>저번 백엔드 프로젝트에서 문서화에 대한 중요성을 인식하고 이번에 컨벤션을 정리하려고 노력했지만 저 역시 Vue를 처음 사용하고 익히는데 급급하다 보니 모든 컨벤션을 정리하는데 큰 어려움을 느꼈고 다음 프로젝트에선 컨벤션을 미리 모두 정하고 진행하는 것이 중요할 것 같습니다. </p>
<p>그러면 여태까지 긴 글 읽어주셔서 감사드리고 다음 프로젝트 회고에서 뵙도록 하겠습니다. 감사합니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW CAMP 15기 16주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-16%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-16%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 11 May 2025 05:37:30 GMT</pubDate>
            <description><![CDATA[<h3 id="프로젝트가-끝이나고">프로젝트가 끝이나고</h3>
<p>13주차 회고 이후 한주라도 회고를 작성하지 않으면 동기분들께 커피를 사겠다는 공략을 걸자마자 15주차에 바로 회고를 작성하지 않는 일이 생기게 되었습니다... 쉬쉬할 생간은 없기에 날이 좋은날 우리 애쓰시고 고생하시는 동기분들께 커피나 아이스티 한잔 돌리도록 하겠습니다...ㅎ</p>
<p>어쨋든 프로젝트가 어제 막 부랴부랴 끝이 나게 되었는데 DB 프로젝트나 백엔드 프로젝트처럼 프로젝트 리뷰를 심도있게 작성할 생각이고 평소 공부하는데 있어선 체력이 딸린다곤 생각 안했는데 요즘 좀 힘들단 생각이 들어 오늘 하루정돈 휴식을 취하고자 합니다. </p>
<p>역시 게임도 알면 알수록 재밌는 것처럼 개발도 알면 알수록 재밌는 것 같습니다. 특히 요즘 유지보수성과 서비스 안정성에 신경을 많이 쓰다보니 새로운 아키텍처를 학습하거나 어떻게하면 더 효율적인 협업이 가능하고 안전하게 서버를 운용할 수 있을지를 막 고민하게 되는데 이 역시 알면 알수록 재밌고 보람찬 것 같습니다.</p>
<p>개발을 오래오래 하고 싶고 진짜 전문가가 되고 싶습니다. 어쩌다 돌아가는 어플리케이션이 아닌 돌아갈 수밖에 없는 어플리케이션을 만들고 싶고 영화도 모든 장면 하나하나에 의미가 담긴 작품을 좋아하는데 제가 만드는 앱 역시 모든 코드에 이유가 포함되고 보는사람으로 하여금 아름다움을 느낄 수 있는 코드를 작성하고 싶습니다. </p>
<p>또한 이제 부트캠프 종료시점까지 앞으로 단 2달 정도 남았는데 너무 재밌을 것 같습니다. 특히 파이널에서 멘토분에게 티칭을 받고 코드 리뷰를 받을 수 있다는 것은 매우 기쁘고 앞으로 더 많은 성장을 할 수 있을 것 같아 기대가 큽니다. </p>
<p>오늘 회고는 이것으로 마치도록 하겠습니다. 모두들 수고하셨습니다!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW CAMP 15기 14주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-14%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-14%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 27 Apr 2025 15:17:33 GMT</pubDate>
            <description><![CDATA[<h2 id="14주차에-대하여">14주차에 대하여</h2>
<h3 id="회고-공략에-대하여">회고 공략에 대하여</h3>
<p>지난주 저는 스스로에게회고를 작성하지 않으면 동기들에게 커피를 대접한는 공약을 걸었습니다. 이 단순한 약속이 생각보다 큰 심리적 동인이 되었고 일요일 늦은 저녁이 되어도 회고를 반드시 마쳐야 한다는 강한 의지를 부여했습니다.
비록 커피를 대접하는 일 자체는 즐거운 경험이지만 자발적으로 스스로에게 제약을 부여하는 것이 실제 실행력을 높인다는 사실을 체감할 수 있었습니다.</p>
<p>앞으로 꾸준한 기록 습관을 만들고 싶은 분들께 자발적 공약 설정을 강력히 추천드리고 싶습니다.</p>
<h3 id="피그마-ui-설계">피그마 UI 설계</h3>
<p>이번 주는 특히 피그마를 통한 UI 설계에 많은 시간을 할애했습니다.</p>
<p>현재 저희 팀은 약 154개의 API를 관리하고 있으며 이 중 45개의 API와 그에 따른 페이지 설계를 담당하고 있습니다.</p>
<p>전공 시절 2주간 20개를 넘는 페이지를 만들어본 경험이 있었지만 이번에는 그 두 배를 넘어서는 분량을 혼자 소화해야 하는 상황이었습니다.</p>
<p>기존 방식으론 설계를 완수하는 것이 사실상 불가능하다고 판단하였고 여러 방법을 찾던중 html.to.design 플러그인을 발견했습니다. 해당 플러그인은 HTML+CSS로 구축한 페이지를 피그마로 변환해주는 기능을 제공하고 더 놀라운 것은 Flexbox 구조까지 인식하여 초벌 설계를 빠르게 완성할 수 있게 도와준다는 것이었습니다. </p>
<p>하지만 자동화로 생성된 결과물은 역시나 유지보수성이 떨어진다는 문제가 있었고 이를 보완하기 위해 우선 피그마를 다시 공부하게 되었고 과거 기억들을 스멀스멀 다시 가져와서 Auto Layout과 컴포넌트화 기능을 사용하여 플러그인이 만들어주는 산출물에서 유사한 구조를 컴포넌트로 추출하고 디자인 토큰을 정리하여 재사용성과 통일성을 높일 수 있었습니다. </p>
<p>결과적으로 저는 일주일 만에 45개 이상의 페이지를 도출할 수 있었고 많은 페이지를 만들다 보니 자주 쓰는 색상이나 글꼴, 여백과 같은 것들을 정리해야 겠단 생각을 하게 되었고 이를 기반으로 디자인 시스템을 도출하여 자연스럽게 하나의 통일된 톤 앤 매너를 갖춘 어플리케이션을 만들 수 있게 되었습니다. </p>
<p>저는 서비스 전체의 레이아웃이 일관되어야 사용자 경험이 좋아진다라고 생각하는편입니다. 그래서 레이아웃의 경우에도 개발 관점에서의 효율성 뿐만 아니라 디자인 일관성과 통의성을 통한 사용자 경험을 높이기 위해 레이아웃을 크게 세가지 유형으로 나눠보았습니다. </p>
<p>레이아웃 유형 세가지</p>
<ul>
<li>사이드바 + 메인형(마이페이지, 사업자 마이페이지)</li>
<li>독립형 메인형(포인트 충전, 환불 등)</li>
<li>풀스크린 중앙정렬형(로그인, 회원가입, 복구신청 등)</li>
</ul>
<p>계속해서 반복한 페이지들의 공통적인 레이아웃을 쪼개봤을 때 위의 세개의 레이아웃에 포함된다는 것을 알게 되었고 각각의 유형에 대해 넓이, 높이, 패딩, 마진 등을 설정하고 그 안에 main만 변경하다보니 매우 효율적으로 페이지를 추가할 수 있게 되었고 이 뿐만이 아니라 통일된 어플리케이션을 구성하게 되어 개발 효율성과 유지보수성을 크게 끌어올리면서 사용자 경험도 높일 수 있는 설계를 할수 있게 된 것 같아 매우 큰 기쁨을 느끼게 되었습니다. </p>
<p>그리고 저는 프론트엔드에선 사용자 중심 UI 설계가 매우 중요하다고 생각하고 이탈률 최소화와 직관성 강화를 위해 모임 개설처럼  입력해야 할 정보가 많은 플로우에서 한 화면에 모든 정보를 입력받게 하면 이탈률이 증가한다는 것을 UX 원칙에서 학습한 바 있어 다음과 같은 방식으로 해결하게 되었습니다.</p>
<p>문제해결 방법</p>
<ul>
<li>정보를 세 단계로 나누어 받는 구조로 설계하기</li>
<li>각 단계별로 명확한 피드백을을 주기</li>
<li>선택한 버튼에 색상 변화를 주어 직관성을 강화하기</li>
<li>모바일 사용성을 고려하여 모든 버튼/입력 요소의 터치 영역을 최소 44px 이상 확보하기</li>
</ul>
<p>이를 통해 결과적으로 사용자의 피로도도 낮추고 이탈률을 낮추는 UI 흐름을 구축할 수 있게 되었습니다. </p>
<h3 id="리액트와-vue의-차이">리액트와 Vue의 차이</h3>
<p>이번 주는 Vue.js를 처음 접하게 되었습니다. 처음에는 JSX의 부재, 번거로운 속성 설정 등으로 인해 Vue에 부정적인 인상을 받았습니다. 하지만 양방향 바인딩을 경험하면서 생각이 바뀌었습니다. React에서는 상당한 수작업이 필요한 바인딩 작업을 Vue는 자연스럽게 처리해주었고 학습 진입 장벽이 낮은 프레임워크라는 Vue의 특성을 직접 체감할 수 있었습니다.</p>
<p>그리고 익숙한 기술을 넘어서 다른 프레임워크의 사고방식을 접하는 것은 성장에 크게 도움이 된다는 것을 다시한번 깨닫게 되는 경험이었던 것 같습니다. </p>
<h3 id="토스-api를-보면서">토스 api를 보면서</h3>
<p>어쩌다가 토스 api 설계에 대한 설명을 해주는 토스에서 제공하는 공식 유튜브 영상을 보게 되었는데 정말 많은 깨달음을 얻게 되었습니다. </p>
<p>제가 해당 영상에서 확인하기론 온라인 결제가 필요한 가맹점의 경우에 PG 시스템을 통해 카드사 인증 호출부터 승인, 매입 처리 등을 진행하게 되는데 기존 PG 연동의 경우에 가맹점 서버에 의존이 생기는 모듈을 설치해야만 했고 이해하기 힘든 요청 / 파라미터들을 넘기도록 해서 고객 중심으로 보면 조금 아쉬운점이 있는 서비스를 제공했고 토스페이먼츠는 결제 자체와 연관된 경험뿐만 아니라 가맹점의 기술적인 개발 경험도 중요하다고 판단하여 이러한 불편을 개선하기 위한 전략이 필요하다고 판단하였고 모든 시스템을 변경하는 것은 기존 레거시 코드나 배포 환경, 관련 데이터 센터 등에 갑자기 큰 변경을 가하는 것이므로 기존 가맹점이 아닌 신규 연동 개발 가맹점을 대상으로만 개편된 연동 SDK를 점차 제공하는 방식을 채택하고 기존에 복잡했던 모든 일련의 과정들은 삭제하고 토스페이먼츠의 SDK와 서비스 서버레이어에서 최대한 대신 수행하고 외부로 드러나는 인터페이는 잘 포장해서 새로운 가맹점이 쉽게 접근할 수 있도록 하는 방법을 제공하는 것으로 알고 있고 Payments API의 경우에 목표가 고객 편의를 우선시 하고 쉽고 간결한 디자인을 사용하기 위해 디자인 원칙을 설정했다고 하는데 저는 해당 부분이 너무 기억에 많이 남습니다. </p>
<p>저는 RESTful API는 CRUD와 Method Http Status가 일치해야 한다고 그냥 무조건 지켜야 하는 원칙처럼 생각한것에 반면에 토스페이먼츠는 오히려 RESTful Design을 고집하기 보단 HTTP 클라이언트 모듈이 DELETE, PUT 미지원하거나 가맹점 인프라, 방화벽 문제로 DELETE, PUT 불가한 상황들을 고려하여 NOT Pure RESTful API로 오로지 자원에 접근하는 경우에는 무조건 GET이고 자원을 변경하는 경우엔 POST로 처리하도록 설계한 부분이 매우 의아하면서도 의미있는 설계라는 생각이 들었고 일관성을 부여하기 위해 일부러 api에 대한 Request와 Response를 일치시켜 클라이언트가 인터페이스를 쉽게 사용하도록 설계했다는 부분도 매우 영감을 받는 부분이었습니다. </p>
<h2 id="마무리">마무리</h2>
<p>이번 주는 UI/UX 설계, 디자인 시스템 정비, 프론트 기술 스택 확장, API 철학에 대한 고민 등 다양한 관점에서 깊은 통찰과 실질적인 성장 경험을 얻은 주였습니다. </p>
<p>백엔드 공부를 하면서 아키텍처에 대한 고민을 많이 하게되고 즐거움을 느끼게 되었는데 어쩌다보니 프론트엔드에서도 디자인 시스템을 구축한다던가 컴포넌트 설계를 하는 식의 유지보수성을 높이는 방법에 대해 계속 고민하게 되고 지금은 안정적이지 않거나 효율적이지 않은 코드를 보면 넘어가질 못하는 정도가 되었습니다. 
하고 싶은 것이 너무나도 많은 주였지만 아쉽게도 시간이라는 제한 속에서 늘 부족함을 느끼며 한주가 지나가버렸지만 다음주엔 휴일도 많으니 꼭 다음 단계들을 수행해보고자 합니다. </p>
<h3 id="15주차-목표">15주차 목표</h3>
<ul>
<li>디자인 시스템 최종 정리 및 문서화</li>
<li>API 설계 가이드 작성</li>
<li>Figma 컴포넌트 체계화 및 재정비</li>
<li>Vue와 React를 비교하는 깊이 있는 기술 블로그 작성</li>
<li>테스트 코드 모두 작성</li>
<li>MSA Configure 서버 구성</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW CAMP 15기 13주차 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-13%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW-CAMP-15%EA%B8%B0-13%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 20 Apr 2025 05:48:15 GMT</pubDate>
            <description><![CDATA[<h3 id="부트캠프-13주차-회고-백엔드-프로젝트를-마무리하며">부트캠프 13주차 회고: 백엔드 프로젝트를 마무리하며</h3>
<p><strong>3주 회고록을 작성하지 못했던 것에 대한 회개</strong></p>
<p>제가 백엔드 프로젝트에 몰두한다는 핑계로 3주차 회고록을 작성하지 못했는데요.... 저는 회고를 작성하는 시간이 제가 공부한 것들과 생각한것들을 정리하는 시간인데, 회고를 작성하지 못했다는 것은 대략 4주정도 쌓기만 하고 정리는 못했다는 것을 말합니다.</p>
<p>쌓는 것보다 정리하는 것이 더 중요하다는 것을 알고 있는데도 시간이 없다는 핑계로 이전의 악습관을 반복하는 저의 모습을 보며 아쉬움을 크게 느꼈고 이것을 어떻게 하면 고칠 수 있을까 생각하다 역시 어느정도의 제한을 걸어야 악습관을 끊을 수 있을 것 같아 14주차부터 부트캠프 끝날때까지 한주라도 회고록을 밀리면 한 주 밀릴때마다 모든 동기분들께 커피를 돌리면 좋지 않을까 싶습니다.</p>
<p>제한을 강하게 건 만큼 다음주부터 부트캠프 끝날때까지 절대 회고록이 밀리지 않는 저의 모습을 많은 관심과 사랑으로 기대해주시길 바라겠습니다. </p>
<p><strong>백엔드 프로젝트에 대하여</strong></p>
<p>이번 백엔드 프로젝트에 대한 자세한 내용은 사실 <a href="https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B0%B1%EC%97%94%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0">백엔드 프로젝트 회고</a>에서 이미 기술한 바 있는데요. </p>
<p>DB 프로젝트 회고와 동일하게 이번 프로젝트에서 무엇을 했는지 뿐만 아니라 어떤 생각을 했고 어떤 것에 어려움을 느꼈고 뭐가 아쉬웠고 어떻게 해결했는지를 최대한 자세하게 작성해 놓았으니 한번 들어가서 봐주시면 정말 감사할 것 같습니다. </p>
<p>여기서는 짧게 얘기해보자면 이번 프로젝트에서 가장 크게 도움이 되었던 것은 DDD, 테이블 정의서, 테스트 케이스 정의서였는데요. 해당 산출물들은 설계와 기능 구현의 방향성을 잡아주는데 강력한 무기였습니다. </p>
<p>처음에 DDD 설계를 &quot;Why&quot; 해야하는지 감조차 잡을 수 없었는데요. 37개의 테이블을 설계할때까지만 해도 몰랐는데 CQRS 패턴 구조로 프로젝트 구조를 잡을 때 이걸 어떻게 설계해야할지 캄캄해서 10기 선배님들의 프로젝트 구조를 많이 확인했고 그 비로소 &quot;도메인&quot;이라는 것이 무엇인지 이해하게 되었고 DDD 설계를 통해서 자연스럽게 맥락을 나눴던 것이 왜 필요했던 작업인지 깨닫고 만약에 그 작업을 하지 않았더라면 테이블별로 디렉토리를 나눠서 37개의 도메인과 37개의 마이크로서비스가 나올 수도 있었다는 것을 알게되며 이마를 탁치게 되었습니다. </p>
<p>클린코드 아키텍처 책을 읽어보면 뭐만하면 응집도를 높이고 결합도를 해소하는 내용에 대해 나오는데 도메인을 중심으로 모듈을 나누면 의존도를 조절할 수 있구나라는 감각도 생기게 되고 역시 직접 겪어봐야 체득이 되는 것 같습니다. </p>
<p>테이블 정의서도 처음 작성하는게 매우 귀찮았는데 한번 작성하니 모두가 믿을 수 있는 단일 소스가 되었고 작성하는 과정에서 테이블에 대한 이해도도 높아지고 DDL 수정이 있을 경우엔 해당 테이블에 대한 정의서만 변경하면 되니 유지보수가 매우 쉬웠지는 것을 확인할 수 있었습니다. </p>
<p>테스트 케이스 정의서도 처음엔 매우 작성하는게 귀찮았는데 한번 작성하고 보니 누가 이 API를 구현 중이고 구현한 api는 무엇인지에 대해 한눈에 볼 수 있으니 테스트 케이스 정의서는 일종의 API 개발 관리표처럼 작동하여 개인적인 만족도가 매우 높았고, 다음 프로젝트에서도 무조건 도입하면 좋지 않을까 싶습니다. </p>
<p><strong>아쉬운점</strong></p>
<p>저는 이번 프로젝트에서 단순히 기능을 구현하는 것을 넘어 &quot;왜 이 구조여야 할까?&quot;, &quot;유지보수성이 좋은 코드인가&quot;에 초점을 맞춰 최대한 안정적이고 확장성높고 유지보수성 높은 백엔드 프로젝트를 구현하고 싶었습니다. 
하지만 시간이라는 현실적인 제약 앞에서 제가 추구한 구조화의 한계가 명확하게 드러났습니다. </p>
<p>Redis 기반 캐시 처리, RabbitMQ 기반의 비동기 메시징 구조, Prometheus + Grafana 모니터링까지, 저만의 인프라 로드맵이 머릿속에 있었습니다. 그런데 실제 구현 과정에서 우선순위가 밀리는 상황이 생겼고, 한정된 시간 내에 ‘완성도 높은 하나’를 만드는 것이 더 중요하다고 판단하여 모놀로식으로 필수적인 기능을 구현한 다음엔 MSA를 구현하다보니 3주란 시간이 송두리채 사라져있었습니다...</p>
<p>물론 프론트엔드 프로젝트까지 아직 시간이 남아있기 때문에 원래 계획했던 기술들을 적용해볼테지만 Redis나 RabbitMQ와 같은 Docker를 필수적으로 설치해야 하는 기술의 경우엔 다음 데브옵스때 구현해야 하지 않을까 싶기도 합니다만 파이널 프로젝트에선 모두 구현해볼 생각입니다. </p>
<p>그리고 저는 어쩌다보니 팀을 리드하는 역할을 맡게 되었는데 다른 팀원의 트러블슈팅을 돕는데 큰 어려움을 느꼈고 해당 어려움을 해결하기 위해 트러블 슈팅과 관련한 문서화를 제공했지만 다른 분들이 이해하기엔 용이하지 못했던것같아 앞으론 예시와 시각적인 자료를 기반으로한 이해를 중심으로한 문서화를 하는 능력을 길러야 할 것 같습니다. </p>
<h3 id="내가-한-것왜를-중심으로과-배운점">내가 한 것(왜를 중심으로)과 배운점</h3>
<p><strong>프로젝트 구조 설계</strong></p>
<p>저는 과거 프론트엔드 프로젝트를 진행하면서 컴포넌트 파일이 여기저기 순서와 규칙없이 나돌아 댕기고 중복되는 코드가 계속해서 쌓이고 나중엔 코드를 수정하는 것보단 새로 프로젝트를 시작하는게 나을 수준이 되는 것을 보면서 프로젝트 구조 설계에 집착하게 되었고 책임을 분리하는 것에 대한 필요성을 느끼게 되었습니다. </p>
<p>그래서 이번 백엔드 프로젝트 시작하기 전부터 어떻게 프로젝트 구조를 설계할까 많은 고민을 하는 와중에 클린코드 아키텍처 책에서 어떠한 도움을 주지 않을까 열심이 읽었는데 클린코드 아키텍처는 &quot;클린코드&quot;를 위한 아키텍처이지 &quot;구조&quot;를 위한 아키텍처가 아니라는 것을 깨달으며 별 정보를 얻을 수 없었는데 마침 강사님께서 CQRS 패턴 구조를 알려주셨습니다. 저는 그 구조를 보면서 이마를 또 탁 치게되었는데요. 생각해보니 코드를 크게 나누어보면 읽거나 쓰는 것이고 읽거나 쓰는 것에 대한 책임이 다르므로 구조도 다를 수밖에 없고 실제로 나눠보니 파일이 명확하게 정리되고 도메인별로 업무분담 했을 때 서로 충돌하는 파일이 적어지다보니 병합 과정에서 문제가 많지 않다는 것을 확인할 수 있었습니다. </p>
<p>Command측 구조에서 쉽게쉽게 하면 Application layer/Domain layer/infrastucture로 나누지 않아도 되긴 하는데 저는 이후 확장성과 유지보수성을 생각해보면 나눠놓는 것이 좋다고 생각하였고 해당 예상은 적중했습니다. </p>
<p>왜냐하면 제가 Application layer의 Service에서 어쩌다보니 중복되는 코드를 계속해서 작성하게 되었는데 중복되는 코드를 한곳에서 관리하기 위해 util 메서드를 만들어야 하나 고민하던 찰나 Domain 내의 Service가 생각나게 되었고 중복되는 코드들을 Domain Service에서 관리하다보니 자연스럽게 Application Service에선 Repository에 접근하지 않게 되고 메서드별로 필요한 Repository가 다르면 다를수록 응집도가 낮아진다고 클린코드 아키텍처에서 배운바 있는데 해당 문제도 자연스럽게 해결되는 것을 확인할 수 있었습니다. </p>
<p><strong>공통 응답 및 예외처리 구조</strong>
저는 공통 응답(ApiResponse, ErrorResponse)과 예외 처리(GlobalExceptionHandler, BusinessExcpetion, ErrorCode)로직을 모두 시스템화 했는데요. 제가 프론트엔드를 하면서 가장 화가났던 부분이 백엔드 응답의 일관성 부족의 문제였습니다. api별로 파싱해야 하는 방법이 달라지면서 파싱 코드를 모듈화하기도 어렵고 일관성이 없다보니 매번 Swagger를 정독해서 데이터를 추출해야 했습니다.</p>
<p>그래서 저는 이제 데이터를 전달해주는 입장이 되었으므로 예측 가능한 응답 구조를 제공하는 것을 중요하게 생각했고 모든 응답은 ApiResponse로 감쌌고, 모든 예외는 ErrorResponse를 반환하도록 GlobalExceptionHandler를 구성했습니다. </p>
<p>이건 단순히 깔끔한 구조가 아니라, 프론트와의 협업을 위한 배려이자 시스템 설계의 일환이라고 생각합니다.</p>
<p>그리고 여기서 중요한 걸 또 하나 배웠는데 공통 코드에 너무 많은 걸 넣으면 병합이 꼬인다는 것입니다. 저는 ErrorCode Enum 하나에 모든 에러에 대한 Error Enum 타입을 관리하도록 구성했는데 그렇다보니 팀원별로 필요한 ErrorCode를 하나씩 추가하고 수정하다보니 병합과정에서 계속해서 소리소문없이 사라지는 문제가 발생하는 것을 보며 아 팀원끼리 사용하는 공통된 파일은 최대한 변경되지 않도록 해야 하고 확장가능한 방법으로 설계를 해야 한다는 것을 다시한번 깨닫게 되었습니다. </p>
<p><strong>보안과 Spring Security</strong>
처음에는 Spring Security 개념자체를 이해하는것도 너무 어려워서 Spring Security만 구현하면 보안이 완성이 되는 줄 착각했는데 구현하고 보니 Spring Security는 그저 인증/인가를 컨트롤 하는데 조금 더 쉽게 컨트롤할 수 있게 해주는 도구라는 것을 알게되었습니다. </p>
<p>그래서 어떻게하면 보안을 올릴 수 있을까 생각해봤는데 우선 수업에서 배운 가장 basic한 방법인 jwtToken을 accessToken과 refreshToken을 두개를 만들고 accessToken의 유효시간을 짧게 해서 인증 토큰을 관리하는 것을 구현하긴 했는데 생각해보니 accessToken의 유효시간을 10분이라고 설정했을 때 로그아웃 이후에 accessToken으로 언제든지 웹사이트에 들어올 수 있는 것을 확인하게 되었고 그래서 로그아웃 이후에 기존에 존재하던 블랙리스트 테이블에 로그아웃한 회원을 집어넣고 로그인을 하게 되면 블랙리스트 테이블에서 제거하는 것으로 api에 접근하지 못하게 하였고 매번 api 호출시마다 DB에서 검사를 하는 것은 성능 오버헤드가 발생할 여지가 많기 때문에 추후에 Redis를 사용하여 가볍고 빠르게 세션으로 관리하는 것으로 변경할 생각입니다.  </p>
<p><strong>MSA 구현과정</strong></p>
<p>저는 제가 맡은 User 도메인을 별도의 마이크로서비스 서버로 분리하고 Spring Cloud Gateway를 단일 진입점으로 두고, 인증 책임은 Gateway가, 인가는 각 서비스에서 담당하게 구성하였습니다. 이는 책임의 명확한 분리를 실현하 것이라고 할 수 있습니다. 이 과정에서 Eureka를 통한 서비스 레지스트리와 FeignClient를 도입하여 서비스 간 통신을 유연하게 만들었고, 추후 수평 확장을 고려해 포트를 무작위로 설정하고 로드밸런싱도 함께 적용했습니다. </p>
<p>물론 여기까지는 정말 기본적이고 서버의 운영의 안정성을 위한 모니터링과 내부결함 패턴을 적용하고 서버간 에러 전파를 막고 문제 발생시 관리자에게 디스코드로 전송하는 자동화까지 구현해야 하지만 역시 아직은 꿈과 같은 일이었습니다...</p>
<h3 id="배운점-및-느낀점">배운점 및 느낀점</h3>
<p><strong>문서화는 무엇보다 중요하다</strong></p>
<p>이번 프로젝트를 하면서 가장 크게 느낀 건, 기술적 실력보다 더 중요한 건 지식을 전달할 수 있는 능력이라는 것이었습니다. </p>
<p>깃허브 사용 방법과 같은 기반이되는 기술에서 문제가 있었는데 해당 내용에 대해 시스템화하여 문서화하지 못했던 것이 아쉬웠던 것 같고 이 뿐만 아니라 제가 구현한 모든 api나 설계 과정들을 해당 프로젝트에 대한 기반 지식이 없는 사람들도 모두 이해할 수 있을 정도로 문서화를 해야 한다는 생각을 하게 되었고 다음 프로젝트에선 제가 구현한 구조나 컨벤션이 왜 그런 구조가 되었는지를 설명 가능한 문서화를 하는 것을 목표로 하고 있습니다. </p>
<h3 id="마무리하며">마무리하며</h3>
<p>이번 13주차 프로젝트는 기술적으로 성장했다기보다 &#39;설계하는 개발자&#39;로서 사고하는 법을 훈련한 시간이었다고 생각합니다. 기술은 많고, 구현할 건 한도 끝도 없지만 어떤 문제를 왜 그렇게 해결했는가, 그 흐름을 설명할 수 있는가, 그 구조가 협업에 도움이 되는가를 늘 고민하는 습관이 이번 프로젝트를 통해 제 안에 자리잡게 되는 기반이되는 시간이었다고 생각합니다. </p>
<p>다음 프로젝트에선 지금보다 더 나은 구조를 만들고 더 쉽게 협업하고 더 안정적으로 운영할 수 있는 서비스를 만들고 싶습니다. 그리고 그 과정을 계속 기록하면서 협업에 능통한 개발자가 되기를 희망합니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BE15 백엔드 링크업 프로젝트 회고]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B0%B1%EC%97%94%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B0%B1%EC%97%94%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 20 Apr 2025 04:06:02 GMT</pubDate>
            <description><![CDATA[<h2 id="프로젝트-회고">프로젝트 회고</h2>
<h3 id="1-프로젝트-개요">1. 프로젝트 개요</h3>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/1b3dc49f-9272-43c1-911f-6ddf28602151/image.gif" alt=""></p>
<p>이번 프로젝트에서 가장 큰 도움이 되었던 세 가지는 <strong>DDD 설계</strong>, <strong>테이블 정의서</strong>, <strong>테스트 케이스 정의서</strong>였습니다.</p>
<p>물론 이 모든 것이 유의미하려면 그 기반이 되는 <strong>요구사항 명세서와 ERD</strong>가 견고해야 합지만 그 위에 구조적 설계를 문서화한 이 세 요소는 실제 개발 단계에서 <strong>협업 효율성과 방향성 유지</strong>에 결정적인 역할을 했습니다.</p>
<p><strong>DDD 설계서</strong></p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/1b778999-3dbc-4a4a-a568-df8b32dc9005/image.jpg" alt=""></p>
<p>처음엔 ‘도메인 주도 설계(DDD)’ 문서를 왜 작성해야 하는지 감조차 잡히지 않았습니다.</p>
<p>하지만 프로젝트를 마친 지금은 <strong>DDD 없이 이 프로젝트를 완성하는 것은 불가능했을 것</strong>이라 확신합니다.</p>
<p>저희 프로젝트는 총 <strong>37개의 테이블</strong>을 설계했고 이 모든 테이블이 각 기능에서 동일하게 쓰이지는 않았습니다.</p>
<p>결국 중요한 것은 <strong>각 테이블이 어떤 &#39;맥락(Context)&#39;에서 필요하고 사용되는가</strong>를 파악하는 것이었습니다. </p>
<p>이 과정을 통해 자연스럽게 도출된 각 &#39;맥락&#39;은 곧 하나의 도메인이 되었고 각 도메인은 프로젝트 소스의 최상위 디렉토리로 구성되었습니다.</p>
<p>DDD 설계를 통해 얻은 이점을 정리해보자면</p>
<ul>
<li>각 도메인은 <strong>응집력 있는 내부 구조</strong>를 가지며</li>
<li>도메인 간 <strong>의존성을 최소화</strong>할 수 있었고</li>
<li>추후 MSA로의 분리를 고려할 때 <strong>독립적 서비스 분리 기준</strong>이 명확해졌습니다</li>
</ul>
<p>만약 이 과정을 거치지 않았다면, 도메인 간 의존성이 얽히고설켜 <strong>MSA 전환은 거의 불가능</strong>했을 것입니다.</p>
<p>따라서 DDD는 단순한 설계 도구가 아닌 시스템 구조를 올바르게 분해하고 설계하는 핵심 절차임을 이번 프로젝트를 통해 알게되었고 앞으로 이번에 배운 도메인 설계를 더 탄탄하게 학습하여 완벽한 수준의 도메인 설계란 무엇인지에 대해 학습할 것입니다. </p>
<p><strong>테이블 정의서</strong></p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/1efc5c0c-46e4-4ac7-8015-7ee1a4c281a0/image.jpg" alt=""></p>
<p>처음에는 엑셀로 테이블 정의서를 작성하고, 여기에 스크립트까지 정리하는 일이 매우 번거롭게 느껴졌습니다.</p>
<p>그런데 한 번 정리해두고 나니 <strong>이보다 명확한 협업 도구는 없었습니다.</strong></p>
<p>테이블 정의서를 작성하면서 내가 맡은 테이블의 구조에 대해 더 깊게 고민해볼 수 있고 내가 맡은 테이블 구조와 변경 사항도 한눈에 확인 할 수 있고 DDL 스크립트도 실시간으로 관리할 수 있었으며 다른 팀원이 수정 내용을 반영할 때 <strong>“그 테이블 스크립트 바꿨어”</strong> 한마디면 DDL을 손쉽게 수정할 수 있어 DDL을 처음 구성하는 것은 어려웠지만 관리하는 것은 어렵지 않았습니다.</p>
<p>물론 DB를 공유할 수 있는 상황이라면 이러한 작업은 필요하지 않겠지만 DB를 공유하지 못하는 상황에선 정의서를 작성하는 것이 최고의 커뮤니케이션 수단이었다고 생각합니다. </p>
<p><strong>테스트 케이스 정의서</strong>
<img src="https://velog.velcdn.com/images/low_level_v99/post/74689ff6-97ea-4631-ba28-f935123ac069/image.jpg" alt=""></p>
<p>마찬가지로 처음엔 이 정의서를 만드는 일이 매우 귀찮았습니다.</p>
<p>하지만 작성이 완료되고 나서는 이 문서 하나로 다음과 같은 효과를 누릴 수 있었습니다.</p>
<ul>
<li><strong>API의 전체 흐름을 구조적으로 파악</strong>할 수 있었고</li>
<li><strong>담당자별 엔드포인트 관리</strong>가 가능했으며</li>
<li><strong>성공 여부 표시를 통해 구현 상태 파악</strong>이 쉬워졌습니다.</li>
</ul>
<p>물론, Swagger가 이런 역할을 어느 정도 해주지만 Swagger는 <strong>실행 이후의 문서화</strong>이고 테스트 성공 여부나 담당자 등의 <strong>개발 과정에서 필요한</strong> 정보는 제공하지 못하기 때문에 개발 과정에서의 API 개발 흐름 관리측면에서 매우 효과적인 방법인 것 같습니다.</p>
<h3 id="2-하고-싶었던-것-및-아쉬운점">2. 하고 싶었던 것 및 아쉬운점</h3>
<p>이번 프로젝트에서 제가 가장 중점을 둔 가치는 단순한 기능 구현이 아닌 <strong>기획과 설계</strong> 그리고 <strong>유지보수가 가능한 구조의 구축이었습니다.</strong> </p>
<p>인공지능이 일상적으로 활용되는 지금의 시대에 “기능을 구현할 줄 안다”는 것만으로는 큰 의미가 없다고 생각합니다. </p>
<p>진짜 중요한 것은 복잡한 요구사항을 설계로 구체화하고, 시스템을 유지보수 가능하게 설계하는 능력이라고 생각하기 때문에 이번 프로젝트에선 그러한 능력을 함양하는 것을 목표로 하였습니다.</p>
<p><strong>기술적인 아쉬움</strong></p>
<p>이번 프로젝트를 시작하며 제가 설정했던 핵심 목표는 다음과 같습니다.</p>
<ul>
<li>CQRS 패턴을 도입하여 도메인 간 책임을 분리하는 구조 설계</li>
<li>비동기 메시지 기반 아키텍처(RabbitMQ 등)의 적용</li>
<li>모니터링 및 로깅을 통한 서버 안정성 확보</li>
<li>Redis 캐시 활용</li>
<li>기술별 테스트 코드 작성</li>
</ul>
<p>프론트엔드 프로젝트까지 모든 기술들을 접목할 수 있을진 모르겠지만 파이널 프로젝트에선 지금 프로젝트에서 사용했던 CQRS 패턴 구조 뿐만 아니라 파이널 프로젝트 주제에 적합한 패턴 구조를 채택하여 유지보수성을 높이고 MSA 구조에서 안정적으로 서버가 운영되고 자동배포되는 완벽한 서비스를 설계하고 구현하는 것이 저의 최종 목표가 될 것 같습니다. </p>
<p><strong>리드하는 것에 대한 아쉬움</strong></p>
<p>어쩌다보니 이번 프로젝트에서는 제가 팀을 이끄는 입장이 되었고, 동시에 많은 주요 기능을 직접 구현하게 되었습니다. </p>
<p>하지만 백엔드에 대해 본격적으로 공부한 지 얼마 되지 않은 상황에서 제가 맡은 기능을 구현하고 설계하는 과정에 동시에 리드하는 것은 결코 쉽지 않았습니다. </p>
<p>부족함을 느끼는 부분은 다음과 같습니다. </p>
<ul>
<li>제 역할에 집중하느라 다른 팀원들의 트러블슈팅에 충분히 도움을 주지 못했던 점</li>
<li>전체 구조를 조율하면서 <strong>우선순위 설정과 태스크 전환</strong>에 어려움을 겪었던 점은 전문 개발자로서의 부족함을 체감하게 해주었습니다</li>
</ul>
<p>분야는 다르지만이전 회사 경험을 떠올려보면 내 일만 잘하는 것은 결코 충분하지 않다는 것을 누구보다 잘 알고 있습니다. </p>
<p>팀원 간 요청이 동시다발적으로 들어올 때 빠르게 다른 업무로 전환을 할 수 있고 우선순위를 설정하여 전체 흐름을 관리할 수 있는 능력이 실무에서 무엇보다 중요한 진짜 실력이라고 생각했고 이전 회사에서 제 사수분을 보면서 가장 배우고 싶은 부분이 해당 능력이었습니다. </p>
<p>그런데도 아직 제가 담당한 일에 치여 다른 사람들의 일을 봐주지 못하는 저를 보며 더 큰 아쉬움을 느낄수밖에 없었습니다.</p>
<p>그래서 저는 프론트엔드 프로젝트에선 저희 이번 백엔드 프로젝트에서 가장 문제였던 버전 관리 도구인 깃과 깃허브와 관련하여 그럴듯하게 정리한 컨벤션이 아닌 팀내에서 실제로 적용할 수 있는 진짜 브랜치/커밋/코딩 컨벤션을 정착하는 것을 목표로 하고있습니다. </p>
<p>또한 저희 프로젝트에 대한 기반 지식이 없던 사람들도 바로 투입될 수 있는 문서화를 통해 협업 과정 자체를 시스템화하여 협업 과정 자체를 성장하는 연습을 해보고자 합니다.</p>
<h3 id="3-내가-한-것-및-할-것">3. 내가 한 것 및 할 것</h3>
<p>이번 프로젝트에서 제가 맡은 주요 책임과 역할 그리고 그 과정에서 고민했던 설계, 기술적 시도와 의도를 중심으로 정리해보고자 합니다. </p>
<p>*<em>프로젝트 주요 담당 영역 정리 *</em></p>
<ul>
<li>프로젝트 노션 구조 설계</li>
<li>전체 프로젝트 구조 설계 및 CQRS 패턴 기반 구조 설계</li>
<li>MSA 설계 및 구현</li>
<li>Spring Security 활용한 인증/인가 흐름 전반 구성</li>
<li>공통 응답/예외 처리 구조화</li>
<li>회원 도메인 및 포인트 도메인 전체 구현</li>
</ul>
<p><strong>프로젝트 노션 구조 설계</strong>
<img src="https://velog.velcdn.com/images/low_level_v99/post/7ea53fdf-c5dc-4411-ab45-3af9abd18f19/image.png" alt=""></p>
<p>먼저 프로젝트의 협업 환경을 위한 노션 구조를 설계했습니다. 제 개인적으로 사용하고 있는 시간 관리 템플릿 기반으로 구성했고 여전히 이보다 더 직관적인 구조는 없는 것 같습니다. </p>
<p>저는 스크롤이 많은 인터페이스나 깊게 들어가야 하는 메뉴 구조는 사용자 경험 측면에서 불편하다고 생각합니다. 특히 프로젝트와 관련된 문서를 관리해야 하는 목적에서 사용하는 노션 페이지라면 한눈에 필요한 모든 자원에 접근할 수 있는 버튼들만 메인 페이지에 위치하면 된다고 생각합니다. </p>
<p>그래서 문서화 영역은 왼쪽, 작업(WBS)은 중앙, 산출물은 오른쪽에 배치하여 직관적인 동선과 즉시성 높은 접근성을 확보했고 향후 데브옵스나 파이널 프로젝트에서도 이 구조를 유지할 예정이지만, 더 나은 구조를 발견한다면 언제든지 개선할 생각입니다.</p>
<p><strong>CQRS 패턴 구조 설계</strong></p>
<pre><code>📁 linkupUser
├── 📄 build.gradle
├── 📄 settings.gradle
├── 📁 src
│   └── 📁 main
│       ├── 📁 java
│       │   └── 📁 com.learningcrew.linkupuser
│       │       ├── 📄 LinkupUserApplication.java
│       │       ├── 📁 client
│       │       ├── 📁 command
│       │       │   └── 📁 application
│       │       │       ├── 📁 controller
│       │       │       ├── 📁 dto
│       │       │       └── 📁 service
│       │       ├── 📁 domain
│       │       │   ├── 📁 aggregate
│       │       │   └── 📁 repository
│       │       ├── 📁 infrastructure
│       │       │   └── 📁 repository
│       │       └── 📁 query
│       │           ├── 📁 controller
│       │           ├── 📁 dto
│       │           │   ├── 📁 request
│       │           │   └── 📁 response
│       │           ├── 📁 mapper
│       │           └── 📁 service
│       └── 📁 resources
│           ├── 📄 application.yml
│           └── 📁 mappers
│               └── 📄 사용자_Mapper.xml
</code></pre><p>백엔드 프로젝트를 시작하면서 가장 먼저 고민했던 것은 <strong>프로젝트 구조의 설계</strong>였습니다. </p>
<p>이전 프론트엔드 프로젝트 경험에서 컴포넌트가 무분별하게 퍼지고, 코드가 중복되며, 협업이 어려워지는 구조를 경험했기에 부트캠프에선 진행하는 프로젝트에선 꼭 <strong>맡은 기능과 책임을 기준으로 명확히 구분된 구조</strong>를 만들어야겠다는 생각을 했습니다. </p>
<p>그래서 그래서 클린코드 아키텍처 책을 읽으면서 클래스와 함수를 최대한 작게 나누고 유지보수성을 위해 구현체가 아니라 인터페이스에 의존하는 DIP를 구현하는 것까지는 알게되었는데 전체적인 프로젝트 구조를 어떻게 구성해야 할지는 전혀 감을 잡지 못한 상황이었습니다(프로젝트 구조 아키텍처가 아니라 “클린코드” 아키텍처이니 그럴수밖에….)  </p>
<p>그런 와중에 강사님께서 소개해주신 <strong>CQRS(Command-Query Responsibility Segregation)</strong> 패턴은 말 그대로 “유레카”였습니다. Command(쓰기)와 Query(읽기)의 책임을 분리하면 코드가 명확해지고 각각 필요한 모듈과 구성만 갖추게 되어 <strong>파일 간 결합도가 낮고 유지보수성이 뛰어난 구조</strong>를 만들 수 있다는 것을 알게되었습니다.</p>
<p><strong>Command Layer의 아키텍처 설계</strong></p>
<p>특히 감명 깊었던 부분은 Command 영역 내의 <strong>Application Service와 Domain Service의 분리입니다.</strong></p>
<p>Command측 구조에는 Application layer의 service가 있고 Domain측 Service가 있습니다. </p>
<p>저는 처음엔 둘다 Service가 있는지 가마득하게 잊고 그냥 단순한 MVC 구조처럼 Application layer의 Controller 핸들러에서 Application 내의 Service를 호출하고 바로 Domain 내의 Repository를 호출하여 DB에 반영되도록 했었는데 그렇다보니 너무 중복되는 코드가 많다는 것을 느꼈습니다. </p>
<p>그래서 중복되는 코드들을 어디에서 관리할까 util 폴더를 만들까 했는데 생각해보니 Domain내에도 Service가 있다는 것을 뒤늦게 깨달았고 지금은 Application Service측에선 비즈니스 로직을 처리하기 위해 Domain Service를 조율하는 역할만 하고 실제 코드 구현은 Domain Service 측에서 담당하고 있고 여러 Domain 내에서의 공통된 코드가 있을 때만 common측 service에서만 넣어서 관리하고 있습니다. </p>
<p>그 결과 <strong>기능별 관심사가 명확히 분리된 구조</strong>를 갖추게 되었고, 유지보수성과 테스트 편의성이 크게 향상되었습니다.</p>
<p><strong>결합도 해소와 리팩토링</strong></p>
<p>클린코드 아키텍처에서는 클래스간의 결합도 척도를 스태틱 변수와 인스턴스 변수가 클래스 내부에서 모든 메서드들이 사용하고 있는지 얼만큼 사용하고 있는지에 따라 측정합니다. </p>
<p>처음엔 Application Service에서 Repository를 그대로 의존성 주입해서 사용했기 때문에 사용하는 테이블의 개수만큼 Repository를 의존성 주입받아서 사용하게 되었고 결국엔 클래스 내부의 메서드들중 일부만 사용하는 Repository가 늘어나게 되었고 이것은 유지보수성과 확장성 관점에서 추후 문제가 될 것이라는 것을 깨닫고 위에서 말했듯이 재사용할 수 있는 코드들은 Domain Service 내의 메서드를 추가하여 해당 코드를 재사용하도록 리팩토링 하였고 컨트롤러와 서비스를 이메일 관련 된것이나 친구 관련 된 것이나계정과 관련된 것이나 인증과 관련된 것을 다 다른 컨트롤러 클래스와 서비스 클래스로 구분하게 되었습니다. </p>
<p>물론 아직 User 도메인에 인증 관련된 기능들이 포함되어 있어서 아직 완벽하게 쪼갠 것은 아니긴 합니다. 그래서 추후에 확장성을 생각하면 인증과 관련된 것도 별도의 도메인으로 나눠서 관리하고자 합니다. </p>
<p><strong>DIP 원칙 적용</strong></p>
<p>처음에 구현할 땐 컨트롤러에서 서비스를 호출할 때 바로 서비스 구현체의 메서드를 호출했는데요. 다른 팀의 동기 동생의 코드를 보면서 동기 동생이 서비스 구현체가 아닌 인터페이스를 의존하여 의존성 주입을 하는 것을 확인할 수 있었고 생각해보니 제가 작성한 코드는 클래스와 서비스간의 강한 의존성이 생기는 것을 확인할 수 있었고 클린코드 아키텍처에서 학습한 DIP와 관련된 내용이 생각났습니다. 그래서 컨트롤러에서 서비스 구현체를 의존하는 것이 아니라 인터페이스를 의존하도록 수정하였고 서비스 구현체는 숨겨서 언제든 구현체를 변경할 수 있는 구조로 리팩토링 하였습니다. </p>
<p>아직 전체적인 프로젝트 구조상에선 DIP가 지켜지지 않고 있는것 같아서 이부분은 문서화를 하여 팀원분들과 공유하여 전체적으로 구조상 DIP를 잘 지킨 프로젝트를 만들면 좋을 것 같습니다.</p>
<p><strong>공통 응답 및 예외처리 구조 정형화</strong></p>
<p>이번 프로젝트에서 제가 팀원들에게 실질적인 도움을 줄 수 있었던 부분은 <strong>공통 응답 구조와 예외 처리 구조</strong>의 정형화이지 않을까 싶습니다. </p>
<p>지금 상황에선 저희가 백엔드와 프론트 모두 담당하고 있긴 하지만 제가 프론트엔드만 담당했을 땐 서버로부터 전달받는 요청의 타입이 매번 다른 것은 정말 최악이었습니다. 왜냐하면 응답받는 데이터 타입이 동일하면 유틸 메서드 하나로 의도한 데이터에 접근하면 되는데 매번 다른 응답이 오게 되면 api별로 다른 파싱 코드를 작성해야 하므로 매우 불편했습니다. </p>
<p>그래서 이제 응답을 날리는 입장이 되는 사람이 되었으니깐 꼭 구조화하여 날려야겠다는 생각을 하게 되고 모든 응답을 ApiResponse로 묶어서 data 필드에 무조건 data가 들어가서 프론트에서 받을 수 있도록 구조화하였습니다. </p>
<p>그리고 예외가 발생했을 때 모든 예외들을 처리할 수 있는 GlobalExceptionHandler를 구현하였고 팀원들별로 커스텀한 Exception 클래스 뿐만 아니라 인증 및 인가 실패에 대한 예외 처리, 유효성 검사 예외 처리, 예상하지 못한 모든 예외들까지도 모두 받을 수 있도록 하였고 각각의 예외 클래스에서 메세지와 상태코드를 추출하여 공통 ErrorResponse를 생성하여 응답을 보낼 수 있도록 모두 구조를 잡아놓았습니다. </p>
<p>그래서 다른 팀원분들은 미리 만들어 놓은 예외 클래스로 ErrorCode와 메세지를 넣어서 날리기만 하면 미리 세팅해둔 설정에 따라 에러 메시지와 상태 코드가 포함되서 응답으로 전달되니 프론트엔드에선 항상 일정한 예외 구조의 응답을 받게 될 뿐만 아니라 예외를 처리하는 것을 단순화할 수 있었습니다. </p>
<p>해당 구조는 매우매우 마음에 드는 구조이고 처음 구조한 이외로 변경되는 부분이 없이 잘 사용하고 있고 문제는 ErrorCode Enum에 모든 ErrorCode를 넣다보니 팀원들별로 추가나 수정이 빈번하게 발생하게 되었고 병합하기 이전에 존재하던 ErrorCode가 병합 이후에는 없어지는 경우가 빈번하게 발생하게 되었습니다. </p>
<p>그래서 여기서 얻은 깨달음은 절대 모든 팀원들이 빈번하게 수정하는 코드엔 모두 집어넣으면 안되겠닫는 것을 절실히 깨닫게 되었습니다. 그래서 ErrorCode Enum도 도메인별로 나눠야 할지 지금 고민중이고 ErrorCode뿐만 아니라 서로 공통으로 사용하고 있는 클래스들중에서 빈번하게 수정이 필요한 것은 뭐가 있고 무엇을 나눠야 할지 고민하고 있는 상황입니다. </p>
<p>실무에선 더 많은 사람들끼리 같은 파일을 수정하게 될텐데 그때를 생각해보면 어떻게 안정적으로 많은 사람들간에 공통적으로 사용하는 파일을 관리할 수 있을지에 대해 고민해볼 수 있는 정말 좋은 기회였고 가장 좋은 것은 공통으로 접근할 코드의 경우엔 미리 컨벤션을 맞추는 것이 필요하고 최대한 파일을 작게 나눠서 관리하는 것이 좋고 언제든지 확장할 수 있는 구조를 갖추는 것이 중요할 것 같습니다.</p>
<p><strong>MSA 설계 및 구현</strong></p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/5bd9a21a-5a18-4760-bb1b-7b3d7d365bb6/image.jpg" alt=""></p>
<p>이번 프로젝트에서 가장 구조적으로 큰 변화는 <strong>모놀로식에서 MSA(Microservice Architecture)</strong> 구조로 전환한 경험이었습니다. </p>
<p>처음에는 하나의 서버로 모든 기능을 처리하는 모놀로식 구조에서 시작했지만, 점차 도메인의 독립성과 확장 가능성을 고려하여 <strong>회원(User) 도메인을 별도의 서비스로 분리</strong>하였고, 이를 기점으로 전체 구조를 MSA로 전환하였습니다.</p>
<p>MSA 구조는 다음과 같은 구성을 기반으로 설계했습니다. </p>
<ul>
<li><strong>Spring Cloud Gateway</strong>: 단일 진입점. 인증 필터를 처리하며 라우팅 책임을 수행.</li>
<li><strong>Eureka Server</strong>: 마이크로서비스들의 서비스 등록/탐색을 위한 레지스트리.</li>
<li><strong>Feign Client</strong>: 마이크로서비스 간의 통신을 추상화하여 각 서비스 간 직접 호출 가능.</li>
<li><strong>User-Service, Common-Service 등</strong>: 각각의 도메인에 대한 독립 서비스 구성.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/b249ceb3-4f72-412e-8122-e0745f2d62a2/image.png" alt=""></p>
<p>저희는 처음엔 모놀로식으로 모든 기능을 구현한 후에 나중에 제가 구현하고 있던 도메인인 User를 기존 서버에서 분리시켜 새로운 User 서버를 구현하였고 추가적으로 Eureka Server와 Spring Cloud Gateway를 구현하여 Eureka Server에서 Spring Cloud Gateway, User Service, Common Service를 관리하고 단일 진입점인 Gateway에서 인증에 대한 책임을 전가하고 각각의 마이크로 서비스에선 인가에 대한 검사를 하고 인스턴스간 통신은 Gateway를 거치는 방식이 아니라 인스턴스간 직접적인 통신을 할 수 있도록 MSA 구조를 설계하였습니다. </p>
<p>서비스 간의 통신은 Gateway를 반드시 거치지 않고, 필요에 따라 <strong>Feign을 통한 직접 호출 방식도 병행</strong>하였습니다. 이는 인증의 흐름은 Gateway가 책임지고, 인가는 각 서비스 내부에서 처리하는 구조로 역할을 분리하기 위함입니다. </p>
<p>하나의 서버내에 모든 관련된 기능들이 포함된 구조가 아니라 통신을 통한 기능 구현 구조로 변경되었기 때문에 User 서버가 켜져있어도 Common 서버가 다운되면 문제가 될 수 있기 때문에 운영 안정성을 높일 수 있는 대책도 필요하고 에러가 발생했을 때 다른 마이크로서비스에 에러가 전파되지 않도록 하고 설정 정보를 한 곳에서 관리하는 추가적인 작업이 필요하다는 것을 알고 있기에 아직 완벽한 MSA를 구현하지 못한 것이 아쉬울 뿐입니다. </p>
<p>따라서 추후 Config Server, 로그 집계, 트래픽 모니터링, 장애 감지 등의 <strong>운영 안정화 도구</strong>들은 이후 도입할 예정이고 가능하다면 실시간 장애 알림(Discord Webhook 등)까지 구현하여 <strong>운영 대응 체계</strong>도 세우고 싶습니다.</p>
<p><strong>Spring Security 및 보안 구조 설계</strong></p>
<p>저는 프론트엔드를 했을 땐 보안에 대한 생각을 깊게 해본적이 없습니다. 오히려 보안을 강화하는 것에 대해 사용자 경험 측면에서 안좋게 바라봤습니다. 그래서 로그인을 하지 않는 앱이 사용자가 회원가입이나 로그인을 해야 하는 번거로움을 한번 들여주니깐 좋은 앱이지 않을까 하는 생각을 했었는데 백엔드를 공부하면 할수록 사용자 경험을 좋게 하는 것은 단순히 디자인이 예쁘거나 번거로움을 줄여주거나 의도한대로 액션이 일어나는 것 뿐만 아니라 이 서비스를 믿고 사용할 수 있도록 하는 것이 아닐까라는 생각을 점점 하게 되었습니다. </p>
<p>그래서 서버 안정성을 위해 위에서 MSA 구조도 서버 부하와 에러 위임 전파 방지 관점에서 중요한 설계란 생각이 들었고 보안 역시 사용자가 믿고 사용하기에 매우 중요한 부분이 아닐까라는 생각을 하게되었습니다. </p>
<p>처음엔 Spring Security를 사용하면 그냥 보안이 강력하게 될 줄 알았습니다. 왜냐하면 그냥 이해하는 것조차 어려웠거든요….ㅎ 그런데 점점 공부하다보니 Spring Security가 해주는 것은 인증과 인가를 조금 더 간편하게 처리할 수 있도록 해주는 도구라는 것을 깨달았습니다. </p>
<p>요청에서 컨트롤러까지 오는 그 과정에서 필터를 설정하여 인증과 인가에 대한 필터를 설정할 수 있고 인증 필터에선 기본적으론 아이디와 비밀번호로 인증을 처리하거나 아니면 JwtTokenAuthentication과 같은 커스텀 필터를 만들 수 있도록 해주는 것이지 결국엔 제가 필터 인터페이스를 구현해서 필터 구현체를 생성하고 해당 필터 구현체 내부에서 발급해준 토큰의 유효성을 검사하고 유효하면 다음 필터로 넘어가는 것을 직접 설정해주어야 했고 보안을 높이는 기능은 Spring Security에게 없다는 것을 알았습니다. </p>
<p>그래서 JwtToken을 사용할 때 다들 사용하는 공통 방법인 AccessToken과 refereshToken 두개를 만들어서 AccessToken의 유효시간을 짧게 하고 AccessToken의 유효시간이 다되었을 때 refereshToken을 클라이언트로부터 전달받아서 DB에 있으면 다시 AccessToken을 발급해주는데 이렇게만 구현하면 로그아웃하고 10분동안 특정 회원의 AccessToken을 막을 방법이 없게 되서 블랙리스트 테이블에 로그아웃을 하게 되면 해당 회원을 넣고 인증시에 블랙리스트 테이블에서 해당 회원이 있는지를 확인하는 작업을 처리하였습니다. 그런데 해당 작업은 DB로 처리하기엔 매번 api 호출마다 DB에서 조회해야 하는 다소 리소스가 필요한 작업이기 때문에 추후에 Redis를 사용하여 적은 리소스로 높은 성능으로 빠르게 처리할 수 있도록 리팩토링 할 계획입니다. </p>
<p>그리고 계좌 정보를 저장하고 환불을 처리하는 과정에서 <strong>보안 취약점</strong>에 대해 고민해보게 되었는데요, 현재는 DB에 계좌 정보를 직접 저장하고 있지만 이는 지불 카드 산업 데이터 보안 표준 기준에서 문제가 될 수 있다는 것을 백엔드 프로젝트 이후에 다른 동료분들을 통해 알게되었습니다.</p>
<p>그래서 저는 향후에는 <strong>PG사에 계좌 정보를 저장하고</strong> 사용자-계좌 연동에 필요한 <strong>토큰 정보만을 보관</strong>하는 방식으로 전환할 예정입니다.</p>
<h3 id="3-배운점-및-느낀점">3. 배운점 및 느낀점</h3>
<p><strong>문서화</strong></p>
<p>이번 프로젝트는 저에게 기술적인 성장 그 자체였고 동시에 <strong>소통과 협업의 본질에 대해 깊이 고민하게 해준 소중한 경험</strong>이었습니다.</p>
<p>프로젝트를 진행하면서 제가 맡은 도메인이나 기능들이 다소 복잡하고 규모가 크다 보니, 팀원 분들께서 고맙다는 말을 자주 전해주셨습니다. 그런데 실제로는 저야말로 이런 수준 높은 요구사항과 다양한 기술 스택을 실험해볼 수 있는 기회를 주신 팀원 분들께 더 감사한 마음이었습니다.</p>
<p>그러나 프로젝트를 진행하면서 한가지 아쉬움이 남았습니다. </p>
<p>한편, 제가 경험하고 체득한 지식과 기술을 충분히 공유하지 못했다는 점에서는 <strong>상당한 아쉬움</strong>도 남았습니다. 그로 인해 “내가 알고 있는 것”과 “팀이 함께 알고 있는 것”의 간극이 생길 수 있다는 사실을 체감했고, “모든 것은 결국 문서화로 완성된다”는 교훈을 얻게 되었습니다.</p>
<p>제가 이번 프로젝트에서 문서화로 남긴 부분은 다음과 같습니다. </p>
<ol>
<li><p>프로젝트 구조 및 디렉토리 컨벤션<img src="https://velog.velcdn.com/images/low_level_v99/post/8bb78f62-4138-4c1f-a301-e1f0a60aef75/image.png" alt=""></p>
</li>
<li><p>예외 처리 구조 및 사용 방법
<img src="https://velog.velcdn.com/images/low_level_v99/post/8d37bc7a-2c02-4a3b-8550-2102534f7cec/image.png" alt=""></p>
</li>
<li><p>환경 변수 등록 가이드
<img src="https://velog.velcdn.com/images/low_level_v99/post/20b73aa7-851b-4040-bab8-455d8bb20da5/image.png" alt=""></p>
</li>
<li><p>MSA 구조 전환 가이드
<img src="https://velog.velcdn.com/images/low_level_v99/post/da0eb432-470b-4734-a870-28e3f731b5d3/image.png" alt=""></p>
</li>
<li><p>코딩 컨벤션 및 코드 스타일
<img src="https://velog.velcdn.com/images/low_level_v99/post/9732982d-f781-492a-9151-e2319da2d3e8/image.png" alt=""></p>
</li>
<li><p>한/영 표기 기준
<img src="https://velog.velcdn.com/images/low_level_v99/post/020499fb-8c20-4b3e-8e2d-8249006e3026/image.png" alt=""></p>
</li>
<li><p>브랜치 컨벤션 및 관리 기준
<img src="https://velog.velcdn.com/images/low_level_v99/post/c8ba53ad-ed9f-4e89-b8b0-5ec66fde5aae/image.png" alt=""></p>
</li>
</ol>
<p>위의 문서들을 작성하며 가장 고민했던 것은 다음과 같습니다. </p>
<ul>
<li>이 문서가 과연 다른 사람에게 진짜 ‘전달’이 되고 있는가?</li>
</ul>
<p>저의 개인적인 관점에선 충분한 설명이라 여겼지만 팀원들이 이해하지 못하는 경우를 많이 보게 되었고 그 과정을 통해 문서의 품질은 누구에게 잘보이기 위한 것이 아니라 팀원의 이해도에 달려 있다라는 것을 깨달았습니다. </p>
<p>그래서 앞으로는 더 많은 예시와 시각적 정리 그리고 직관적인 표현 방식을 통해 구조적으로 예쁜 문서가 아닌 팀원들이 이해하기에 용이한 완벽한 문서를 작성하는 것이 저의 목표입니다.</p>
<p><strong>소통을 위한 안건함</strong></p>
<p>저번 DB 프로젝트를 진행하면서 소통의 문제점을 언급한바 있고 소통 문제를 해결하기 위한 방법으로써 안건함을 다음 프로젝트에서 진행해보고 싶다고 얘기한바 있고 이번 프로젝트에서 안건함을 도입해서 진행해봤습니다. </p>
<p>처음에는 ERD 작성까지는 활용도가 낮았지만, <strong>서버 개발이 시작되면서부터는 팀 내 의사결정과 논의 사항을 정리하는 데 큰 도움이 되었습니다.</strong> 하지만 여전히 다음과 같은 한계가 있었습니다. </p>
<ul>
<li>제목만 있고 내용이 비어있는 경우가 많다</li>
<li>작성된 안건을 확인하지 않는 경우도 존재</li>
</ul>
<p>이러한 문제를 보완하기 위해선 다음과 같은 체계적인 관리가 필요하다는 생각을 하게 되었습니다. </p>
<ul>
<li>안건 작성 양식의 표준화</li>
<li>확인 여부를 표시할 수 있는 체계 구축</li>
<li>디스코드 혹은 슬랙과 연동하여 <strong>알림 시스템 구현</strong></li>
</ul>
<p><strong>회고록은 정말 중요하다</strong></p>
<p>저번 DB 프로젝트 진행에 있어 정말 중요했던 것이 바로 회고록이였습니다. 그래서 이번 프로젝트에도 회고록을 도입했고 정말 감사하게도 같은 팀원분중 여진님께서 저희가 진행했던 팀미팅에 대한 회고록을 많이 담당해주셨습니다.</p>
<p>작성된 회고록을 통해 일정시간이 지난 후에도 저희가 무슨 얘기를 했었고 어떤 생각이었는지를 쉽게 확인할 수 있었고 각 회의별 액션 아이템을 추출하여 본질적으로 무엇을 해야할지에 대해 한눈에 확인하고 정리하는데 매우 도움이 되었던 것 같습니다. </p>
<p><strong>ChatGPT는 나의 자동화 도구</strong></p>
<p>저는 이번에  ChatGPT를 최대한 사용하지 않을 생각이었고 처음 코드 구현과정에선 모든 코드를 제가 작성했고 공부할 때만 개념의 깊이를 높이고 개념이 맞는지 확인하는 목적으로만 사용했던 것 같습니다. </p>
<p>왜냐하면 이전 자바 미니 프로젝트를 진행 했을 때 ChatGPT에 의존해서 프로젝트를 진행했었는데 결국에 남는 것은 아무것도 없다는 것을 허무함을 크게 느꼈기 때문입니다. </p>
<p>그런데 코드를 작성하다보니 동일하진 않지만 형식이 비슷한 코드들을 계속해서 작성하게 되고 제가 A부터 Z까지 작성할 수 있는 코드를 매번 처음부터 구현하는 것은 비효율적이라는 생각이 들었습니다. </p>
<p>그래서 제가 구조화한 틀 안에서 내가 원하는 스타일로 빠르게 코드를 생성하는 도구로서 ChatGPT를 사용했고 내가 구현할 수 없는 코드를 무비판적으로 받아들이는 것을 엄격하게 차단하고 자동화 파트너로서만 사용하는 것은 지금 시대에 효율적으로 업무를 처리하는 기술이지 않을까 싶습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체지향의 시작]]></title>
            <link>https://velog.io/@low_level_v99/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@low_level_v99/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Sat, 29 Mar 2025 05:42:00 GMT</pubDate>
            <description><![CDATA[<h2 id="언어란-무엇인가">언어란 무엇인가?</h2>
<blockquote>
<p>언어는 기호 체계이며 의미 전달 수단이다. </p>
</blockquote>
<p>언어라는 것은 사람이 소통을 위해 사용하는 언어와 컴퓨터 세계에서 사용하는 언어로 구분될 수 있는데요, 그 주체가 사람인지 시스템인지에 따라 나뉘긴 하지만 결국 중요한 것은 언어라는 것은 의미를 전달하고 해석하기 위한 기호 체계라는 것은 동일한 것 같습니다. </p>
<p>즉, 언어의 본질은 기호 + 문법 + 의미의 조합이고 컴퓨터 세상에서의 언어도 이 규칙을 지켜야 하는 것이죠</p>
<p>그렇다면 컴퓨터 세상에서의 언어는 정말 다양한 언어들이 존재하는데 이 언어들은 어떻게 구분될까요?</p>
<p>저는 언어의 사용방법에 따라 크게 명령형 언어와 선언형 언어로 구분할 수 있을 것 같습니다. </p>
<p>즉, html, css, js, python, java, c 등등은 서로 같은 언어가 아니라 구분을 할 수 있다는 것입니다. </p>
<h3 id="선언형declarative-언어">선언형(Declarative) 언어</h3>
<p>HTML, CSS, XML와 같은 것들이 포함되는 언어입니다. 이 언어들은 표현만 하고 실행 로직은 없습니다. 즉, 사람이 시스템한테 명령을 내리는 것이 아니라 이미 의미와 실행 규칙이 정해진 구문들을 선언하여 구조를 잡거나 스타일을 입히는 방법으로 언어를 사용하는 것입니다. </p>
<p>선언형 언어도 목적에 따라 구조를 잡는 것을 목적으로 한 마크업 언어나 스타일을 목적으로 한 스타일 시트 언어로 구분할 수 있습니다. </p>
<h3 id="명령형imperative-언어">명령형(Imperative) 언어</h3>
<p>반면에 명령형 언어는 개발자가 시스템에게 명령을 내릴 수 있도록 문법(Syntax)과 의미(Semantics)가 있고 실행 로직을 컴퓨터가 이해할 수 있는 언어로 변경할 수 있는 컴파일 또는 실행 체계를 포함한 언어를 의미합니다. </p>
<h2 id="객체지향을-이해">객체지향을 이해</h2>
<p>개발을 처음 시작했을 때 저는 &#39;Java는 객체지향 언어다&#39;, &#39;Spring은 IoC와 DI를 제공한다&#39;는 말을 그냥 활자 그대로 이해했는데요. 사실 처음에는 전혀 이해하지 못했다는 것입니다 ㅎㅎ</p>
<p>하지만 시간이 흐를수록 그 말들이 무슨 의미인지, 단순한 기술 용어 이상의 철학과 설계 원칙을 담고 있다는 것을 깨닫게 되었습니다. </p>
<p>이 글은 제가 객체지향과 설계 원칙, 그리고 스프링 프레임워크와의 연결을 이해해가는 과정을 아래에서 정리해보고자 합니다. </p>
<h2 id="프로그래밍-방식의-두-축-절차지향-vs-객체지향">프로그래밍 방식의 두 축, 절차지향 vs 객체지향</h2>
<p>개발자들은 수십 년간 더 나은 개발을 위해 어떤 방식으로 프로그램을 설계하고 구현할지에 대해 치열하게 고민해왔을 것입니다. 그 결과 두 가지 주요 패러다임이 나왔고 다음과 같습니다: </p>
<h3 id="절차지향-procedural-programming">절차지향 (Procedural Programming)</h3>
<ul>
<li><p>코드가 위에서 아래로 순차적으로 실행되며, 데이터와 함수가 분리되어 있습니다.</p>
</li>
<li><p>대표 언어: C</p>
</li>
</ul>
<h3 id="객체지향-object-oriented-programming">객체지향 (Object-Oriented Programming)</h3>
<ul>
<li><p>현실 세계의 개념을 추상화하여 객체로 표현합니다</p>
</li>
<li><p>데이터(속성)와 함수(행위)를 객체 내부에 캡슐화합니다</p>
</li>
<li><p>객체들 간의 메시지 전달로 협력하여 기능을 구현하는 것이 포인트입니다</p>
</li>
<li><p>대표 언어: Java, Kotlin, Python, C++ 등</p>
</li>
</ul>
<h2 id="좋은-객체지향-코드란-무엇일까">좋은 객체지향 코드란 무엇일까?</h2>
<p>객체지향으로 개발한다고 해서 모두가 좋은 코드를 작성하는 것은 아닙니다. 저도 처음에 자바라는 언어를 배우고 뭣모르고 코드를 짜봤는데 어떻게 코드를 작성해야할지 암담했습니다. 그래서 어떻게 코드를 작성하는 것이 좋을까라는 것을 고민에서 찾아보니 객체지향 설계를 도와주는 설계 원칙과 패턴들이 있다는 것을 알게되었습니다. </p>
<h3 id="solid-원칙">SOLID 원칙</h3>
<p>객체지향 설계의 핵심 원칙들:</p>
<ul>
<li><p>Single Responsibility Principle (단일 책임 원칙)</p>
</li>
<li><p>Open-Closed Principle (개방-폐쇄 원칙)</p>
</li>
<li><p>Liskov Substitution Principle (리스코프 치환 원칙)</p>
</li>
<li><p>Interface Segregation Principle (인터페이스 분리 원칙)</p>
</li>
<li><p>Dependency Inversion Principle (의존성 역전 원칙)</p>
</li>
</ul>
<h3 id="디자인-패턴">디자인 패턴</h3>
<ul>
<li><p>객체지향 원칙들을 기반으로, 반복되는 문제를 해결하기 위한 검증된 설계 방식</p>
</li>
<li><p>예: Singleton, Factory, Proxy, Strategy, Observer 등</p>
</li>
</ul>
<p>이 둘은 서로 유기적으로 연결됩니다</p>
<blockquote>
<p>즉, 디자인 패턴들은 SOLID 원칙을 실천하는 구체적인 도구이며 SOLID 원칙은 OOP 설계를 잘 수행하기 위한 추상적인 기준이라고 할수 있습니다. </p>
</blockquote>
<h2 id="스프링과-객체지향-설계">스프링과 객체지향 설계</h2>
<p>처음에 Spring은 <strong>DI(의존성 주입)</strong>과 <strong>IoC(제어의 역전)</strong>을 제공한다는 설명만 들었을 땐 정확히 와닿지 않았습니다. 하지만 아래 개념들을 이해하면서 그 의미가 명확해졌습니다.</p>
<h3 id="ioc-inversion-of-control">IoC (Inversion of Control)</h3>
<ul>
<li><p>제어권을 개발자가 아닌 프레임워크가 갖는 구조</p>
</li>
<li><p>개발자는 객체를 직접 생성하지 않고 <strong>IoC Container(Spring Container)</strong>에게 객체 생성을 맡김</p>
</li>
<li><p>라이브러리는 개발자가 호출하지만 프레임워크는 개발자의 코드를 호출함</p>
</li>
</ul>
<p>Spring에서는 이를 ApplicationContext라는 IoC Container가 구현하고 있습니다.</p>
<blockquote>
<p>즉, IoC Container는 객체를 새로 만들어주는 존재가 아니라 <strong>개발자가 제공한 정보(POJO + 설정 정보)</strong>를 기반으로 생명주기를 관리해주는 자동화 시스템인 것입니다. </p>
</blockquote>
<h3 id="pojo와-configuration-metadata">POJO와 Configuration Metadata</h3>
<ul>
<li><p>POJO: 순수한 자바 객체 (비즈니스 로직을 담은 클래스)</p>
</li>
<li><p>Configuration Metadata: 객체를 어떻게 생성하고 연결할지를 기술한 정보 (예: @Configuration, @Bean, XML 등)</p>
</li>
</ul>
<p>Spring은 POJO를 빈으로 등록하고, DI를 통해 객체 간의 결합도를 낮추고, 유연하게 변경이 가능한 구조를 제공합니다.</p>
<h3 id="di-dependency-injection">DI (Dependency Injection)</h3>
<ul>
<li><p>의존성이 필요한 객체를 내부에서 new로 생성하지 않고 외부에서 주입 받는 방식</p>
</li>
<li><p>주입을 통해 클래스는 자신이 사용하는 의존 객체의 구현에 대해 알 필요가 없고 인터페이스에만 의존할 수 있습니다</p>
</li>
<li><p>이는 곧 추상화에 의존 → OCP, DIP 실현으로 이어지게 됩니다. </p>
</li>
</ul>
<h2 id="결론">결론</h2>
<h4 id="oop-→-solid-→-디자인-패턴-→-프레임워크">OOP → SOLID → 디자인 패턴 → 프레임워크</h4>
<p>결국, 우리가 사용하는 스프링 프레임워크는 OOP 철학을 실천할 수 있도록 돕는 도구이며, 이를 위해 내부적으로 IoC, DI, 프록시, AOP 등의 메커니즘을 활용한다고 정리할 수 있을 것 같습니다. </p>
<p>따라서 저는 다음과 같은 순서를 따라가며 각각의 항목에 대 더욱 깊은 이해로 나아가고자 합니다. </p>
<ol>
<li><p>프로그래밍 언어와 그 문법/의미 구조에 대한 이해</p>
</li>
<li><p>OOP의 본질: 추상화, 캡슐화, 메시지 전달, 설계의 유연함</p>
</li>
<li><p>설계 원칙(SOLID)과 디자인 패턴의 필요성</p>
</li>
<li><p>이러한 철학이 구현된 프레임워크(Spring)의 내부 동작</p>
</li>
</ol>
<h3 id="💡-마치며">💡 마치며</h3>
<p>공부를 하다 갑자기 언어란 뭐지? 객체지향 프로그래밍이란 뭐지? 디자인 패턴은? SOLID는? 그렇다면 Spring은? 이라는 생각이 들면서 그러한 모든 일련의 과정들을 제 나름대로 정리해보고자 이번 글을 작성한 것입니다. </p>
<p>아직 이해하지 못한 것도 많고 특정 개념에 대한 설명을 요구하면 정리해서 말을 하지 못하는 경우가 많은데 점점더 이거는 이거야라고 분명하게 얘기할 수 있는 것들이 많아지는 저를 보며 개발자로서 성장하고 있다는 생각이 듭니다. </p>
<p>그럼 다음에는 더 의미있고 깊이있는 주제로 찾아오겠습니다. 긴 글 읽어주셔서 정말 감사드립니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring이 제공하는 IoC와 DI는 단순한 기능이 아니다]]></title>
            <link>https://velog.io/@low_level_v99/Spring%EC%9D%B4-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-IoC%EC%99%80-DI%EB%8A%94-%EB%8B%A8%EC%88%9C%ED%95%9C-%EA%B8%B0%EB%8A%A5%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@low_level_v99/Spring%EC%9D%B4-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-IoC%EC%99%80-DI%EB%8A%94-%EB%8B%A8%EC%88%9C%ED%95%9C-%EA%B8%B0%EB%8A%A5%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Fri, 28 Mar 2025 03:40:13 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>Spring Framework를 처음 공부할 때 &quot;Spring은 IoC와 DI를 제공한다&quot;는 개념을 들으면서 시작하실 겁니다. 저도 처음에는 IoC는 뭐고, DI는 뭐고, IoC Container는 뭔지 스스로 잘 정리했다고 생각하고 넘어갔는데 나중에 막상 IoC가 무엇인지 DI가 무엇인지 얘기해보라고 하면 당당하게 정돈된 내용을 얘기하지 못하는 저의 모습을 발견할 수 있었습니다. </p>
<p>그래서 IoC가 무엇이고 DI는 무엇인지에 대해 제대로 알아야겠단 생각을 하게 되면서 이번에 깊이 공부를 하게되었고 결국엔 특히 DI 개념이 객체지향 설계의 철학을 실현하는 방식이라는 것을 깨달았고 이것이 결국엔 SOLID 원칙의 OCP나 DIP와 같은 개념과 맞닿아 있는 기술이라는 것을 깨달으면서 Spring은 정말 잘 만든 프레임워크라는 것을 다시 한번 느끼게 되었습니다. </p>
<p>정리하자면 이번 글에서는 Spring이 제공하는 IoC와 DI가 무엇인지 알아보고 DI가 어떻게 SOLID 원칙 중 DIP를 어떻게 실현하는지에 대해 정리해보겠습니다. </p>
<h3 id="iocinversion-of-control란-무엇인가">IoC(Inversion of Control)란 무엇인가?</h3>
<p>IoC는 &quot;제어의 역전&quot;이라는 뜻입니다. 전통적인 절차적 프로그래밍에서는 객체를 생성하고 연결하고 실행하는 제어권이 개발자에게 있었습니다. 하지만 IoC는 이 제어권을 <strong>프레임워크(즉, Spring)</strong>에게 넘겨주는 개념입니다.</p>
<p>기존 방식</p>
<pre><code class="language-java">// 기존 방식
UserService service = new UserService(new UserRepository());</code></pre>
<p>IoC 방식 </p>
<pre><code class="language-java">// IoC 방식 (Spring이 객체를 생성하고 주입)
@Autowired
private UserService userService;</code></pre>
<h3 id="ioc-container란">IoC Container란?</h3>
<p>Spring에서는 이 IoC 개념을 ApplicationContext라는 이름의 IoC 컨테이너를 통해 실현합니다. 이 컨테이너는 단순히 객체를 만들어주는 공장이 아닙니다. 객체의 생명주기를 관리하고, 필요한 시점에 의존성을 자동으로 주입해주는 역할을 합니다.</p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/150f8cef-541c-430c-b56e-f42a8be0734a/image.png" alt=""></p>
<p>IoC에 대한 개념을 처음 접하게 되면 이런 생각이 드실 겁니다. &quot;그렇다면 개발자는 뭘 해야 돼...?&quot; 개발자는 IoC Container에게 2가지 정보를 제공하면 됩니다. </p>
<ol>
<li>POJO (Plain Old Java Object)</li>
</ol>
<ul>
<li>순수한 자바 객체입니다. 특정 인터페이스나 클래스를 상속하면 안됩니다. </li>
<li>우리가 작성한 비즈니스 로직의 주체입니다. </li>
</ul>
<ol start="2">
<li>Configuration Metadata (설정 정보)</li>
</ol>
<ul>
<li>POJO를 어떻게 생성하고, 어떻게 연결하고, 어떤 시점에 사용할 것인지에 대한 전략 및 설정에 대한 부분입니다. </li>
<li>대표적인 설정 방법은 다음과 같습니다<ul>
<li>어노테이션 기반: @Component, @Service, @Repository, @Configuration, @Bean</li>
<li>XML 설정</li>
<li>자바 코드 기반 설정 (JavaConfig)</li>
</ul>
</li>
</ul>
<p>즉, 개발자는 객체를 생성하고 의존관계를 설정하는 코드를 직접 작성하지 않고 단지 <strong>필요한 객체(POJO)</strong>와 <strong>구성 정보(Bean 설정 또는 어노테이션)</strong>만 Spring에게 넘깁니다. 그리고 나머지는 Spring이 알아서 처리합니다.</p>
<p>이로 인해 개발자는 객체의 생성과 연결 방식에 신경 쓰지 않고 순수 비즈니스 로직에만 집중할 수 있게 됩니다. </p>
<p>이에 대한 자세한 설명을 알고싶으신 분들은 <a href="https://docs.spring.io/spring-framework/reference/core/beans/basics.html">Spring 공식문서</a>에서 확인하시는 것을 강력하게 권장드립니다. </p>
<h3 id="didependency-injection---객체-간의-결합을-약하게-만드는-기술">DI(Dependency injection) - 객체 간의 결합을 약하게 만드는 기술</h3>
<p>DI는 객체가 자신이 사용할 객체를 직접 생성하지 않고 외부로부터 주입받는 방식을 의미합니다. </p>
<p>아래의 두개의 예시는 결합도가 높은 설계와 결합도가 낮은 설계에 대한 예시를 보여주고 있습니다. </p>
<p><strong>예시 1 : 결합도가 높은 설계(안 좋은 예)</strong></p>
<pre><code class="language-java">public class OrderService {
    private final UserRepository userRepository = new MemoryUserRepository(); // 강한 결합
}</code></pre>
<p><strong>예시2: 결합도가 낮은 설계(좋은 예)</strong></p>
<pre><code class="language-java">public class OrderService {
    private final UserRepository userRepository;

    // 생성자 주입
    public OrderService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}
</code></pre>
<p>둘의 차이가 보이시나요? 안 좋은 예의 경우엔 클래스 내부에서 필요한 개체를 직접 생성하고 있고 좋은 예의 경우엔 클래스 내부에서 개체를 직접 생성하는 방식이 아닌 외부에서 전달받고 있습니다. </p>
<p>즉, DI는 필요한 개체간 협력 방식을 설계하는 전략이고 필요한 개체가 어떤 구체화된 개체인지 알 필요 없이 전달받은 개체를 주입하여 사용할 수 있도록 하는 개념입니다.</p>
<p>더 나아가 Spring은 <strong>IoC 컨테이너를 활용해 이 주입을 자동화</strong>하는 하는 것이며 이것이 Spring 설계의 핵심입니다. Spring은 IOC 구현 기술로 DI를 사용하고 있다고 이해하는 것이 정확합니다. </p>
<p>개발자는 단지 필요한 추상화된 의존성만 선언하면 IoC 컨테이너가 알아서 객체의 생성 책임과 생명주기를 관리해주니 개발자는 비즈니스 로직에만 집중할 수 있게 되니 너무 편리하지 않나요?</p>
<h3 id="di와-dip의-관계">DI와 DIP의 관계</h3>
<blockquote>
<p>DIP(Dependency Inversion Principle): 고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 추상화(인터페이스)에 의존해야 한다.</p>
</blockquote>
<p>위의 내용은 SOLID 원칙 중 DIP의 개념에 대해 정리한 것입니다. 텍스트만 읽어보면 이해하기 쉽지 않습니다. 그런데 DI라는 방법을 통해 DIP가 적용되는 과정을 보시면 아 어떤 개념인지 곧바로 감을 잡으실 수 있으실 겁니다. </p>
<p>우선 상위 모듈과 하위 모듈을 정리해야 할 것 같습니다. 오해하시면 안되는 것이 상위와 하위라는 명칭에 의해 상위 모듈과 하위 모듈은 상속의 관계라고 혼동할 수 있는데 둘은 그런 관계가 아닙니다. </p>
<p>상위 모듈은 하위 모듈을 필요로 하는 개체입니다. 그리고 하위 모듈은 필요의 대상이 되는 개체입니다. </p>
<p>객체 지향 프로그래밍에선 모든 것이 개체이고 개체간의 연결관계를 설정할 때 상위 모듈에서 하위 모듈을 강하게 결합하고 있다면 유연성은 떨어지게 됩니다. </p>
<p>상위 모듈이 하위 모듈을 강하게 연결하는 예시는 다음과 같습니다.</p>
<pre><code class="language-java">class MechanicalKeyboard {
    public void type() {
        System.out.println(&quot;Typing on mechanical keyboard...&quot;);
    }
}

class Computer {
    private MechanicalKeyboard keyboard; // 구체적인 구현 클래스에 직접 의존

    public Computer() {
        this.keyboard = new MechanicalKeyboard(); // 직접 객체 생성
    }

    public void useKeyboard() {
        keyboard.type();
    }
}</code></pre>
<p>위의 예시에서 <code>Computer</code> 클래스는 <code>MechanicalKeyboard</code>를 필요로 하고 있습니다. 즉, <code>Computer</code> 클래스는 상위 모듈이고 <code>MechanicalKeyboard</code>는 하위 모듈입니다. 그런데 <code>Computer</code> 클래스의 내부 구조를 보니 생성자 함수 내부에서 <code>MechanicalKeyboard</code>를 생성하여 필드값으로 저장하고 메서드 내부에서 해당 객체를 사용하고 있는 것을 확인할 수 있습니다. </p>
<p>이러한 상황에서 만약에 <code>MechanicalKeyboard</code>가 아니라<code>WirelessKeyboard</code>를 필요로 하게 되면 어떻게 될까요? 
해당 구현체에 맞게 또 코드를 수정해야 되는 문제가 생깁니다. OCP(개방-폐쇄의 원칙)을 위반하게 됩니다. 
위의 예시로만 보면 겨우 몇개의 코드만 수정하면 되지만 프로젝트 단위가 커지면 커질수록 이 문제는 심각해질 것입니다. </p>
<p>그렇다면 어떻게 이 문제를 해결할 수 있을까요?
정답은 결합도를 느슨하게 해주는 것입니다. 너무 말이 추상적이죠? 이것을 구체적으로 가능하게 하는 방법중 하나가 DI인 것입니다. 즉, DI는 DIP를 가능하게 하는 방법중 하나인 것입니다. </p>
<p>위에서 DI는 뭐라고 했죠? DI는 내부에서 자원을 생성하는 것이 아니라 외부에서 자원을 가져오는 것입니다. DI를 적용한 결합도를 느슨하게 한 예시는 다음과 같습니다.</p>
<pre><code class="language-java">// 추상화된 인터페이스
interface Keyboard {
    void type();
}

// 다양한 키보드 구현체
class MechanicalKeyboard implements Keyboard {
    public void type() {
        System.out.println(&quot;Typing on mechanical keyboard...&quot;);
    }
}

class WirelessKeyboard implements Keyboard {
    public void type() {
        System.out.println(&quot;Typing on wireless keyboard...&quot;);
    }
}

// DIP 적용: 인터페이스에 의존
class Computer {
    private Keyboard keyboard;

    // 의존성 주입 (Dependency Injection)
    public Computer(Keyboard keyboard) {
        this.keyboard = keyboard;
    }

    public void useKeyboard() {
        keyboard.type();
    }
}

public class DIPExample {
    public static void main(String[] args) {
        Keyboard mechanical = new MechanicalKeyboard();
        Computer pc1 = new Computer(mechanical);
        pc1.useKeyboard();

        Keyboard wireless = new WirelessKeyboard();
        Computer pc2 = new Computer(wireless);
        pc2.useKeyboard();
    }
}</code></pre>
<p>위의 예시를 확인해보시면 이제 더이상 <code>Computer</code>는 <code>MechanicalKeyboard</code>라는 구체화된 클래스에 의존적이지 않아도 됩니다. <code>Computer</code>는 이제 <code>Keyboard</code>라는 인터페이스에 의존적이게 되면서 해당 인터페이스를 구현하는 어떤 구현체든 상관없이 모두 가져와서 사용할 수 있게 됩니다. </p>
<p>즉, 상위 모듈은 DI 방법을 통해 하위 모듈이 아니라 인터페이스에 의존하게 되면서 인터페이스에만 집중해서 이 인터페이스에서 정의한 코드만 사용할거고 이것만 필요하고 이거를 누가 어떻게 구현했는지는 상관을 전혀 안하고 클래스를 설계할 수 있게 됩니다. </p>
<h3 id="정리">정리</h3>
<blockquote>
<p>&quot;IoC는 DI를 자동화하고 DI는 DIP를 구현한다. &quot;</p>
</blockquote>
<p>위의 내용들을 토대로 IoC와 DI, 그리고 결론적으론 DIP 구현에 대한 개념이 유기적으로 연결된다는 것을 확인해볼 수 있었고 결론적으로 Spring은 우리가 객체지향적으로 더 잘 설계할 수 있도록 도와주는, 훌륭한 설계 보조자라는 것을 다시한번 깨달으며 앞으로 Spring의 구조를 더 면밀하게 분석해보면서 객체 지향에 대한 전반적인 개념을 모두 정리하는 것이 저의 목표입니다. </p>
<p>긴 글 읽어주셔서 감사드리고 오늘 하루도 수고 많으셨습니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 Beyond SW캠프 15기 9주차]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-Beyond-SW%EC%BA%A0%ED%94%84-15%EA%B8%B0-9%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-Beyond-SW%EC%BA%A0%ED%94%84-15%EA%B8%B0-9%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Tue, 25 Mar 2025 14:08:38 GMT</pubDate>
            <description><![CDATA[<h3 id="9주차에-대하여">9주차에 대하여</h3>
<p>드디어 Spring Framework를 본격적으로 배우기 시작했다. 처음으로 Spring Framework를 접했을 때 바로 『Clean Code』의 함수(메서드) 관련 챕터가 떠올랐다. 그 챕터에서는 함수가 두 줄을 넘지 않아야 한다고 강조하는데 이는 곧 클라이언트가 호출하는 코드 즉 추상화 레벨이 가장 높은 함수가 내부 구현에 대해 전혀 알 필요가 없도록 설계하라는 의미처럼 보였다. 그리고 Spring Framework는 그러한 철학을 극도로 구현한 기능을 제공하는 듯했다.</p>
<p>라이브러리와 프레임워크의 차이에 대해 늘 “제어권을 누가 갖느냐”로 구분하라고들 말한다. 하지만 프론트에서 React와 같은 라이브러리나 프레임워크를 사용할 때는 이 차이가 크게 와 닿지 않는 경우가 많았다. 예컨대 React는 컴포넌트 기반으로 UI를 구성하는 규칙이 있고 그 규칙에 맞춰 코드를 작성해야 한다. 그럼에도 React는 프레임워크가 아니라 라이브러리로 분류되며 사실상 UI 쪽 기능에 집중된 라이브러리다.</p>
<p>반면 Spring을 사용하면서는 “아, 이게 바로 진짜 프레임워크구나”라는 생각이 절로 들었다. 필요한 빈을 IoC 컨테이너에 등록하기만 하면 스프링이 자동으로 객체를 생성해주고 의존성을 주입해준다. 덕분에 개발자는 반복적이고 복잡한 설정 대신 비즈니스 로직에만 집중할 수 있게 된다. 이 과정을 지켜보며 스프링이 알아서 처리해주는 범위가 놀라울 정도로 넓다는 사실에 감탄했다.</p>
<p>더 나아가 Spring Boot를 접했을 때는 한층 더 큰 감동을 느꼈다. Spring Boot는 Spring Framework보다 훨씬 간소화되어 개발자가 고려해야 할 요소가 더 적다. 예를 들어 ‘spring-boot-starter-web’ 하나만 추가해도 필요한 의존성 대부분이 자동으로 관리되니 프론트엔드에서 여러 라이브러리를 의존성 패키지로 관리하고 충돌에 시달리던 기억과 비교하면 혁명적이라는 생각이 들었다.</p>
<p>Spring Web MVC 역시 인상적이다. Node.js에서 Express 프레임워크를 사용할 때는 복잡한 설정으로 핸들러를 하나하나 등록하고, 포트 설정부터 응답 처리까지 모두 직접 제어해야 하며 전달받은 데이터도 직접 전처리해야 한다. 하지만 Spring Web MVC는 거의 모든 것을 스스로 처리해주고 개발자는 단지 컨트롤러만 설정하면 된다. 그 외에 요청과 응답에 관한 설정은 전부 스프링이 알아서 관리하니 너무나 놀라울 따름이다.</p>
<h3 id="느낀점-및-배운점">느낀점 및 배운점</h3>
<p>이번 주에 드디어 백엔드 프로젝트를 시작했는데 팀원 한 분과 처음부터 크게 부딪치는 일이 생겼다. </p>
<p>처음에는 많이 당황스럽고 기분이 좋지 않았지만 감정에 치우치기보다는 이성적으로 접근했다. 지금 이 문제를 해결했을 때와 그렇지 않았을 때의 결과를 비교해보니 해결하는 편이 앞으로의 프로젝트 진행에 훨씬 유리하다는 결론이 나왔기 때문이다.</p>
<p>그래서 우선 상대방 입장에서 어떤 문제가 있었는지 진심으로 고민해봤고 그 과정에서 내 문제점도 함께 생각해볼 수 있었다. 결국 내 잘못된 부분을 인정하고 사과를 전했다.</p>
<p>또 이전 회사에서의 경험을 떠올려보니 마찰이 생겼을 때 무작정 참기만 하는 것은 절대 좋지 않았다. 그래서 내가 인지한 문제점을 있는 그대로 말씀드렸고 다행히도 팀원분께서도 진지하게 들어주시고 사과해 주셨다. 덕분에 지금은 전혀 문제가 없을 뿐 아니라 팀 분위기가 더욱 좋아졌다. 오히려 이전 팀보다 소통이 원활해졌고 프로젝트에 대한 집중도도 크게 상승했다.</p>
<p>이번 일을 통해 다시금 ‘고통 없는 성장은 없다’는 말을 실감했다. 문제가 생겨야 비로소 성장과 더 좋은 결과를 이끌어낼 수 있다는 사실을 또 한 번 깨닫게 된 계기였다.</p>
<h3 id="앞으로의-계획">앞으로의 계획</h3>
<ol>
<li>기술적 역량 심화</li>
</ol>
<ul>
<li>Spring Framework 및 Spring Boot<ul>
<li>기존에 학습한 IoC, DI, AOP 등의 개념을 실제 프로젝트에 더욱 적극적으로 적용해보고, 추가로 Spring Security, Spring Data JPA 등 주요 모듈의 동작 원리를 심화 학습해 보고자 한다. </li>
</ul>
</li>
</ul>
<ol start="2">
<li>프로젝트 진행</li>
</ol>
<ul>
<li>요구사항 정의서 초안 작성<ul>
<li>이전 프로젝트에서는 요구사항 정의서를 처음부터 너무 완벽하게 구성하려다 많은 시간이 소요된 아쉬움이 있었다.  </li>
<li>이를 통해 초기 기획과 실제 구현 간의 갭을 효과적으로 줄이고, 요구사항 변경에 유연하게 대처할 수 있을 것으로 기대한다. </li>
</ul>
</li>
<li>한/영 속성 표기표<ul>
<li>이전 프로젝트에서 유용했던 컨벤션 중 하나가 한글 명칭과 영어 명칭을 일관적으로 정의한 표였다.</li>
<li>이번에도 우리 프로젝트에서 사용하는 주요 용어, 접두사(prefix), 접미사(suffix) 등을 한/영으로 미리 정의해두어, 데이터베이스 설계나 코드 내 변수·필드명 등에서 혼선이 생기지 않도록 할 예정이다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 Beyond SW캠프 15기 8주차]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-Beyond-SW%EC%BA%A0%ED%94%84-15%EA%B8%B0-8%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-Beyond-SW%EC%BA%A0%ED%94%84-15%EA%B8%B0-8%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Sun, 16 Mar 2025 14:01:40 GMT</pubDate>
            <description><![CDATA[<h3 id="🤫-8주차-그리고-부트캠프-전-과정을-돌아보며">🤫 8주차 그리고 부트캠프 전 과정을 돌아보며</h3>
<blockquote>
<p>내가 가고 있는 길에 대한 방향성 검토</p>
</blockquote>
<p>벌써 부트캠프에 참여하게 된지 대략 2개월이라는 시간이 흐르게 되었습니다. 짧다면 짧고 길다면 긴 시간동안 많은 성장과 변화의 기회를 가졌다고 생각합니다. </p>
<p>새로운 개념에 대한 학습 뿐만 아니라 배울점으로 가득찬 부트캠프라는 공간에서 원초적으로 나는 어떤 개발자가 되고 싶은지에 대한 초석을 다지고 개인적으로 어떤 수행 과정이 필요한지에 대한 단계들에 대한 정보를 얻고 정리할 수 있는 기회를 매일매일 얻고 있습니다. 우선 구체적으로 나는 &quot;어떤 개발자가 되고 싶은가?&quot;에 대한 생각들을 나름대로 정리해봤습니다. </p>
<p><strong>💡 나는 어떤 개발자가 되고 싶은가?</strong></p>
<ol>
<li><p>사용자 경험의 극대화</p>
<p>저는 이전부터 느꼈지만 남을 이해시키는 여러가지 방법들 중 최선의 방법을 도출하는 것을 좋아하는 것 같습니다. 단순히 사람과 사람간의 커뮤니케이션 속에서도 상대방의 상황과 환경을 고려하여 적합한 단어를 선택하여 대화가 유연하게 흐르는 것을 좋아합니다. </p>
<p>저는 디자인을 단순히 &quot;예쁨&quot;의 영역이 아니라 의사소통의 도구라고 생각하는데요, 만약에 텍스트로 그 의미가 전달 될 수 있다면 텍스트만 사용해도 된다고 생각하는 편입니다. </p>
<p>따라서 기술적으론 목표한 의미를 효과적으로 전달하는 장치를 설계하여 결론적으론 사용자 경험을 높이는 방법을 고민하는 과정에서 큰 즐거움을 느끼는 것 같습니다.  </p>
</li>
<li><p>설계와 최적화에 대한 관심</p>
<p>저는 또한 효율적이고 유지보수가 용이한 코드를 작성하는 것에 대한 희열을 느끼곤 하는데요. 예시로 클린코드에서 하나의 함수내 2<del>30줄 내외의 코드를 단지 1</del>2줄의 코드로 변환하는 것을 보며 아름다움과 경외감을 느꼈고 비효율적인 작업을 최소화하는 과정에서 큰 보람을 느끼는 편입니다. </p>
</li>
<li><p>기술적 역량</p>
<p>저는 프론트 쪽을 대략 1~2년 정도 공부하면서 react, next-js, typescript 등을 조금 깊게 공부하였고 디자인툴도 피그마, AdobeXD, 포토샵, 프리미어 프로 등의 툴을 다룰 수 있고 백엔드 쪽은 현재 자바쪽으론 현재 부트캠프에서 학습하고 있고 추가적으로 node.js를 다룰 수 있습니다. </p>
</li>
<li><p>소통 및 계획 능력</p>
<p>작년에 해외 한류박람회를 기획하고 운영하는 회사에서 근무했었는데 이때 정말 많은 사람들과 소통할 수 있는 기회를 가졌었습니다. 클라이언트인 정부쪽 관리자들 뿐만 아니라 개발자, 디자이너, 벤더사, 현장 스태프, 제작 업체등 다양한 직종의 사람들과 소통하는 과정에서 클라이언트의 요구사항을 분석하는 해독 능력을 향상할 수 있었고 반대로 외주 업체에게 어떻게 요청을 해야하는지에 대한 방법을 고민하고 설계하는 과정이 소통능력 향상에 있어 매우 중요한 경험이었던 것 같고 또한 큰 단위의 실행 계획을 세우는 것부터 정말 작은 단위 예로들어 대사관님들이 어느 지점에 내려서 어떤 경로로 이동하고 스탠바이 해야 하는지 그 과정을 초단위로 설계하는 과정이 계획 능력 향상에 매우 중요했던 것 같습니다. </p>
</li>
</ol>
<p>따라서 저는 제가 좋아하는 것과 저의 현재 기술 스택 및 역량들을 생각해보면 기획과 디자인을 포함한 다양한 분야의 경험을 바탕으로, 목표한 의미가 정확히 전달할 수 있는 웹 앱을 설계하고효율적인 시스템 설계와 자동화를 통해 서비스 개발 기간을 단축을 목표로 하는 풀스택 개발자가 적성에 맞을 것 같단 결론을 내리게 되었습니다. </p>
<p>따라서 저는 앞으로 사용자 경험을 극대화하고, 효율적이고 최적화된 시스템 설계를 실현하는 것을 목표로 앞으로의 학습을 진행하고자 합니다. </p>
<p>*<em>💡 그렇다면 나는 무엇을 해야할까? *</em></p>
<ol>
<li><p>문제 파악 능력 강화</p>
<p>다른말로 하면 독해인데, 독해는 사실 풀스택이든 프론트이든 백엔드이든 어떤 직업이든 필수적으로 수반되어야 하는 능력이라고 생각합니다. </p>
<p>제가 해보고 싶은 것은 <code>KISA</code>내의 입찰 공고의 제안요청서를 분석하고 그 안에서 구체적인 요구사항을 명확하게 파악한 후, 각 요구사항을 어떻게 해결할 수 있을지에 대한 기술정 방법을 찾고 해당 방법을 실제 구현하는 절차와 언어, 패턴등을 정의하여 구현 가능한 해결책을 제시하는 연습을 해보고 싶고 자바로 해결 가능한 제안요청서의 경우엔 실제로 최종 프로젝트에서 해결해보는 경험을 갖고 싶습니다. </p>
</li>
<li><p>문서화 능력</p>
<p>현재 매주 블로그를 작성하는 것도 문서화 능력을 기르기 위한 초석에 해당하는데요, 이 뿐만 아니라 실제 현업에선 주간 보고서와 월간 보고서를 작성하고 하나의 프로젝트에 대한 최종 보고서를 작성하는 일을 해야 하는 것으로 알고 있습니다. 
따라서 현업에서 이와 같은 일을 수행하기 위해선 지금부터라도 기술적 내용을 명확하게 작성하는 연습을 할 필요가 있을 것 같습니다. </p>
</li>
<li><p>자동화 경험 쌓기</p>
<p>비효율적인 작업을 자동화하는 경험을 부트캠프 내에서 쌓고, 실제 프로젝트에서 이를 적용하여 개발 과정에서 발생하는 반복적인 작업을 효율적으로 처리하는 경험을 쌓고자 합니다. </p>
</li>
<li><p>TDD 실습</p>
<p>클린 코드를 보든 실제 현업에서 일을 하시는 분들의 얘기를 들어보면 항상 테스트 코드에 대한 중요성을 얘기하는 것을 심심찮게 확인할 수 있습니다. 저 또한 단순한 미니 프로젝트를 진행하면서 디버깅의 어려움을 느꼈고 이에 따라 유닛별 테스트 코드를 작성하는 것의 중요성을 절실히 느끼고 있고 따라서 다음 프로젝트에선 TDD 프로세스에 따라 프로젝트를 진행해보고 싶습니다. </p>
</li>
<li><p>영어 능력</p>
<p>클린 코드를 읽으면서 함수명을 서술식으로 작성하라는 저자의 주장에 대해 깊이 있는 공감을 하려면 우선적으로 영어 공부를 해야겠단 생각을 하게되었습니다. 그리고 우리가 코드를 한국어로 작성하지 않는 이상 영어를 공부하는 것은 소통의 목적이 아니더라도 개발자라면 필수적인 역량인것 같단 생각을 요즘들어 하고 있습니다. </p>
<p>클린 코드 책을 읽으면서 가장 공감이 든 부분이 시스템은 단순히 모듈이나 기능들의 나열이 아니라 하나의 스토리로 구성된다는 것이었는데 그 스토리를 보다 잘 이해하기 위해선 영어를 정확하게 이해하고 활용하는 능력이 매우 중요할 것 같습니다. </p>
</li>
</ol>
<h3 id="😎-느낀점-및-배운점">😎 느낀점 및 배운점</h3>
<p>*<em>💡 시간 관리 체계화 *</em></p>
<p>부트캠프에 참여하면서 시간 관리의 중요성을 다시 한 번 실감했습니다. 그동안 &quot;시간 관리를 하고 있다&quot;고 느꼈지만, 실제로는 제대로 관리되지 않은 경우가 많았습니다. 급한 일에 쫓기거나 중요한 일을 미루는 일이 반복되었고, 그 원인은 반복적인 피드백 부족과 전체적인 일정 관리의 부재 때문이라고 생각합니다.</p>
<p>이를 해결하기 위해 저는 체계화된 시간 관리 방법에 대해 깊이 고민했습니다. 이 과정에서 중요한 것은 주기적인 피드백과 전체적인 일정을 한눈에 볼 수 있는 시스템을 구축하는 것이었습니다.</p>
<p>다음 <a src="https://velog.io/@low_level_v99/%EC%8B%9C%EA%B0%84-%EA%B4%80%EB%A6%AC-%EC%B2%B4%EA%B3%84%ED%99%94">시간 관리 체계화 포스팅</a>에서 상세히 정리한 것처럼, 시간을 전략적으로 활용하고 진행 상황을 주기적으로 점검하여 실천적인 피드백을 반영하여 중요한 일에 집중하고, 불필요한 일을 최소화하면서 학습과 업무를 더욱 효율적으로 처리할 것을 기대하고 있고 백엔드 프로젝트 까지 보다 체계화된 시간 관리 방법이 어떻게 효과가 있었는지에 대해선 추후에 정리하고자 합니다. </p>
<p>*<em>💡 폴더 관리 체계화 *</em></p>
<p>시간 관리만큼 중요한 것이 파일 및 자료 관리입니다. 부트캠프 진행 중에 점점 쌓여가는 자료들, 특히 강의 소스 코드, 프로젝트 자료, 스터디 관련 파일들이 하나의 폴더에 섞여 있어 원하는 자료를 빠르게 찾는 데 어려움을 겪었습니다.</p>
<p>이 문제를 해결하기 위해 저는 이전 회사에서 수천 개의 파일을 관리했던 경험을 되새기며, 디렉토리 구조를 체계화하여 명확하게 분류하기 시작했습니다. 이 과정에서 가장 중요한 것은 주제별로 명확한 구분을 두고, 필요한 자료를 쉽게 찾을 수 있는 시스템을 만드는 것이었습니다. 이는 제 업무를 효율적으로 관리하는 데 큰 도움이 되었으며, 검색 시간 절약과 업무 흐름의 개선을 가져왔습니다.</p>
<p>이와 관련된 방법은 <a src="https://velog.io/@low_level_v99/%EB%94%94%EB%A0%89%ED%86%A0%EB%A6%AC-%EA%B5%AC%EC%A1%B0-%EC%B2%B4%EA%B3%84%ED%99%94-%EA%B3%BC%EC%A0%95">디렉토리 구조 체계화 포스팅</a>에서 더 자세히 다뤘으니, 관심 있는 분들은 참고해주시기 바랍니다.</p>
<h3 id="🧐-앞으로의-계획">🧐 앞으로의 계획</h3>
<p>부트캠프의 8주차를 마무리하며, 저는 제 성장 과정을 되돌아보고 향후 목표와 계획을 체계적으로 정리할 수 있었습니다. 그동안 많은 것을 배우고 경험했지만, 여전히 부족한 점이 많은것은 사실인 것 같습니다. 그럼에도 불구하고 이젠 제가 어떤 개발자가 되고 싶은지도 확실해졌고 이를 통해 풀스택 개발자로서의 목표를 더 구체적으로 정의할 수 있게 되었고 그 목표를 달성하기 위해 필요한 학습과 실습을 체계적으로 정리할 수 있다는 것 만으로도 많은 성장을 이룬 것 같습니다. </p>
<p>앞으로의 계획을 바탕으로, 제 역량을 지속적으로 키우고, 사용자 경험을 극대화하는 시스템 설계와 효율적인 개발을 실현할 수 있는 개발자로 성장하고자 최선을 다하겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[시간 관리 체계화]]></title>
            <link>https://velog.io/@low_level_v99/%EC%8B%9C%EA%B0%84-%EA%B4%80%EB%A6%AC-%EC%B2%B4%EA%B3%84%ED%99%94</link>
            <guid>https://velog.io/@low_level_v99/%EC%8B%9C%EA%B0%84-%EA%B4%80%EB%A6%AC-%EC%B2%B4%EA%B3%84%ED%99%94</guid>
            <pubDate>Sun, 16 Mar 2025 12:22:54 GMT</pubDate>
            <description><![CDATA[<h3 id="문제의식">문제의식</h3>
<p>현재 저는 시간 관리에 대한 어려움을 겪고 있습니다. 매일 일정 관리에 애쓰고 있지만, 중요한 일을 끝내지 못하거나 미뤄두는 일이 반복되곤 했습니다. 특히 시험 준비나 프로젝트 진행 중에 계획보다 시간이 부족해져 늘 쫓기며 공부하고 업무를 처리하는 모습을 되돌아볼 수 있었습니다.</p>
<p>이 문제의 근본적인 원인은 체계적인 계획 부족과 우선순위 설정의 실패에서 비롯되었다고 생각합니다. 그동안 저는 단기적인 할 일 목록만 작성하고 이를 수행하려 했습니다. 하지만 이로 인해 장기적인 목표나 전체적인 일정을 놓치게 되었고, 급한 일에 몰두하다 보니 중요한 일이 미뤄지고 결국엔 시간에 쫓기게 되는 반복적인 상황을 겪었습니다.</p>
<p>또한, 진행 상황을 체크하고 피드백을 받는 시스템이 부족하여 미처 끝내지 못한 일을 그저 넘기는 일이 반복되었습니다. 이러한 문제를 해결하기 위해서는 시간을 체계적으로 관리하고 목표를 확실히 달성할 수 있는 시스템을 구축해야 한다고 확신하게 되었습니다.</p>
<h3 id="시간관리-체계화-방법-구조화하기">시간관리 체계화 방법 구조화하기</h3>
<p>효율적인 시간 관리를 위해서는 명확한 목표 설정과 실현 가능한 계획 수립이 필요합니다. 저는 그동안 시간 관리에서의 실패를 토대로 구체적인 시간 관리 체계를 설정하게 되었습니다. 아래는 제가 생각한 시간 관리 체계화 방법입니다.</p>
<p>1) 수시로 진행 상황 체크하기</p>
<p>하루를 체계적으로 관리하려면 할 일의 우선순위를 설정하고, 매일 진행 상황을 체크하는 것이 필요합니다. 진행 중인 작업을 피드백하며 목표 달성 여부를 점검하고, 미진한 부분은 내일의 계획에 반영하여 지속적으로 개선해 나가고자 합니다.</p>
<ul>
<li>피드백을 통한 점검: 하루의 끝에서 오늘 목표를 얼마나 잘 수행했는지 점검하고, 어떤 부분에서 어려움이 있었는지 파악합니다. 이를 통해 내일의 계획을 더 효율적으로 수정할 수 있도록 합니다</li>
<li>하루 내내 수차례 점검: 하루 중간중간에 진행 상황을 점검하면서, 계획을 조정하고 피드백을 적용하여 더 나은 방식으로 목표를 향해 나아갈 수 있도록 합니다.</li>
</ul>
<p>2) 목표 설정과 구체화</p>
<p>시간 관리의 핵심은 목표를 명확히 설정하고 구체화하는 것입니다. 저는 그동안 단기 목표만 설정하고 이를 수행하려 했으나, 그로 인해 장기적인 목표를 놓치거나 전체적인 일정을 관리하지 못했습니다. 이제는 장기 목표와 단기 목표를 명확히 구분하여 설정하고, 이를 체계적으로 관리하려 합니다</p>
<ul>
<li>장기 목표와 단기 목표 나누기: 예를 들어, 자격증 취득, 정보처리기사 실기, 풀스택 개발자가 되는 것 등과 같은 장기적인 목표를 설정하고, 이를 달성하기 위한 단기 목표를 설정하고자 합니다. </li>
<li>목표의 우선순위 정하기: 장기 목표는 전체적인 방향성을 제공하지만, 단기 목표는 실질적으로 매일 해야 할 일들을 관리하는데 중점을 둡니다.</li>
<li>구체적인 실행 계획 세우기: 목표를 달성하기 위한 단계별 실천 계획을 세우고, 이를 실천 가능한 작은 단위로 나누어 실행해 나가고자 합니다. </li>
</ul>
<p>3) 목표 성격에 맞는 구분</p>
<p>또한 목표의 성격에 따라 구분하고 관리하는 것이 중요하다고 생각합니다. 자격증 취득, 프로젝트 진행, 영어 능력 향상 등은 각각 다른 성격을 가진 목표이기 때문에, 이를 별도로 관리하여 실천할 수 있도록 하고자 합니다. </p>
<ul>
<li>[퀘스트] 섹션을 통한 관리: 자격증 취득이나 프로젝트와 관련된 목표는 [퀘스트] 섹션에서 관리하고, 각 퀘스트 섹션에서 세부 일정과 내용을 일정에 맞춰 관리하고자 합니다. </li>
<li>[목표] 섹션을 통한 관리: 영어 능력 향상, 문서화 능력 등과 같은 개인적이고 추상적인 목표는 [목표] 섹션에서 관리하며, 이를 실제 실행 가능한 작은 일로 변환하여 오늘 해야 할 일에 포함시켜 순차적으로 하나씩 제가 하고자 하는 일을 수행하고자 합니다. </li>
</ul>
<p>4) 목표 자동화 및 연계
목표와 관련된 항목을 자동화하여 실행 가능한 목표와 일정을 연계할 수 있도록 시스템을 구축하고자 합니다. 이를 통해 목표 설정과 일정 관리가 더 효율적으로 이뤄질 수 있도록 할 것입니다.</p>
<ul>
<li>목표와 계획 자동화: 예를 들어, 노션을 사용하여 [목표] 섹션과 [계획] 섹션을 자동으로 연결하여, 목표 달성을 위한 실천 계획을 자동으로 연계하고, 이를 실시간으로 확인할 수 있게 할 것입니다. </li>
</ul>
<h3 id="앞으로의-계획">앞으로의 계획</h3>
<p>현재 설계한 시간 관리 체계화 방법을 백엔드 프로젝트와 정보처리기사 실기 준비에 적용할 예정입니다. 한 달 뒤, 이 방법이 과연 실제로 어떤 도움이 되었는지, 어떤 점에서 개선이 필요한지 평가해볼 계획입니다. 그 후, 피드백을 바탕으로 더욱 효율적이고 실행 가능한 시스템으로 개선하고자 합니다.</p>
<p>시간 관리 체계화는 단순히 일정을 맞추는 것이 아니라, 지속 가능한 성장을 위한 중요한 습관임을 잘 알고 있습니다. 목표 설정과 구체적인 계획 수립을 통해, 진행 상황을 체크하고 목표를 달성하는 능력을 키워나가며, 자기계발과 프로젝트 성공을 이룰 수 있도록 최선을 다하겠습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[디렉토리 구조 체계화 과정]]></title>
            <link>https://velog.io/@low_level_v99/%EB%94%94%EB%A0%89%ED%86%A0%EB%A6%AC-%EA%B5%AC%EC%A1%B0-%EC%B2%B4%EA%B3%84%ED%99%94-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@low_level_v99/%EB%94%94%EB%A0%89%ED%86%A0%EB%A6%AC-%EA%B5%AC%EC%A1%B0-%EC%B2%B4%EA%B3%84%ED%99%94-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Sun, 16 Mar 2025 10:31:12 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-의식">문제 의식</h3>
<p>현재 한화시스템 부트캠프에서 제공되는 소스 코드, 강의 자료, 프로젝트 파일 등이 점점 많아지면서 자료를 효율적으로 관리하고 빠르게 접근하는 데 어려움을 겪고 있습니다. 매일 진행하는 학습과 실습을 통해 쌓여가는 자료들이 많아짐에 따라, 검색과 파일 관리가 점점 더 복잡해지고 있습니다. 이러한 문제를 해결하기 위해 자료를 체계적으로 관리하고, 효율적인 접근 방식을 마련할 필요성을 느꼈습니다.</p>
<p>부끄럽지만 현재 제 파일 관리 상태는 아래와 같습니다. 한눈에 봐도 정리가 되어 있지 않고, 원칙 없이 파일들이 혼재되어 있는 상황입니다. 이러한 관리 방식은 다른 개발자와 협업을 하기에 불편하고 비효율적이기 때문에, 체계적인 관리가 필요함을 강하게 인식하게 되었습니다.</p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/baff777f-2c1a-4868-a31f-2ed29754a130/image.png" alt=""></p>
<p>부끄럽지만 현재 개인 문서 관리의 상태를 보면, 폴더 구조에 대한 원칙이 전혀 없으며, 이로 인해 자료 검색이 불편하고, 필요한 파일을 찾는 데 시간이 소요됩니다. 저는 그동안 체계적이지 않은 폴더 관리로 인한 불편함을 겪었고, 폴더 구조 정리의 중요성을 깨닫게 되었습니다.</p>
<p>그리고 부트캠프의 형님께서 항상 말씀하신 &quot;처음부터 모든 것을 완벽하게 설계하는 사람은 없지만, 어지르지 않는 것을 습관화해놓은 사람은 처음부터 어느 정도 구조가 잡혀있다&quot;라는 조언을 떠올리며, 지금이라도 파일 구조를 체계화해야겠다는 생각을 하게 되었습니다.</p>
<h3 id="해결방법-찾기">해결방법 찾기</h3>
<p>문제를 해결하기 위해 이전 회사에서의 경험을 바탕으로 MICE 원칙을 적용하여 자료를 조직적이고 직관적인 방식으로 관리하고자 했습니다. 이전 회사에서 한류박람회를 기획하고 운영할 때, 수천 개의 파일을 관리해야 했습니다. 이때 정리된 폴더 구조가 없었다면, 업무가 불가능했을 것입니다. 모든 업무를 진행하기 위해 필요한 파일을 빠르게 찾는 것이 필수적이었기 때문입니다.</p>
<p>저는 당시 MICE 원칙을 적용하여 파일을 간단하게 기억하고 쉽게 접근할 수 있도록 폴더 구조를 설정했습니다. 그때의 핵심 규칙은 다음과 같았습니다:</p>
<p>그때의 핵심 규칙은 다음과 같았습니다. </p>
<ul>
<li>큰 주제에서 작은 주제로 나누기</li>
<li>업무 외 항목은 최상위 폴더로 구분하기</li>
<li>조회가 자주 이루어지는 폴더는 빠르게 접근할 수 있도록 배치 (해당 규칙은 업무와 관련된 폴더만 적용)</li>
</ul>
<p>이 규칙들을 기반으로 한화시스템 부트캠프와 다른 강의 및 프로젝트들에 대해 각각 독립적인 최상위 폴더를 설정하여 관리하고자 하는데요 마지막 규칙인 &quot;조회가 자주 이루어지는 폴더는 빠르게 접근할 수 있도록 배치&quot;하는 규칙은 업무에서만 필요한 것 같아 해당 규칙은 제외한 나머지 규칙들만을 적용하여 관리하고자 합니다. </p>
<h3 id="디렉토리-구조">디렉토리 구조</h3>
<p><strong>1. 한화시스템 부트캠프 관련 자료 (hanwha-system-bootcamp)</strong></p>
<p>한화시스템 부트캠프 관련 자료는 크게 강의 자료, 프로젝트 및 스터디 자료로 나누어 관리합니다. 강의 자료는 주제별로 세분화하고, 각 강의의 소스 코드와 실습 코드를 포함하여 체계적으로 관리합니다. 또한, 프론트엔드, 백엔드, 데이터베이스 등 각 프로젝트와 최종 프로젝트 관련 자료도 따로 관리하고자 합니다. </p>
<pre><code class="language-bash">hanwha-system-bootcamp
│
├── lecture                # 강의 자료 및 소스 코드
│   ├── database           # 데이터베이스 강의 자료
│   │   ├── lecture_source # 데이터베이스 강의 자료
│   │   └── practice       # 데이터베이스 문제 풀이
│   ├── java               # 자바 강의 자료
│   │   ├── lecture_source # 자바 강의 자료
│   │   ├── source         # 자바 소스 코드
│   │   └── practice       # 자바 문제 풀이
│   ├── structures_and_algorithms # 자료구조 및 알고리즘 강의
│   │   ├── lecture_source # 자료구조 강의 자료
│   │   └── practice       # 자료구조 문제 풀이
│   ├── JSP                # JSP 강의 자료
│   │   ├── lecture_source # JSP 강의 자료
│   │   ├── source         # JSP 소스 코드
│   │   └── practice       # JSP 문제 풀이
│   ├── front_end          # 프론트엔드 강의 자료
│   │   ├── lecture_source # 프론트엔드 강의 자료
│   │   ├── source         # 프론트엔드 소스 코드
│   │   └── practice       # 프론트엔드 문제 풀이
│   └── dev_ops            # DevOps 강의 자료
│       ├── lecture_source # DevOps 강의 자료
│       ├── source         # DevOps 소스 코드
│       └── practice       # DevOps 문제 풀이
│
├── project                # 프로젝트 관련 자료
│   ├── database           # 데이터베이스 프로젝트
│   │   └── billon_db      # 데이터베이스 프로젝트 소스 코드
│   ├── back_end           # 백엔드 프로젝트
│   │   └── beautiful_routes # 백엔드 프로젝트 소스
│   ├── front_end          # 프론트엔드 프로젝트
│   └── dev_ops            # DevOps 프로젝트
│
└── study                  # 스터디 자료
    ├── clean_code         # 클린 코드 스터디 자료
    └── time_management    # 시간 관리 스터디 자료</code></pre>
<p><strong>2. 개인 강의 관련 자료(저는 develup_lectures라고 지었습니다)</strong></p>
<p>한화시스템 부트캠프 외에 추가적으로 진행한 JSP, 프론트엔드 관련 강의를 관리하는 폴더입니다. 외부 강의를 듣고 관련 자료를 source 폴더에 저장하여 소스 코드를 체계적으로 관리할 수 있습니다. </p>
<pre><code class="language-bash">develup_lectures
│
├── JSP
│   ├── spring_boot_basic
│   │   └── source        # Spring Boot Basic 소스 코드
│   ├── spring_boot_principle
│   │   └── source        # Spring Boot Principle 소스 코드
│   ├── spring_boot_MVC
│   │   └── source        # Spring Boot MVC 소스 코드
│
├── front_end
│   ├── react
│   ├── next
│   └── node
</code></pre>
<p><strong>3. 개인 프로젝트(저는 develup_projects라고 지었습니다)</strong></p>
<p>DevelUp 강의 외에도 제가 개인적으로 진행하는 프로젝트들을 관리하는 디렉토리입니다. 각 프로젝트에 대한 소스 코드 및 프로젝트 관리 자료를 체계적으로 분리하여 관리하고자 합니다. </p>
<pre><code class="language-bash">develup_projects
│
├── JSP
│   └── [프로젝트 이름]
│
├── front_end
│   ├── blog
│   ├── social_media
│   └── map
│
└── automation
</code></pre>
<p><strong>정리</strong></p>
<ol>
<li>큰 주제에서 작은 주제로 나누기</li>
</ol>
<ul>
<li>각 강의는 소스 코드와 문제 풀이를 별도의 폴더로 관리하여 학습 자료를 직관적으로 구분합니다.</li>
</ul>
<ol start="2">
<li>업무 외 항목은 최상위 폴더에 두기</li>
</ol>
<ul>
<li>한화시스템 부트캠프 외의 강의와 프로젝트는 별도의 최상위 폴더에 구분하여 관리합니다. 이를 통해 외부 강의와 프로젝트에 대한 자료를 독립적으로 관리할 수 있습니다.</li>
</ul>
<ol start="3">
<li>효율적인 자료 관리</li>
</ol>
<ul>
<li>각 폴더는 주제별로 구분하여, 필요한 자료를 빠르게 찾을 수 있도록 폴더 구조를 명확히 하였습니다.</li>
</ul>
<h3 id="결과">결과</h3>
<p>아래는 디렉토리를 구조화하고 나서의 저의 개인 파일 관리 상태입니다. 위의 이전 파일 관리 상태와 비교해보시면 얼마나 큰 변화가 있는지 한눈에 파악하실 수 있으실 겁니다. </p>
<p><img src="https://velog.velcdn.com/images/low_level_v99/post/7861d076-104a-4d20-a740-c526f468e57a/image.png" alt=""></p>
<p>파일 관리 상태를 체계적으로 정리한 이후, 이전과는 비교할 수 없을 정도로 효율적이고 직관적인 구조를 구현하게 되었습니다. 
결과적으로 파일을 찾는 데 걸리는 시간이 크게 줄어들었고, 업무와 학습을 진행하면서 필요한 자료를 빠르고 쉽게 찾을 수 있게 되었습니다. </p>
<p>이번 폴더 구조 정리 작업은 단지 폴더 관리에 그치지 않고, 효율적인 업무 처리와 학습의 집중도를 높이는 정말 중요한 변화였습니다.</p>
<p>저는 앞으로 정리된 파일 관리 방식은 앞으로도 계속해서 유지하고, 추가적인 파일이 쌓일 때마다 체계적으로 분류하여 더 이상 혼란스러운 파일 관리에 빠지지 않도록 할 것이고 이러한 체계화 과정을 습관화하여 뭐든지 생각하지 않고도 자연스럽게 기본 구조를 잡게 되는 체계화된 사람이 되는 것이 목표입니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한화시스템 BEYOND SW캠프 7주차]]></title>
            <link>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW%EC%BA%A0%ED%94%84-7%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@low_level_v99/%ED%95%9C%ED%99%94%EC%8B%9C%EC%8A%A4%ED%85%9C-BEYOND-SW%EC%BA%A0%ED%94%84-7%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Wed, 12 Mar 2025 05:28:04 GMT</pubDate>
            <description><![CDATA[<h3 id="😋-7주차에-대하여">😋 7주차에 대하여</h3>
<p>이번 주에는 자바 미니 프로젝트를 진행하며, 우리나라 길에 대한 공공 데이터를 활용하여 최적화된 길을 추천하는 서비스를 구현했습니다. 다양한 기능들을 구현하면서 객체 지향 프로그래밍(OOP)을 적용하려 했지만, 생각보다 OOP를 고려하며 구현하는 것은 매우 어려웠습니다. 그리고 원초적으로 돌아가서 왜 자바를 사용할 때 OOP에 맞게 구현해야 하는지 그 맥락에 대한 궁금증이 생겼고, 이에 대한 자세한 내용은 다른 <a src="https://velog.io/@low_level_v99/JAVA-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8DOOP-%EB%84%88-%EB%AD%94%EB%8D%B0">포스팅</a>에서 정리하였습니다.</p>
<p>저는 해당 글을 정리하는 과정에서 객체 지향 프로그래밍 방법론에 따라 프로젝트를 설계하는 것이 얼마나 중요한지 그 중요성에 깨닫게 되었고, 지금은 단순 미니 프로젝트를 구현하는 것이기 때문에 OOP를 적용하는 것은 오히려 비효율적이고 개발 기간만 늘리는 고리타분한 방법론이지만, 이 방법론은 기본적으로 규모가 큰 앱의 기반으로 하는 방법론이라는 것을 깨닫게 되면서 앞으로 큰 규모의 앱을 운영하고 개발하기 위해선 객체 지향 프로그래밍 방법에 대한 개념을 더 잘 알고, 이것을 구현하는 방법을 제대로 아는 것이 중요하다는 것을 깨닫게 되는 기회였습니다.</p>
<p><strong>SOLID 원칙과 디자인 패턴의 적용</strong>
그리고 저는 수업에서 들은 SOLID 원칙과 디자인 패턴도 적용하여 구현하려 했지만, 이 역시도 쉽지 않은 과정이었습니다. 그리고 이 과정은 단지 개념 이해뿐만 아니라 경험이 쌓여야만 어떠한 특정 환경에서 어떠한 특정 패턴이나 원칙을 적용하는 것이 자연스러워질 수 있단 생각이 들어 최대한 많은 프로젝트를 진행해봐야겠다는 생각을 하게 되었습니다.</p>
<p><strong>디버깅과 TDD의 중요성</strong>
그리고 코드가 많이지면 많아질수록 디버깅하는 것이 어려웠고, 어디서 에러가 나는지 찾아가는 과정이 시간도 오래 걸리고 비용이 커진다는 것을 깨닫게 되었습니다. 그래서 TDD 개발 방법론에 따라 개발 초기부터 유닛별로 테스트를 통해 프로젝트를 하나씩 쌓아가는 과정의 중요성도 깨닫게 되었습니다.</p>
<p><strong>클린 코드 작성의 중요성</strong>
그리고 저는 지금 &#39;클린 코드&#39; 책을 읽으면서 협업시 중요한 요소들에 대해 이해하고 적용해보려고 노력하고 있는데요. 그 일환으로 주석도 달고 이름도 업무와 관련된 직관적인 이름을 쓰려고 노력했습니다. 처음에는 추가적인 작업이 많아져서 그만할까 싶었지만, 스스로도 일주일 뒤의 코드를 읽으면 까먹게 되고, 주석을 보며 바로 이해할 수 있는 걸 보면서 주석의 중요성과 이름의 중요성을 다시금 깨닫게 되었습니다.</p>
<p><strong>SQLD 시험 준비</strong>
또한 저는 이번 주에 SQLD 시험을 같이 준비해야 했었는데요...ㅠㅠ 데이터베이스 수업 시간에 배웠던 개념뿐만 아니라 다양한 함수들과 복잡한 관계들을 해석하는 것이 정말 어려웠는데요. 다행히도 시험 문제는 그렇게 어렵지 않아서 합격할 수 있지 않을까 하는 기대를 품고 있습니다.</p>
<h3 id="😎-느낀점-및-배운점">😎 느낀점 및 배운점</h3>
<p>점점 공부할 내용이 많아지고 복잡도와 난이도가 높아지고 있습니다. 또한 이전에 학습한 내용들이 점점 까먹으면서 복습의 중요성을 많이 느끼고 있습니다. 이를 해결하기 위해선 계획을 더 세세하게 세워야겠단 생각을 하게 되었습니다. 제가 해야 되는 것들을 더 이상 큰 단위로 관리하기엔 힘들다는 생각이 들었고, 더 작은 단위로 나누니깐 오히려 단계별로 순차적으로 빼먹지 않고 필요한 것들을 챙길 수 있어 해야 할 일들의 복잡도가 낮아지는 것을 확인할 수 있었습니다. 그리고 알고리즘 같은 것들도 하나하나 코드적으로 접근하면 어려운데, 이것을 여러 맥락으로 나눠서 조금씩 구현한 것을 합친다고 생각하고 분할적으로 접근하니 문제가 쉬워지는 것을 확인할 수 있었습니다.</p>
<h3 id="🧐-앞으로의-계획">🧐 앞으로의 계획</h3>
<ol>
<li><p><strong>OOP 개념 심화 학습</strong>
앞으로는 객체 지향 설계를 더 잘 이해하고, 실제 대규모 프로젝트에서 이를 어떻게 적용할 수 있을지 고민할 것입니다. 객체 간의 관계 설정과 클래스 설계에서 발생할 수 있는 문제들을 해결할 수 있도록 더 많은 연습을 할 계획입니다.</p>
</li>
<li><p><strong>SOLID 원칙과 디자인 패턴 적용</strong>
다양한 프로젝트에서 SOLID 원칙과 디자인 패턴을 실제로 적용해보며, 각 상황에 맞는 원칙과 패턴을 자연스럽게 적용할 수 있는 능력을 기를 것입니다.</p>
</li>
<li><p><strong>TDD 실천</strong>
테스트 주도 개발(TDD)을 실천하여, 코드 품질을 높이고, 개발 초기부터 발생할 수 있는 문제들을 미리 예방할 수 있도록 하겠습니다. 각 기능을 구현할 때마다 유닛 테스트를 작성하고, 점진적으로 프로젝트를 구축해 나갈 계획입니다.</p>
</li>
<li><p><strong>클린 코드 작성 강화</strong>
주석 달기와 직관적인 변수명 사용을 습관화하여, 코드의 가독성과 유지보수성을 높이겠습니다. 협업을 고려하여 팀원들과의 원활한 소통을 위해 클린 코드 작성의 중요성을 계속 실천할 것입니다.</p>
</li>
<li><p><strong>SQLD 관련 지식 심화</strong>
SQLD 시험 준비를 통해 배운 데이터베이스 설계와 쿼리 최적화에 대한 내용을 심화하여 학습하고, 실제 프로젝트에서 데이터베이스 설계를 보다 효율적으로 할 수 있도록 노력할 것입니다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] ISP(인터페이스 분리 원칙)의 대체제, 인터페이스 default 메서드?]]></title>
            <link>https://velog.io/@low_level_v99/JAVA-ISP%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%B6%84%EB%A6%AC-%EC%9B%90%EC%B9%99%EC%9D%98-%EB%8C%80%EC%B2%B4%EC%A0%9C-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-default-%EB%A9%94%EC%84%9C%EB%93%9C</link>
            <guid>https://velog.io/@low_level_v99/JAVA-ISP%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%B6%84%EB%A6%AC-%EC%9B%90%EC%B9%99%EC%9D%98-%EB%8C%80%EC%B2%B4%EC%A0%9C-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-default-%EB%A9%94%EC%84%9C%EB%93%9C</guid>
            <pubDate>Mon, 10 Mar 2025 04:14:16 GMT</pubDate>
            <description><![CDATA[<h3 id="java-8-이후의-default-메서드">Java 8 이후의 default 메서드</h3>
<p>Java 8에서 도입된 default 메서드는 인터페이스에서 메서드의 기본 구현을 제공할 수 있게 해주는 새로운 기능입니다. 이는 인터페이스를 구현하는 클래스에서 해당 메서드를 사용하지 않더라도 기본 구현을 사용할 수 있도록 해주어, 기존 인터페이스 설계를 확장하는 데 유용하게 활용될 수 있습니다. </p>
<p>그런데 저는 이 기능이 <strong>SOLID 원칙 중 하나인 인터페이스 분리 원칙(ISP, Interface Segregation Principle)</strong>을 해결할 수 있을지에 대한 고민을 해보게 되었는데요, 이번 포스팅에서는 default 메서드가 ISP 원칙을 완전히 해결할 수 있는지, 그리고 인터페이스 분리에 대한 개발자들의 고민이 어떻게 변화했는지에 대해 논의해 보겠습니다.</p>
<h3 id="1-인터페이스-분리-원칙isp과-그-중요성">1. 인터페이스 분리 원칙(ISP)과 그 중요성</h3>
<p>우선 인터페이스 분리 원칙에 대해 자세하게 알아봅시다. <strong>인터페이스 분리 원칙(ISP)</strong>은 SOLID 원칙 중 하나로, 클래스가 필요하지 않은 메서드에 의존하지 않도록 인터페이스를 설계해야 한다는 것입니다. 즉, 인터페이스는 클래스가 필요한 메서드만을 강제해야 하며, 필요하지 않은 메서드는 강제하지 않아야 한다는 원칙입니다. 이를 통해, 각 클래스는 자신이 필요한 메서드만 구현하고, 불필요한 의존성을 피할 수 있습니다.</p>
<p>인터페이스가 너무 많은 메서드를 강제하거나, 클래스가 사용하지 않는 메서드를 구현해야 한다면, 이는 ISP 원칙을 위반하는 것입니다. 예를 들어, 하나의 인터페이스가 여러 기능을 강제할 때, 구현 클래스는 그 중 일부만 필요하더라도 모든 메서드를 구현해야 하므로 불필요한 의존성이 발생합니다. 이로 인해 인터페이스가 너무 커지고, 클래스가 불필요한 메서드를 구현해야 하는 문제가 발생할 수 있습니다.</p>
<h3 id="default-메서드와-isp-원칙">default 메서드와 ISP 원칙</h3>
<p>Java 8에서 default 메서드가 도입되면서, 인터페이스는 기본 구현을 제공할 수 있게 되었고, 이는 구현 클래스가 해당 메서드를 사용하지 않더라도 강제적으로 구현하지 않도록 하는 중요한 기능을 제공합니다. default 메서드는 기본 구현을 제공함으로써, 인터페이스 설계를 유연하게 만들고, 새로운 기능을 추가할 때 기존 클래스에 영향을 미치지 않게 하여 ISP 원칙을 유연하게 해결할 수 있게 해주는 것처럼 보입니다.</p>
<p>인터페이스를 설계하다보면 새로운 기능을 추가할 때 기존 클래스들을 수정해야 하는 경우가 자주 발생합니다. 하지만 default 메서드를 통해 기존 클래스를 수정하지 않고도 새로운 기능을 추가할 수 있게 되었고, 구현 클래스가 default 메서드를 오버라이드하지 않으면 기본 구현을 사용하게 되므로, 구현해야 할 메서드를 강제하지 않도록 하는 측면에서 ISP 원칙을 보다 유연하게 처리할 수 있을 것 같습니다. </p>
<p>그러나, 결론적으로 default 메서드가 ISP 원칙을 완전히 해결할 수 있는 것은 아니다라는 점을 이해하는 것이 중요합니다. 인터페이스가 너무 커지거나 여러 메서드를 강제하는 구조에서는 여전히 불필요한 메서드를 강제할 가능성이 있기 때문입니다. default 메서드는 기본 구현을 제공하는 기능이지만, 인터페이스가 너무 커지면 여전히 클래스가 필요 없는 메서드를 구현해야 하는 문제가 발생할 수 있습니다. </p>
<h3 id="default-메서드가-가진-한계">default 메서드가 가진 한계</h3>
<p>default 메서드는 기본 구현을 제공하는 장점이 있지만, 그에 따라 인터페이스가 커지거나 불필요한 메서드가 포함될 위험도 커지게 되었습니다. default 메서드를 과도하게 사용하게 되면, 인터페이스가 너무 커지고 관리가 어려워지며, 각 인터페이스가 갖는 책임이 모호해질 수 있습니다. 또한, 너무 많은 기능을 인터페이스에 넣게 되면, 구현 클래스가 의도치 않게 여러 메서드를 구현해야 하는 상황이 발생할 수 있습니다.</p>
<p>인터페이스 설계의 핵심은 각 인터페이스가 단일 책임을 가지도록 하는 것이라는 걸 다시 한번 생각해봐야 합니다. default 메서드를 남발하면, 인터페이스의 크기가 커지고 관리가 어려워질 수 있기 때문에  결국, 인터페이스가 커지지 않도록 적절하게 분리하고, 각 인터페이스가 명확한 책임을 가질 수 있도록 설계 하는 것이 인터페이스 설계에 있어 무엇보다 중요한 것 같습니다. </p>
<h3 id="default-기능을-활용한-isp-원칙-적용-방법">default 기능을 활용한 ISP 원칙 적용 방법</h3>
<p>default 메서드는 기본 구현을 제공하여 인터페이스의 변경에 따른 영향을 최소화할 수 있는 장점이 있지만, 그 사용이 과도하면 인터페이스의 크기가 커지고, 불필요한 메서드를 포함하게 될 위험이 있습니다. 이에 따라 default 메서드를 적절하게 활용하면서 ISP 원칙을 적용한 인터페이스를 설계해야 하며 저는 다음과 같이 설계 시 고려사항을 정리해 보았습니다. </p>
<ol>
<li>인터페이스 분리: 각 인터페이스가 단일 책임을 갖고, 불필요한 메서드를 포함하지 않도록 설계하기. efault 메서드를 남발하지 않고, 인터페이스의 크기를 최소화하기</li>
<li>default 메서드의 적절한 사용: default 메서드는 기본 구현이 필요한 경우에만 사용해야 하며, 인터페이스에 불필요한 메서드를 추가하는 것이 아닌, 기능을 확장하는 방식으로 활용하기. </li>
</ol>
<h3 id="결론">결론</h3>
<p><strong>default 메서드는 ISP 원칙을 완전히 해결하지 못한다</strong></p>
<p>결론적으로 Java 8 이후 default 메서드는 ISP 원칙을 해결하는 데 일부 도움을 주는 기능
이지만, 완전한 해결책은 아니다라고 할 수 있을 것 같습니다. 기본 구현을 제공하여 인터페이스 변경에 따른 영향을 최소화할 수 있지만, 인터페이스가 커지거나 불필요한 메서드를 강제하는 상황을 막기 위해서는 여전히 인터페이스 분리가 중요해 보입니다. </p>
<p>따라서 인터페이스 설계 시에는 기본 구현을 남발하지 않고, default 메서드는 필요할 때만 사용하며, 인터페이스의 책임을 작게 분리하는 것이 ISP 원칙을 준수하면서도 유연하고 확장 가능한 시스템을 설계하는 것을 유의하시길 바랍니다. </p>
]]></description>
        </item>
    </channel>
</rss>