<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>patchnotes</title>
    <link>https://lazypatchnotes.tistory.com/</link>
    <description>lazypatchnotes 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Thu, 14 May 2026 12:54:33 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>PARKpatchnotes</managingEditor>
    <item>
      <title>[89일차]웹 서비스 풀사이클 개발의 이해: 프로세스부터 아키텍처까지</title>
      <link>https://lazypatchnotes.tistory.com/116</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;웹 서비스를 구축한다는 것은 단순히 코드를 작성하는 행위를 넘어선다. 요구사항 분석부터 배포, 그리고 유지보수에 이르는 전체 수명 주기(SDLC)를 이해하고, 이를 뒷받침하는 아키텍처와 연동 기술을 파악해야만 견고한 서비스를 만들 수 있다. 본 글에서는 웹 서비스 풀사이클 개발을 위한 핵심 이론을 소프트웨어 개발 프로세스, 아키텍처, 그리고 프론트엔드-백엔드 연동의 세 가지 관점에서 정리한다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 소프트웨어 개발 프로세스 (SDLC)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;소프트웨어 개발 프로세스는 품질 향상, 일정 준수, 명확한 의사소통, 그리고 궁극적으로 고객 만족도를 높이기 위한 필수적인 체계다.&lt;/p&gt;
&lt;div&gt;
&lt;div data-full-size-image-uri=&quot;https://encrypted-tbn1.gstatic.com/licensed-image?q=tbn:ANd9GcS0cqb23WB7JdPB1L8trqMCK39OW6KncKZNSRlNIHOXO6IJLfTFqExbdDaNwWqkAU3tzTW8E8KALJYAT2lweyi3I35sfP3PIRT7ia8myWDT28Iyxvc&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;3999&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cngnjW/dJMcaivkAiA/I7PTi5uTDBiBcyAdTml7f1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cngnjW/dJMcaivkAiA/I7PTi5uTDBiBcyAdTml7f1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cngnjW/dJMcaivkAiA/I7PTi5uTDBiBcyAdTml7f1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcngnjW%2FdJMcaivkAiA%2FI7PTi5uTDBiBcyAdTml7f1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3999&quot; height=&quot;3999&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;3999&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div&gt;&lt;span&gt;Shutterstock&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;1.1 요구사항 수집 및 분석&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;모든 개발의 시작점이다. 이해관계자의 요구사항을 수집하고, 이를 기능/비기능 요구사항으로 분류하여 분석한다. 이 내용은 문서화되어야 하며, 실제 구현 가능한지 검증하는 단계를 거친다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;1.2 시스템 설계&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;분석된 요구사항을 기술적인 설계도로 변환하는 과정이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;상위 설계:&lt;/b&gt; 전체 시스템의 아키텍처, 모듈 구조, 데이터의 흐름, 인터페이스 등을 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;하위 설계:&lt;/b&gt; 데이터베이스 스키마, 클래스 다이어그램, 알고리즘, 에러 처리 전략 등 세부적인 로직을 설계한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,0&quot;&gt;설계 원칙:&lt;/b&gt; 좋은 설계를 위해서는 모듈화, 캡슐화, 재사용성, 확장성을 고려해야 하며, 응집도는 높이고(High Cohesion) 결합도는 낮추는(Low Coupling) 방향을 지향해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;1.3 구현 (Implementation)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;설계도를 바탕으로 실제 코드를 작성한다. 단순히 기능 구현에 그치지 않고 통합, 단위 테스트, 코드 리뷰, 리팩토링 과정을 통해 코드의 품질을 높인다. 또한, 시큐어 코딩을 통한 보안 구현과 유지보수를 위한 문서화 및 버전 관리(Git 등)가 병행되어야 한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;1.4 테스트&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;결함을 조기에 발견하고 품질을 보증하는 단계다. JUnit, Selenium, Cypress 등의 도구를 활용해 자동화할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;단위(Unit) 테스트:&lt;/b&gt; 개별 모듈이나 함수의 기능을 검증한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;통합(Integration) 테스트:&lt;/b&gt; 모듈 간의 상호작용 및 인터페이스를 검증한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,2,0&quot;&gt;시스템/인수 테스트:&lt;/b&gt; 전체 시스템의 동작과 사용자 요구사항 충족 여부를 확인한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,3,0&quot;&gt;비기능 테스트:&lt;/b&gt; 성능(부하), 보안, 회귀 테스트 등이 포함된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;1.5 배포 (Deployment) 및 CI/CD&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;개발된 소프트웨어를 실제 사용자 환경에 릴리스하는 과정이다. 현대적 개발 환경에서는 CI/CD(지속적 통합/지속적 배포) 파이프라인을 구축하여 자동화한다.&lt;/p&gt;
&lt;div&gt;
&lt;div data-full-size-image-uri=&quot;https://encrypted-tbn3.gstatic.com/licensed-image?q=tbn:ANd9GcT2ZM6qoeA3nOwbBRq8M2KXQ7oA8zZlMfGMAywMvq0WK6bwpEZ2dWL7H1-HJsyq97JaamCMTo1K_YBELdeE9dUBNEuvdOFSmICUM5y59KJcZDkjvzg&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;3076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4tWeD/dJMcabJOp7w/viwtVCyNOI6oPQAgDaCHKK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4tWeD/dJMcabJOp7w/viwtVCyNOI6oPQAgDaCHKK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4tWeD/dJMcabJOp7w/viwtVCyNOI6oPQAgDaCHKK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4tWeD%2FdJMcabJOp7w%2FviwtVCyNOI6oPQAgDaCHKK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3999&quot; height=&quot;3076&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;3076&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div&gt;&lt;span&gt;Shutterstock&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;탐색&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;배포 전략:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,1,0,0&quot;&gt;롤링(Rolling):&lt;/b&gt; 구버전 서버를 하나씩 신버전으로 교체한다. 무중단 배포가 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,1,1,0&quot;&gt;블루-그린(Blue-Green):&lt;/b&gt; 신버전 환경(Green)을 별도로 구축해 테스트한 뒤, 트래픽을 한 번에 전환한다. 롤백이 용이하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,1,2,0&quot;&gt;카나리(Canary):&lt;/b&gt; 소수의 사용자에게만 신버전을 먼저 배포하여 안정성을 확인한 뒤 전체로 확대한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;모니터링:&lt;/b&gt; Datadog, Prometheus, Grafana 등을 통해 시스템의 성능과 에러를 실시간으로 감시해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;1.6 개발 방법론&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,0&quot;&gt;폭포수 모델(Waterfall):&lt;/b&gt; 각 단계가 순차적으로 진행되는 전통적 방식이다. 요구사항이 명확하고 변경이 적은 프로젝트에 적합하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,1,0&quot;&gt;애자일(Agile):&lt;/b&gt; 반복적이고 점진적인 개발을 지향한다. 고객의 피드백을 지속적으로 반영하며 Scrum, Kanban 등의 프레임워크가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size26&quot;&gt;2. 웹 서비스 아키텍처&lt;/h2&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;웹 서비스 아키텍처는 시스템의 뼈대를 구성하는 요소들의 집합이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;25&quot; data-ke-size=&quot;size23&quot;&gt;2.1 클라이언트-서버 모델&lt;/h3&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;웹의 가장 기본적인 구조로, 서비스를 요청하는 클라이언트와 서비스를 제공하는 서버로 나뉜다. 역할 분담이 명확하고 데이터의 중앙 집중 관리가 가능하지만, 서버에 트래픽이 집중될 경우 단일 장애점(SPOF)이 될 수 있다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size23&quot;&gt;2.2 프론트엔드와 백엔드&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;28&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,0,0&quot;&gt;프론트엔드:&lt;/b&gt; 사용자와 직접 상호작용하는 영역이다. HTML/CSS/JS를 기본으로 하며, 최근에는 React, Vue.js 같은 프레임워크를 통해 컴포넌트 기반의 반응형 프로그래밍(Reactive Programming)을 주로 수행한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,1,0&quot;&gt;백엔드:&lt;/b&gt; 비즈니스 로직 처리, 데이터 관리, 보안 등을 담당한다. Spring(Java), Django(Python), Node.js, Laravel(PHP) 등의 프레임워크가 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;2.3 데이터 저장 및 처리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;30&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,0,0&quot;&gt;데이터베이스(DB):&lt;/b&gt; 정형화된 데이터는 RDBMS(MySQL, PostgreSQL)에, 비정형 데이터나 유연한 스키마가 필요한 데이터는 NoSQL(MongoDB, Redis)에 저장한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,1,0&quot;&gt;캐싱(Caching):&lt;/b&gt; 자주 조회되는 데이터를 Redis나 Memcached 같은 인메모리 저장소에 두어 DB 부하를 줄이고 응답 속도를 높인다. 무효화(Invalidation) 전략(TTL, 명시적 삭제)을 잘 수립해야 데이터 정합성 문제를 막을 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,2,0&quot;&gt;전문 검색(Full-text Search):&lt;/b&gt; ElasticSearch 등을 활용하여 대용량 텍스트 데이터에 대한 역색인(Inverted Index) 구조를 구축, 빠른 검색 성능을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;2.4 비동기 처리 및 확장성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;32&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;32,0,0&quot;&gt;잡(Job) 서버:&lt;/b&gt; 이메일 발송, 파일 변환 등 시간이 오래 걸리는 작업은 메인 서버에서 직접 처리하지 않고 메시지 큐(RabbitMQ, Kafka)와 워커(Worker) 서버를 통해 비동기로 처리하여 사용자 응답 속도를 보장한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;32,1,0&quot;&gt;확장성(Scalability):&lt;/b&gt; 서버 사양을 높이는 수직적 확장(Scale-up)보다는, 서버 대수를 늘리는 수평적 확장(Scale-out)이 클라우드 환경에 더 적합하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;33&quot; data-ke-size=&quot;size23&quot;&gt;2.5 클라우드 인프라 및 보안&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;34&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,0,0&quot;&gt;클라우드 서비스 모델:&lt;/b&gt; 인프라만 빌리는 IaaS(AWS EC2), 플랫폼을 빌리는 PaaS(Heroku), 소프트웨어를 빌리는 SaaS(Google Workspace)로 나뉜다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,1,0&quot;&gt;보안:&lt;/b&gt; 네트워크(방화벽, WAF), 데이터(암호화), 애플리케이션(인증/인가, 시큐어 코딩), 운영(로깅, 패치) 등 계층별 보안 전략이 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;35&quot; data-ke-size=&quot;size26&quot;&gt;3. 백엔드와 프론트엔드 연동&lt;/h2&gt;
&lt;p data-path-to-node=&quot;36&quot; data-ke-size=&quot;size16&quot;&gt;아키텍처의 두 핵심 축인 프론트엔드와 백엔드는 HTTP 프로토콜을 통해 소통한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;37&quot; data-ke-size=&quot;size23&quot;&gt;3.1 HTTP와 API&lt;/h3&gt;
&lt;p data-path-to-node=&quot;38&quot; data-ke-size=&quot;size16&quot;&gt;HTTP는 무상태(Stateless)와 비연결성(Connectionless)을 특징으로 한다. 클라이언트와 서버는 약속된 인터페이스인 API를 통해 데이터를 주고받는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;39&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;39,0,0&quot;&gt;REST API:&lt;/b&gt; 자원을 URL로, 행위를 HTTP Method(GET, POST 등)로 표현하는 아키텍처 스타일이다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;39,1,0&quot;&gt;GraphQL:&lt;/b&gt; 클라이언트가 필요한 데이터 구조를 정의하여 요청하는 방식으로, 오버페칭(Over-fetching) 문제를 해결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;40&quot; data-ke-size=&quot;size23&quot;&gt;3.2 데이터 교환 및 비동기 통신&lt;/h3&gt;
&lt;p data-path-to-node=&quot;41&quot; data-ke-size=&quot;size16&quot;&gt;데이터 포맷으로는 가볍고 가독성이 좋은 JSON이 표준처럼 사용된다. 브라우저에서는 AJAX 기술(Fetch API, Axios)을 사용하여 페이지 전체를 새로고침하지 않고도 필요한 데이터만 비동기로 서버와 교환한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;42&quot; data-ke-size=&quot;size23&quot;&gt;3.3 실시간 데이터 처리&lt;/h3&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;HTTP는 기본적으로 클라이언트의 요청이 있어야만 응답을 주는 단방향 통신이다. 실시간성이 필요한 경우 다른 기술이 필요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;44&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;44,0,0&quot;&gt;Polling:&lt;/b&gt; 클라이언트가 주기적으로 서버에 데이터를 요청한다. (서버 부하 발생 가능)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;44,1,0&quot;&gt;WebSocket:&lt;/b&gt; 양방향 통신 채널을 열어 실시간으로 데이터를 주고받는다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;44,2,0&quot;&gt;SSE (Server-Sent Events):&lt;/b&gt; 서버에서 클라이언트로 단방향 실시간 이벤트를 전송한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;45&quot; data-ke-size=&quot;size23&quot;&gt;3.4 인증(Authentication)과 보안(CORS)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;46&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;46,0,0&quot;&gt;인증 방식:&lt;/b&gt; 전통적인 세션-쿠키 방식과 모바일/SPA 환경에 적합한 토큰 기반의 JWT(Json Web Token) 방식이 있다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;46,1,0&quot;&gt;CORS (Cross-Origin Resource Sharing):&lt;/b&gt; 브라우저는 보안상의 이유로 다른 도메인(Origin)으로의 요청을 차단한다. 서버 측에서 적절한 CORS 헤더 설정을 통해 허용된 출처의 접근을 관리해야 한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/116</guid>
      <comments>https://lazypatchnotes.tistory.com/116#entry116comment</comments>
      <pubDate>Tue, 27 Jan 2026 13:57:35 +0900</pubDate>
    </item>
    <item>
      <title>[88일차]클라우드 컴퓨팅의 이해와 마이크로서비스 아키텍처</title>
      <link>https://lazypatchnotes.tistory.com/115</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;현대 IT 인프라의 표준이 된 클라우드 컴퓨팅은 단순한 서버 임대 서비스를 넘어 소프트웨어 아키텍처와 개발 방법론 전반에 영향을 미치고 있다. 본 글에서는 클라우드 컴퓨팅의 등장 배경과 핵심 원칙, 그리고 이를 기반으로 한 마이크로서비스 아키텍처(MSA)의 개념을 정리한다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 컴퓨팅 패러다임의 변화&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;클라우드 컴퓨팅이 등장하기까지 컴퓨팅 환경은 하드웨어와 네트워크 기술의 발전에 따라 진화해왔다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,0&quot;&gt;메인프레임(Mainframe):&lt;/b&gt; 1960~70년대의 거대한 중앙 컴퓨터 시대를 의미한다. 터미널(Terminal)을 통해 중앙 서버에 접속하는 방식이었으며, 시분할 시스템(Time Sharing System)을 통해 다수의 사용자가 하나의 자원을 나누어 썼다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;클라이언트-서버(Client-Server):&lt;/b&gt; PC의 보급과 인터넷의 발전으로 등장했다. 클라이언트가 데이터를 요청하고 서버가 응답하는 분산 처리 구조로, 현재 웹 환경의 기초가 되었다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0&quot;&gt;그리드 컴퓨팅(Grid Computing):&lt;/b&gt; 분산된 컴퓨팅 자원을 초고속 네트워크로 연결하여 하나의 거대한 슈퍼컴퓨터처럼 활용하는 기술이다. 주로 과학 연산 등 대규모 데이터 처리에 사용되었으며 클라우드의 기술적 모태가 되었다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0&quot;&gt;클라우드 컴퓨팅(Cloud Computing):&lt;/b&gt; 인터넷을 통해 컴퓨팅 리소스(서버, 스토리지, DB 등)를 필요한 만큼 빌려 쓰고, 사용한 만큼 비용을 지불하는 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;2. 클라우드 컴퓨팅의 핵심 원칙과 특징&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;핵심 원칙&lt;/h3&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;클라우드가 성립하기 위해서는 다음과 같은 기술적, 운영적 원칙이 전제되어야 한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;공유된 컴퓨팅 자원:&lt;/b&gt; 물리적 자원을 여러 사용자가 논리적으로 공유한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;컴퓨팅 자원의 가상화:&lt;/b&gt; 하이퍼바이저(Hypervisor) 등을 통해 물리적 하드웨어를 가상 머신(VM)이나 컨테이너 형태로 추상화한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,2,0&quot;&gt;탄력성(Elasticity):&lt;/b&gt; 트래픽이나 리소스 수요의 증감에 따라 인프라를 유동적으로 확장하거나 축소할 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,3,0&quot;&gt;자동 제어:&lt;/b&gt; 자원 할당과 회수가 관리자의 수동 개입 없이 시스템에 의해 자동으로 이루어진다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,4,0&quot;&gt;종량제 과금(Metering):&lt;/b&gt; 전기나 수도처럼 사용한 리소스의 양(시간, 용량, 트래픽)만큼만 비용을 청구한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;장점과 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;장점:&lt;/b&gt; 비즈니스 민첩성(Agility) 확보, 트래픽 변화에 대응하는 탄력성, 초기 투자 비용 절감, 고가용성(Availability) 보장.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;단점:&lt;/b&gt; 관리 미흡 시 예측보다 높은 비용 발생(Cost Shock), 벤더 종속(Lock-in) 문제, 새로운 환경에 대한 학습 난이도.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;개방형과 폐쇄형&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;퍼블릭 클라우드(Public):&lt;/b&gt; AWS, Azure, GCP 등 누구나 사용할 수 있는 개방형 환경.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;프라이빗 클라우드(Private):&lt;/b&gt; 특정 기업이나 조직 내부에서만 사용하는 폐쇄형 환경. 보안이 중요할 때 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;3. 서비스 모델과 경제적 타당성&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;서비스 모델 (Service Models)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;클라우드는 제공하는 관리 범위에 따라 세 가지 모델로 구분된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;IaaS (Infrastructure as a Service):&lt;/b&gt; 서버, 스토리지, 네트워크 등 인프라 자원만 임대한다. OS와 애플리케이션은 사용자가 직접 관리한다. (예: AWS EC2)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;PaaS (Platform as a Service):&lt;/b&gt; 애플리케이션 개발 및 실행을 위한 플랫폼을 제공한다. 인프라 관리는 클라우드 제공자가 담당한다. (예: Heroku, Google App Engine)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,2,0&quot;&gt;SaaS (Software as a Service):&lt;/b&gt; 완성된 소프트웨어를 서비스 형태로 제공한다. (예: Google Docs, Dropbox)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;경제적 관점: CAPEX에서 OPEX로&lt;/h3&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;클라우드 도입의 가장 큰 경제적 의의는 자본 지출(CAPEX)에서 운영 지출(OPEX)로의 전환이다. 초기 하드웨어 구축 비용을 없애고, 매달 발생하는 운영 비용으로 리스크를 분산할 수 있다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;구축 형태의 비교&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,0&quot;&gt;In-house / On-premise:&lt;/b&gt; 자체 전산실에 서버를 구축하고 직접 운영. 보안과 통제권이 가장 높다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,1,0&quot;&gt;Colocation:&lt;/b&gt; 서버는 소유하되, 데이터센터의 공간과 네트워크 시설만 임대.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,2,0&quot;&gt;Managed Service:&lt;/b&gt; 서버 운영 및 관리를 외부 전문 업체에 위탁.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,3,0&quot;&gt;Cloud:&lt;/b&gt; 인프라 소유권 없이 서비스만 이용.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;클라우드가 부적합한 경우&lt;/h3&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;모든 시스템이 클라우드에 적합한 것은 아니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,0,0&quot;&gt;레거시 시스템:&lt;/b&gt; 클라우드 환경으로 마이그레이션하기에 기술적 부채가 너무 큰 경우.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,1,0&quot;&gt;미션 크리티컬 시스템:&lt;/b&gt; 생명과 직결되거나 극도의 안정성이 요구되어 0.1초의 지연이나 외부 네트워크 의존도 허용할 수 없는 경우.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,2,0&quot;&gt;기밀 데이터:&lt;/b&gt; 법적 규제나 보안상의 이유로 데이터의 외부 반출이 금지된 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size26&quot;&gt;4. 마이크로서비스 아키텍처 (MSA)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;클라우드 환경의 탄력성을 극대화하기 위해 소프트웨어 아키텍처 또한 진화했다.&lt;/p&gt;
&lt;div&gt;
&lt;div data-full-size-image-uri=&quot;https://encrypted-tbn3.gstatic.com/licensed-image?q=tbn:ANd9GcSjaW6wQ3QTaGPgHZiRv4YaOux0AMhGzERIOYcZUhMmWT3oeibaSR2Zd8T11JYNXkrxEJ6RVAKZSTqM57rlag6BzbucLfFC3bm_PLqhqhE3fHDaVdg&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;3199&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVXB5C/dJMcadOh4xl/QO4cK8SEjYtsGhHc12Pqm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVXB5C/dJMcadOh4xl/QO4cK8SEjYtsGhHc12Pqm1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVXB5C/dJMcadOh4xl/QO4cK8SEjYtsGhHc12Pqm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVXB5C%2FdJMcadOh4xl%2FQO4cK8SEjYtsGhHc12Pqm1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3999&quot; height=&quot;3199&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;3199&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div&gt;&lt;span&gt;Shutterstock&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;모놀리틱(Monolithic) vs 마이크로서비스(Microservices)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;30&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,0,0&quot;&gt;모놀리틱 아키텍처:&lt;/b&gt; 모든 기능이 하나의 거대한 코드베이스와 프로세스로 통합된 형태다. 개발 초기에는 단순하지만, 규모가 커질수록 빌드/배포 시간이 길어지고 특정 기능의 장애가 전체 시스템으로 전파될 위험이 있다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,1,0&quot;&gt;마이크로서비스 아키텍처:&lt;/b&gt; 시스템을 독립적으로 배포 가능한 작은 서비스 단위로 쪼갠 형태다. 각 서비스는 API를 통해 통신한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;MSA의 핵심&lt;/h3&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;MSA는 단순히 기술적인 유행이 아니라 조직과 비즈니스의 문제를 해결하기 위한 도구다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;33&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스별로 서로 다른 기술 스택을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;특정 서비스에 트래픽이 몰릴 경우 해당 서비스만 스케일 아웃(Scale-out)하여 효율을 높일 수 있다.&lt;/li&gt;
&lt;li&gt;기술적 복잡도(네트워크 통신, 데이터 정합성 등)는 증가하지만, 배포의 유연성과 조직의 확장성을 확보하는 데 중점을 둔다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;34&quot; data-ke-size=&quot;size26&quot;&gt;5. 맺음말: 좋은 소프트웨어 엔지니어란&lt;/h2&gt;
&lt;p data-path-to-node=&quot;35&quot; data-ke-size=&quot;size16&quot;&gt;기술은 끊임없이 변화한다. 메인프레임에서 클라우드로, 모놀리틱에서 MSA로 패러다임이 바뀌어도 변하지 않는 '좋은 엔지니어'의 자질은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;36&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,0,0&quot;&gt;대화가 되는 사람:&lt;/b&gt; 복잡한 기술적 문제를 동료나 비개발자가 이해하기 쉽게 설명할 수 있는 커뮤니케이션 능력.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,1,0&quot;&gt;함께 일하는 것이 즐거운 사람:&lt;/b&gt; 협업 태도가 좋고 팀의 분위기에 긍정적인 영향을 주는 사람.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,2,0&quot;&gt;끈기와 호기심을 가진 사람:&lt;/b&gt; 해결되지 않는 문제에 집요하게 파고들며, 새로운 기술에 대해 '왜?'라는 질문을 던지는 사람.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,3,0&quot;&gt;컴퓨터 시스템에 대해 넓고 깊게 아는 사람:&lt;/b&gt; 특정 언어나 프레임워크에 매몰되지 않고 OS, 네트워크, 하드웨어 등 근본적인 원리를 이해하는 사람.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;36,4,0&quot;&gt;좋은 습관을 가진 사람:&lt;/b&gt; 코드를 깔끔하게 작성하고, 문서를 남기며, 지속적으로 학습하는 습관이 몸에 밴 사람.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;37&quot; data-ke-size=&quot;size16&quot;&gt;결국 도구(Cloud, MSA)는 바뀔 수 있지만, 문제를 해결하고 시스템을 견고하게 만드는 것은 엔지니어의 본질적인 역량에 달려 있다.&lt;/p&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/115</guid>
      <comments>https://lazypatchnotes.tistory.com/115#entry115comment</comments>
      <pubDate>Mon, 26 Jan 2026 10:41:21 +0900</pubDate>
    </item>
    <item>
      <title>[87일차]연결의 기술과 만드는 철학: 네트워크 &amp;amp; 소프트웨어 공학</title>
      <link>https://lazypatchnotes.tistory.com/114</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터 과학(CS)의 세계에서 하드웨어와 운영체제가 '개인'을 위한 기초라면, &lt;b data-index-in-node=&quot;44&quot; data-path-to-node=&quot;3&quot;&gt;네트워크&lt;/b&gt;는 개인과 개인을 연결하는 '사회'이고, &lt;b data-index-in-node=&quot;71&quot; data-path-to-node=&quot;3&quot;&gt;소프트웨어 공학&lt;/b&gt;은 그 위에서 가치를 창출하는 '건설 철학'이다. 이번 글에서는 데이터가 흐르는 길인 네트워크의 원리와, 견고한 소프트웨어를 만드는 공학적 방법론에 대해 정리한다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;4&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. 컴퓨터 네트워크: 데이터가 흐르는 길&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;네트워크는 단순히 선을 연결하는 것이 아니라, 서로 다른 시스템이 대화할 수 있도록 규칙(Protocol)을 정하는 과정이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;1.1 통신망의 기초&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;디지털 시대에 우리는 왜 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;8&quot;&gt;디지털 신호&lt;/b&gt;를 선호하는가? 아날로그는 외부 간섭에 약하지만, 디지털(0과 1)은 정보를 복구하기 쉽고(적은 정보 손실), 수학적 연산을 통해 &lt;b data-index-in-node=&quot;93&quot; data-path-to-node=&quot;8&quot;&gt;암호화&lt;/b&gt;가 용이하기 때문이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;데이터를 전송하는 방식에는 여러 기준이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;전송 방식:&lt;/b&gt; 한 번에 한 비트씩 보내면 &lt;b data-index-in-node=&quot;22&quot; data-path-to-node=&quot;10,0,0&quot;&gt;직렬(Serial)&lt;/b&gt;, 여러 비트를 동시에 보내면 **병렬(Parallel)**이다. 또한, 클럭 신호에 맞춰 약속된 시간에 보내면 &lt;b data-index-in-node=&quot;95&quot; data-path-to-node=&quot;10,0,0&quot;&gt;동기식&lt;/b&gt;, 시작/정지 비트를 사용해 임의로 보내면 &lt;b data-index-in-node=&quot;122&quot; data-path-to-node=&quot;10,0,0&quot;&gt;비동기식&lt;/b&gt;이라 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;전송 방향:&lt;/b&gt; 라디오처럼 듣기만 하면 &lt;b data-index-in-node=&quot;20&quot; data-path-to-node=&quot;10,1,0&quot;&gt;단방향&lt;/b&gt;, 무전기처럼 번갈아 말하면 &lt;b data-index-in-node=&quot;39&quot; data-path-to-node=&quot;10,1,0&quot;&gt;반이중(Half-Duplex)&lt;/b&gt;, 전화기처럼 동시에 말하고 들으면 **전이중(Full-Duplex)**이다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,2,0&quot;&gt;망의 범위:&lt;/b&gt; 좁은 사무실은 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;10,2,0&quot;&gt;LAN&lt;/b&gt;, 도시는 &lt;b data-index-in-node=&quot;24&quot; data-path-to-node=&quot;10,2,0&quot;&gt;MAN&lt;/b&gt;, 국가나 대륙을 넘어서면 &lt;b data-index-in-node=&quot;42&quot; data-path-to-node=&quot;10,2,0&quot;&gt;WAN&lt;/b&gt;으로 분류한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;1.2 OSI 7계층 모델과 프로토콜&lt;/h3&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;네트워크 통신의 복잡성을 해결하기 위해 ISO는 통신 과정을 7단계로 표준화했다. 이를 &lt;b data-index-in-node=&quot;49&quot; data-path-to-node=&quot;12&quot;&gt;OSI 7계층&lt;/b&gt;이라 한다.&lt;/p&gt;
&lt;div&gt;
&lt;div data-full-size-image-uri=&quot;https://encrypted-tbn3.gstatic.com/licensed-image?q=tbn:ANd9GcSm1FxSTn4tvyXSwJ4CEpPhzku5RuTi089q6UNZxShEauSLUhkfuBAKbGEoAzSJECA0QAhhJRjNY4Z28w3FCsThkqctb1Md8fBwZ98leafh2NzAeF4&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3998&quot; data-origin-height=&quot;2999&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQUxlM/dJMcagEj9WZ/Kk8EPfKWCuIGNViMCWKkL1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQUxlM/dJMcagEj9WZ/Kk8EPfKWCuIGNViMCWKkL1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQUxlM/dJMcagEj9WZ/Kk8EPfKWCuIGNViMCWKkL1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQUxlM%2FdJMcagEj9WZ%2FKk8EPfKWCuIGNViMCWKkL1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3998&quot; height=&quot;2999&quot; data-origin-width=&quot;3998&quot; data-origin-height=&quot;2999&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;Physical (물리 계층):&lt;/b&gt; 0과 1을 전기 신호로 변환한다. (장비: 허브, 리피터)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;Data Link (데이터 링크 계층):&lt;/b&gt; 물리적 주소(MAC)를 사용하여 인접 기기 간 신뢰성 있는 전송을 담당한다. 전송 단위를 **프레임(Frame)**이라 한다. (장비: 스위치, 브릿지)
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,1,0,0&quot;&gt;이더넷(Ethernet):&lt;/b&gt; 유선 LAN의 표준. &lt;b data-index-in-node=&quot;27&quot; data-path-to-node=&quot;14,1,1,0,0&quot;&gt;CSMA/CD&lt;/b&gt; 기술을 써서 데이터 충돌을 감지하고, 충돌 시 임의 시간 대기(Exponential Backoff) 후 재전송한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,1,1,0&quot;&gt;와이파이(Wi-Fi):&lt;/b&gt; 무선은 충돌 감지가 어려워 &lt;b data-index-in-node=&quot;28&quot; data-path-to-node=&quot;14,1,1,1,0&quot;&gt;CSMA/CA&lt;/b&gt; (충돌 회피) 방식을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,2,0&quot;&gt;Network (네트워크 계층):&lt;/b&gt; 데이터를 목적지까지 가장 안전하고 빠르게 보낼 경로(라우팅)를 찾는다. 단위는 **패킷(Packet)**이다. (IP, ICMP, IPSec)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,3,0&quot;&gt;Transport (전송 계층):&lt;/b&gt; 양 끝단(End-to-End)의 사용자들이 신뢰성 있게 데이터를 주고받게 한다. (TCP, UDP)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,4,0&quot;&gt;Session / Presentation / Application:&lt;/b&gt; 세션을 관리하고, 데이터 형식을 변환(암호화/압축)하며, 사용자가 실제 접하는 응용 프로그램(HTTP, FTP 등) 단계를 의미한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15&quot;&gt;신뢰성을 위한 기술들:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;흐름 제어(Sliding Window):&lt;/b&gt; 수신 측이 처리할 수 있는 만큼만 데이터를 보낸다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;오류 검출:&lt;/b&gt; 간단하게는 1의 개수를 맞추는 &lt;b data-index-in-node=&quot;24&quot; data-path-to-node=&quot;16,1,0&quot;&gt;패리티 비트&lt;/b&gt;부터, 데이터 다항식 연산을 이용한 &lt;b data-index-in-node=&quot;50&quot; data-path-to-node=&quot;16,1,0&quot;&gt;체크섬(Checksum)&lt;/b&gt; 등을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;1.3 IP 네트워크와 주소 지정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;인터넷은 거대한 약속, 즉 **프로토콜(Protocol)**의 집합이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;IP 주소:&lt;/b&gt; 네트워크상의 집 주소다. 과거에는 A, B, C 클래스로 나누었으나 낭비가 심해, 현재는 &lt;b data-index-in-node=&quot;57&quot; data-path-to-node=&quot;19,0,0&quot;&gt;CIDR(사이더)&lt;/b&gt; 블록을 이용해 유연하게 주소를 할당한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;Port(포트):&lt;/b&gt; 집 안의 '방 번호'와 같다. 하나의 IP(서버) 안에서 웹(80), 메일(25) 등 어떤 프로세스가 데이터를 받을지 구분한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,2,0&quot;&gt;TCP vs UDP:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,2,1,0,0&quot;&gt;TCP:&lt;/b&gt; 연결 지향형. 3-way Handshake(SYN, SYN-ACK, ACK)를 통해 연결을 맺고 데이터를 확실히 보낸다. 느리지만 정확하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,2,1,1,0&quot;&gt;UDP:&lt;/b&gt; 비연결형. 데이터를 던지기만 한다(Datagram). 스트리밍처럼 속도가 중요할 때 쓴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;20&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size26&quot;&gt;2. 소프트웨어 공학: 코딩을 넘어 공학으로&lt;/h2&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;소프트웨어 공학(Software Engineering)은 소프트웨어의 개발, 운용, 유지보수에 체계적이고 정량적인 접근법을 적용하는 것이다. 즉, **&quot;최소한의 비용으로 최대한의 품질을 뽑아내는 기술&quot;**이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;2.1 품질과 프로세스&lt;/h3&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;소프트웨어는 눈에 보이지 않아 품질 보증이 어렵다. 이를 관리하기 위해 조직의 성숙도를 평가하는 모델이 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,0,0&quot;&gt;CMMI:&lt;/b&gt; 조직의 개발 프로세스 역량을 5단계(Initial ~ Optimizing)로 평가한다. 레벨이 높을수록 프로세스가 정량적으로 관리되고 최적화되어 있음을 의미한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,1,0&quot;&gt;형상 관리(SCM):&lt;/b&gt; 소스 코드의 변경 사항을 버전별로 관리하여, 실수했을 때 언제든 과거로 되돌릴 수 있게 한다(Git 등).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;2.2 개발 방법론: 폭포수 vs 애자일&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;소프트웨어를 만드는 방식은 크게 두 가지 철학으로 나뉜다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;28&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,0,0&quot;&gt;폭포수 모델 (Waterfall):&lt;/b&gt; 고전적 방식. &lt;b data-index-in-node=&quot;28&quot; data-path-to-node=&quot;28,0,0&quot;&gt;요구사항 &amp;rarr; 설계 &amp;rarr; 구현 &amp;rarr; 검증 &amp;rarr; 유지보수&lt;/b&gt;가 물이 떨어지듯 순차적으로 진행된다. 다음 단계로 넘어가면 되돌리기 어렵다. 명확한 요구사항이 있는 프로젝트에 적합하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,1,0&quot;&gt;애자일 모델 (Agile):&lt;/b&gt; 변화에 유연하게 대응하는 방식. &quot;계획을 따르는 것보다 &lt;b data-index-in-node=&quot;47&quot; data-path-to-node=&quot;28,1,0&quot;&gt;변화에 대응&lt;/b&gt;하는 것&quot;, &quot;문서보다 &lt;b data-index-in-node=&quot;66&quot; data-path-to-node=&quot;28,1,0&quot;&gt;작동하는 소프트웨어&lt;/b&gt;&quot;를 중시한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;28,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,1,1,0,0&quot;&gt;스크럼(Scrum):&lt;/b&gt; 짧은 주기(Sprint)로 개발하고 피드백을 받는다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,1,1,1,0&quot;&gt;XP(eXtreme Programming):&lt;/b&gt; 짝 프로그래밍(Pair Programming) 등을 통해 품질을 극한으로 높인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;2.3 클린 코드와 리팩토링&lt;/h3&gt;
&lt;p data-path-to-node=&quot;30&quot; data-ke-size=&quot;size16&quot;&gt;&quot;돌아가기만 하는 코드&quot;는 시한폭탄과 같다. 유지보수 가능한 코드를 작성해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;31&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,0,0&quot;&gt;코드 리뷰:&lt;/b&gt; 동료들이 내 코드를 검토하는 과정. 버그 발견뿐만 아니라 지식 공유의 장이 된다. 격식을 갖춘 **코드 인스펙션(Inspection)**이나 &lt;b data-index-in-node=&quot;86&quot; data-path-to-node=&quot;31,0,0&quot;&gt;FTR&lt;/b&gt; 같은 방식도 있다. 이때 핵심은 &quot;작성자를 비난하지 않고 코드 자체만 비판하는 것&quot;이다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,1,0&quot;&gt;리팩토링(Refactoring):&lt;/b&gt; 외부 동작은 그대로 둔 채, 내부 구조를 깔끔하게 개선하는 작업. 기술 부채를 갚는 과정이다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,2,0&quot;&gt;클린 코드:&lt;/b&gt; 읽기 쉽고, 의도가 명확하며, 중복이 없는 코드. 이것이 뒷받침되어야 애자일한 대응도 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;32&quot; data-ke-size=&quot;size23&quot;&gt;마치며&lt;/h3&gt;
&lt;p data-path-to-node=&quot;33&quot; data-ke-size=&quot;size16&quot;&gt;네트워크가 전 세계를 하나로 묶어주는 신경망이라면, 소프트웨어 공학은 그 신경망 위에서 돌아가는 시스템을 건강하게 유지하는 면역 체계와 같다. OSI 7계층의 흐름을 이해하고, 애자일한 사고방식으로 클린 코드를 작성하는 것. 이것이 훌륭한 엔지니어가 갖춰야 할 기본 소양이다.&lt;/p&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/114</guid>
      <comments>https://lazypatchnotes.tistory.com/114#entry114comment</comments>
      <pubDate>Fri, 23 Jan 2026 09:34:05 +0900</pubDate>
    </item>
    <item>
      <title>[86일차]하드웨어부터 데이터까지: 컴퓨터 구조, OS, 그리고 데이터베이스</title>
      <link>https://lazypatchnotes.tistory.com/113</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;지난 글에서 정보의 표현과 논리 회로라는 가장 기초적인 단위를 다루었다면, 이번에는 그 위에서 돌아가는 거대한 시스템을 조망해본다. 컴퓨터 하드웨어의 설계 원칙(컴퓨터 구조), 하드웨어를 효율적으로 관리하는 소프트웨어(운영체제), 그리고 현대 서비스의 핵심인 데이터 관리(데이터베이스)까지, 개발자가 반드시 알아야 할 시스템의 뼈대를 정리한다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;4&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. 컴퓨터 구조의 설계와 구현&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터는 마법 상자가 아니다. 철저하게 계산된 공학적 설계물이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;1.1 하드웨어의 핵심: CPU와 ISA&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터의 두뇌인 **CPU(중앙처리장치)**는 크게 세 부분으로 나뉜다. 연산 순서를 제어하는 &lt;b data-index-in-node=&quot;53&quot; data-path-to-node=&quot;8&quot;&gt;제어장치(Control Unit)&lt;/b&gt;, 실제 계산을 담당하는 &lt;b data-index-in-node=&quot;85&quot; data-path-to-node=&quot;8&quot;&gt;ALU(산술논리연산장치)&lt;/b&gt;, 그리고 연산 데이터를 잠시 저장하는 초고속 메모리인 **레지스터(Register)**다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;소프트웨어가 하드웨어와 소통하기 위해서는 약속이 필요한데, 이를 **ISA(명령어 집합 구조)**라고 한다. (예: x86, ARM). 반면, 이 ISA를 실제 물리적으로 어떻게 구현했는지를 **마이크로아키텍처(Microarchitecture)**라고 하며, Intel과 AMD가 같은 x86 명령어를 쓰면서도 성능이 다른 이유가 바로 이 설계가 다르기 때문이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;CISC:&lt;/b&gt; 복잡하고 다양한 명령어를 지원 (코드 길이 감소, 하드웨어 복잡).&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;RISC:&lt;/b&gt; 단순하고 핵심적인 명령어만 지원 (하드웨어 단순, 파이프라이닝 유리).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;현대 CPU는 효율을 극대화하기 위해 &lt;b data-index-in-node=&quot;21&quot; data-path-to-node=&quot;11&quot;&gt;명령어 파이프라인(Instruction Pipeline)&lt;/b&gt; 기법을 사용한다. 마치 공장 조립 라인처럼, 하나의 명령어가 끝나기 전에 다음 명령어를 미리 가져와 실행하여 처리량(Throughput)을 높인다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;1.2 기억장치의 계층 구조 (Memory Hierarchy)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&quot;빠른 것은 비싸고, 싼 것은 느리다.&quot; 이 경제적 법칙을 극복하기 위해 컴퓨터는 계층 구조를 택했다. CPU에 가까울수록 빠르지만 용량이 작고, 멀수록 느리지만 용량이 크다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;레지스터:&lt;/b&gt; CPU 내부. 가장 빠름.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;캐시 메모리 (L1, L2, L3):&lt;/b&gt; CPU와 주기억장치 사이의 속도 차 완충.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,2,0&quot;&gt;주기억장치 (RAM):&lt;/b&gt; 실행 중인 프로그램이 상주.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,3,0&quot;&gt;보조기억장치 (HDD, SSD):&lt;/b&gt; 전원이 꺼져도 데이터 저장.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;2283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZWCv0/dJMcaiB4oWv/Uh5nBevaKmkgEz7zOIjR7K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZWCv0/dJMcaiB4oWv/Uh5nBevaKmkgEz7zOIjR7K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZWCv0/dJMcaiB4oWv/Uh5nBevaKmkgEz7zOIjR7K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZWCv0%2FdJMcaiB4oWv%2FUh5nBevaKmkgEz7zOIjR7K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3999&quot; height=&quot;2283&quot; data-origin-width=&quot;3999&quot; data-origin-height=&quot;2283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-path-to-node=&quot;16&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size26&quot;&gt;2. 프로그램의 번역과 실행&lt;/h2&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;우리가 작성한 고수준 언어(C, Java, Python)는 컴퓨터가 이해할 수 없다. 번역 과정이 필수적이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;2.1 언어의 레벨과 번역기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;컴파일러:&lt;/b&gt; 소스 코드 전체를 한 번에 기계어(목적 코드)로 번역한다. 실행 속도가 빠르다. (C, C++)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;인터프리터:&lt;/b&gt; 코드를 한 줄씩 해석하며 실행한다. 수정이 용이하나 실행 속도는 느리다. (Python, JS)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,2,0&quot;&gt;하이브리드:&lt;/b&gt; 중간 코드(Bytecode)로 컴파일 후, 가상 머신(VM) 위에서 실행한다. (Java)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;2.2 빌드 과정: 링커와 로더&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;소스 코드가 목적 파일(Object File)로 변환되었다고 끝이 아니다. 여러 목적 파일과 라이브러리를 하나로 합치는 **링커(Linker)**의 작업을 거쳐야 비로소 실행 파일(.exe)이 된다. 이후 프로그램을 실행하면 **로더(Loader)**가 이를 메모리에 적재하여 CPU가 처리할 수 있게 만든다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;23&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size26&quot;&gt;3. 운영체제(OS): 시스템의 지휘자&lt;/h2&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25&quot;&gt;운영체제&lt;/b&gt;는 컴퓨터 하드웨어 자원을 효율적으로 관리하고, 사용자에게 편리한 인터페이스를 제공하는 &lt;b data-index-in-node=&quot;53&quot; data-path-to-node=&quot;25&quot;&gt;시스템 소프트웨어&lt;/b&gt;다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;3.1 커널(Kernel)과 시스템 콜&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;OS의 핵심 심장부를 &lt;b data-index-in-node=&quot;12&quot; data-path-to-node=&quot;27&quot;&gt;커널&lt;/b&gt;이라 한다. 메모리에 상주하며 프로세스, 메모리, 입출력 등 핵심 자원을 관리한다. 응용 프로그램은 하드웨어를 직접 제어할 수 없다. 따라서 커널에게 &quot;파일을 읽어줘&quot;, &quot;화면에 띄워줘&quot;라고 부탁해야 하는데, 이 인터페이스를 **시스템 콜(System Call)**이라고 한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;28&quot; data-ke-size=&quot;size23&quot;&gt;3.2 프로세스 관리와 스케줄링&lt;/h3&gt;
&lt;p data-path-to-node=&quot;29&quot; data-ke-size=&quot;size16&quot;&gt;프로그램이 저장장치에 있는 코드 덩어리라면, &lt;b data-index-in-node=&quot;25&quot; data-path-to-node=&quot;29&quot;&gt;프로세스&lt;/b&gt;는 메모리에 적재되어 실행 중인 프로그램이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;30&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,0,0&quot;&gt;생명주기:&lt;/b&gt; 생성(Start) &amp;rarr; 준비(Ready) &amp;rarr; 실행(Running) &amp;rarr; 대기(Waiting) &amp;rarr; 종료(Terminated)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,1,0&quot;&gt;스레드(Thread):&lt;/b&gt; 프로세스 내에서 실행되는 흐름의 단위. 프로세스 자원을 공유하므로 생성 및 전환 비용이 저렴하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;CPU는 한 번에 하나의 일만 할 수 있다. 따라서 여러 프로세스를 번갈아 가며 실행하여 동시에 실행되는 것처럼 보이게 하는 &lt;b data-index-in-node=&quot;70&quot; data-path-to-node=&quot;31&quot;&gt;스케줄링&lt;/b&gt;이 중요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;32&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;32,0,0&quot;&gt;선점형(Preemptive):&lt;/b&gt; OS가 강제로 CPU를 뺏어올 수 있음 (현대 OS).&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;32,1,0&quot;&gt;비선점형(Non-preemptive):&lt;/b&gt; 프로세스가 끝날 때까지 기다려줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;33&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;34&quot; data-ke-size=&quot;size26&quot;&gt;4. 메모리와 입출력 관리 (가상화의 마법)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;35&quot; data-ke-size=&quot;size16&quot;&gt;OS는 한정된 물리 자원을 추상화하여 무한한 것처럼 보이게 한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;36&quot; data-ke-size=&quot;size23&quot;&gt;4.1 가상 메모리 (Virtual Memory)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;37&quot; data-ke-size=&quot;size16&quot;&gt;실제 RAM 용량보다 더 큰 프로그램을 실행할 수 있게 해주는 기술이다. **MMU(Memory Management Unit)**가 가상 주소를 물리 주소로 실시간 변환한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;38&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;38,0,0&quot;&gt;페이징(Paging):&lt;/b&gt; 메모리를 고정 크기(Page)로 잘라서 관리. 외부 단편화 해결.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;38,1,0&quot;&gt;세그먼테이션(Segmentation):&lt;/b&gt; 논리적 단위(함수, 배열 등)로 잘라서 관리.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;38,2,0&quot;&gt;Page Fault:&lt;/b&gt; 필요한 데이터가 RAM에 없을 때 발생하며, 이때 보조기억장치에서 데이터를 가져온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;39&quot; data-ke-size=&quot;size16&quot;&gt;이 시스템이 효율적인 이유는 &lt;b data-index-in-node=&quot;16&quot; data-path-to-node=&quot;39&quot;&gt;참조의 지역성(Locality)&lt;/b&gt; 때문이다. 프로그램은 한 번 참조한 데이터 근처(공간적)나, 최근에 참조한 데이터(시간적)를 다시 쓸 확률이 매우 높다. 이를 이용해 &lt;b data-index-in-node=&quot;109&quot; data-path-to-node=&quot;39&quot;&gt;TLB&lt;/b&gt;나 캐시의 적중률을 높인다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;40&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;41&quot; data-ke-size=&quot;size26&quot;&gt;5. 데이터베이스: 데이터의 구조화&lt;/h2&gt;
&lt;p data-path-to-node=&quot;42&quot; data-ke-size=&quot;size16&quot;&gt;데이터가 자산인 시대, 데이터를 어떻게 저장하고 무결성을 유지하느냐는 핵심 이슈다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;43&quot; data-ke-size=&quot;size23&quot;&gt;5.1 관계형 데이터베이스 (RDBMS)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;44&quot; data-ke-size=&quot;size16&quot;&gt;데이터를 2차원 표(Table) 형태로 관리한다. 엄격한 스키마와 관계를 통해 데이터의 중복을 최소화하고 일관성을 유지한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;45&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;45,0,0&quot;&gt;구성:&lt;/b&gt; 튜플(Tuple, 행), 속성(Attribute, 열), 식별자(PK).&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;45,1,0&quot;&gt;트랜잭션(Transaction):&lt;/b&gt; 작업의 완전성을 보장하는 단위. &lt;b data-index-in-node=&quot;37&quot; data-path-to-node=&quot;45,1,0&quot;&gt;ACID&lt;/b&gt; 특성(원자성, 일관성, 고립성, 지속성)을 반드시 만족해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;45,2,0&quot;&gt;SQL:&lt;/b&gt; 데이터베이스와 대화하는 언어. (DML: 조회/수정, DDL: 구조 정의, DCL: 권한 제어, TCL: 트랜잭션 제어)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;46&quot; data-ke-size=&quot;size23&quot;&gt;5.2 ORM (Object-Relational Mapping)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;47&quot; data-ke-size=&quot;size16&quot;&gt;개발자가 SQL을 직접 짜지 않고, 객체지향 언어(Java, Python 등)의 객체(Class)를 통해 DB를 다루는 기술이다. 생산성은 높여주지만, 복잡한 쿼리에서는 성능 최적화가 필요하다. (예: JPA, Django ORM)&lt;/p&gt;
&lt;hr data-path-to-node=&quot;48&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;49&quot; data-ke-size=&quot;size26&quot;&gt;6. 차세대 데이터 관리: 벡터 DB와 NoSQL&lt;/h2&gt;
&lt;p data-path-to-node=&quot;50&quot; data-ke-size=&quot;size16&quot;&gt;정형화된 데이터를 넘어 비정형 데이터와 AI 시대를 위한 DB가 부상하고 있다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;51&quot; data-ke-size=&quot;size23&quot;&gt;6.1 벡터 데이터베이스 (Vector DB)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;52&quot; data-ke-size=&quot;size16&quot;&gt;텍스트, 이미지 등 비정형 데이터를 &lt;b data-index-in-node=&quot;20&quot; data-path-to-node=&quot;52&quot;&gt;벡터 임베딩(Vector Embedding)&lt;/b&gt;, 즉 숫자의 배열로 변환하여 저장한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;53&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;53,0,0&quot;&gt;핵심:&lt;/b&gt; 단순히 키워드가 같은 것을 찾는 게 아니라, **의미적 유사도(Similarity)**가 가까운 것을 찾는다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;53,1,0&quot;&gt;기술:&lt;/b&gt; 방대한 벡터 공간에서 빠르게 이웃을 찾기 위해 &lt;b data-index-in-node=&quot;30&quot; data-path-to-node=&quot;53,1,0&quot;&gt;LSH&lt;/b&gt;, &lt;b data-index-in-node=&quot;35&quot; data-path-to-node=&quot;53,1,0&quot;&gt;ANNOY&lt;/b&gt; 등의 근사 탐색 알고리즘을 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;53,2,0&quot;&gt;활용:&lt;/b&gt; AI 추천 시스템, 챗봇의 지식 검색(RAG), 이미지 검색 등.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;54&quot; data-ke-size=&quot;size23&quot;&gt;6.2 NoSQL&lt;/h3&gt;
&lt;p data-path-to-node=&quot;55&quot; data-ke-size=&quot;size16&quot;&gt;RDBMS의 경직된 스키마를 벗어나, 유연성과 확장성(Scale-out)에 초점을 맞춘 DB다. 대용량 분산 처리에 적합하며, Document(MongoDB), Key-Value(Redis) 등 다양한 형태가 존재한다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;56&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;57&quot; data-ke-size=&quot;size23&quot;&gt;마치며&lt;/h3&gt;
&lt;p data-path-to-node=&quot;58&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터 구조가 튼튼한 건물을 짓기 위한 자재와 공법이라면, 운영체제는 그 건물을 관리하는 시스템이고, 데이터베이스는 건물 안에 채워지는 귀중한 자산들을 체계적으로 정리하는 금고와 같다. 이 기초적인 흐름을 이해하는 것은 단순히 지식을 쌓는 것을 넘어, 시스템 전체를 관통하는 통찰력을 기르는 첫걸음이다.&lt;/p&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/113</guid>
      <comments>https://lazypatchnotes.tistory.com/113#entry113comment</comments>
      <pubDate>Thu, 22 Jan 2026 18:43:49 +0900</pubDate>
    </item>
    <item>
      <title>[85일차]컴퓨터의 언어부터 설계까지: 정보의 표현과 구조적 이해</title>
      <link>https://lazypatchnotes.tistory.com/112</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;개발자로서의 성장은 코드를 '작성'하는 것에서 멈추지 않고, 코드가 '동작'하는 원리를 이해하는 데서 시작된다. 단순히 라이브러리나 프레임워크를 사용하는 것을 넘어, 컴퓨터가 데이터를 어떻게 이해하고 처리하는지, 그리고 그 하드웨어적인 설계가 소프트웨어에 어떤 영향을 미치는지 파악하는 것은 매우 중요하다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이 글에서는 CS 지식의 가장 밑바닥이라 할 수 있는 &lt;b data-index-in-node=&quot;30&quot; data-path-to-node=&quot;4&quot;&gt;정보의 표현&lt;/b&gt;과 &lt;b data-index-in-node=&quot;38&quot; data-path-to-node=&quot;4&quot;&gt;컴퓨터의 설계&lt;/b&gt; 원리에 대해 깊이 있게 다뤄보고자 한다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;5&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. 기초를 공부해야 하는 이유&lt;/h2&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;왜 우리는 당장 실무에 쓰이지 않을 것 같은 0과 1, 그리고 하드웨어 구조를 배워야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, 소통의 비용을 줄이기 위함이다. 엔지니어 간의 대화에서 '오버플로우(Overflow)', 'MSB', '부동소수점 오차' 같은 용어는 현상을 설명하는 가장 정확하고 효율적인 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 원리에 대한 이해는 문제 해결의 열쇠가 된다. 원인 모를 버그가 발생했을 때, 컴퓨터 내부 동작 방식을 아는 사람은 문제의 본질을 꿰뚫어 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째, 사고방식의 확장이다. 컴퓨터의 제약 사항과 논리 구조를 이해하면, 단순히 기능을 구현하는 것을 넘어 '효율적'이고 '최적화'된 설계를 할 수 있는 바탕이 마련된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;결국 기초 지식은 나의 생각을 논리적으로 표현하고, 시스템을 장악하기 위한 필수 무기이다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;10&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size26&quot;&gt;2. 디지털 정보의 표현 (Data Representation)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터는 전기가 흐르거나(On), 흐르지 않는(Off) 물리적 현상을 논리적인 정보로 변환하여 세상을 이해한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;2.1 디지털(Digital)과 비트(Bit)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;**디지털(Digital)**이란 연속적인 값(아날로그)을 불연속적인 값으로 표현하는 방식이다. 컴퓨터는 전압의 고저를 통해 **0(False)**과 **1(True)**이라는 두 가지 상태만을 인식한다. 이 정보의 최소 단위를 **비트(Bit, Binary Digit)**라고 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;하나의 비트는 너무 작기 때문에 컴퓨터는 비트들을 묶어서 데이터를 처리한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;Nibble (니블):&lt;/b&gt; 4bit를 묶은 단위이다. 16진수(Hexadecimal) 한 자리를 표현하기에 적합하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;Byte (바이트):&lt;/b&gt; 8bit를 묶은 단위이다. 현대 컴퓨터 시스템에서 데이터를 처리하는 가장 기본적인 단위가 된다. (예: 00111000)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;2.2 비트의 위치: MSB와 LSB&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;비트가 나열되어 있을 때, 각 위치가 가지는 가중치는 다르다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;MSB (Most Significant Bit):&lt;/b&gt; 최상위 비트. 가장 왼쪽의 비트로, 숫자의 크기에 가장 큰 영향을 미치거나 부호(Sign)를 결정하는 중요한 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;LSB (Least Significant Bit):&lt;/b&gt; 최하위 비트. 가장 오른쪽의 비트로, 짝수/홀수를 결정하거나 값의 미세한 변화를 담당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;2.3 문자의 표현: ASCII와 Unicode&lt;/h3&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;숫자뿐만 아니라 문자도 2진수로 약속되어 저장된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,0&quot;&gt;ASCII Code (아스키 코드):&lt;/b&gt; 7bit를 사용하여 영문 대소문자, 숫자, 특수기호를 표현한다. 128개의 문자만 표현 가능하여 한글이나 다른 언어를 담기엔 역부족이었다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,1,0&quot;&gt;Unicode (유니코드):&lt;/b&gt; 전 세계의 모든 문자를 일관되게 표현하기 위해 만들어진 국제 표준이다. UTF-8, UTF-16 등의 인코딩 방식을 통해 가변적인 길이(1~4바이트)로 문자를 저장하며, 현대 웹과 OS의 표준이 되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;23&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size26&quot;&gt;3. 이진수로 표현한 정수와 실수&lt;/h2&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터가 가장 잘하는 것은 '계산'이다. 하지만 0과 1만으로 음수와 소수점이 있는 실수를 표현하는 것은 생각보다 복잡한 설계를 요구한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;3.1 음수의 표현과 뺄셈의 원리&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터 하드웨어에는 '뺄셈기'가 별도로 존재하지 않는 경우가 많다. 대신 &lt;b data-index-in-node=&quot;41&quot; data-path-to-node=&quot;27&quot;&gt;음수를 표현하는 방식을 교묘히 이용하여 뺄셈을 덧셈으로 처리&lt;/b&gt;한다. (&lt;span data-index-in-node=&quot;79&quot; data-math=&quot;A - B&quot;&gt;$A - B$&lt;/span&gt;를 $A + (-B)$로 계산)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;28&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,0,0&quot;&gt;부호와 절대치(Sign and Magnitude):&lt;/b&gt; 최상위 비트(MSB)를 부호 비트로 쓴다 (0은 양수, 1은 음수). 하지만 +0과 -0이 존재하는 모순이 생기고 연산이 복잡하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,1,0&quot;&gt;1의 보수 (1's Complement):&lt;/b&gt; 모든 비트를 반전시킨다(0-&amp;gt;1, 1-&amp;gt;0). 여전히 +0과 -0 문제는 존재한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,2,0&quot;&gt;2의 보수 (2's Complement):&lt;/b&gt; 1의 보수에 1을 더한다. &lt;b data-index-in-node=&quot;39&quot; data-path-to-node=&quot;28,2,0&quot;&gt;현대 컴퓨터가 사용하는 표준 방식&lt;/b&gt;이다. +0과 -0의 중복을 없애고, 뺄셈을 완벽하게 덧셈 회로로 수행할 수 있게 해준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;3.2 실수의 표현: 고정소수점과 부동소수점&lt;/h3&gt;
&lt;p data-path-to-node=&quot;30&quot; data-ke-size=&quot;size16&quot;&gt;실수(Real Number)는 정수 사이에 무한한 숫자가 존재하기에 표현이 더욱 까다롭다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;31&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,0,0&quot;&gt;고정 소수점 (Fixed Point):&lt;/b&gt; 소수점의 위치를 고정해두고 정수부와 소수부를 나눈다. 구현은 단순하지만 표현할 수 있는 수의 범위가 매우 좁다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,1,0&quot;&gt;부동 소수점 (Floating Point):&lt;/b&gt; 소수점의 위치가 둥둥 떠다닌다(Float)는 의미다. 수를 &lt;span data-index-in-node=&quot;58&quot; data-math=&quot;1.xxxx \times 2^n&quot;&gt;$1.xxxx \times 2^n$&lt;/span&gt; 형태(가수와 지수)로 저장한다. (IEEE 754 표준).
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;31,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,1,1,0,0&quot;&gt;장점:&lt;/b&gt; 매우 큰 수나 매우 작은 수를 표현할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;31,1,1,1,0&quot;&gt;단점:&lt;/b&gt; 정확한 값이 아닌 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;31,1,1,1,0&quot;&gt;근사값&lt;/b&gt;을 저장하므로, 미세한 정밀도 오차가 발생할 수 있다. 금융 계산 등에서 주의가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;32&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;33&quot; data-ke-size=&quot;size26&quot;&gt;4. 컴퓨터 연산 하드웨어 (논리회로)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;34&quot; data-ke-size=&quot;size16&quot;&gt;소프트웨어의 논리 연산은 하드웨어 레벨에서 '게이트(Gate)'라는 물리적 회로를 통해 수행된다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;35&quot; data-ke-size=&quot;size23&quot;&gt;4.1 기본 논리 게이트&lt;/h3&gt;
&lt;p data-path-to-node=&quot;36&quot; data-ke-size=&quot;size16&quot;&gt;명제 논리를 전기 신호로 구현한 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;37&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;37,0,0&quot;&gt;기본 게이트:&lt;/b&gt; AND(둘 다 참일 때 참), OR(하나라도 참이면 참), NOT(반전).&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;37,1,0&quot;&gt;범용 게이트:&lt;/b&gt; NAND, NOR. 이 두 가지 게이트만 있으면 위의 모든 기본 게이트를 만들어낼 수 있어 칩 설계 시 매우 중요하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;37,2,0&quot;&gt;배타적 논리합 (XOR):&lt;/b&gt; 두 입력이 &lt;b data-index-in-node=&quot;21&quot; data-path-to-node=&quot;37,2,0&quot;&gt;다를 때만&lt;/b&gt; 1을 출력한다. 이 특성은 이진수 덧셈에서 자리 올림(Carry)을 제외한 합을 구하는 데 핵심적인 역할을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vbaXW/dJMcaiWmV84/RTGAFoqcTJpizlm4Wy4B61/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vbaXW/dJMcaiWmV84/RTGAFoqcTJpizlm4Wy4B61/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vbaXW/dJMcaiWmV84/RTGAFoqcTJpizlm4Wy4B61/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvbaXW%2FdJMcaiWmV84%2FRTGAFoqcTJpizlm4Wy4B61%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2000&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;39&quot; data-ke-size=&quot;size23&quot;&gt;4.2 가산기 (Adder): 계산하는 회로&lt;/h3&gt;
&lt;p data-path-to-node=&quot;40&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터의 덧셈은 XOR와 AND 게이트의 조합으로 이루어진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;41&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;41,0,0&quot;&gt;반가산기 (HA, Half Adder):&lt;/b&gt; 두 비트를 더해 합(Sum)과 자리올림(Carry)을 출력한다. 이전 자리에서 올라온 올림수를 처리하지 못한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;41,1,0&quot;&gt;전가산기 (FA, Full Adder):&lt;/b&gt; 하위 비트에서 올라온 자리올림수(Carry In)까지 포함하여 3개의 비트를 더할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;41,2,0&quot;&gt;리플 캐리 가산기 (Ripple Carry Adder):&lt;/b&gt; 전가산기를 여러 개 연결하여 다비트(Multi-bit) 덧셈을 수행한다. 단, 하위 비트의 캐리가 상위로 전달될 때까지 기다려야 하므로 지연 시간(Delay)이 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;41,3,0&quot;&gt;가감산기 (Adder-Subtractor):&lt;/b&gt; XOR 게이트를 활용해 하나의 회로로 덧셈과 뺄셈을 모두 수행하도록 만든 회로다. (2의 보수 개념 활용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;42&quot; data-ke-size=&quot;size23&quot;&gt;4.3 ALU (Arithmetic Logic Unit)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;CPU의 핵심 부품인 ALU(산술논리연산장치)는 위의 가산기와 논리 게이트들을 모아놓은 집합체다. 제어 신호에 따라 덧셈, 뺄셈, AND, OR 등의 연산을 수행한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;44&quot; data-ke-size=&quot;size23&quot;&gt;4.4 조합 논리와 순차 논리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;45&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;45,0,0&quot;&gt;조합 논리 (Combinational Logic):&lt;/b&gt; 현재의 입력만이 출력을 결정한다. (예: 가산기, ALU). 기억 능력이 없다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;45,1,0&quot;&gt;순차 논리 (Sequential Logic):&lt;/b&gt; 현재의 입력뿐만 아니라 **'이전 상태(과거의 입력)'**가 출력에 영향을 미친다. 이를 위해 값을 저장하는 **메모리(플립플롭, 레지스터)**가 필요하다. 컴퓨터가 '기억'을 가지고 프로그램을 수행할 수 있는 기반이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;46&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;47&quot; data-ke-size=&quot;size26&quot;&gt;5. 튜링 기계와 폰 노이만 구조&lt;/h2&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터의 설계 철학은 수학적 모델에서 시작하여 실용적 구조로 발전했다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;49&quot; data-ke-size=&quot;size23&quot;&gt;5.1 튜링 기계 (Turing Machine)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;50&quot; data-ke-size=&quot;size16&quot;&gt;앨런 튜링이 제안한 개념적인 계산 모델이다. 무한한 테이프에 기호를 쓰고 지우는 단순한 작업만으로도 세상의 모든 계산 가능한 문제를 해결할 수 있음을 증명했다. 이는 현대 컴퓨터 소프트웨어의 이론적 기원이 된다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;51&quot; data-ke-size=&quot;size23&quot;&gt;5.2 폰 노이만 구조 (Von Neumann Architecture)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;52&quot; data-ke-size=&quot;size16&quot;&gt;초기 컴퓨터(에니악 등)는 프로그램을 바꿀 때마다 전선을 재배치해야 했다. 폰 노이만은 **&quot;프로그램(명령어)도 데이터처럼 메모리에 저장해두고 꺼내 쓰자&quot;**는 혁신적인 제안을 했다. 이를 **프로그램 내장 방식(Stored-program concept)**이라고 한다.&lt;/p&gt;
&lt;div&gt;
&lt;div data-full-size-image-uri=&quot;https://encrypted-tbn2.gstatic.com/licensed-image?q=tbn:ANd9GcRRnu6sIAO_2xB6HIjM_KZ650z1Nh01Op8pIWtZw7q8R3aOHPFCSo-Ba5D3TuqUu1sI-O61ugFwsGDt1xIUAoWbBvt6UAcAscXNYeJb0YzXlVadh54&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2995&quot; data-origin-height=&quot;2708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHMUms/dJMcabwcFio/UO14qVE9aLQq1xoAuNXmi0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHMUms/dJMcabwcFio/UO14qVE9aLQq1xoAuNXmi0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHMUms/dJMcabwcFio/UO14qVE9aLQq1xoAuNXmi0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHMUms%2FdJMcabwcFio%2FUO14qVE9aLQq1xoAuNXmi0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;560&quot; data-origin-width=&quot;2995&quot; data-origin-height=&quot;2708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;54&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;54,0,0&quot;&gt;구조:&lt;/b&gt; CPU(제어장치+ALU), 메모리, 입출력 장치, 버스(Bus)로 구성된다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;54,1,0&quot;&gt;특징:&lt;/b&gt; 현재 우리가 사용하는 거의 모든 컴퓨터(PC, 스마트폰)는 폰 노이만 구조를 따른다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;54,2,0&quot;&gt;폰 노이만 병목현상:&lt;/b&gt; CPU의 속도는 비약적으로 빨라졌지만, 메모리의 속도가 이를 따라가지 못해 전체 시스템 성능이 저하되는 현상이 발생하기도 한다. 이를 해결하기 위해 캐시(Cache) 메모리 등이 도입되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;55&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;56&quot; data-ke-size=&quot;size26&quot;&gt;6. 마치며&lt;/h2&gt;
&lt;p data-path-to-node=&quot;57&quot; data-ke-size=&quot;size16&quot;&gt;우리가 작성한 코드는 결국 컴파일되어 0과 1의 조합으로 변하고, 메모리에 적재되어(폰 노이만), ALU(조합 논리)와 레지스터(순차 논리)를 오가며 처리된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;58&quot; data-ke-size=&quot;size16&quot;&gt;이러한 하드웨어와 데이터 표현의 기초 원리를 이해하는 것은 건물을 지을 때 단단한 지반을 다지는 것과 같다. 이 지식을 바탕으로 앞으로 이어질 &lt;b data-index-in-node=&quot;80&quot; data-path-to-node=&quot;58&quot;&gt;컴퓨터 구조, 운영체제, 데이터베이스&lt;/b&gt; 등의 심화 학습에서 &quot;왜 이렇게 설계되었는가?&quot;에 대한 답을 스스로 찾을 수 있게 될 것이다.&lt;/p&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/112</guid>
      <comments>https://lazypatchnotes.tistory.com/112#entry112comment</comments>
      <pubDate>Wed, 21 Jan 2026 14:32:40 +0900</pubDate>
    </item>
    <item>
      <title>[84일차]모니터링 시스템과 전체 회고</title>
      <link>https://lazypatchnotes.tistory.com/111</link>
      <description>&lt;p&gt;웹 기반 문서 편집기 프로젝트를 진행하며 기능 구현뿐만 아니라 안정적인 운영을 위한 DevOps 환경 구축에도 힘썼다. 특히 CI/CD 파이프라인의 상태를 실시간으로 확인하고, 애플리케이션이 구동되는 쿠버네티스 클러스터의 리소스를 시각화하는 과정은 서비스의 신뢰성을 높이는 핵심 단계였다. 이번 포스팅에서는 파이프라인 알림 설정과 클러스터 모니터링 구축 과정을 정리한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 파이프라인 모니터링 (Pipeline Monitoring)&lt;/h2&gt;
&lt;h3&gt;개념 및 필요성&lt;/h3&gt;
&lt;p&gt;CI/CD 파이프라인 모니터링은 빌드, 테스트, 배포의 전 과정이 성공적으로 수행되었는지, 혹은 어느 지점에서 실패했는지를 개발자가 즉각적으로 인지할 수 있도록 돕는 시스템이다.&lt;br&gt;개발자가 매번 젠킨스(Jenkins) 대시보드에 접속해 빌드 상태를 확인하는 것은 비효율적이다. 배포 실패 시 즉각적인 대응을 하지 못하면 서비스 장애로 이어질 수 있기 때문에, 팀이 주로 사용하는 커뮤니케이션 도구(Slack 등)로 알림을 자동 전송하는 과정이 필수적이다.&lt;/p&gt;
&lt;h3&gt;구현 방법: Jenkins와 Slack 연동&lt;/h3&gt;
&lt;p&gt;릴리스 브랜치(release branch)를 통해 배포를 제어하고, 각 단계의 결과에 따라 슬랙으로 메시지를 보낸다. Jenkins Pipeline 스크립트(Jenkinsfile) 내 &lt;code&gt;post&lt;/code&gt; 블록을 활용하면 빌드 성공/실패 여부에 따라 맞춤형 메시지를 구성할 수 있다.&lt;/p&gt;
&lt;h4&gt;  Jenkinsfile 예시 코드&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-groovy&quot;&gt;pipeline {
    agent any
    stages {
        stage(&amp;#39;Build&amp;#39;) {
            steps {
                sh &amp;#39;./gradlew build&amp;#39;
            }
        }
        // ... (Test, Deploy stages) ...
    }

    // 빌드 후 처리 (알림 발송)
    post {
        success {
            script {
                def msg = &amp;quot;✅ 빌드 성공: ${env.JOB_NAME} [${env.BUILD_NUMBER}]&amp;quot;
                slackSend(channel: &amp;#39;#deploy-alarm&amp;#39;, color: &amp;#39;good&amp;#39;, message: msg)
            }
        }
        failure {
            script {
                def msg = &amp;quot;❌ 빌드 실패: ${env.JOB_NAME} [${env.BUILD_NUMBER}]\n확인 요망: ${env.BUILD_URL}&amp;quot;
                slackSend(channel: &amp;#39;#deploy-alarm&amp;#39;, color: &amp;#39;danger&amp;#39;, message: msg)
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 설정하면 빌드가 끝나는 즉시 슬랙 채널로 알림이 오며, 실패 시 로그를 바로 확인할 수 있는 URL을 제공해 트러블슈팅 속도를 높인다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. 클러스터 모니터링 (Cluster Monitoring)&lt;/h2&gt;
&lt;h3&gt;개념 및 필요성&lt;/h3&gt;
&lt;p&gt;클러스터 모니터링은 쿠버네티스(Kubernetes) 환경 내의 노드(Node)와 파드(Pod)가 사용하는 CPU, 메모리, 네트워크 등의 시스템 자원 상태를 지속적으로 관찰하는 것이다.&lt;br&gt;애플리케이션이 정상적으로 떠 있더라도 메모리 누수(Memory Leak)가 발생하거나 CPU 사용량이 치솟으면 서비스가 멈출 수 있다.&lt;br&gt;따라서 &lt;strong&gt;메트릭 데이터(Metric Data, 시간이 지남에 따라 변하는 수치 데이터)&lt;/strong&gt;를 수집하고 이를 시각화하여, 장애 징후를 사전에 포착해야 한다.&lt;/p&gt;
&lt;h3&gt;구현 방법: Prometheus와 Grafana&lt;/h3&gt;
&lt;p&gt;모니터링의 표준 조합인 &lt;strong&gt;프로메테우스(Prometheus)&lt;/strong&gt;와 &lt;strong&gt;그라파나(Grafana)&lt;/strong&gt;를 사용한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prometheus&lt;/strong&gt;: 클러스터 내의 메트릭 데이터를 주기적으로 수집(Pull 방식)하고 저장한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grafana&lt;/strong&gt;: 수집된 데이터를 차트와 그래프 형태의 대시보드로 시각화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;설치 과정이 복잡할 수 있으나, 쿠버네티스 패키지 매니저인 Helm을 사용하면 &lt;code&gt;kube-prometheus-stack&lt;/code&gt;을 통해 한 번에 쉽게 설치할 수 있다.&lt;/p&gt;
&lt;h4&gt;  Helm 설치 및 설정 예시&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 1. Prometheus 커뮤니티 Helm 리포지토리 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 2. 모니터링 스택 설치 (Prometheus + Grafana + AlertManager 포함)
helm install my-monitoring prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace

# 3. 설치 확인
kubectl get pods -n monitoring&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;설치 후 그라파나 서비스의 포트 포워딩을 통해 대시보드에 접속하면, 클러스터의 건강 상태를 한눈에 파악할 수 있는 대시보드가 자동으로 구성되어 있음을 확인할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. 프로젝트 최종 정리 (Project Wrap-up)&lt;/h2&gt;
&lt;p&gt;이번 웹 문서 편집기 프로젝트는 단순한 구현을 넘어 소프트웨어 개발 생명주기(SDLC) 전체를 아우르는 경험이었다.&lt;br&gt;전체 프로세스는 다음과 같이 진행되었다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;요구사항 정의 및 설계&lt;/strong&gt;: 어떤 기능을 제공할 것인지 정의하고, 시스템 아키텍처와 DB 스키마를 설계했다.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;코드 구현&lt;/strong&gt;: 핵심 기능인 동시 편집과 문서 관리 기능을 개발했다.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;테스트&lt;/strong&gt;: 단위 테스트(Unit Test)를 통해 개별 로직의 정합성을 검증했다.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD&lt;/strong&gt;: Jenkins를 구축하여 코드 변경 사항이 자동으로 빌드되고 배포되도록 자동화했다.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E2E 테스트&lt;/strong&gt;: 실제 사용자 시나리오를 바탕으로 종단 간 테스트를 수행해 전체 흐름을 점검했다.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;모니터링&lt;/strong&gt;: 앞서 언급한 Slack 알림과 Prometheus/Grafana를 통해 운영 안정성을 확보했다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;회고&lt;/h2&gt;
&lt;p&gt;개발의 끝은 배포가 아니라 &lt;strong&gt;&amp;#39;안정적인 운영&amp;#39;&lt;/strong&gt;이라는 점을 깨달았다. 코드가 기능적으로 완벽하더라도 인프라 상황을 모니터링하지 못한다면 반쪽짜리 서비스일 뿐이다.&lt;br&gt;이번 프로젝트를 통해 구축한 모니터링 시스템은 향후 발생할 수 있는 잠재적 이슈를 선제적으로 방어하는 든든한 방패가 될 것이다.&lt;/p&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/111</guid>
      <comments>https://lazypatchnotes.tistory.com/111#entry111comment</comments>
      <pubDate>Mon, 19 Jan 2026 12:29:42 +0900</pubDate>
    </item>
    <item>
      <title>[83일차]AWS 클라우드 기반 Jenkins CI/CD 파이프라인 구축 및 자동화</title>
      <link>https://lazypatchnotes.tistory.com/110</link>
      <description>&lt;h2&gt;1. 클라우드 인프라 도입 배경 및 AWS 활용 계획&lt;/h2&gt;
&lt;p&gt;클라우드 도입은 초기 하드웨어 투자 비용을 절감하고 자원을 유연하게 확장할 수 있는 장점이 있다. 그러나 자원 관리 소홀 시 과도한 비용 발생 및 클라우드 사업자에 대한 의존이 단점으로 작용할 수 있다. &lt;/p&gt;
&lt;h3&gt;EC2 (Elastic Compute Cloud)&lt;/h3&gt;
&lt;p&gt;EC2는 Jenkins Master와 각 Agent를 구동하는 가상 서버로 사용된다. 워크로드에 따라 인스턴스 사양을 변경하여 성능과 비용의 최적화를 구현한다.&lt;/p&gt;
&lt;h3&gt;AMI (Amazon Machine Image)&lt;/h3&gt;
&lt;p&gt;AWS AMI를 통해 OS, 라이브러리 및 환경 설정 상태를 이미지로 보관한다. 이를 통해 서버 장애 시 즉각적인 복구가 가능하며 동일한 환경에서 모든 Agent가 동작하도록 보장한다.&lt;/p&gt;
&lt;h3&gt;ECR (Elastic Container Registry)&lt;/h3&gt;
&lt;p&gt;ECR은 빌드된 도커 이미지를 저장하는 중앙 저장소로 활용된다. 이는 Jenkins 파이프라인과 연동되어 검증된 이미지만을 안전하게 배포할 수 있는 신뢰 체인을 형성한다.&lt;/p&gt;
&lt;h3&gt;S3 (Simple Storage Service)&lt;/h3&gt;
&lt;p&gt;S3는 정적 웹 에셋, 빌드 로그, 파이프라인 결과물을 저장하는 데에 사용된다. 높은 내구성을 바탕으로 데이터를 안전하게 보존하며, 프론트엔드 배포를 위한 효율적인 스토리지 역할을 수행한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. CI/CD 파이프라인 아키텍처 및 Agent 설계&lt;/h2&gt;
&lt;p&gt;본 파이프라인은 Jenkins Master-Agent 구조를 활용하여 환경 격리와 리소스 효율성을 극대화하도록 설계되었다.&lt;/p&gt;
&lt;h3&gt;Agent 용도별 분리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;jnlp&lt;/strong&gt;: Docker 및 Terraform 클라이언트를 포함하여 인프라 제어와 통신을 담당한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;builder&lt;/strong&gt;: 단위 테스트 및 빌드 전용 Agent로, 특정 런타임(Node.js 등)에 의존적인 작업을 격리한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dind (Docker-in-Docker)&lt;/strong&gt;: 컨테이너 이미지 빌드를 위한 독립적 Docker 데몬 환경을 제공한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tester&lt;/strong&gt;: Selenium 등 무거운 테스트 도구를 실행하여 테스트 환경 독립성을 보장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;3. 단계별 상세 공정 및 설계 근거&lt;/h2&gt;
&lt;h3&gt;  단계 1: 소스 코드 검증 및 단위 테스트 (CI)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 작업&lt;/strong&gt;: SCM Checkout, Unit Test, Coverage Report (c8 활용)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;목적 및 이유&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;조기 발견 (Fail Fast)&lt;/strong&gt;: 코드 오류를 빌드 전 단계에서 조기에 발견하여 수정 비용을 절감한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;정량적 품질 관리&lt;/strong&gt;: c8을 활용한 코드 커버리지 측정으로 테스트 누락 구간을 수치화하고 품질 관리를 강화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  단계 2: 빌드 및 컨테이너 패키징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 작업&lt;/strong&gt;: Production Build, Docker Image Build, AWS ECR Push&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;목적 및 이유&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;환경 일관성 확보&lt;/strong&gt;: Docker 컨테이너를 사용하여 환경 간의 의존성 문제를 근본적으로 제거한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Artifact 관리&lt;/strong&gt;: ECR에 빌드된 이미지를 버전별로 저장하여 즉각적인 롤백이 가능하게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  단계 3: 스테이징 배포 (IaC)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 작업&lt;/strong&gt;: Terraform을 활용한 AWS EC2 스테이징 환경 프로비저닝 및 배포&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;목적 및 이유&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;인프라의 코드화 (IaC)&lt;/strong&gt;: 서버 설정을 코드로 관리하여 재현성을 높이고 수동 설정 실수를 방지한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;검증 환경 분리&lt;/strong&gt;: Production과 동일한 조건에서 사전 테스트를 수행하여 배포 리스크를 줄인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  단계 4: 인수 테스트 및 자원 회수&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 작업&lt;/strong&gt;: Selenium 기반 E2E 테스트, 스테이징 리소스 삭제(destroy)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;목적 및 이유&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;사용자 관점 검증 (E2E)&lt;/strong&gt;: 실제 사용자 시나리오를 브라우저 수준에서 검증한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비용 최적화&lt;/strong&gt;: 테스트 이후 임시 AWS 리소스를 삭제하여 불필요한 비용 발생을 방지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  단계 5: 프로덕션 릴리즈 및 스모크 테스트&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 작업&lt;/strong&gt;: 최종 배포 및 서비스 정상 작동 확인&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;목적 및 이유&lt;/strong&gt;: 배포 직후 핵심 기능을 점검하여 서비스 가용성을 확정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;4. 기대 효과&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;클라우드 네이티브 환경 최적화&lt;/strong&gt;: AWS 서비스를 적재적소에 활용하여 인프라 관리 효율성을 증대할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;배포 속도 및 안정성&lt;/strong&gt;: IaC 및 자동화된 테스트를 통해 배포 주기를 단축하고 오류를 줄인다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;유연한 장애 대응&lt;/strong&gt;: AMI와 ECR에 저장된 이미지를 활용해 재난 복구 및 롤백 능력을 강화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/110</guid>
      <comments>https://lazypatchnotes.tistory.com/110#entry110comment</comments>
      <pubDate>Fri, 16 Jan 2026 14:28:06 +0900</pubDate>
    </item>
    <item>
      <title>[82일차]Selenium 개요 및 구성 요소 및 테스트 예시</title>
      <link>https://lazypatchnotes.tistory.com/109</link>
      <description>&lt;p&gt;Selenium은 웹 브라우저 자동화를 위한 오픈소스 프레임워크이다. 주로 웹 애플리케이션의 테스트 자동화에 사용되며, 웹 기반의 반복적인 행정 업무 자동화 등 브라우저 제어가 필요한 다양한 영역에 활용될 수 있다. Selenium은 크게 세 가지 주요 구성 요소로 이루어진다.&lt;/p&gt;
&lt;h2&gt;1.1. Selenium WebDriver&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;여러 브라우저(Chrome, Firefox, Safari, Edge 등)를 제어할 수 있는 언어별 라이브러리를 제공한다.&lt;/li&gt;
&lt;li&gt;개발자는 이를 통해 직접 코드를 작성하여 브라우저의 동작을 세밀하게 제어할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1.2. Selenium IDE&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;브라우저에서의 사용자 상호작용을 녹화하고 재생할 수 있는 도구이다.&lt;/li&gt;
&lt;li&gt;Chrome이나 Firefox의 확장 프로그램 형태로 설치하여 별도의 코딩 없이 테스트 케이스를 생성할 수 있으며, 빠른 프로토타이핑에 적합하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1.3. Selenium Grid&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;분산 환경에서 테스트를 수행하기 위한 도구이다.&lt;/li&gt;
&lt;li&gt;Hub가 중앙에서 요청을 수신하고 이를 여러 Node(테스트 머신)에 분배하여 병렬로 테스트를 실행한다.&lt;/li&gt;
&lt;li&gt;이를 통해 테스트 시간을 단축하고 다양한 OS 및 브라우저 환경에서�� 호환성을 효율적으로 검증할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;E2E(End-to-End) 테스트의 이해&lt;/h1&gt;
&lt;p&gt;E2E 테스트는 시스템의 종단 간 테스트를 의미하며, 사용자 관점에서 애플리케이션의 흐름이 처음부터 끝까지 올바르게 동작하는지 확인하는 과정이다.&lt;/p&gt;
&lt;h2&gt;목적&lt;/h2&gt;
&lt;p&gt;유닛 테스트(Unit Test)만으로는 확인하기 어려운 GUI와 백엔드 로직 간의 연결성, 실제 데이터 ��름, 시스템 전체의 동작 여부를 검증하는 것을 목적으로 한다.&lt;/p&gt;
&lt;h2&gt;특징&lt;/h2&gt;
&lt;p&gt;실제 브라우저 환경에서 사용자의 입력과 그에 따른 출력을 확인하므로, 사용자 경험과 가장 밀접한 테스트 방식이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;Selenium 기반 E2E 테스트 실습 절차&lt;/h1&gt;
&lt;p&gt;웹 기반 문서 편집기 프로젝트에서 효율적인 테스트를 수행하기 위한 단계별 프로세스는 다음과 같다.&lt;/p&gt;
&lt;h2&gt;3.1. 시나리오 기록 및 기초 검증&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Selenium IDE 활용&lt;/strong&gt;: 브라우저에서 문서 작성, 저장, 수정 등 주요 사용자 시나리오를 녹화한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;재생 및 확인&lt;/strong&gt;: Command-line runner를 통해 기록된 시나리오를 재생하며 초기 단계의 결함을 발견한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.2. 코드 기반 자동화 테스트 전환&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Selenium IDE에서 생성된 시나리오를 Pytest 등의 프레���워크용 코드로 내보내기(Export)한다.&lt;/li&gt;
&lt;li&gt;이후 객체 지향적인 코드 구조로 재구성하여 유지보수성을 높인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.3. 동적 요소 처리 (Timing 이슈 해결)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implicit Wait&lt;/strong&gt;: 특정 요소가 나타날 때까지 일정 시간 동안 브라우저를 전역적으로 대기시킨다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explicit Wait&lt;/strong&gt;: 특정 조건(예: 요소의 가시성, 클릭 가능 여부)이 충족될 때까지 특정 요소만 대기한다. 이는 불필요한 대기 시간을 줄여 테스트 효율을 높인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;테스트 고도화 전략&lt;/h1&gt;
&lt;h2&gt;4.1. 검증(Assertion) 강화&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;시나리오가 단순히 동작하는 것을 넘어, 올바른 결과값이 출력되었는지 확인하기 위해 적절한 위치에 Assertion을 삽입한다.&lt;/li&gt;
&lt;li&gt;텍스트 일치 여부, 요소의 존재 여부, URL 변경 등을 체크하여 테스트의 신뢰도를 확보한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.2. 코드 공용화 및 구조화&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;여러 테스트 케이스에서 공통으로 사용되는 로그인 과정, 페이지 이동 등의 로직은 별도의 모듈로 분리하여 공용화한다.&lt;/li&gt;
&lt;li&gt;이는 코드 중복을 방지하고 브라우저 환경 변화에 유연하게 대응하게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.3. Headless Browser 활용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;GUI가 없는 Headless Browser 모드를 적용하면 리소스를 절약하고 테스트 실행 속도를 향상시킬 수 있다.&lt;/li&gt;
&lt;li&gt;이는 특히 지속적 통합(CI) 환경에서 자동화 테스트를 수행할 때 필수적이다.&lt;/li&gt;
&lt;li&gt;필요에 따라 옵션을 조정하여 디버깅 시에는 화면을 보고, 실제 배포 파이프라인에서는 화면 없이 실행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4.4. 환경 설정 최적화 (Nginx Reverse Proxy)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;개발 환경에서 프론트엔드와 백엔드의 Origin이 달라 발생하는 CORS 문제를 해결하기 위해 Nginx Reverse Proxy를 활용할 수 있다.&lt;/li&gt;
&lt;li&gt;이를 통해 FE와 BE를 Same Origin으로 구성하면 보안 정책으로 인한 테스트 제약을 최소화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;Selenium 테스트 코드 구현 예시&lt;/h1&gt;
&lt;p&gt;다음은 Python의 pytest 프레임워크와 Selenium WebDriver를 활용한 구체적인 구현 방법이다.&lt;/p&gt;
&lt;h2&gt;5.1. 기초적인 문서 작성 테스트 코드&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By

def test_document_creation():
    # WebDriver 설정 (Chrome)
    driver = webdriver.Chrome()
    driver.get(&amp;quot;http://localhost:3000&amp;quot;) # 편집기 접속 주소

    # 요소 찾기 및 동작 수행
    title_input = driver.find_element(By.ID, &amp;quot;doc-title&amp;quot;)
    title_input.send_keys(&amp;quot;테스트 문서 제목&amp;quot;)

    save_button = driver.find_element(By.ID, &amp;quot;save-btn&amp;quot;)
    save_button.click()

    # 결과 검증 (Assertion)
    success_message = driver.find_element(By.ID, &amp;quot;status-msg&amp;quot;).text
    assert &amp;quot;저장되었습니다&amp;quot; in success_message

    driver.quit()&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.2. Explicit Wait를 활용한 동적 요소 처리&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def test_dynamic_loading(driver):
    # 특정 요소가 화면에 나타날 때까지 최대 10초간 대기
    wait = WebDriverWait(driver, 10)
    editor_area = wait.until(
        EC.presence_of_element_located((By.CLASS_NAME, &amp;quot;ql-editor&amp;quot;))
    )

    editor_area.send_keys(&amp;quot;문서 본문 내용을 입력한다.&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;설명: &lt;code&gt;presence_of_element_located&lt;/code&gt;는 해당 요소가 DOM에 존재할 때까지 기다린다. 이를 통해 네트워크 지연이나 렌더링 속도 차이로 발생하는 에러를 방지할 수 있다.&lt;/p&gt;
&lt;h2&gt;5.3. Headless Browser 및 옵션 설정&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from selenium.webdriver.chrome.options import Options

def setup_headless_driver():
    options = Options()
    options.add_argument(&amp;#39;--headless&amp;#39;)          # 화면 없이 실행
    options.add_argument(&amp;#39;--no-sandbox&amp;#39;)        # 리눅스 환경 필수 옵션
    options.add_argument(&amp;#39;--disable-dev-shm-usage&amp;#39;) # 공유 메모리 부족 방지

    driver = webdriver.Chrome(options=options)
    return driver&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.4. 공통 기능의 모듈화 (Page Object Model 개념 적용)&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class EditorPage:
    def __init__(self, driver):
        self.driver = driver
        self.url = &amp;quot;http://localhost:3000/edit&amp;quot;

    def navigate(self):
        self.driver.get(self.url)

    def write_content(self, text):
        self.driver.find_element(By.ID, &amp;quot;editor&amp;quot;).send_keys(text)

    def save(self):
        self.driver.find_element(By.ID, &amp;quot;save&amp;quot;).click()

# 실제 테스트 케이스에서의 활용
def test_with_pom(driver):
    editor = EditorPage(driver)
    editor.navigate()
    editor.write_content(&amp;quot;공용화된 코드를 통한 테스트 실행&amp;quot;)
    editor.save()&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;테스트 수행 시 주의사항 및 결론&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ID 값의 고유성 확보&lt;/strong&gt;: 테스트 안정성을 위해 HTML 요소에 &lt;code&gt;data-testid&lt;/code&gt;와 같은 테스트 전용 속성을 부여하는 것이 권장된다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;독립적인 테스트 환경&lt;/strong&gt;: 각 테스트 케이스는 서로 의존성 없이 독립적으로 실행되어야 한다. 테스트 시작 전후에 데이터베이스를 초기화하거나 세션을 정리하는 과정이 필요하다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;에러 스크린샷 활용&lt;/strong&gt;: 테스트 실패 시 &lt;code&gt;driver.save_screenshot(&amp;#39;error.png&amp;#39;)&lt;/code&gt;를 호출하도록 구성하면 실패 원인을 빠르게 파악할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;위와 같은 자동화 테스트 도입을 통해 웹 기반 문서 편집기 프로젝트는 코드 변경에 따른 사이드 이펙트를 최소화하고, 안정적인 사용자 경험을 제공하는 고품질의 서비스를 구축할 수 있다.&lt;/p&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/109</guid>
      <comments>https://lazypatchnotes.tistory.com/109#entry109comment</comments>
      <pubDate>Thu, 15 Jan 2026 00:01:51 +0900</pubDate>
    </item>
    <item>
      <title>[81일차]웹 기반 문서 편집기 제작 프로젝트 - 단위 테스트</title>
      <link>https://lazypatchnotes.tistory.com/108</link>
      <description>&lt;h1&gt;백엔드(BE) 단위 테스트&lt;/h1&gt;
&lt;p&gt;단위 테스트는 개별 함수나 메서드를 독립적으로 검증하는 과정이다. 모듈 간 의존성이 존재하는 경우 &lt;strong&gt;Mock(가짜 객체)&lt;/strong&gt;을 사용하여 테스트 대상을 분리해야 한다.&lt;/p&gt;
&lt;h3&gt;테스트 재현성 확보&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Makefile을 사용하여 테스트 실행 절차를 자동화한다.&lt;/li&gt;
&lt;li&gt;주의사항: Makefile은 들여쓰기에 반드시 Tab을 사용해야 하며, Space 사용 시 문법 에러가 발생하므로 편집기 설정을 확인해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;테스트 범위&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;요구사항 명세서에 정의된 모든 API에 대한 정상 동작 검증.&lt;/li&gt;
&lt;li&gt;잘못된 URL 요청 및 권한 없는(Unauthorized) 접근에 대한 예외 처리 검증.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1&gt;프런트엔드(FE) 단위 테스트&lt;/h1&gt;
&lt;p&gt;프런트엔드 테스트는 사용자 인터페이스(UI)와 사용자 경험(UX)을 포함하므로 백엔드와는 다른 접근 방식이 필요하다.&lt;/p&gt;
&lt;h3&gt;주요 테스트 항목&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;UI 렌더링 상태&lt;/li&gt;
&lt;li&gt;내부 콜백 함수 동작&lt;/li&gt;
&lt;li&gt;페이지 이동(Navigation) 로직 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;사용 라이브러리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CRA(Create React App) 환경에 기본 포함된 도구 활용:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@testing-library/react&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@testing-library/jest-dom&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@testing-library/user-event&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CI 환경 설정&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm test&lt;/code&gt; 명령어 앞에 &lt;code&gt;CI=true&lt;/code&gt; 옵션을 부여하면 Watch 모드가 비활성화되어 지속적 통합(CI) 서버에서 일회성 테스트를 수행하기에 적합하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;백엔드 컨테이너화 (Docker)&lt;/h1&gt;
&lt;p&gt;도커는 애플리케이션 실행에 필요한 환경을 이미지로 빌드하여 어디서든 동일하게 실행할 수 있게 한다.&lt;/p&gt;
&lt;h3&gt;Dockerfile 구성 분석&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Base Image&lt;/strong&gt;: &lt;code&gt;node:18&lt;/code&gt;을 기반으로 실행 환경을 구축한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의존성 설치&lt;/strong&gt;: &lt;code&gt;npm ci --omit=dev&lt;/code&gt;를 통해 불필요한 개발용 라이브러리를 제외하고 프로덕션용 패키지만 설치한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;환경 변수&lt;/strong&gt;: &lt;code&gt;PORT&lt;/code&gt;, &lt;code&gt;CORS_ALLOWED_ORIGIN&lt;/code&gt; 등을 설정하여 보안 및 네트워크를 제어한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;상태 확인(Healthcheck)&lt;/strong&gt;: &lt;code&gt;curl&lt;/code&gt;을 통해 컨테이너의 서비스가 정상적으로 응답하는지 주기적으로 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docker Compose 설정&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DB 서비스&lt;/strong&gt;: &lt;code&gt;MariaDB&lt;/code&gt; 이미지를 사용하며, 호스트의 &lt;code&gt;./db&lt;/code&gt; 디렉토리를 컨테이너와 연결(Volume)하여 데이터를 보존한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;네트워크&lt;/strong&gt;: &lt;code&gt;notes&lt;/code&gt;라는 이름의 논리적 네트워크를 생성하여 서비스 간 통신을 격리하고 보안을 강화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;프런트엔드 컨테이너화&lt;/h1&gt;
&lt;p&gt;리액트와 같은 SPA(Single Page Application)는 빌드된 결과물을 정적 서버(&lt;code&gt;serve&lt;/code&gt; 등)를 통해 배포해야 한다.&lt;/p&gt;
&lt;h3&gt;런타임 환경 변수 주입 (docker-entrypoint.sh)&lt;/h3&gt;
&lt;p&gt;리액트는 빌드 시점에 환경 변수가 고정되는 특성이 있다. 이를 해결하기 위해 컨테이너 실행 시점에 환경 변수를 &lt;code&gt;window._ENV&lt;/code&gt; 객체로 추출하여 &lt;code&gt;env.js&lt;/code&gt; 파일을 생성하는 쉘 스크립트를 사용한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;REACT_APP_&lt;/code&gt;으로 시작하는 환경 변수를 스캔한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;build/env.js&lt;/code&gt; 파일에 해당 변수들을 작성한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;serve&lt;/code&gt; 명령어로 정적 파일 서버를 실행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Docker Compose 설정&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;백엔드 API 주소(&lt;code&gt;REACT_APP_API_BASE_URL&lt;/code&gt;)를 환경 변수로 설정하여 프런트엔드 컨테이너가 백엔드와 통신할 수 있도록 연결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;로컬 클러스터 시험 배포 (Kubernetes)&lt;/h1&gt;
&lt;p&gt;컨테이너화된 앱을 실제 클러스터 환경에서 운영하기 위한 설정 단계이다.&lt;/p&gt;
&lt;h3&gt;ConfigMap 활용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;서비스의 설정 정보(BE 접속 주소, 포트 등)를 이미지와 분리하여 관리한다.&lt;/li&gt;
&lt;li&gt;이는 동일한 이미지를 설정만 바꿔서 개발/검증/운영 환경에 배포할 수 있게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;절차&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose&lt;/code&gt;로 로컬에서 검증을 마친 후, 생성된 이미지를 쿠버네티스 객체(Deployment, Service, ConfigMap)로 변환하여 배포를 진행한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/108</guid>
      <comments>https://lazypatchnotes.tistory.com/108#entry108comment</comments>
      <pubDate>Wed, 14 Jan 2026 00:02:24 +0900</pubDate>
    </item>
    <item>
      <title>[80일차]웹 기반 문서 편집기 제작 프로젝트 설계</title>
      <link>https://lazypatchnotes.tistory.com/106</link>
      <description>&lt;h2&gt;  BE 설계&lt;/h2&gt;
&lt;h3&gt;  구조 설계서&lt;/h3&gt;
&lt;p&gt;구조 설계서는 소프트웨어의 구조를 설계하여 기술한 문서이다. 이 문서는 사용 도구와 도구의 버전, 패키지 구조 설정 방법 등을 다룬다.&lt;/p&gt;
&lt;h4&gt;주요 내용&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;도구 및 도구의 버전&lt;/strong&gt;: 프로젝트에서 사용할 도구들과 그에 따른 버전을 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;패키지 구조&lt;/strong&gt;: 패키지 구조를 설계 및 설명한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;세팅&lt;/strong&gt;: 프로젝트 초기화 및 기본 설정 과정을 다룬다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;라우터&lt;/strong&gt;: 경로 관리와 라우팅을 담당하는 구조를 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;모델&lt;/strong&gt;: 데이터베이스와의 상호 작용을 담당하는 모델을 설계한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;유틸&lt;/strong&gt;: 공통적으로 사용될 유틸리티 함수들을 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;미들웨어&lt;/strong&gt;: 요청과 응답 사이의 작업들을 처리하기 위한 미들웨어를 정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  데이터베이스 설계&lt;/h3&gt;
&lt;p&gt;프로덕션용(실제 운영) 데이터베이스와 로컬 테스트용 데이터베이스를 명확히 구분하여 사용해야 한다.&lt;/p&gt;
&lt;h3&gt;  개발 환경 셋업&lt;/h3&gt;
&lt;p&gt;빈 프로젝트에 기본 패키지를 설치하고, 환경 변수와 설정 코드를 작성한 후 응용 코드와 뼈대를 작성한다. 작성된 코드를 이용해 로컬 실행 및 빌드 결과를 간단히 확인한다.&lt;/p&gt;
&lt;h4&gt;TIP&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;빌드 후 별도의 서버 배포 없이 결과를 확인하려면 아래 명령어를 활용한다.&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx serve &amp;lt;빌드 폴더 위치&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  사용자 인증(Authentication)&lt;/h3&gt;
&lt;p&gt;사용자 인증은 인증 정보를 통해 사용자가 유효한지 확인하는 과정이다. 인증은 암호화된 비밀번호와 이메일을 통해 이루어진다. 이 과정에서는 &lt;code&gt;bcrypt&lt;/code&gt; 라이브러리를 활용하여 비밀번호를 암호화한다.&lt;/p&gt;
&lt;h3&gt;  사용자 인가(Authorization)&lt;/h3&gt;
&lt;p&gt;사용자 인가는 요청한 자원에 대해 사용자가 접근 권한을 가지고 있는지를 확인하는 과정이다.&lt;/p&gt;
&lt;h3&gt;  CORS 정책&lt;/h3&gt;
&lt;p&gt;CORS 정책은 특정 URL로부터의 요청만 허용하여 보안을 강화하는 정책이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;  FE 설계&lt;/h2&gt;
&lt;h3&gt;  구조 설계서&lt;/h3&gt;
&lt;p&gt;구조 설계서는 프로젝트 전반의 구조를 정의한 문서이다. 주요 도구와 버전, 패키지 구조 등을 기술한다.&lt;/p&gt;
&lt;h4&gt;주요 내용&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;도구 및 도구의 버전&lt;/strong&gt;: 프로젝트에서 사용하는 도구와 해당 버전을 명시한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;패키지 구조&lt;/strong&gt;: 프로젝트에서 사용되는 파일 및 폴더 구조를 설계한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;컴포넌트&lt;/strong&gt;: 재사용 가능한 컴포넌트를 설계하고 구성한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Utility&lt;/strong&gt;: 공통 함수들을 설계 및 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React Query Hooks&lt;/strong&gt;: 리액트 환경에서 데이터 관리를 효율적으로 처리하기 위한 퀴리 훅스를 정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  상세 설계서&lt;/h3&gt;
&lt;p&gt;상세 설계서는 구조 설계서를 기반으로 각 파일의 위치와 역할을 더욱 구체적으로 기술한 문서이다.&lt;/p&gt;
&lt;h4&gt;주요 내용&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;컴포넌트&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;&lt;em&gt;일반 컴포넌트&lt;/em&gt;: 재사용 가능한 기본 컴포넌트를 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;페이지 컴포넌트&lt;/em&gt;: 각각의 페이지를 구성하는 컴포넌트를 설계한다.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HOC (Higher-Order Component)&lt;/em&gt;: 컴포넌트 로직의 재사용성을 높이기 위한 고차 함수형 컴포넌트를 정의한다.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;디자인 컴포넌트&lt;/em&gt;: UI와 스타일링을 위한 컴포넌트를 설계한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  개발 환경 셋업&lt;/h3&gt;
&lt;p&gt;개발 환경은 &lt;code&gt;react&lt;/code&gt;와 &lt;code&gt;typescript&lt;/code&gt;를 기반으로 설정한다. CRA(Create React App)를 이용하여 기본 템플릿을 생성하고, &lt;code&gt;craco&lt;/code&gt;를 통해 추가 설정을 적용한다.&lt;/p&gt;
&lt;h4&gt;TIP&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;깔끔한 경로 설정&lt;/strong&gt;: 상대 경로 사용을 간소화하고 명확히 하기 위해 &lt;code&gt;tsconfig-paths-webpack-plugin&lt;/code&gt; 라이브러리를 활용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;환경 변수 처리&lt;/strong&gt;: &lt;code&gt;.env&lt;/code&gt; 파일을 사용해 환경 변수를 정의하되, production build에는 적용되지 않을 수 있다. 이를 해결하기 위해 빌드 단계에서 &lt;code&gt;env.js&lt;/code&gt; 파일을 생성하고 DOM의 &lt;code&gt;window&lt;/code&gt; 객체에 환경 변수를 정의하여 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;이 문서는 웹 기반 문서 편집기 제작 프로젝트의 설계 및 구현 단계를 정리한 것으로, 백엔드와 프런트엔드 설계를 각각 다루고 있다. 상세한 설계와 구현 전략을 통해 효율적이고 안정적인 프로젝트 개발을 도모한다.&lt;/p&gt;</description>
      <category>Programmers</category>
      <author>PARKpatchnotes</author>
      <guid isPermaLink="true">https://lazypatchnotes.tistory.com/106</guid>
      <comments>https://lazypatchnotes.tistory.com/106#entry106comment</comments>
      <pubDate>Mon, 12 Jan 2026 16:07:22 +0900</pubDate>
    </item>
  </channel>
</rss>