<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Seum.Lee Story</title>
    <link>https://revivalearth.tistory.com/</link>
    <description>print('Thank GOD')</description>
    <language>ko</language>
    <pubDate>Tue, 2 Jun 2026 04:57:55 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Seum Lee</managingEditor>
    <image>
      <title>Seum.Lee Story</title>
      <url>https://tistory1.daumcdn.net/tistory/8365576/attach/b7fab9d038694a419c9d8d8f0c8a5f5a</url>
      <link>https://revivalearth.tistory.com</link>
    </image>
    <item>
      <title>OS 시스템 기초 핵심 개념</title>
      <link>https://revivalearth.tistory.com/entry/OS-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B8%B0%EC%B4%88-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90</link>
      <description>&lt;h1&gt;1. 운영체제&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;운영체제란 무엇인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제(OS)는 컴퓨터 하드웨어와 사용자(혹은 애플리케이션) 사이에서 중재자 역할을 하는 소프트웨어의 집합이다. CPU, 메모리, 디스크, 네트워크 장치 등 한정된 자원을 여러 프로그램이 동시에 사용할 때 충돌 없이 배분해 주는 것이 핵심 임무다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제의 설계 목표는 네 가지로 요약된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;처리 능력(Throughput) 향상&lt;/b&gt; : 단위 시간당 처리하는 작업량을 늘린다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반환 시간(Turnaround Time) 감소&lt;/b&gt; : 작업 제출부터 완료까지 걸리는 시간을 줄인다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 가능도(Availability) 향상&lt;/b&gt; : 시스템이 즉시 사용 가능한 상태를 오래 유지한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;신뢰도(Reliability) 향상&lt;/b&gt; : 오류 없이 정확하게 작동한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 &quot;고가용성(HA)&quot; 설계라는 말을 자주 듣는데, 이것이 바로 사용 가능도와 신뢰도를 동시에 높이는 아키텍처 전략이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UNIX와 LINUX&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UNIX&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1960년대 AT&amp;amp;T 벨 연구소에서 개발된 UNIX는 현대 OS 설계의 원형이다. 대부분 C언어로 작성되어 이식성이 높고, 파일 시스템은 루트(&lt;code&gt;/&lt;/code&gt;)를 최상위로 하는 트리 구조를 따른다. &lt;b&gt;시분할 시스템(Time Sharing System)&lt;/b&gt; 방식으로 여러 사용자가 CPU를 번갈아 사용할 수 있게 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조는 두 층으로 나뉜다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;커널(Kernel)&lt;/b&gt; : 프로그램과 하드웨어 사이의 인터페이스를 담당한다. 메모리 관리, 프로세스 스케줄링, 파일 시스템 접근 등 핵심 기능이 모두 여기에 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쉘(Shell)&lt;/b&gt; : 사용자와 시스템 사이의 인터페이스다. 사용자가 입력한 명령을 해석해 커널에 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LINUX&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리누스 토발즈가 1991년 개발한 UNIX 계열 오픈소스 OS다. 서버, 클라우드, 임베디드 환경에서 사실상의 표준으로 쓰인다. 주요 명령어를 실무 맥락과 함께 정리하면 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파일 조작&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;실무 팁&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 내용 출력&lt;/td&gt;
&lt;td&gt;짧은 설정 파일 확인 시 자주 쓴다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 복사&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-r&lt;/code&gt; 옵션으로 디렉토리째 복사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 이동 / 이름 변경&lt;/td&gt;
&lt;td&gt;이름 변경도 &lt;code&gt;mv&lt;/code&gt;로 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 삭제&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-rf&lt;/code&gt;는 되돌릴 수 없으니 신중하게&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 검색&lt;/td&gt;
&lt;td&gt;&lt;code&gt;find / -name &quot;*.log&quot;&lt;/code&gt; 형태로 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;디렉토리 조작&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 목록 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mkdir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;디렉토리 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rmdir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;빈 디렉토리 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;디렉토리 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pwd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 경로 출력&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로세스 관련&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;실행 중인 프로세스 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;프로세스 종료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fork&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 프로세스 생성 (시스템 콜)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용자 및 권한&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;who&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 접속 중인 사용자 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chown&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 소유자와 그룹 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chmod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 보호 모드(권한) 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;chmod 권한 체계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;chmod&lt;/code&gt;는 파일에 대한 읽기(r), 쓰기(w), 실행(x) 권한을 사용자(user), 그룹(group), 기타(other) 세 대상에 대해 설정한다. 8진수 표기법을 사용하며, &lt;code&gt;rwx&lt;/code&gt;를 이진수로 변환해 숫자로 표현한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;r = 4 (100)
w = 2 (010)
x = 1 (001)

rwx = 4+2+1 = 7
rw- = 4+2+0 = 6
r-x = 4+0+1 = 5
r-- = 4+0+0 = 4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;chmod 755 a.txt
# 사용자: rwx (7) = 읽기 + 쓰기 + 실행
# 그룹:   r-x (5) = 읽기 + 실행
# 기타:   r-x (5) = 읽기 + 실행

chmod 644 config.yaml
# 사용자: rw- (6) = 읽기 + 쓰기
# 그룹:   r-- (4) = 읽기만
# 기타:   r-- (4) = 읽기만&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 &lt;code&gt;chmod 777&lt;/code&gt;(모든 권한 개방)은 보안상 권장하지 않는다. 웹 서버 설정 파일이나 SSH 키 파일에는 소유자만 읽을 수 있는 &lt;code&gt;600&lt;/code&gt; 또는 &lt;code&gt;400&lt;/code&gt;이 일반적이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;2. 기억장치&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기억장치 관리 전략&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램을 주기억장치(RAM)에 올리는 과정은 세 가지 전략 결정을 포함한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;반입 전략 : 언제 올릴까?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;요구 반입&lt;/b&gt; : 프로그램이나 데이터가 실제로 필요해질 때 적재한다. 수요 기반이라 메모리를 효율적으로 쓸 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예상 반입&lt;/b&gt; : 곧 필요할 것을 미리 예측해 올린다. 적중하면 빠르지만, 빗나가면 자원 낭비다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배치 전략 : 어디에 올릴까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 공간 중 어느 자리에 프로그램을 배치할지 결정한다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;전략&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;최초 적합(First Fit)&lt;/td&gt;
&lt;td&gt;빈 공간 중 첫 번째에 배치&lt;/td&gt;
&lt;td&gt;탐색이 빠르다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최적 적합(Best Fit)&lt;/td&gt;
&lt;td&gt;단편화가 가장 작게 남는 곳&lt;/td&gt;
&lt;td&gt;공간 낭비가 적다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최악 적합(Worst Fit)&lt;/td&gt;
&lt;td&gt;단편화가 가장 많이 남는 곳&lt;/td&gt;
&lt;td&gt;남은 공간이 커서 재활용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단편화(Fragmentation)&lt;/b&gt; 란 메모리 공간이 조각조각 나뉘어 실제로는 충분한 공간이 있지만 연속된 빈 공간이 없어 할당이 안 되는 현상이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주기억장치 할당 기법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01_memory_allocation.png&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7VRFp/dJMcabROCdN/7uVGveISeiMAIZK4QpETQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7VRFp/dJMcabROCdN/7uVGveISeiMAIZK4QpETQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7VRFp/dJMcabROCdN/7uVGveISeiMAIZK4QpETQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7VRFp%2FdJMcabROCdN%2F7uVGveISeiMAIZK4QpETQ0%2Fimg.png&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;1184&quot; height=&quot;366&quot; data-filename=&quot;01_memory_allocation.png&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;연속 할당&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단일 분할 할당&lt;/b&gt; 은 한 번에 한 명의 사용자만 메모리 사용자 영역을 사용하는 방식이다. 단순하지만 멀티태스킹이 안 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;오버레이 기법&lt;/b&gt; : 실행할 프로그램이 주기억장치보다 클 때, 프로그램을 여러 조각으로 나눠 필요한 부분만 순서대로 올려서 실행한다. 현재는 가상 메모리가 이 역할을 대체한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스와핑 기법&lt;/b&gt; : 실행 중인 프로그램 전체를 디스크로 잠시 내려놓고(swap out), 다른 프로그램을 올린다(swap in). 문맥 교환 비용이 크다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다중 분할 할당&lt;/b&gt; 은 여러 프로그램을 동시에 메모리에 올리는 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고정 분할(정적)&lt;/b&gt; : 메모리를 미리 고정된 크기로 나눠놓는다. 단순하지만 내부 단편화가 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가변 분할(동적)&lt;/b&gt; : 프로그램 크기에 맞게 그때그때 영역을 나눈다. 고정 분할의 단편화 문제를 줄이기 위해 도입되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;가상기억장치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상기억장치는 보조기억장치(디스크)의 일부를 주기억장치처럼 사용하는 기법이다. 실제 RAM이 부족해도 더 많은 프로그램을 동시에 실행할 수 있다. 현대 OS의 기본 메모리 관리 방식이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;페이징 기법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램과 메모리 영역을 동일한 크기의 단위로 자른다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램을 자른 단위 : &lt;b&gt;페이지(Page)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;메모리를 자른 단위 : &lt;b&gt;페이지 프레임(Page Frame)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 크기가 같으므로 외부 단편화가 없다. 다만 페이지 내 남는 공간(내부 단편화)은 여전히 발생할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;페이지 부재(Page Fault)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 필요한 페이지가 현재 RAM에 없는 상황이다. 이때 디스크에서 해당 페이지를 가져와야 하는데, RAM이 꽉 차 있으면 기존 페이지 중 하나를 내보내야 한다. 어떤 페이지를 내보낼지 결정하는 것이 &lt;b&gt;페이지 교체 알고리즘&lt;/b&gt; 이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;페이지 교체 알고리즘 비교&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;알고리즘&lt;/th&gt;
&lt;th&gt;기준&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OPT(최적 교체)&lt;/td&gt;
&lt;td&gt;앞으로 가장 오래 쓰지 않을 페이지&lt;/td&gt;
&lt;td&gt;이론적으로 최적이나, 미래를 알 수 없어 실제 구현 불가. 비교 기준으로 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FIFO&lt;/td&gt;
&lt;td&gt;가장 먼저 들어온 페이지&lt;/td&gt;
&lt;td&gt;구현이 단순. Belady의 역설(프레임 늘려도 폴트 증가) 발생 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LRU&lt;/td&gt;
&lt;td&gt;가장 오랫동안 사용 안 된 페이지&lt;/td&gt;
&lt;td&gt;실무에서 가장 많이 쓰이는 근사 알고리즘의 기준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LFU&lt;/td&gt;
&lt;td&gt;사용 빈도가 가장 낮은 페이지&lt;/td&gt;
&lt;td&gt;자주 쓰이지만 최근에는 안 쓰인 페이지를 보호하지 못함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NUR&lt;/td&gt;
&lt;td&gt;최근에 사용하지 않은 페이지&lt;/td&gt;
&lt;td&gt;참조 비트 + 변형 비트 사용. LRU 근사 구현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SCR(2차 기회)&lt;/td&gt;
&lt;td&gt;오래됐지만 자주 쓰이는 페이지는 보호&lt;/td&gt;
&lt;td&gt;FIFO의 단점을 보완&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 Linux 커널은 LRU 기반의 변형 알고리즘을 사용하며, 활성 리스트와 비활성 리스트를 나눠 페이지를 관리한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지역성(Locality)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스가 실행될 때 메모리 참조는 균일하게 분산되지 않는다. 특정 구역에 집중되는 경향이 있는데, 이것을 지역성이라 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시간 지역성&lt;/b&gt; : 최근에 접근한 데이터는 곧 다시 접근될 가능성이 높다. 반복문 안의 변수가 대표적인 예다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 지역성&lt;/b&gt; : 현재 접근한 주소 근처 데이터에도 곧 접근할 가능성이 높다. 배열 순차 접근이 대표 예다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 지역성 원리가 &lt;b&gt;워킹 셋(Working Set)&lt;/b&gt; 이론의 기반이다. 워킹 셋은 프로세스가 일정 시간 동안 자주 참조하는 페이지들의 집합으로, 이 집합이 모두 RAM에 올라와 있을 때 페이지 폴트가 적게 발생한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;세그멘테이션 기법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이징이 고정 크기로 자른다면, 세그멘테이션은 논리적 의미 단위로 자른다. 코드 영역, 데이터 영역, 스택 영역처럼 프로그램의 논리 구조에 맞는 크기로 분할하며, 각 세그먼트는 고유한 이름과 크기를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;3. 프로세스&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스는 실행 중인 프로그램이다. 디스크에 저장된 실행 파일(프로그램)이 메모리에 올라와 CPU 시간을 할당받아 동작하는 순간부터 프로세스가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 각 프로세스마다 &lt;b&gt;PCB(Process Control Block)&lt;/b&gt; 를 만들어 관리한다. PCB에는 프로세스 상태, 고유 식별자(PID), CPU 레지스터 값, 메모리 정보, 입출력 상태, 계정 정보 등이 담긴다. 프로세스가 CPU를 내놓고 다시 받을 때 PCB에 저장된 정보를 복원해 이어서 실행한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스 상태 전이&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02_process_state.png&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwKNlL/dJMcabj4fq8/KiWb7k6RyuBtFHclnKlm01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwKNlL/dJMcabj4fq8/KiWb7k6RyuBtFHclnKlm01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwKNlL/dJMcabj4fq8/KiWb7k6RyuBtFHclnKlm01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwKNlL%2FdJMcabj4fq8%2FKiWb7k6RyuBtFHclnKlm01%2Fimg.png&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;397&quot; height=&quot;576&quot; data-filename=&quot;02_process_state.png&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;디스패치&lt;/b&gt; : 준비 상태에서 실행 상태로 전이. 스케줄러가 CPU를 이 프로세스에 배정하는 행위다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Wake Up&lt;/b&gt; : 대기 상태에서 준비 상태로 전이. I/O 완료 등의 이벤트가 발생하면 깨어난다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스풀링(Spooling)&lt;/b&gt; : 출력이나 입력 데이터를 디스크에 임시로 저장해두는 기법. 프린터 큐가 대표적인 예다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스레드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드는 프로세스 내의 실행 단위다. 하나의 프로세스 안에서 여러 스레드가 메모리 공간을 공유하면서 동시에 작업을 처리할 수 있다. 프로세스보다 생성과 전환 비용이 낮아 &quot;경량 프로세스&quot;라고도 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 웹 서버는 요청마다 스레드를 생성하거나(Thread per Request), 스레드 풀을 만들어 재사용하는 방식으로 동시 요청을 처리한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스래싱(Thrashing)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 교체가 너무 자주 일어나 실제 작업보다 페이지를 올리고 내리는 데 더 많은 시간을 쓰는 현상이다. 메모리가 부족한 상태에서 프로세스를 너무 많이 올리면 발생한다. 워킹 셋 기반 관리로 완화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스 스케줄링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한정된 CPU를 여러 프로세스에 어떻게 배분할지 결정하는 것이 스케줄링이다. 크게 비선점과 선점 방식으로 나뉜다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비선점 스케줄링&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 중인 프로세스를 강제로 빼앗을 수 없다. 프로세스가 자발적으로 CPU를 내놓거나 작업을 마칠 때까지 기다린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FCFS(First Come First Served)&lt;/b&gt;&lt;br /&gt;먼저 들어온 순서대로 처리한다. 구현이 간단하지만, 긴 작업이 앞에 있으면 짧은 작업이 오래 기다리는 호위 효과(Convoy Effect)가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SJF(Shortest Job First)&lt;/b&gt;&lt;br /&gt;실행 시간이 짧은 프로세스를 먼저 처리한다. 평균 대기 시간이 최소화되지만, 긴 프로세스는 계속 밀릴 수 있다(기아 현상).&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대기 시간 = 앞 프로세스의 반환 시간&lt;/li&gt;
&lt;li&gt;반환 시간 = 대기 시간 + 실행 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HRN(Highest Response-Ratio Next)&lt;/b&gt;&lt;br /&gt;SJF의 기아 현상을 보완하기 위해 우선순위를 동적으로 부여한다.&lt;/p&gt;
&lt;pre class=&quot;fix&quot;&gt;&lt;code&gt;우선순위 = (대기 시간 + 서비스 시간) / 서비스 시간&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오래 기다린 프로세스일수록 우선순위가 높아지므로, 기아 현상이 완화된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;선점 스케줄링&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 중인 프로세스에서 CPU를 강제로 빼앗아 다른 프로세스에 줄 수 있다. 반응성이 중요한 시스템(대화형, 실시간)에 적합하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Round Robin&lt;/b&gt; : 각 프로세스에 동일한 시간 할당량(Time Quantum)을 부여하고 순환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SRT(Shortest Remaining Time)&lt;/b&gt; : SJF의 선점 버전. 현재 실행 중인 것보다 남은 시간이 짧은 프로세스가 오면 교체한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다단계 큐&lt;/b&gt; : 프로세스를 여러 우선순위 큐로 분류해 관리한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다단계 피드백 큐&lt;/b&gt; : 실행 시간에 따라 프로세스가 낮은 우선순위 큐로 이동하는 동적 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;4. 네트워크&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;IP 주소 체계&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IPv4&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;32비트(8비트 &amp;times; 4)로 구성된다. &lt;code&gt;192.168.1.100&lt;/code&gt; 같은 점-십진수 표기법을 쓴다. 약 43억 개의 주소를 가질 수 있는데, 인터넷 확산으로 고갈 문제가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 구분:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;클래스&lt;/th&gt;
&lt;th&gt;첫 번째 옥텟 범위&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;0~127&lt;/td&gt;
&lt;td&gt;대규모 네트워크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;128~191&lt;/td&gt;
&lt;td&gt;중규모 네트워크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;192~223&lt;/td&gt;
&lt;td&gt;소규모 네트워크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;224~239&lt;/td&gt;
&lt;td&gt;멀티캐스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;240~255&lt;/td&gt;
&lt;td&gt;실험용 예약&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서브네팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 네트워크 주소를 여러 개의 작은 네트워크로 나누는 작업이다. IP 주소를 네트워크 부분과 호스트 부분으로 구분하는 비트 마스크가 &lt;b&gt;서브넷 마스크&lt;/b&gt; 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시: &lt;code&gt;192.168.1.0/24&lt;/code&gt;에서 &lt;code&gt;/24&lt;/code&gt;는 앞 24비트가 네트워크 주소라는 의미다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;IP  주소: 192.168.1.100  &amp;rarr; 11000000.10101000.00000001.01100100
서브넷:   255.255.255.0  &amp;rarr; 11111111.11111111.11111111.00000000
네트워크: 192.168.1.0    (AND 연산 결과)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IPv6&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;128비트(16비트 &amp;times; 8)로 구성된다. 주소 고갈 문제 해결 외에 인증성, 기밀성, 데이터 무결성을 프로토콜 수준에서 지원한다. 주소 유형은 세 가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유니캐스트&lt;/b&gt; : 1:1 통신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;멀티캐스트&lt;/b&gt; : 1:다 통신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;애니캐스트&lt;/b&gt; : 1:가장 가까운 1 통신 (유니캐스트처럼 보이지만 가장 가까운 노드가 응답)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSI 7계층 참조 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 통신을 7개의 계층으로 추상화한 모델이다. 계층별로 역할이 분리되어 있어, 특정 계층의 기술이 바뀌어도 다른 계층에는 영향이 없다는 것이 핵심 설계 원칙이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;03_osi_layers.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;1150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRectp/dJMcagZTNkx/4lAxFoqZi0OicufovtgPH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRectp/dJMcagZTNkx/4lAxFoqZi0OicufovtgPH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRectp/dJMcagZTNkx/4lAxFoqZi0OicufovtgPH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRectp%2FdJMcagZTNkx%2F4lAxFoqZi0OicufovtgPH1%2Fimg.png&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;235&quot; height=&quot;979&quot; data-filename=&quot;03_osi_layers.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;1150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 L4(전송 계층), L7(응용 계층) 같은 표현을 자주 쓴다. 예를 들어 &quot;L7 로드밸런서&quot;는 HTTP 헤더나 URL 경로를 분석해 트래픽을 분산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TCP/IP 프로토콜 스택&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSI 7계층이 이론 모델이라면, TCP/IP는 인터넷에서 실제로 동작하는 프로토콜 스택이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-05-25 22.54.31.png&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dziB10/dJMcahR2W7u/uOk5hbxirKOsx2JKABfwxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dziB10/dJMcahR2W7u/uOk5hbxirKOsx2JKABfwxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dziB10/dJMcahR2W7u/uOk5hbxirKOsx2JKABfwxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdziB10%2FdJMcahR2W7u%2FuOk5hbxirKOsx2JKABfwxK%2Fimg.png&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;249&quot; height=&quot;429&quot; data-filename=&quot;스크린샷 2026-05-25 22.54.31.png&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TCP(Transmission Control Protocol)&lt;/b&gt;&lt;br /&gt;전송 계층에서 동작한다. 연결을 먼저 맺고(3-way handshake) 데이터를 주고받는 &lt;b&gt;연결 지향&lt;/b&gt; 방식이다. 데이터 순서 보장, 오류 재전송, 흐름 제어를 제공한다. 웹(HTTP), 이메일, 파일 전송에 쓰인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UDP(User Datagram Protocol)&lt;/b&gt;&lt;br /&gt;연결 설정 없이 바로 데이터를 보내는 &lt;b&gt;비연결형&lt;/b&gt; 방식이다. 오버헤드가 낮고 빠르다. 스트리밍 영상, 게임, DNS 쿼리처럼 약간의 손실보다 속도가 중요한 경우에 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IP(Internet Protocol)&lt;/b&gt;&lt;br /&gt;네트워크 계층에서 동작한다. 패킷이 출발지에서 목적지까지 경로를 찾아가도록 하는 역할이다. 비연결형이며 신뢰성은 보장하지 않는다(TCP가 보완).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기타 주요 프로토콜&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;프로토콜&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ICMP&lt;/td&gt;
&lt;td&gt;IP와 함께 동작하며 오류 메시지 및 통신 상태를 전달. &lt;code&gt;ping&lt;/code&gt; 명령이 ICMP를 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARP&lt;/td&gt;
&lt;td&gt;IP 주소를 MAC 주소로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RARP&lt;/td&gt;
&lt;td&gt;MAC 주소를 IP 주소로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTCP&lt;/td&gt;
&lt;td&gt;RTP 패킷의 전송 품질을 제어하는 프로토콜. 영상 통화 품질 모니터링에 쓰임&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패킷 교환 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 일정 크기의 패킷으로 나눠 전송하는 방식으로, 현대 인터넷의 기반이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가상 회선 방식&lt;/b&gt;&lt;br /&gt;통신 전에 경로를 미리 설정한다. 모든 패킷이 같은 경로로 전달되므로 순서가 보장된다. ATM 네트워크가 대표적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터그램 방식&lt;/b&gt;&lt;br /&gt;경로를 미리 설정하지 않는다. 각 패킷이 독립적으로 경로를 선택한다. 인터넷(IP)이 이 방식이다. 순서가 뒤바뀔 수 있어 TCP가 재조립을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;네트워크 장비&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;05_network_devices.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKNHud/dJMcajvAbvr/yUx2yUUYe0T0XqZzVWE9lK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKNHud/dJMcajvAbvr/yUx2yUUYe0T0XqZzVWE9lK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKNHud/dJMcajvAbvr/yUx2yUUYe0T0XqZzVWE9lK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKNHud%2FdJMcajvAbvr%2FyUx2yUUYe0T0XqZzVWE9lK%2Fimg.png&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;242&quot; height=&quot;552&quot; data-filename=&quot;05_network_devices.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;장비&lt;/th&gt;
&lt;th&gt;동작 계층&lt;/th&gt;
&lt;th&gt;주요 역할&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;리피터&lt;/td&gt;
&lt;td&gt;1계층&lt;/td&gt;
&lt;td&gt;신호 재생/증폭. 장거리 전송&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;허브&lt;/td&gt;
&lt;td&gt;1계층&lt;/td&gt;
&lt;td&gt;여러 장치를 연결. 수신 신호를 모든 포트로 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;브리지&lt;/td&gt;
&lt;td&gt;2계층&lt;/td&gt;
&lt;td&gt;LAN과 LAN 연결. MAC 주소 기반 필터링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L2 스위치&lt;/td&gt;
&lt;td&gt;2계층&lt;/td&gt;
&lt;td&gt;브리지의 발전형. MAC 주소로 특정 포트에만 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;라우터&lt;/td&gt;
&lt;td&gt;3계층&lt;/td&gt;
&lt;td&gt;LAN-LAN, LAN-WAN 연결. 최적 경로 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L3 스위치&lt;/td&gt;
&lt;td&gt;3계층&lt;/td&gt;
&lt;td&gt;L2 스위치 + 라우터 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L4 스위치&lt;/td&gt;
&lt;td&gt;4계층&lt;/td&gt;
&lt;td&gt;TCP/UDP 포트 기반 로드 밸런싱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L7 스위치&lt;/td&gt;
&lt;td&gt;7계층&lt;/td&gt;
&lt;td&gt;HTTP 헤더, URL, 쿠키까지 분석해 세밀한 트래픽 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;게이트웨이&lt;/td&gt;
&lt;td&gt;전 계층&lt;/td&gt;
&lt;td&gt;서로 다른 프로토콜을 사용하는 네트워크 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;브리지 회선 수 공식&lt;/b&gt; : n개의 브리지로 서브넷 구성 시 전송 가능한 회선 수는 &lt;code&gt;n(n-1)/2&lt;/code&gt;개다. &lt;b&gt;망형 토폴로지와 같은 공식&lt;/b&gt; 이라는 점에 주의한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;라우팅 프로토콜&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패킷의 최적 경로를 결정하는 프로토콜이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;04_routing.png&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhKMdf/dJMb99T2iH9/K2GzjZRza2NXo40TSqxyW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhKMdf/dJMb99T2iH9/K2GzjZRza2NXo40TSqxyW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhKMdf/dJMb99T2iH9/K2GzjZRza2NXo40TSqxyW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhKMdf%2FdJMb99T2iH9%2FK2GzjZRza2NXo40TSqxyW0%2Fimg.png&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;885&quot; height=&quot;374&quot; data-filename=&quot;04_routing.png&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;RIP&lt;/b&gt; : 구현이 단순하지만 최대 15홉 제한이 있어 대규모 네트워크에 부적합하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OSPF&lt;/b&gt; : RIP의 단점을 보완한다. 링크 상태 변화 시 즉시 전파하므로 수렴 속도가 빠르다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BGP&lt;/b&gt; : 인터넷 AS(자율 시스템) 간 경로를 관리하는 프로토콜로, 인터넷 백본의 핵심이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;흐름 제어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;송수신 속도 차이로 인한 데이터 손실을 방지한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정지-대기(Stop-and-Wait)&lt;/b&gt; : 패킷을 하나 보내고 확인 응답을 받을 때까지 기다린다. 단순하지만 효율이 낮다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;슬라이딩 윈도우(Sliding Window)&lt;/b&gt; : 확인 응답을 기다리지 않고 윈도우 크기만큼 연속으로 보낸다. TCP가 이 방식을 사용하며, 실무에서 네트워크 처리량을 높이는 핵심 메커니즘이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;네트워크 토폴로지&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-05-25 22.55.34.png&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zbgGP/dJMcabROCe7/W9akwJt1BGtyusHKCO1LkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zbgGP/dJMcabROCe7/W9akwJt1BGtyusHKCO1LkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zbgGP/dJMcabROCe7/W9akwJt1BGtyusHKCO1LkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzbgGP%2FdJMcabROCe7%2FW9akwJt1BGtyusHKCO1LkK%2Fimg.png&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;1050&quot; height=&quot;307&quot; data-filename=&quot;스크린샷 2026-05-25 22.55.34.png&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;토폴로지&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;장애 시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;성형(Star)&lt;/td&gt;
&lt;td&gt;중앙 허브/스위치에 연결. 현재 LAN의 표준&lt;/td&gt;
&lt;td&gt;중앙 장애 시 전체 마비&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;버스형(Bus)&lt;/td&gt;
&lt;td&gt;하나의 회선에 모두 연결&lt;/td&gt;
&lt;td&gt;회선 단절 시 전체 마비&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;링형(Ring)&lt;/td&gt;
&lt;td&gt;원형으로 연결&lt;/td&gt;
&lt;td&gt;한 노드 장애 시 전체 영향&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;계층형(Tree)&lt;/td&gt;
&lt;td&gt;버스형 확장. 계층 구조&lt;/td&gt;
&lt;td&gt;상위 노드 장애 시 하위 전체 영향&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;망형(Mesh)&lt;/td&gt;
&lt;td&gt;모든 노드가 서로 연결&lt;/td&gt;
&lt;td&gt;일부 장애에도 통신 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;망형 공식&lt;/b&gt; : 노드 n개일 때 필요 회선 수 = &lt;code&gt;n(n-1)/2&lt;/code&gt;, 노드당 필요 포트 수 = &lt;code&gt;n-1&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;5. 기타 신기술&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SW 관련 신기술&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;블록체인&lt;/b&gt;&lt;br /&gt;데이터를 중앙 서버 없이 P2P 네트워크의 여러 노드에 분산 저장한다. 한 번 기록된 데이터를 변경하려면 체인 전체를 바꿔야 하므로 위변조가 어렵다. 암호화폐 외에도 스마트 계약, 공급망 추적에 활용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;매시업(Mashup)&lt;/b&gt;&lt;br /&gt;여러 서비스의 API를 조합해 새로운 서비스나 애플리케이션을 만드는 기법이다. 지도 API + 부동산 데이터를 합쳐 새로운 서비스를 만드는 것이 대표적인 예다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SOA(서비스 지향 아키텍처)&lt;/b&gt;&lt;br /&gt;IT 시스템을 재사용 가능한 서비스 단위로 구성하는 설계 방식이다. 마이크로서비스 아키텍처(MSA)의 전신이라 볼 수 있다. 계층 구조는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;표현 계층 &amp;rarr; 업무 프로세스 계층 &amp;rarr; 서비스 중간 계층 &amp;rarr; 애플리케이션 계층 &amp;rarr; 데이터 저장 계층&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SaaS(Software as a Service)&lt;/b&gt;&lt;br /&gt;소프트웨어의 필요한 기능만 인터넷으로 구독해 사용하는 방식이다. Google Workspace, Slack, Salesforce가 대표적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;디지털 트윈&lt;/b&gt;&lt;br /&gt;물리적 사물이나 시스템을 소프트웨어로 가상화한 모델이다. 제조 공장의 설비를 디지털로 복제해 고장을 사전 예측하거나 시뮬레이션하는 데 쓰인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HW 관련 신기술&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RAID (Redundant Array of Inexpensive Disks)&lt;/b&gt;&lt;br /&gt;여러 디스크를 묶어 성능이나 안정성을 높이는 기술이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;06_raid.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sLpPH/dJMb99NeElr/E29pUg4ch8DFxlatiWCSF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sLpPH/dJMb99NeElr/E29pUg4ch8DFxlatiWCSF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sLpPH/dJMb99NeElr/E29pUg4ch8DFxlatiWCSF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsLpPH%2FdJMb99NeElr%2FE29pUg4ch8DFxlatiWCSF0%2Fimg.png&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;380&quot; height=&quot;670&quot; data-filename=&quot;06_raid.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;레벨&lt;/th&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;최소 디스크&lt;/th&gt;
&lt;th&gt;손상 허용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RAID 0&lt;/td&gt;
&lt;td&gt;스트라이핑&lt;/td&gt;
&lt;td&gt;2개&lt;/td&gt;
&lt;td&gt;0개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 1&lt;/td&gt;
&lt;td&gt;미러링&lt;/td&gt;
&lt;td&gt;2개&lt;/td&gt;
&lt;td&gt;1개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 2~4&lt;/td&gt;
&lt;td&gt;비트/바이트/워드 단위 패리티&lt;/td&gt;
&lt;td&gt;3개&lt;/td&gt;
&lt;td&gt;1개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 5&lt;/td&gt;
&lt;td&gt;분산 패리티&lt;/td&gt;
&lt;td&gt;3개&lt;/td&gt;
&lt;td&gt;1개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 6&lt;/td&gt;
&lt;td&gt;이중 분산 패리티&lt;/td&gt;
&lt;td&gt;4개&lt;/td&gt;
&lt;td&gt;2개&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 DB 서버나 NAS에는 RAID 5 또는 RAID 6이 주로 사용된다. RAID 0은 속도가 빠르지만 디스크 하나만 고장나도 데이터 전체를 잃으므로 중요 데이터에는 쓰지 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DB 관련 신기술&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하둡(Hadoop)&lt;/b&gt;&lt;br /&gt;더그 커팅과 마이크 캐퍼렐라가 개발한 오픈소스 분산 컴퓨팅 플랫폼이다. 구글 맵리듀스 엔진을 기반으로 하며 Java로 구현되었다. 수십 TB에서 PB 규모의 데이터를 여러 서버에 분산 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;맵리듀스(MapReduce)&lt;/b&gt;&lt;br /&gt;대용량 데이터를 분산 처리하는 프로그래밍 모델이다.&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;Map 단계  : 데이터를 키-값 쌍으로 분류 (흩어진 데이터를 연관성 있는 그룹으로 묶음)
Reduce 단계 : 중복 제거 및 집계 (원하는 결과 데이터 추출)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어 빈도 분석을 예로 들면, Map에서 각 단어를 &lt;code&gt;(단어, 1)&lt;/code&gt; 형태로 출력하고, Reduce에서 같은 단어의 카운트를 모두 더한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OLAP(Online Analytical Processing)&lt;/b&gt;&lt;br /&gt;다차원 데이터를 다양한 각도에서 집계&amp;middot;분석해 의사결정을 지원하는 방식이다. BI(Business Intelligence) 도구가 내부적으로 OLAP을 활용한다. OLTP(실시간 트랜잭션 처리)와 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 마이닝&lt;/b&gt;&lt;br /&gt;대량의 데이터에서 숨겨진 패턴, 상관관계, 규칙을 찾아내는 기법이다. 머신러닝 알고리즘을 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DB 회복 기법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB가 손상되었을 때 정상 상태로 되돌리는 작업이다. 로그 파일에 기록된 트랜잭션 정보를 활용한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;REDO&lt;/b&gt; : 완료(COMMIT)된 트랜잭션 중 아직 디스크에 반영되지 않은 것을 다시 실행한다. &quot;완료된 작업을 다시 한다.&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UNDO&lt;/b&gt; : 완료되지 않은(COMMIT 없는) 트랜잭션이 변경한 내용을 되돌린다. &quot;미완 작업을 없던 일로 한다.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기법&lt;/th&gt;
&lt;th&gt;갱신 시점&lt;/th&gt;
&lt;th&gt;가능한 회복&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;연기 갱신 기법&lt;/td&gt;
&lt;td&gt;트랜잭션 완료 후 실제 갱신&lt;/td&gt;
&lt;td&gt;REDO만 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;즉각 갱신 기법&lt;/td&gt;
&lt;td&gt;부분 완료 전이라도 즉시 반영&lt;/td&gt;
&lt;td&gt;REDO + UNDO 모두 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;병행 제어와 교착 상태&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 트랜잭션이 동시에 DB에 접근할 때 일관성을 유지하는 것이 &lt;b&gt;병행 제어&lt;/b&gt; 다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로킹(Locking)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터에 접근하기 전 잠금(Lock)을 요청하고, 허락된 트랜잭션만 접근할 수 있게 하는 기법이다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;로킹 단위&lt;/th&gt;
&lt;th&gt;로크 수&lt;/th&gt;
&lt;th&gt;관리 난이도&lt;/th&gt;
&lt;th&gt;병행성&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;크다 (예: 테이블 전체)&lt;/td&gt;
&lt;td&gt;적다&lt;/td&gt;
&lt;td&gt;쉽다&lt;/td&gt;
&lt;td&gt;낮다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;작다 (예: 행 단위)&lt;/td&gt;
&lt;td&gt;많다&lt;/td&gt;
&lt;td&gt;어렵다&lt;/td&gt;
&lt;td&gt;높다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;교착 상태(Dead Lock)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;07_deadlock.png&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTkLhT/dJMcah5D8h4/h2xxO6WbegvhKF3IEt0SV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTkLhT/dJMcah5D8h4/h2xxO6WbegvhKF3IEt0SV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTkLhT/dJMcah5D8h4/h2xxO6WbegvhKF3IEt0SV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTkLhT%2FdJMcah5D8h4%2Fh2xxO6WbegvhKF3IEt0SV1%2Fimg.png&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;389&quot; height=&quot;225&quot; data-filename=&quot;07_deadlock.png&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착 상태 발생의 필요충분 조건 4가지:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상호 배제&lt;/b&gt; : 자원은 한 번에 한 프로세스만 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;점유와 대기&lt;/b&gt; : 자원을 점유한 채로 다른 자원을 기다림&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점&lt;/b&gt; : 점유된 자원을 강제로 빼앗을 수 없음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;환형 대기&lt;/b&gt; : 프로세스들이 원형으로 서로의 자원을 기다림&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 가지 조건이 모두 성립해야 교착 상태가 발생한다. 해결 방법은 다음과 같다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방법&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;예방&lt;/td&gt;
&lt;td&gt;네 조건 중 하나를 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;회피&lt;/td&gt;
&lt;td&gt;은행원 알고리즘으로 안전한 상태만 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;발견&lt;/td&gt;
&lt;td&gt;주기적으로 교착 상태 탐지 후 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;회복&lt;/td&gt;
&lt;td&gt;교착 상태 프로세스 종료 또는 자원 선점&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;타임스탬프 순서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션마다 시작 시각을 타임스탬프로 부여하고, 이 순서대로 실행을 직렬화하는 병행 제어 기법이다. 로킹 방식에서 발생할 수 있는 교착 상태를 원천 방지할 수 있다. 순서를 정하는 방법 중 가장 보편적으로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;부록 &amp;mdash; 주요 공식 정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;숫자로 기억하는 핵심 공식&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;공식&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;망형 토폴로지 회선 수&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n(n-1)/2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;브리지 n개의 회선 수&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n(n-1)/2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;망형 노드당 필요 포트&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chmod rwx &amp;rarr; 8진수&lt;/td&gt;
&lt;td&gt;r=4, w=2, x=1 합산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HRN 우선순위&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(대기시간 + 서비스시간) / 서비스시간&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SJF 반환 시간&lt;/td&gt;
&lt;td&gt;&lt;code&gt;대기시간 + 실행시간&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;자주 혼동하는 개념 정리&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;혼동 포인트&lt;/th&gt;
&lt;th&gt;구분 방법&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;REDO vs UNDO&lt;/td&gt;
&lt;td&gt;REDO = 완료된 작업 재실행 / UNDO = 미완 작업 취소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TCP vs UDP&lt;/td&gt;
&lt;td&gt;TCP = 연결형, 신뢰성 / UDP = 비연결형, 속도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARP vs RARP&lt;/td&gt;
&lt;td&gt;ARP = IP&amp;rarr;MAC / RARP = MAC&amp;rarr;IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LRU vs LFU&lt;/td&gt;
&lt;td&gt;LRU = 최근에 안 쓴 것 교체 / LFU = 빈도가 낮은 것 교체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;페이지 vs 세그먼트&lt;/td&gt;
&lt;td&gt;페이지 = 고정 크기 / 세그먼트 = 논리 단위 크기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IGP vs EGP&lt;/td&gt;
&lt;td&gt;IGP = 같은 AS 내부 / EGP = AS 간 라우팅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/32</guid>
      <comments>https://revivalearth.tistory.com/entry/OS-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B8%B0%EC%B4%88-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90#entry32comment</comments>
      <pubDate>Mon, 25 May 2026 22:56:23 +0900</pubDate>
    </item>
    <item>
      <title>소프트웨어 개발 보안 구축 핵심 개념</title>
      <link>https://revivalearth.tistory.com/entry/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B0%9C%EB%B0%9C-%EB%B3%B4%EC%95%88-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90</link>
      <description>&lt;h1&gt;소프트웨어 개발 보안 구축&lt;/h1&gt;
&lt;h1&gt;1. Secure SDLC&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안은 개발이 끝나고 붙이는 패치가 아니다. 요구사항을 정의하는 순간부터 배포 이후까지, 개발 생명 주기 전 단계에 보안을 내재화하는 것이 Secure SDLC의 핵심이다. 나중에 발견된 취약점을 고치는 비용은 설계 단계에서 예방하는 비용의 수십 배에 달한다는 것은 현업에서 자주 체감하는 사실이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 방법론 세 가지가 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CLASP&lt;/td&gt;
&lt;td&gt;Cigital&lt;/td&gt;
&lt;td&gt;SDLC 초기 단계 보안 강화에 초점. 역할 기반 활동 정의.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SDL&lt;/td&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;MS 내부에서 출발해 공개된 방법론. 위협 모델링 포함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seven Touchpoints&lt;/td&gt;
&lt;td&gt;Gary McGraw&lt;/td&gt;
&lt;td&gt;모범 사례를 SDLC 7개 접점에 통합. 코드 리뷰&amp;middot;위험 분석 강조.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;User Token License Flow-2026-05-25-035145.png&quot; data-origin-width=&quot;3177&quot; data-origin-height=&quot;1780&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnvxWA/dJMcabYEsjK/5EkfhLwpzB55FxxPewdOIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnvxWA/dJMcabYEsjK/5EkfhLwpzB55FxxPewdOIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnvxWA/dJMcabYEsjK/5EkfhLwpzB55FxxPewdOIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnvxWA%2FdJMcabYEsjK%2F5EkfhLwpzB55FxxPewdOIk%2Fimg.png&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;3177&quot; height=&quot;1780&quot; data-filename=&quot;User Token License Flow-2026-05-25-035145.png&quot; data-origin-width=&quot;3177&quot; data-origin-height=&quot;1780&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;2. 보안 요소 (CIA + 인증&amp;middot;부인방지)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현업에서 보안 설계를 논할 때 가장 먼저 나오는 프레임이 CIA Triad다. 여기에 인증과 부인방지를 더하면 보안 요소 전체 그림이 완성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;User Token License Flow-2026-05-25-035200.png&quot; data-origin-width=&quot;5376&quot; data-origin-height=&quot;1675&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w2VTR/dJMcabxw5th/z58c9gd4KL4vULPka6h4QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w2VTR/dJMcabxw5th/z58c9gd4KL4vULPka6h4QK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w2VTR/dJMcabxw5th/z58c9gd4KL4vULPka6h4QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw2VTR%2FdJMcabxw5th%2Fz58c9gd4KL4vULPka6h4QK%2Fimg.png&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;5376&quot; height=&quot;1675&quot; data-filename=&quot;User Token License Flow-2026-05-25-035200.png&quot; data-origin-width=&quot;5376&quot; data-origin-height=&quot;1675&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CIA Triad&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기밀성 (Confidentiality)&lt;/b&gt;: 인가된 사용자만 데이터에 접근할 수 있어야 한다. 전송 중 패킷이 탈취되더라도 암호화가 되어 있으면 내용을 읽을 수 없다. HTTPS, VPN이 이 원칙을 구현한 대표적인 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;무결성 (Integrity)&lt;/b&gt;: 데이터가 인가되지 않은 방식으로 수정되어서는 안 된다. 해시값 비교나 디지털 서명이 대표적인 구현 방법이다. 파일을 배포할 때 SHA-256 해시를 함께 공개하는 관행이 바로 이 원칙을 따른 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가용성 (Availability)&lt;/b&gt;: 인가된 사용자는 필요할 때 언제든 정보와 자원을 사용할 수 있어야 한다. DDoS 공격이 가용성을 노리는 대표적인 위협이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인증과 부인방지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증(Authentication)은 접속한 주체가 정말 그 사람인지 확인하는 행위다. 인증 방식은 다섯 가지 기반으로 분류된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;지식 기반&lt;/b&gt;: 비밀번호, PIN처럼 &quot;알고 있는 것&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소유 기반&lt;/b&gt;: OTP 토큰, 스마트카드처럼 &quot;가지고 있는 것&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;생체 기반&lt;/b&gt;: 지문, 홍채처럼 &quot;나 자신인 것&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;위치 기반&lt;/b&gt;: 특정 IP 대역, 국가처럼 &quot;있는 위치&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;행위 기반&lt;/b&gt;: 서명 패턴, 타이핑 리듬처럼 &quot;행동 방식&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부인방지(Non-repudiation)는 송신자나 수신자가 나중에 &quot;나는 그런 적 없다&quot;고 발뺌하지 못하도록 증거를 남기는 것이다. 전자서명이 가장 전형적인 구현이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;3. 시큐어 코딩&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안 취약점의 상당수는 애플리케이션 코드 레벨에서 비롯된다. 시큐어 코딩은 이 취약점을 코드 작성 단계에서 예방하는 실천이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;입력 데이터 검증 관련 취약점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부에서 들어오는 모든 입력은 잠재적으로 악의적일 수 있다는 전제로 코드를 작성하는 것이 기본이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;경로 순회 (Path Traversal)&lt;/b&gt;: ../ 같은 상대 경로 기호를 악용해 허가되지 않은 파일에 접근하는 공격이다. 예를 들어 파일 다운로드 기능에서 파일명 파라미터를 그대로 경로에 사용하면 서버의 /etc/passwd까지 노출될 수 있다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# 취약한 코드: 입력값을 그대로 경로에 사용
filename = request.args.get('file')
with open(f&quot;/var/uploads/{filename}&quot;) as f:  # ../../../etc/passwd 가능
    return f.read()

# 개선: 경로를 정규화하고 허용 디렉토리 내인지 검증
import os
base_dir = &quot;/var/uploads&quot;
filename = request.args.get('file')
safe_path = os.path.realpath(os.path.join(base_dir, filename))
if not safe_path.startswith(base_dir):
    abort(403)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SQL 삽입 (SQL Injection)&lt;/b&gt;: 입력값에 SQL 구문을 섞어 DB를 조작하거나 인증을 우회하는 공격이다. 실무에서 여전히 OWASP Top 10에 빠지지 않는 단골 취약점이다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# 취약한 코드: 문자열 포매팅으로 쿼리 조합
query = f&quot;SELECT * FROM users WHERE id='{user_id}'&quot;  # ' OR '1'='1 삽입 가능

# 개선: 파라미터 바인딩 사용
cursor.execute(&quot;SELECT * FROM users WHERE id = %s&quot;, (user_id,))
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;XSS (Cross-Site Scripting)&lt;/b&gt;: 악의적인 스크립트를 웹 페이지에 삽입해 다른 사용자의 브라우저에서 실행시키는 공격이다. 세션 쿠키 탈취, 피싱 페이지 삽입 등에 활용된다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# 취약한 코드: 사용자 입력을 HTML에 그대로 출력
return f&quot;&amp;lt;p&amp;gt;안녕하세요, {username}&amp;lt;/p&amp;gt;&quot;  # &amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt; 삽입 가능

# 개선: 출력 시 HTML 이스케이프 처리
from markupsafe import escape
return f&quot;&amp;lt;p&amp;gt;안녕하세요, {escape(username)}&amp;lt;/p&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 버퍼 오버플로&lt;/b&gt;: 할당된 메모리 범위를 넘어 데이터를 쓸 때 발생한다. C/C++ 환경에서 자주 나타나며, 공격자가 이를 이용해 임의 코드를 실행시킬 수 있다. Python, Java 등 메모리 관리 언어를 사용하면 이 위험이 크게 줄어든다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;보안 기능 관련 취약점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하드 코딩&lt;/b&gt;: API 키, DB 패스워드, 암호화 키를 소스코드에 직접 쓰는 관행이다. 코드가 깃허브에 올라가는 순간 탈취 위험이 생긴다. 환경변수나 시크릿 관리 서비스(AWS Secrets Manager, HashiCorp Vault 등)로 분리하는 것이 올바른 방향이다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;# 권장하지 않는 방식
DB_PASSWORD = &quot;super_secret_123&quot;

# 권장 방식: 환경변수에서 읽기
import os
DB_PASSWORD = os.environ.get(&quot;DB_PASSWORD&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TOCTOU (Time Of Check To Time Of Use) 경쟁 조건&lt;/b&gt;: 파일 존재 여부를 검사(Check)한 시점과 실제 사용(Use) 시점 사이의 간격을 파고드는 취약점이다. 멀티스레드 환경이나 공유 자원 접근 시 빈번하게 나타난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;널 포인터 역참조&lt;/b&gt;: 널 포인터가 가리키는 메모리 위치에 접근하면 프로그램이 충돌하거나 예측 불가능한 동작이 발생한다. 반드시 널 체크를 선행하는 습관이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스택 가드&lt;/b&gt;: 버퍼 오버플로 공격을 탐지하기 위한 방어 기법이다. 복귀 주소와 변수 사이에 특정 카나리(canary) 값을 넣어두고, 이 값이 변조되면 오버플로우로 판단해 실행을 중단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;접근 제어자 범위&lt;/b&gt;: public &amp;rarr; protected &amp;rarr; default &amp;rarr; private 순으로 접근 범위가 좁아진다. 실무에서는 정보 은닉 원칙에 따라 가능한 한 좁은 접근 범위를 선택하는 편이 안전하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;4. 암호화&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;User Token License Flow-2026-05-25-035212.png&quot; data-origin-width=&quot;6582&quot; data-origin-height=&quot;2675&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi9iGg/dJMcafta5Fa/1phsizxrkUagILYbfux0Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi9iGg/dJMcafta5Fa/1phsizxrkUagILYbfux0Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi9iGg/dJMcafta5Fa/1phsizxrkUagILYbfux0Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi9iGg%2FdJMcafta5Fa%2F1phsizxrkUagILYbfux0Fk%2Fimg.png&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;6582&quot; height=&quot;2675&quot; data-filename=&quot;User Token License Flow-2026-05-25-035212.png&quot; data-origin-width=&quot;6582&quot; data-origin-height=&quot;2675&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개인키(대칭키) 암호화&lt;/h2&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-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스트림 방식&lt;/b&gt;: 평문과 동일한 길이의 키스트림을 생성해 비트 단위로 XOR 연산한다. 실시간 통신에 적합하다. 대표 알고리즘으로 LFSR, RC4가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;블록 방식&lt;/b&gt;: 데이터를 고정 크기 블록으로 나눠 한 블록씩 암호화한다. 대표 알고리즘은 아래와 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DES&lt;/td&gt;
&lt;td&gt;미국 NBS&lt;/td&gt;
&lt;td&gt;1975&lt;/td&gt;
&lt;td&gt;64비트 키&lt;/td&gt;
&lt;td&gt;현재는 취약. 3DES로 보완했으나 느림.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEED&lt;/td&gt;
&lt;td&gt;KISA&lt;/td&gt;
&lt;td&gt;1999&lt;/td&gt;
&lt;td&gt;128비트 키&lt;/td&gt;
&lt;td&gt;국내 표준 블록 암호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES&lt;/td&gt;
&lt;td&gt;미국 NIST&lt;/td&gt;
&lt;td&gt;2001&lt;/td&gt;
&lt;td&gt;128/192/256비트 키&lt;/td&gt;
&lt;td&gt;현재 가장 널리 쓰이는 표준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARIA&lt;/td&gt;
&lt;td&gt;국정원+산학연&lt;/td&gt;
&lt;td&gt;2004&lt;/td&gt;
&lt;td&gt;AES 규격 준용&lt;/td&gt;
&lt;td&gt;국내 표준, 경량 환경에 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 제안 주체 연도 키/블록 크기 비고&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AES는 현재 사실상의 글로벌 표준이다. 신규 시스템을 설계할 때 특별한 이유가 없다면 AES-256을 기준으로 삼는 것이 일반적이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공개키(비대칭키) 암호화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공개키로 암호화하고 개인키로 복호화한다. 키 배포 문제를 해결하지만, 대칭키 방식에 비해 연산이 훨씬 느리다. 그래서 실제 데이터 암호화보다는 대칭키를 안전하게 교환하거나 전자서명을 생성하는 용도로 주로 쓰인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RSA&lt;/b&gt;: 라이베스트, 샤미르, 애들먼이 개발한 공개키 알고리즘이다. 큰 수의 소인수분해가 현실적으로 어렵다는 수학적 난제를 기반으로 한다. 현재도 TLS 핸드셰이크, 전자서명에 광범위하게 사용된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 데이터를 고정 길이의 값으로 변환한다. 단방향 함수이므로 복호화가 불가능하다. 데이터 무결성 검증, 패스워드 저장에 활용된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MD5&lt;/td&gt;
&lt;td&gt;128비트&lt;/td&gt;
&lt;td&gt;1991년 라이베스트 개발. 충돌 취약점 발견으로 보안 용도로는 권장하지 않음.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-256 / SHA-512&lt;/td&gt;
&lt;td&gt;256 / 512비트&lt;/td&gt;
&lt;td&gt;NSA&amp;middot;NIST 발표. 현재 가장 많이 쓰이는 해시 계열.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N-NASH&lt;/td&gt;
&lt;td&gt;128비트&lt;/td&gt;
&lt;td&gt;일본 NTT 발표.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SNEFRU&lt;/td&gt;
&lt;td&gt;가변&lt;/td&gt;
&lt;td&gt;머클이 1990년 발표. 32비트 프로세서 최적화.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 출력 크기 비고&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패스워드를 저장할 때 MD5나 SHA-1을 단순히 적용하는 것은 권장하지 않는다. 레인보우 테이블 공격에 취약하기 때문이다. bcrypt, Argon2, PBKDF2처럼 솔트(salt)와 반복 연산을 적용한 알고리즘을 쓰는 편이 현재 기준에 맞다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무선 보안 프로토콜&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WEP &amp;rarr; TKIP(WPA) &amp;rarr; WPA2 순으로 보안 수준이 높아졌다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;WEP&lt;/b&gt;: 초기 무선랜 보안 프로토콜. 취약점이 많아 현재는 사용하지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TKIP&lt;/b&gt;: WEP의 취약점을 보완한 데이터 보안 프로토콜. WPA에 사용됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WPA2&lt;/b&gt;: 현재 표준. AES 기반 CCMP 암호화를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;5. 보안 아키텍처와 솔루션&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 단일 보안 제품 하나로 모든 위협을 막을 수 없다. 여러 보안 솔루션을 계층적으로 배치하는 심층 방어(Defense in Depth) 전략이 현실적인 접근이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 보안 솔루션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;방화벽 (Firewall)&lt;/b&gt;: 네트워크 경계에서 트래픽을 필터링한다. 허용할 IP와 포트를 정의하고, 그 외는 차단한다. 하지만 허용된 포트를 통한 애플리케이션 레이어 공격(예: HTTP를 통한 SQL 인젝션)은 막지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;침입 탐지 시스템 (IDS)&lt;/b&gt;: 공격을 탐지하지만 자동 차단은 하지 않는다. 두 가지 방식이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;오용 탐지&lt;/b&gt;: 알려진 공격 패턴(시그니처)과 비교해 탐지한다. 알려지지 않은 공격(제로데이)은 놓칠 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이상 탐지&lt;/b&gt;: 정상 상태 기준선을 설정하고 벗어난 행동을 탐지한다. 오탐율이 높을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;침입 방지 시스템 (IPS)&lt;/b&gt;: IDS에 자동 차단 기능을 더한 것이다. 비정상 트래픽을 능동적으로 격리한다. &quot;방화벽 + IDS&quot;의 조합으로 이해하면 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;웹 방화벽 (WAF)&lt;/b&gt;: SQL 인젝션, XSS 등 웹 계층 공격에 특화된 방화벽이다. 일반 방화벽이 놓치는 HTTP 레이어 공격을 잡아낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;VPN&lt;/b&gt;: 공중망 인터넷을 통해 암호화된 사설 터널을 구성한다. 재택근무 환경에서 사내망 접근에 광범위하게 쓰인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NAC (Network Access Control)&lt;/b&gt;: 내부망에 접속하는 단말의 MAC 주소를 등록&amp;middot;관리해 비인가 단말의 접속을 차단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DLP (Data Loss Prevention)&lt;/b&gt;: 내부 데이터가 외부로 유출되는 것을 감지하고 차단한다. 이메일, USB, 클라우드 업로드 경로를 모니터링한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ESM (Enterprise Security Management)&lt;/b&gt;: 여러 보안 장비에서 발생하는 로그와 이벤트를 통합 관리하는 플랫폼이다. 개별 장비를 각각 들여다보는 것보다 상관 분석이 가능해 위협 탐지 정확도가 높아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AAA&lt;/b&gt;: 보안 접근 통제의 세 가지 핵심 기능이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인증 (Authentication)&lt;/b&gt;: 본인 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인가 (Authorization)&lt;/b&gt;: 권한 부여&lt;/li&gt;
&lt;li&gt;&lt;b&gt;과금 (Accounting)&lt;/b&gt;: 접근 기록과 자원 사용 추적&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ISMS (정보보호관리체계)&lt;/b&gt;: 조직의 정보 자산을 안전하게 보호하기 위한 절차와 대책의 체계다. 국내에서는 KISA가 운영하며, ISO 27001을 기반으로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;6. 주요 공격 기법&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서비스 거부 공격 (DoS / DDoS)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 정상적으로 제공하지 못하도록 가용성을 공격하는 방식이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ping of Death&lt;/td&gt;
&lt;td&gt;ICMP 패킷 크기를 허용 범위 이상으로 전송해 시스템 충돌 유발&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smurf Attack&lt;/td&gt;
&lt;td&gt;출발지 IP를 피해자로 위조한 ICMP 브로드캐스트로 대량 응답 집중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SYN Flooding&lt;/td&gt;
&lt;td&gt;TCP 3-way 핸드셰이크를 미완성 상태로 방치해 연결 자원 소진&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TearDrop&lt;/td&gt;
&lt;td&gt;IP 단편화 오프셋을 변조해 재조합 과정에서 과부하 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LAND Attack&lt;/td&gt;
&lt;td&gt;송신&amp;middot;수신 IP를 동일하게 설정해 무한 응답 루프 유발&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDoS&lt;/td&gt;
&lt;td&gt;봇넷(좀비 PC 집합)을 이용해 여러 지점에서 동시 공격. Trin00, TFN, TFN2k, Stacheldraht 등의 툴 활용.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공격 원리&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SYN Flooding은 현업에서도 자주 접하는 공격이다. 이에 대응하기 위한 SYN Cookie, Rate Limiting 설정을 서버 운영 시 기본으로 챙기는 편이 좋다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;세션&amp;middot;네트워크 탈취 공격&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;세션 하이재킹&lt;/b&gt;: 클라이언트와 서버 사이의 세션을 가로채는 공격이다. TCP 3-way 핸드셰이크 과정에 끼어드는 TCP 세션 하이재킹이 대표적이다. 세션 토큰을 탈취하거나 시퀀스 번호를 예측해 세션을 강탈한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ARP Spoofing&lt;/b&gt;: ARP는 IP 주소를 MAC 주소로 변환하는 프로토콜인데, 이 과정에서 자신의 MAC 주소를 공격 대상인 것처럼 위조해 트래픽을 가로채는 공격이다. 같은 네트워크 내 중간자 공격(MITM)의 전형적인 수단이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스니핑&lt;/b&gt;: 네트워크를 지나는 패킷을 수동적으로 도청한다. 암호화되지 않은 프로토콜(HTTP, FTP, Telnet)은 스니핑에 취약하다. HTTPS, SSH, SFTP를 쓰는 이유 중 하나가 여기 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;악성코드&amp;middot;사회공학 공격&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;랜섬웨어&lt;/b&gt;: 내부 파일을 암호화한 뒤 복호화 대가로 금전을 요구한다. 백업과 오프라인 복사본이 현재로서 가장 현실적인 대응책이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백도어&lt;/b&gt;: 개발자나 공격자가 정상 인증 절차를 우회해 시스템에 접근하도록 숨겨둔 통로다. 탐지 방법으로는 무결성 검사, 열린 포트 확인, 로그 분석, SetUID 파일 검사가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;워터링 홀&lt;/b&gt;: 공격 대상이 자주 방문하는 웹사이트를 미리 감염시켜 방문자를 감염시키는 방식이다. 표적 집단의 행동 패턴을 사전에 연구한다는 점에서 정교한 APT 공격에 자주 활용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;APT (Advanced Persistent Threat)&lt;/b&gt;: 특정 조직을 목표로 장기간에 걸쳐 조직적으로 침투하는 공격이다. 단발성 공격이 아니라 정찰, 침투, 내부 이동, 정보 탈취까지 단계적으로 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;키로거&lt;/b&gt;: 키보드 입력을 몰래 기록해 패스워드, 카드 번호 등 민감한 정보를 탈취한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기타 공격&amp;middot;취약점 용어&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;스미싱&lt;/td&gt;
&lt;td&gt;SMS + 피싱. 문자 링크로 악성 앱 설치 유도.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스피어 피싱&lt;/td&gt;
&lt;td&gt;특정 대상을 선정해 지속적으로 맞춤형 이메일 발송.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;큐싱&lt;/td&gt;
&lt;td&gt;QR코드 + 피싱. QR 스캔 시 악성 사이트로 유도.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;브루트 포스&lt;/td&gt;
&lt;td&gt;가능한 모든 값을 대입해 패스워드를 찾는 무차별 공격.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;크리덴셜 스터핑&lt;/td&gt;
&lt;td&gt;이미 유출된 계정 정보를 다른 서비스에 무작위 대입.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제로데이 공격&lt;/td&gt;
&lt;td&gt;취약점이 공개되기 전에 이미 해당 취약점을 악용하는 공격.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;트로이 목마&lt;/td&gt;
&lt;td&gt;정상 프로그램으로 위장한 악성코드. 사용자가 직접 실행.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;웜&lt;/td&gt;
&lt;td&gt;자가 복제하며 네트워크를 통해 스스로 전파하는 악성코드.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;멀버타이징&lt;/td&gt;
&lt;td&gt;정상 광고 네트워크에 악성 코드를 심어 배포하는 방식.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공급망 공격&lt;/td&gt;
&lt;td&gt;소프트웨어 공급망에 침투해 악성코드를 정상 배포물에 삽입.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 디들링&lt;/td&gt;
&lt;td&gt;처리될 데이터를 처리 전에 몰래 변조하는 방식.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POODLE&lt;/td&gt;
&lt;td&gt;TLS 연결을 SSL 3.0으로 강제 다운그레이드 후 취약점 악용.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDE 취약점&lt;/td&gt;
&lt;td&gt;오피스 문서에 포함된 DDE 프로토콜을 통한 악성코드 실행.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용어 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;7. 보안 관련 기타 개념&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;보안 아키텍처&lt;/b&gt;: 보안 요소들 간의 관계와 구조를 정의한 설계 체계다. 어떤 보안 통제를 어떤 계층에 적용할지 그림을 그리는 작업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;보안 프레임워크&lt;/b&gt;: 안전한 정보 시스템 환경을 유지하기 위한 체계적 틀이다. ISO 27001, BS7799가 대표적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EDR (Endpoint Detection and Response)&lt;/b&gt;: 엔드포인트(PC, 서버 등)에서 발생하는 위협을 모니터링하고 대응한다. 기존 백신과 달리 행위 기반으로 탐지하므로 알려지지 않은 위협에도 반응한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TMS (Threat Management System)&lt;/b&gt;: 전사적 IT 인프라에 대한 위협 정보를 통합 관리하는 시스템이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DTLS&lt;/b&gt;: UDP 기반 통신에 SSL/TLS와 유사한 보안 기능을 제공한다. VoIP나 게임처럼 실시간성이 중요한 UDP 통신에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비트 로커 (BitLocker)&lt;/b&gt;: 윈도우 전용 볼륨 암호화 기능이다. TPM(신뢰 플랫폼 모듈) 칩과 AES-128을 결합해 디스크 전체를 암호화한다. 분실된 노트북의 데이터를 보호하는 데 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CC (Common Criteria) 인증&lt;/b&gt;: 정보보안 제품의 보안 기능을 국제적으로 평가하는 기준이다. EAL 1~7 등급으로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ISAC (정보공유분석센터)&lt;/b&gt;: 산업별 사이버 위협 정보를 공유하고, 실시간 경보 및 분석 체계를 운영하는 기관이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BCP (Business Continuity Planning)&lt;/b&gt;: 재해&amp;middot;장애 상황에서도 비즈니스를 지속하기 위한 계획이다. RTO(목표 복구 시간), RPO(목표 복구 시점), BIA(업무 영향 분석)를 기반으로 수립한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;봇넷(C&amp;amp;C 구조)&lt;/b&gt;: 악성코드에 감염된 좀비 PC들을 C&amp;amp;C(Command and Control) 서버가 원격 조종하는 구조다. DDoS 공격, 스팸 발송, 크리덴셜 스터핑 등에 활용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;부록 &amp;mdash; 암호화 알고리즘 한눈에 비교&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;대칭키 vs 비대칭키 vs 해시&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;대칭키&lt;/td&gt;
&lt;td&gt;하나의 키&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;td&gt;대량 데이터 암호화&lt;/td&gt;
&lt;td&gt;AES, DES, SEED, ARIA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비대칭키&lt;/td&gt;
&lt;td&gt;공개키 + 개인키 쌍&lt;/td&gt;
&lt;td&gt;가능 (개인키로)&lt;/td&gt;
&lt;td&gt;키 교환, 전자서명&lt;/td&gt;
&lt;td&gt;RSA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;해시&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;불가 (단방향)&lt;/td&gt;
&lt;td&gt;무결성 검증, 패스워드 저장&lt;/td&gt;
&lt;td&gt;SHA-256, MD5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 키 구조 복호화 가능 주요 용도 대표 알고리즘&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;보안 솔루션 계층 배치&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;2&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;계층&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;솔루션&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;핵심 역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,1,0,0&quot;&gt;경계 (Perimeter)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,1,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,1,1,0&quot;&gt;방화벽 (Firewall)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,1,2,0&quot;&gt;허가되지 않은 네트워크 접근을 IP/Port 기반으로 차단&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,2,0,0&quot;&gt;애플리케이션 (App)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,2,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,2,1,0&quot;&gt;IPS / WAF&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,2,2,0&quot;&gt;패킷 침입 탐지 및 웹 애플리케이션 취약점 공격 방어&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,3,0,0&quot;&gt;접근 제어 (Access)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,3,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,3,1,0&quot;&gt;NAC&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,3,2,0&quot;&gt;네트워크 접속 단말의 무결성 검증 및 인증 관리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,4,0,0&quot;&gt;엔드포인트 (Endpoint)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,4,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,4,1,0&quot;&gt;EDR&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,4,2,0&quot;&gt;단말 내부의 이상 행위 모니터링 및 실시간 위협 대응&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,5,0,0&quot;&gt;통합 관제 (Monitoring)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,5,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,5,1,0&quot;&gt;ESM / SIEM&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,5,2,0&quot;&gt;분산된 보안 로그를 통합하여 상관관계 분석 및 경보&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;User Token License Flow-2026-05-25-035438.png&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;4155&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caloxK/dJMcagyQoOM/u3osdpTKfFkJRktXe2eaq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caloxK/dJMcagyQoOM/u3osdpTKfFkJRktXe2eaq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caloxK/dJMcagyQoOM/u3osdpTKfFkJRktXe2eaq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaloxK%2FdJMcagyQoOM%2Fu3osdpTKfFkJRktXe2eaq1%2Fimg.png&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;205&quot; height=&quot;786&quot; data-filename=&quot;User Token License Flow-2026-05-25-035438.png&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;4155&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공격 유형 분류 요약&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;User Token License Flow-2026-05-25-035522.png&quot; data-origin-width=&quot;3601&quot; data-origin-height=&quot;2498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PLR1y/dJMcadPB5Jq/sKAYz5gVH3ZPGM3HoHbkgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PLR1y/dJMcadPB5Jq/sKAYz5gVH3ZPGM3HoHbkgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PLR1y/dJMcadPB5Jq/sKAYz5gVH3ZPGM3HoHbkgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPLR1y%2FdJMcadPB5Jq%2FsKAYz5gVH3ZPGM3HoHbkgk%2Fimg.png&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;3601&quot; height=&quot;2498&quot; data-filename=&quot;User Token License Flow-2026-05-25-035522.png&quot; data-origin-width=&quot;3601&quot; data-origin-height=&quot;2498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;2&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;공격 목표&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;주요 공격 기법&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,1,0,0&quot;&gt;가용성 파괴&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,1,1,0&quot;&gt;DoS / DDoS&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,1,2,0&quot;&gt;서비스에 과부하를 주어 정상 사용자가 이용하지 못하게 함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,2,0,0&quot;&gt;기밀성 침해&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,2,1,0&quot;&gt;스니핑, ARP Spoofing, 세션 하이재킹&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,2,2,0&quot;&gt;데이터 흐름을 도청하거나 세션을 탈취하여 정보를 훔침&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,3,0,0&quot;&gt;무결성 침해&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,3,1,0&quot;&gt;데이터 디들링, SQL 인젝션&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,3,2,0&quot;&gt;데이터를 악의적으로 변조하거나 잘못된 데이터로 조작함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,4,0,0&quot;&gt;인증 우회&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,4,1,0&quot;&gt;크리덴셜 스터핑, 브루트 포스&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,4,2,0&quot;&gt;계정 정보를 탈취하거나 무작위 대입으로 로그인을 시도함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,5,0,0&quot;&gt;지속 접근&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,5,1,0&quot;&gt;백도어, APT, 공급망 공격&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,5,2,0&quot;&gt;침투 후 몰래 장기간 상주하며 시스템 통제권을 유지함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,6,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,6,0,0&quot;&gt;금전 탈취&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,6,1,0&quot;&gt;랜섬웨어, 피싱&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;2,6,2,0&quot;&gt;데이터를 인질로 잡거나 사용자를 속여 직접적인 이득을 취함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/31</guid>
      <comments>https://revivalearth.tistory.com/entry/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B0%9C%EB%B0%9C-%EB%B3%B4%EC%95%88-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90#entry31comment</comments>
      <pubDate>Mon, 25 May 2026 12:56:24 +0900</pubDate>
    </item>
    <item>
      <title>애플리케이션 테스트 핵심 개념</title>
      <link>https://revivalearth.tistory.com/entry/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
      <description>&lt;h1&gt;1. 애플리케이션 테스트란&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트는 소프트웨어에서 결함을 찾아내는 행위이자 절차다. 두 가지 시각으로 나눌 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;검증(Verification) 테스트&lt;/b&gt;: 개발자 입장에서 &quot;제대로 만들었는가&quot;를 확인한다. 설계 명세를 기준으로 삼는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확인(Validation) 테스트&lt;/b&gt;: 사용자 입장에서 &quot;맞는 것을 만들었는가&quot;를 확인한다. 실제 요구사항이 기준이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 둘은 비슷해 보이지만 전혀 다른 질문에 답한다. 기능은 완벽하게 작동하지만 사용자가 원하는 기능이 아닌 경우가 현장에서 자주 벌어지는 이유가 바로 이 둘의 간극에서 나온다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트의 기본 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트를 설계할 때 자주 놓치는 원리 세 가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파레토 법칙&lt;/b&gt;: 결함의 80%는 전체 모듈의 20%에 집중된다. 실무에서는 이력이 불안정하거나 복잡한 모듈을 먼저 집중 점검하는 근거가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;살충제 패러독스&lt;/b&gt;: 동일한 테스트 케이스로 반복 테스트하면 어느 시점부터 새로운 결함이 발견되지 않는다. 살충제를 계속 뿌리면 내성이 생기는 것과 같다. 이를 피하려면 테스트 케이스를 주기적으로 갱신하거나 다양한 관점으로 바꿔야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오류-부재의 궤변&lt;/b&gt;: 결함이 전혀 없다고 해서 품질이 높은 것은 아니다. 결함이 없어도 사용자의 요구사항을 충족하지 못하면 그 소프트웨어는 쓸모가 없다. 테스트는 &quot;결함 제거&quot;가 아닌 &quot;요구사항 충족 여부&quot;를 최종 목표로 삼아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;2. 테스트 분류 체계&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트는 세 가지 기준으로 분류한다. 기반, 목적, 개발 단계가 그것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트 기반에 따른 분류&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트를 어떤 근거로 설계하느냐에 따라 나뉜다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;명세 기반&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;요구사항 명세, 설계 문서&lt;/td&gt;
&lt;td&gt;동등 분할, 경계값 분석&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구조 기반&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;소스 코드의 내부 구조&lt;/td&gt;
&lt;td&gt;구문 기반, 결정 기반, 조건 기반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;경험 기반&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;테스터의 직관과 경험&lt;/td&gt;
&lt;td&gt;에러 추정, 체크리스트, 탐색적 테스팅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분류 근거 대표 기법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세 기반은 코드를 몰라도 테스트할 수 있고, 구조 기반은 코드를 직접 들여다본다. 경험 기반은 자동화하기 어렵지만 베테랑 QA가 놓치는 엣지 케이스를 잡아내는 데 강하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목적에 따른 분류&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;회복(Recovery)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;결함 발생 후 정상 복구되는지 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;안전(Security)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;외부 침입으로부터 시스템이 보호되는지 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;강도(Stress)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;과부하 상황에서의 동작 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;성능(Performance)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;응답 시간, 처리량 측정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구조(Structure)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;논리 경로, 코드 복잡도 평가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;회귀(Regression)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;변경 후 기존 기능에 문제가 생기지 않았는지 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;병행(Parallel)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;변경 전후 버전에 동일 데이터를 입력하고 결과를 비교&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 목적&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시험 포인트&lt;/b&gt;: 회귀 테스트는 &quot;이미 테스트된 프로그램의 테스팅을 반복&quot;하는 것이다. 코드 수정 후 기존 기능이 깨지는 현상(Regression)을 잡기 위해 수행한다. CI/CD 파이프라인에서 자동화 테스트가 가장 많이 담당하는 역할이기도 하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정적 테스트 vs 동적 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 여부로 나뉘는 구분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정적 테스트&lt;/b&gt;는 프로그램을 실행하지 않고 코드나 문서를 검토한다. 대표적으로 워크스루(비공식 리뷰)와 인스펙션(공식 절차에 따른 검토)이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동적 테스트&lt;/b&gt;는 실제로 프로그램을 실행해서 결과를 확인한다. 화이트박스와 블랙박스로 세분화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;3. 화이트박스 vs 블랙박스 테스트&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;화이트박스 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스 코드를 오픈한 상태에서 내부 논리 경로를 모두 점검하는 방식이다. 개발자가 직접 수행하는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표 기법은 기초 경로 검사(Base Path Testing)와 제어 구조 검사다. 제어 구조 검사는 다시 조건 검사, 루프 검사, 데이터 흐름 검사로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증 기준은 두 가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;분기(결정) 검증 기준&lt;/b&gt;: 모든 조건문에서 True와 False를 각각 한 번씩 수행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조건 검증 기준&lt;/b&gt;: 복합 조건식에서 각 개별 조건식의 결과를 따로 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 if (A &amp;amp;&amp;amp; B) 같은 조건이 있을 때 분기 기준은 조건문 전체의 True/False만 보지만, 조건 기준은 A와 B 각각의 True/False 조합을 확인한다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;# 분기 검증 기준 예시
def check_age_and_score(age, score):
    if age &amp;gt;= 18 and score &amp;gt;= 60:  # 이 조건 전체의 T/F를 각 1회 수행
        return &quot;합격&quot;
    return &quot;불합격&quot;

# 분기 기준: (True, True) &amp;rarr; &quot;합격&quot; / (False, ...) or (..., False) &amp;rarr; &quot;불합격&quot; 2가지면 충분
# 조건 기준: age&amp;gt;=18 의 T/F, score&amp;gt;=60 의 T/F 각각 확인 &amp;rarr; 더 많은 케이스 필요
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;블랙박스 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 코드를 보지 않고 기능 명세만으로 테스트한다. &quot;기능 테스트&quot;라고도 부른다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;동치 분할(Equivalence Partitioning)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;입력값을 유효/무효 구간으로 나눠 각 구간에서 대표값 하나씩 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;경계값 분석(Boundary Value Analysis)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;구간의 경계 지점 값을 집중 테스트 (경계에서 결함이 자주 발생)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;원인-효과 그래프&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;입력 조건과 출력 결과의 인과 관계를 그래프로 표현해 TC 도출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;오류 예측&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;경험에 의해 발생 가능한 오류를 추정하고 테스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;비교 검사&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;여러 버전의 프로그램에 동일한 TC를 제공해 결과를 비교&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기법 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동치 분할과 경계값 분석은 함께 쓰이는 경우가 많다. 예를 들어 &quot;1 이상 100 이하의 정수&quot;를 입력받는 필드라면 동치 분할로 유효 구간(1~100)과 무효 구간을 나누고, 경계값 분석으로 0, 1, 100, 101을 집중 테스트한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;입력 범위: 1 ~ 100

동치 분할
  - 유효 구간: 1 ~ 100 (대표값: 50)
  - 무효 구간 1: 100 초과 (대표값: 150)
  - 무효 구간 2: 1 미만 (대표값: -10)

경계값 분석
  - 테스트 값: 0, 1, 2, 99, 100, 101
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;4. 개발 단계에 따른 테스트&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단위 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 또는 컴포넌트 단위로 수행하는 첫 번째 테스트다. 주로 구조 기반(화이트박스) 기법을 활용한다. 개발자가 작성한 코드를 개발자 본인이 점검하는 단계이기도 하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;통합 테스트&lt;/h2&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-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비점진적 방식 (빅뱅 통합)&lt;/b&gt;: 모든 모듈을 한꺼번에 합쳐서 테스트한다. 간단하지만 결함 위치를 찾기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;점진적 방식&lt;/b&gt;: 모듈을 하나씩 추가하면서 테스트한다. 결함 추적이 쉬운 대신 시간이 걸린다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;하향식 통합&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;상위 &amp;rarr; 하위&lt;/td&gt;
&lt;td&gt;스텁(Stub)&lt;/td&gt;
&lt;td&gt;초기에 전체 구조 파악 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;상향식 통합&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;하위 &amp;rarr; 상위&lt;/td&gt;
&lt;td&gt;드라이버(Driver)&lt;/td&gt;
&lt;td&gt;하위 모듈을 클러스터로 묶어 통합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;혼합식 (샌드위치)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;양방향&lt;/td&gt;
&lt;td&gt;스텁 + 드라이버&lt;/td&gt;
&lt;td&gt;상위는 하향식, 하위는 상향식 동시 진행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방식 방향 대체 모듈 특징&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스텁(Stub)은 아직 구현되지 않은 하위 모듈을 임시로 대체하는 더미 코드다. 드라이버(Driver)는 반대로 테스트 대상 모듈을 호출해주는 역할을 하는 임시 코드다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# 스텁(Stub) 예시: 하위 모듈이 아직 없을 때 임시 대체
def calculate_tax(price):
    # 실제 구현 전, 고정값 반환으로 상위 모듈 테스트 가능하게
    return price * 0.1  # 스텁

# 드라이버(Driver) 예시: 하위 모듈만 완성됐을 때 호출해주는 임시 주체
def test_driver():
    result = calculate_discount(50000)  # 테스트 대상 하위 모듈 직접 호출
    print(f&quot;할인 금액: {result}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시스템 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완성된 소프트웨어 전체가 요구사항대로 작동하는지 점검한다. 기능뿐 아니라 성능, 보안, 호환성 같은 비기능 요건도 함께 검증한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인수 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 사용자가 요구사항 충족 여부를 최종 확인하는 단계다. 두 가지로 나뉜다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;알파 테스트&lt;/b&gt;: 사용자가 개발자 앞에서, 통제된 환경에서 테스트한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;베타 테스트&lt;/b&gt;: 사용자가 실제 업무 환경에서 직접 테스트한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 베타 테스트는 서비스 출시 직전 소수의 실제 사용자에게 먼저 배포해 피드백을 수집하는 과정과 일치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;5. 테스트 케이스, 시나리오, 오라클&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트 케이스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 항목에 대한 명세서다. 어떤 입력을 주고, 어떤 결과가 나와야 하는지를 사전에 정의해둔 문서라고 볼 수 있다. 테스트 케이스가 잘 작성되어 있어야 반복 가능한 테스트가 가능하고, 자동화도 용이해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트 시나리오&lt;/b&gt;는 테스트 케이스들을 논리적인 순서로 묶은 집합이다. &quot;로그인 &amp;rarr; 상품 검색 &amp;rarr; 장바구니 추가 &amp;rarr; 결제&quot; 같은 사용자 흐름 하나가 하나의 시나리오가 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트 오라클&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 결과가 올바른지 판단하는 기준이다. 사전에 정의된 참값을 대입해 실제 결과와 비교한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;참(True) 오라클&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;모든 입력에 대해 정확한 결과를 제공. 비용이 높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;샘플링 오라클&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;일부 입력값에 대해서만 결과를 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;휴리스틱 오라클&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;경험적으로 결과를 추정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;일관성 오라클&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;변경 전후 결과가 동일한지 확인 (회귀 테스트에 활용)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종류 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;6. 테스트 자동화 도구&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 자동화는 반복적인 회귀 테스트를 사람이 직접 수행하는 비용을 줄이고, 빌드 파이프라인에 통합해 지속적인 품질 관리를 가능하게 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;도구 분류&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정적 실행 도구&lt;/b&gt;: 코드를 실행하지 않고 코드 품질을 분석한다. SonarQube, PMD, Checkstyle이 대표적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트 실행 도구&lt;/b&gt;: 스크립트 언어로 작성된 테스트를 자동 실행한다. Selenium, JUnit 같은 도구가 여기에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;성능 테스트 도구&lt;/b&gt;: 처리량, 응답 시간, 자원 사용률을 측정한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JMeter&lt;/td&gt;
&lt;td&gt;다양한 프로토콜 지원 (HTTP, FTP, JDBC 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoadUI&lt;/td&gt;
&lt;td&gt;Drag &amp;amp; Drop 기반 UI로 편의성이 높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenSTA&lt;/td&gt;
&lt;td&gt;오픈소스 성능 테스트 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도구 특징&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트 통제 도구&lt;/b&gt;: 테스트 계획, 수행, 결과를 관리한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트 하네스(Test Harness)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트나 모듈을 테스트하기 위해 만들어진 코드와 데이터의 집합이다. 구성 요소는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;드라이버&lt;/b&gt;: 테스트 대상 모듈을 호출하는 임시 주체&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스텁&lt;/b&gt;: 아직 구현되지 않은 하위 모듈을 대체하는 더미&lt;/li&gt;
&lt;li&gt;&lt;b&gt;슈트(Suite)&lt;/b&gt;: 여러 테스트 케이스를 묶은 집합&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스크립트&lt;/b&gt;: 자동화 테스트 실행 코드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목 오브젝트(Mock Object)&lt;/b&gt;: 실제 객체를 흉내 내는 가짜 객체. 외부 API나 DB에 의존하지 않고 단위 테스트를 가능하게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# Mock 객체 활용 예시 (pytest-mock)
def get_user_from_db(user_id):
    # 실제로는 DB에서 조회하지만, 테스트에서는 Mock으로 대체
    pass

def test_user_service(mocker):
    mock_db = mocker.patch('myapp.get_user_from_db')
    mock_db.return_value = {&quot;id&quot;: 1, &quot;name&quot;: &quot;홍길동&quot;}

    result = user_service.get_user(1)
    assert result[&quot;name&quot;] == &quot;홍길동&quot;
    # DB 없이도 비즈니스 로직만 독립적으로 테스트 가능
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;7. 결함 관리&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결함이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 설계한 의도와 다르게 동작하거나 다른 결과가 발생하는 것을 결함이라 한다. 단순히 &quot;에러가 발생했다&quot;는 것과는 다르다. 기능이 동작하더라도 의도한 것과 다른 결과라면 결함에 해당한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결함 분류&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;분류 기준&lt;/b&gt;: 시스템 결함, 기능 결함, GUI 결함, 문서 결함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;심각도&lt;/b&gt;: High / Medium / Low 또는 Critical / Major / Normal / Minor / Simple&lt;/li&gt;
&lt;li&gt;&lt;b&gt;우선순위&lt;/b&gt;: Critical / High / Medium / Low 또는 즉시 해결 / 주의 요망 / 대기 / 개선 권고&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심각도와 우선순위는 다를 수 있다. 심각도가 낮은 결함이라도 고객에게 노출도가 높으면 우선순위가 올라갈 수 있고, 반대로 내부 시스템의 치명적 결함이 외부 영향이 적어 일정을 이유로 우선순위가 낮아지는 경우도 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결함 상태 추적&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결함은 발견 이후 상태를 지속적으로 추적하고 관리한다. 분포(어느 모듈에 얼마나 있는가), 추세(시간에 따라 늘고 있는가 줄고 있는가), 에이징(오래된 결함이 방치되고 있지 않은가)을 측정해 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;8. 복잡도와 코드 최적화&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;순환 복잡도 (Cyclomatic Complexity)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드의 논리적 복잡도를 수치로 나타낸 지표다. 값이 낮을수록 테스트하기 쉽고 유지보수가 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공식&lt;/b&gt;: V(G) = E - N + 2&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;E: 간선(Edge, 화살표) 수&lt;/li&gt;
&lt;li&gt;N: 노드(Node) 수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 V(G) &amp;le; 10이면 낮은 복잡도, 10~20은 보통, 20 이상이면 리팩터링을 고려하는 것이 좋다.&lt;/p&gt;
&lt;pre class=&quot;smali&quot;&gt;&lt;code&gt;예시: if/else 분기 2개가 있는 함수
노드 수 N = 5, 간선 수 E = 6 이라면
V(G) = 6 - 5 + 2 = 3
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;소스 코드 최적화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클린 코드로 작성하는 것이 최적화의 출발점이다. 클린 코드 작성 원칙은 다섯 가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가독성&lt;/b&gt;: 이름, 주석, 들여쓰기가 의도를 명확히 드러낸다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단순성&lt;/b&gt;: 한 번에 하나의 일만 한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의존성 배제&lt;/b&gt;: 다른 모듈의 변경이 이 코드에 영향을 주지 않는다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중복성 최소화&lt;/b&gt;: 동일한 로직이 여러 곳에 흩어지지 않는다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추상화&lt;/b&gt;: 세부 구현이 아닌 인터페이스 수준에서 통신한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나쁜 코드의 대표적인 유형도 알아두면 좋다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스파게티 코드&lt;/b&gt;: 로직이 서로 복잡하게 얽혀 어디서 무엇이 실행되는지 추적하기 어려운 코드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외계인 코드&lt;/b&gt;: 너무 오래되어 참고 문서나 원작자가 없어 수정 자체가 두려운 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;소스 코드 품질 분석 도구&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;정적 분석&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;SonarQube&lt;/td&gt;
&lt;td&gt;코드 품질, 버그, 보안 취약점 종합 대시보드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;정적 분석&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;PMD&lt;/td&gt;
&lt;td&gt;Java 중심 정적 분석, 불필요한 코드 탐지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;정적 분석&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;cppcheck&lt;/td&gt;
&lt;td&gt;C/C++ 전용 정적 분석&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;정적 분석&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Checkstyle&lt;/td&gt;
&lt;td&gt;Java 코딩 컨벤션 준수 여부 검사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;동적 분석&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Valgrind&lt;/td&gt;
&lt;td&gt;메모리 누수, 잘못된 메모리 접근 탐지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;동적 분석&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Avalanche&lt;/td&gt;
&lt;td&gt;런타임 결함 탐지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유형 도구 특징&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 분석은 코드를 실행하지 않고도 잠재적 버그를 찾아낸다. 빌드 파이프라인에 SonarQube를 연동하면 PR마다 코드 품질 리포트를 자동으로 받을 수 있다.&lt;/p&gt;</description>
      <category>Software</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/30</guid>
      <comments>https://revivalearth.tistory.com/entry/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%ED%85%8C%EC%8A%A4%ED%8A%B8#entry30comment</comments>
      <pubDate>Mon, 25 May 2026 12:50:27 +0900</pubDate>
    </item>
    <item>
      <title>웹 서버 및 프로그램 구조 이해 (Web / DB)</title>
      <link>https://revivalearth.tistory.com/entry/%EC%9B%B9-%EC%84%9C%EB%B2%84-%EB%B0%8F-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B5%AC%EC%A1%B0-%EC%9D%B4%ED%95%B4-Web-DB</link>
      <description>&lt;h1&gt;1. 개발 환경&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;하드웨어 환경 구성&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01_하드웨어환경구성.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYfxHl/dJMcaa6vS9J/nvlfwemD7OO6kcjtrVMWv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYfxHl/dJMcaa6vS9J/nvlfwemD7OO6kcjtrVMWv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYfxHl/dJMcaa6vS9J/nvlfwemD7OO6kcjtrVMWv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYfxHl%2FdJMcaa6vS9J%2FnvlfwemD7OO6kcjtrVMWv1%2Fimg.png&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;1520&quot; height=&quot;475&quot; data-filename=&quot;01_하드웨어환경구성.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 서버 환경은 크게 네 가지 역할로 나뉜다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구성 요소&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;실무 예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Web Server&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;HTTP 요청 처리, 정적 파일 반환&lt;/td&gt;
&lt;td&gt;Nginx, Apache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;WAS&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;동적 비즈니스 로직 처리&lt;/td&gt;
&lt;td&gt;Tomcat, Node.js&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DB Server&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터 영구 저장 및 조회&lt;/td&gt;
&lt;td&gt;PostgreSQL, MySQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;File Server&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;파일 저장소 역할&lt;/td&gt;
&lt;td&gt;NFS, S3(클라우드)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 이 네 가지를 반드시 물리적으로 분리하는 건 아니다. 소규모 서비스라면 Web Server와 WAS를 한 서버에서 함께 돌리기도 한다. 다만 트래픽이 커지면 각각을 분리해야 병목이 생기는 지점을 독립적으로 스케일링할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;웹 서버의 주요 기능&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서버는 단순히 &quot;요청을 받아 파일을 돌려주는 것&quot; 이상의 역할을 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP/HTTPS 지원&lt;/b&gt;: 보안 통신(TLS) 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;통신 기록(Logging)&lt;/b&gt;: 접근 로그, 에러 로그 관리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정적 파일 관리&lt;/b&gt;: HTML, CSS, 이미지 등 직접 반환 (WAS까지 안 보냄)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대역폭 제한&lt;/b&gt;: 트래픽 폭주 시 서버 보호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가상 호스팅&lt;/b&gt;: 하나의 서버 IP로 여러 도메인을 처리 (예: &lt;code&gt;a.com&lt;/code&gt;, &lt;code&gt;b.com&lt;/code&gt;을 같은 Nginx에서 분기)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인증&lt;/b&gt;: Basic Auth, SSL 인증서 기반 접근 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;소프트웨어 환경&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;soft.png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/we5dv/dJMcaciSLm3/4JZfd0R2fwXnkWIPvpctV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/we5dv/dJMcaciSLm3/4JZfd0R2fwXnkWIPvpctV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/we5dv/dJMcaciSLm3/4JZfd0R2fwXnkWIPvpctV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwe5dv%2FdJMcaciSLm3%2F4JZfd0R2fwXnkWIPvpctV0%2Fimg.png&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;1006&quot; height=&quot;594&quot; data-filename=&quot;soft.png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개발 언어 선정 기준&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암기용 키워드: &lt;b&gt;적효이친범&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;적&lt;/b&gt;정성: 개발 목적에 맞는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효&lt;/b&gt;율성: 처리 능력이 충분한가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이&lt;/b&gt;식성: 다른 환경에서도 동작하는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;친&lt;/b&gt;밀성: 개발팀이 익숙한가 (생산성과 직결)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;범&lt;/b&gt;용성: 커뮤니티/생태계가 충분한가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 친밀성과 범용성이 가장 현실적인 선택 기준이 된다. 아무리 성능이 좋은 언어라도 팀이 모르면 유지보수 비용이 급격히 올라간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;2. 개발 패턴과 방법&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;소프트웨어 아키텍처란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SW 아키텍처는 시스템을 구성하는 요소들이 어떻게 연결되고 상호작용하는지를 표현하는 구조다. 코드를 짜기 전에 &quot;어떤 구조로 만들 것인가&quot;를 결정하는 설계 단계에서 핵심 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;품질 속성은 세 가지 측면에서 바라본다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시스템 측면&lt;/b&gt;: 성능, 보안, 가용성, 안정성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비즈니스 측면&lt;/b&gt;: 출시 일정, 비용, 시장 요구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아키텍처 측면&lt;/b&gt;: 개념적 무결성, 정확성&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;아키텍처 설계 원칙&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모듈화&lt;/b&gt;는 시스템을 기능 단위로 쪼개는 것이다. 각 모듈이 독립적일수록 수정 시 파급 범위를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추상화&lt;/b&gt;는 큰 그림부터 그리고 점차 구체화하는 방식이다. 세 가지로 나뉜다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;과정 추상화: &quot;어떻게&quot;보다 &quot;무엇을&quot; 하는지에 집중 (함수 시그니처 정의)&lt;/li&gt;
&lt;li&gt;자료 추상화: 데이터 내부 구조를 숨김 (클래스, DTO)&lt;/li&gt;
&lt;li&gt;제어 추상화: 실행 흐름의 세부 내용을 숨김 (이벤트 루프, 스케줄러)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정보 은닉&lt;/b&gt;은 캡슐화와 연결되는 개념이다. 모듈 내부 구현을 외부에서 직접 접근하거나 수정하지 못하도록 막는다. 실무에서는 &lt;code&gt;private&lt;/code&gt; 메서드, 내부 패키지 분리, API 게이트웨이 같은 형태로 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단계적 분해&lt;/b&gt;는 상위 개념에서 하위 개념으로 순차적으로 구체화하는 Top-Down 접근 방식이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상위 설계 vs 하위 설계&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;다른 이름&lt;/th&gt;
&lt;th&gt;다루는 내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;상위 설계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;아키텍처 설계 / 예비 설계&lt;/td&gt;
&lt;td&gt;전체 구조, DB 스키마, 인터페이스 정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;하위 설계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;모듈 설계 / 상세 설계&lt;/td&gt;
&lt;td&gt;컴포넌트 내부, 자료구조, 알고리즘&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 설계가 &quot;건물의 평면도&quot;라면, 하위 설계는 &quot;각 방의 내부 도면&quot;에 해당한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;협약에 의한 설계 (Design by Contract)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트가 정상 동작하기 위한 조건을 명시적으로 계약처럼 기술하는 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;선행 조건(Precondition)&lt;/b&gt;: 이 함수를 호출하기 전에 만족해야 하는 조건 (예: 입력값이 null이 아닌 것)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과 조건(Postcondition)&lt;/b&gt;: 함수 실행 후 보장되는 상태 (예: 반환값은 항상 양수)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불변 조건(Invariant)&lt;/b&gt;: 실행 전후에 항상 유지되어야 하는 조건 (예: 리스트의 길이는 음수가 될 수 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def withdraw(account, amount):
    # 선행 조건
    assert amount &amp;gt; 0, &quot;출금액은 0보다 커야 한다&quot;
    assert account.balance &amp;gt;= amount, &quot;잔액이 부족하다&quot;

    account.balance -= amount

    # 결과 조건
    assert account.balance &amp;gt;= 0, &quot;잔액은 음수가 될 수 없다&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;아키텍처 패턴 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍처 패턴은 시스템 전체 구조를 어떻게 잡을지에 대한 검증된 해법이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02_아키텍처패턴.png&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;1262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCJFES/dJMcadvioeQ/7pkgmnBIXDSViFVrElS5P0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCJFES/dJMcadvioeQ/7pkgmnBIXDSViFVrElS5P0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCJFES/dJMcadvioeQ/7pkgmnBIXDSViFVrElS5P0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCJFES%2FdJMcadvioeQ%2F7pkgmnBIXDSViFVrElS5P0%2Fimg.png&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;1904&quot; height=&quot;1262&quot; data-filename=&quot;02_아키텍처패턴.png&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;1262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;패턴&lt;/th&gt;
&lt;th&gt;핵심 구조&lt;/th&gt;
&lt;th&gt;대표 사례&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;레이어&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;계층별로 역할 분리, 인접 계층만 통신&lt;/td&gt;
&lt;td&gt;Spring MVC (Presentation / Service / Repository)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;클라이언트-서버&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서버 1개 + 클라이언트 N개&lt;/td&gt;
&lt;td&gt;웹 서비스 대부분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;파이프-필터&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터가 필터를 순서대로 통과&lt;/td&gt;
&lt;td&gt;UNIX 쉘 파이프(`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MVC&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Model / View / Controller 분리&lt;/td&gt;
&lt;td&gt;Spring, Django, Rails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;마스터-슬레이브&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;마스터가 작업 분배, 슬레이브가 처리&lt;/td&gt;
&lt;td&gt;DB 복제, 분산 연산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;브로커&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;브로커가 서비스 요청자와 제공자를 중개&lt;/td&gt;
&lt;td&gt;Kafka, RabbitMQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;피어-투-피어&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;모든 노드가 클라이언트이자 서버&lt;/td&gt;
&lt;td&gt;BitTorrent, 블록체인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;이벤트-버스&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;퍼블리셔가 이벤트 발행, 구독자가 처리&lt;/td&gt;
&lt;td&gt;푸시 알림, AWS SNS+SQS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;블랙보드&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;공유 저장소에 모든 컴포넌트가 접근&lt;/td&gt;
&lt;td&gt;음성 인식, AI 추론 시스템&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;인터프리터&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기호/언어를 파싱해 실행&lt;/td&gt;
&lt;td&gt;SQL 파서, 스크립트 엔진&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시험 포인트&lt;/b&gt;: 파이프-필터의 대표 예시는 UNIX 쉘이다. 이벤트-버스는 퍼블리시/구독(Pub-Sub) 구조라는 점을 기억한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;3. 객체 지향&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 개념 한눈에&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향의 목표는 현실 세계의 사물을 소프트웨어 객체로 표현하고, 그 객체들이 서로 메시지를 주고받으며 동작하는 시스템을 만드는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;05_객체지향핵심개념.png&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2vzGL/dJMcai4r54D/fkB99SsK5VPeMAskhT94z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2vzGL/dJMcai4r54D/fkB99SsK5VPeMAskhT94z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2vzGL/dJMcai4r54D/fkB99SsK5VPeMAskhT94z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2vzGL%2FdJMcai4r54D%2FfkB99SsK5VPeMAskhT94z1%2Fimg.png&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;1396&quot; height=&quot;709&quot; data-filename=&quot;05_객체지향핵심개념.png&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개념&lt;/th&gt;
&lt;th&gt;한 줄 설명&lt;/th&gt;
&lt;th&gt;실무 연결&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;객체&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터 + 함수(메서드)의 묶음&lt;/td&gt;
&lt;td&gt;클래스의 인스턴스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;클래스&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;객체를 찍어내는 설계도&lt;/td&gt;
&lt;td&gt;&lt;code&gt;class User { ... }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;메시지&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;객체에게 동작을 요청하는 것&lt;/td&gt;
&lt;td&gt;메서드 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;캡슐화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;내부 구현 숨기고 인터페이스만 노출&lt;/td&gt;
&lt;td&gt;&lt;code&gt;private&lt;/code&gt; 필드 + getter/setter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;상속&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;부모 클래스의 속성/메서드를 물려받음&lt;/td&gt;
&lt;td&gt;&lt;code&gt;class Admin extends User&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;다형성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;같은 메서드 호출이 객체마다 다르게 동작&lt;/td&gt;
&lt;td&gt;오버라이딩, 인터페이스 구현&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;// 다형성 예시
interface Shape {
    double area();
}

class Circle implements Shape {
    double radius;
    public double area() { return Math.PI * radius * radius; }
}

class Rectangle implements Shape {
    double w, h;
    public double area() { return w * h; }
}

// 같은 area() 호출이지만 객체에 따라 다르게 동작
Shape s1 = new Circle();
Shape s2 = new Rectangle();
s1.area(); // 원 넓이
s2.area(); // 직사각형 넓이&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체 간 연관성&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;표현&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is member of&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;연관화 (상호 참조)&lt;/td&gt;
&lt;td&gt;학생이 동아리에 속함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is instance of&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;분류화 (같은 클래스의 인스턴스)&lt;/td&gt;
&lt;td&gt;홍길동은 User 클래스의 인스턴스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is part of&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;집단화 (전체-부분 관계)&lt;/td&gt;
&lt;td&gt;엔진은 자동차의 일부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;일반화 / 특수화&lt;/td&gt;
&lt;td&gt;관리자(Admin)는 사용자(User)다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체 지향 분석 방법론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험에서는 방법론별 키워드를 외우는 것이 핵심이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;럼바우&lt;/b&gt;: 객동기 (객체 모델링 / 동적 모델링 / 기능 모델링)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부치&lt;/b&gt;: 미시적 / 거시적 개발 프로세스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제이콥슨&lt;/b&gt;: 유스케이스 중심&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드와 요르돈&lt;/b&gt;: E-R 다이어그램 활용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Wirfs-Brock&lt;/b&gt;: 분석과 설계 구분 없이 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SOLID 원칙&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SOLID는 유지보수하기 좋은 객체 지향 설계를 위한 다섯 가지 원칙이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;06_SOLID원칙.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH3e3V/dJMcadaZ2st/7eSuNJfpllKLNJNNpQaHYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH3e3V/dJMcadaZ2st/7eSuNJfpllKLNJNNpQaHYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH3e3V/dJMcadaZ2st/7eSuNJfpllKLNJNNpQaHYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH3e3V%2FdJMcadaZ2st%2F7eSuNJfpllKLNJNNpQaHYk%2Fimg.png&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;1520&quot; height=&quot;709&quot; data-filename=&quot;06_SOLID원칙.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;원칙&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;핵심 내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;S&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;단일 책임 원칙 (SRP)&lt;/td&gt;
&lt;td&gt;클래스는 하나의 책임만 가져야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;O&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;개방-폐쇄 원칙 (OCP)&lt;/td&gt;
&lt;td&gt;확장에는 열려 있고, 수정에는 닫혀 있어야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;L&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;리스코프 치환 원칙 (LSP)&lt;/td&gt;
&lt;td&gt;자식 클래스는 부모 클래스를 대체할 수 있어야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;I&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;인터페이스 분리 원칙 (ISP)&lt;/td&gt;
&lt;td&gt;사용하지 않는 인터페이스에 의존하지 않아야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;D&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;의존 역전 원칙 (DIP)&lt;/td&gt;
&lt;td&gt;구체 클래스보다 추상(인터페이스)에 의존해야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;4. 모듈&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결합도와 응집도&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 품질을 평가하는 두 가지 축이다. 방향이 반대다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결합도는 낮을수록&lt;/b&gt;, &lt;b&gt;응집도는 높을수록&lt;/b&gt; 좋은 설계다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결합도 (낮은 것이 좋음): 자스제외공내&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1641&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3uYsI/dJMcajbbGUw/W851FoKzI2OV0wXkKgqyc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3uYsI/dJMcajbbGUw/W851FoKzI2OV0wXkKgqyc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3uYsI/dJMcajbbGUw/W851FoKzI2OV0wXkKgqyc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3uYsI%2FdJMcajbbGUw%2FW851FoKzI2OV0wXkKgqyc1%2Fimg.png&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;1641&quot; height=&quot;440&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1641&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;순서&lt;/th&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (낮음)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;자&lt;/b&gt;료(Data)&lt;/td&gt;
&lt;td&gt;단순 데이터 값만 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;b&gt;스&lt;/b&gt;탬프(Stamp)&lt;/td&gt;
&lt;td&gt;자료구조(객체, 배열 등)를 통째로 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;b&gt;제&lt;/b&gt;어(Control)&lt;/td&gt;
&lt;td&gt;제어 플래그를 전달해 상대 모듈의 흐름을 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;b&gt;외&lt;/b&gt;부(External)&lt;/td&gt;
&lt;td&gt;외부 모듈의 변수를 직접 참조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;b&gt;공&lt;/b&gt;통(Common)&lt;/td&gt;
&lt;td&gt;전역 변수 공유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 (높음)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;내&lt;/b&gt;용(Content)&lt;/td&gt;
&lt;td&gt;다른 모듈의 내부 코드/데이터를 직접 참조/수정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;응집도 (높은 것이 좋음)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1892&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sl20w/dJMcaaL95XA/AqAQab1btZmE5h00sK31e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sl20w/dJMcaaL95XA/AqAQab1btZmE5h00sK31e0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sl20w/dJMcaaL95XA/AqAQab1btZmE5h00sK31e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSl20w%2FdJMcaaL95XA%2FAqAQab1btZmE5h00sK31e0%2Fimg.png&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;1892&quot; height=&quot;458&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1892&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;순서&lt;/th&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (낮음)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;우&lt;/b&gt;연(Coincidental)&lt;/td&gt;
&lt;td&gt;아무 관계 없는 기능이 한 모듈에 묶임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;b&gt;논&lt;/b&gt;리(Logical)&lt;/td&gt;
&lt;td&gt;유사한 성격의 기능을 묶음 (같은 타입의 입출력 처리 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;b&gt;시&lt;/b&gt;간적(Temporal)&lt;/td&gt;
&lt;td&gt;특정 시점에 함께 실행되는 것들을 묶음 (초기화 루틴 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;b&gt;절&lt;/b&gt;차(Procedural)&lt;/td&gt;
&lt;td&gt;순서대로 실행되어야 하는 기능들을 묶음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;b&gt;교&lt;/b&gt;통(Communication)&lt;/td&gt;
&lt;td&gt;동일한 입출력 데이터를 다루는 기능들을 묶음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;b&gt;순&lt;/b&gt;차(Sequential)&lt;/td&gt;
&lt;td&gt;앞 기능의 출력이 다음 기능의 입력이 되는 파이프라인 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7 (높음)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;기&lt;/b&gt;능(Functional)&lt;/td&gt;
&lt;td&gt;단 하나의 명확한 기능만 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;팬인 / 팬아웃&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 구조도(구조 차트)에서 모듈 간 호출 관계를 나타내는 지표다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;팬인(Fan-in)&lt;/b&gt;: 해당 모듈을 호출하는 모듈의 수 (들어오는 화살표)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;팬아웃(Fan-out)&lt;/b&gt;: 해당 모듈이 호출하는 모듈의 수 (나가는 화살표)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팬아웃이 너무 높으면 그 모듈이 너무 많은 책임을 지고 있다는 신호다. 반대로 팬인이 높은 모듈은 재사용성이 높은 핵심 모듈일 가능성이 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;IPC (Inter-Process Communication)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 또는 프로세스 간에 데이터를 주고받는 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;07_IPC통신방법.png&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnsIc2/dJMb997zCwp/Nlo0zzR7A0FZrK8RkQPIwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnsIc2/dJMb997zCwp/Nlo0zzR7A0FZrK8RkQPIwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnsIc2/dJMb997zCwp/Nlo0zzR7A0FZrK8RkQPIwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnsIc2%2FdJMb997zCwp%2FNlo0zzR7A0FZrK8RkQPIwk%2Fimg.png&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;1396&quot; height=&quot;648&quot; data-filename=&quot;07_IPC통신방법.png&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방법&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;공유 메모리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;빠르지만 동기화 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;소켓&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;네트워크 기반, 원격 통신 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;세마포어&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;동시 접근 제어(잠금 역할)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;파이프 / 네임드 파이프&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;단방향 / 양방향 데이터 스트림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;메시지 큐&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;비동기 메시지 전달 (Kafka, RabbitMQ의 원형)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;5. 테스트와 코드&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트 케이스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 케이스는 소프트웨어가 요구사항을 제대로 만족하는지 확인하기 위한 시험 항목 명세서다. 단순히 &quot;실행해서 오류 없으면 OK&quot;가 아니라, 어떤 입력에 어떤 결과가 나와야 하는지를 사전에 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 모듈 명세 기법의 기준은 다섯 가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정확성&lt;/b&gt;: 실제로 구현 가능한 내용인가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명확성&lt;/b&gt;: 이중 해석의 여지 없이 단일하게 이해되는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;완전성&lt;/b&gt;: 시스템이 갖춰야 할 모든 것을 기술했는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일관성&lt;/b&gt;: 다른 명세와 충돌하지 않는가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추적성&lt;/b&gt;: 요구사항의 출처와 이유를 역추적할 수 있는가&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;재사용 단위&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단위&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;함수 / 객체&lt;/td&gt;
&lt;td&gt;가장 작은 재사용 단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;컴포넌트&lt;/td&gt;
&lt;td&gt;독립적으로 배포 가능한 기능 묶음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;애플리케이션&lt;/td&gt;
&lt;td&gt;전체 시스템을 통째로 재활용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드 체계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 데이터를 식별하고 분류하기 위한 기호 체계다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드 종류&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;순차 코드&lt;/td&gt;
&lt;td&gt;1, 2, 3, 4&lt;/td&gt;
&lt;td&gt;단순 일련번호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;블록 코드&lt;/td&gt;
&lt;td&gt;1001~1100&lt;/td&gt;
&lt;td&gt;범위로 구분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10진 코드&lt;/td&gt;
&lt;td&gt;1000: 공학, 2000: 문학&lt;/td&gt;
&lt;td&gt;십진 분류법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;그룹 분류 코드&lt;/td&gt;
&lt;td&gt;1-01-001: 본사-총무부-인사계&lt;/td&gt;
&lt;td&gt;계층 구조 표현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;연상 코드&lt;/td&gt;
&lt;td&gt;TV-40: 40인치 TV&lt;/td&gt;
&lt;td&gt;의미를 직관적으로 표현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;표의 숫자 코드&lt;/td&gt;
&lt;td&gt;120-720-1500: 두께&amp;times;폭&amp;times;길이&lt;/td&gt;
&lt;td&gt;수치 자체가 의미를 가짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;합성 코드&lt;/td&gt;
&lt;td&gt;KE-711: 대한항공 711편&lt;/td&gt;
&lt;td&gt;두 가지 이상 코드 결합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;6. 디자인 패턴&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자인 패턴은 모듈 간 관계 및 인터페이스 설계에서 자주 반복되는 문제에 대한 검증된 해법이다. GoF(Gang of Four) 패턴이 가장 많이 쓰인다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;생성 패턴 (객체를 어떻게 만들 것인가)&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;패턴&lt;/th&gt;
&lt;th&gt;핵심&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;추상 팩토리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;관련 객체 그룹을 묶어서 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;빌더&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;복잡한 객체를 단계별로 조립&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;팩토리 메소드&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;객체 생성을 서브 클래스에 위임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;프로토타입&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기존 객체를 복제해서 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;싱글톤&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;인스턴스를 딱 하나만 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구조 패턴 (객체를 어떻게 조합할 것인가)&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;패턴&lt;/th&gt;
&lt;th&gt;핵심&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;어댑터&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;호환되지 않는 인터페이스를 변환 (플러그 변환기와 같은 원리)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;브리지&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기능과 구현을 분리해 독립적으로 확장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;컴포지트&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;단일 객체와 복합 객체를 동일하게 다룸 (트리 구조)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;퍼사드&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;복잡한 서브시스템에 단순한 인터페이스 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;플라이웨이트&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;유사 객체를 공유해 메모리 절약&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;프록시&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;실제 객체 앞에 대리 객체를 두어 접근 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행위 패턴은 이 자료의 범위에서는 생략한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;7. 기타: 프레임워크와 배치&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버 개발 프레임워크&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 서버 사이드 프레임워크는 MVC 구조를 기반으로 한다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;프레임워크&lt;/th&gt;
&lt;th&gt;언어&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Spring&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;국내 엔터프라이즈 환경에서 가장 널리 쓰임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Django&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;빠른 개발, 배터리 포함 철학&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Ruby on Rails&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Ruby&lt;/td&gt;
&lt;td&gt;CoC(설정보다 관례) 원칙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CodeIgniter&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;PHP&lt;/td&gt;
&lt;td&gt;경량 PHP 프레임워크&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;API와 Open API&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API(Application Programming Interface)는 라이브러리나 서비스를 외부에서 사용할 수 있도록 규칙을 정의한 인터페이스다. 그 중 외부에 공개된 것을 Open API라고 부른다. 카카오 지도 API, 기상청 날씨 API 등이 대표적이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배치 프로그램&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치는 &quot;정해진 시간에 대량의 데이터를 자동으로 처리&quot;하는 프로그램이다. 실시간으로 처리하기 부담스러운 작업을 새벽 시간대에 몰아서 처리하는 방식으로 많이 쓰인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 프로그램이 갖춰야 할 요소 다섯 가지:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대용량 데이터&lt;/b&gt; 처리 능력&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동화&lt;/b&gt;: 사람이 개입하지 않아도 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;견고성&lt;/b&gt;: 예외 상황에서도 비정상 종료 없이 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;안정성 / 신뢰성&lt;/b&gt;: 중복 실행, 누락 없이 정확하게 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능&lt;/b&gt;: 정해진 시간 내에 완료&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 스케줄러는 세 가지를 기억한다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;스케줄러&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Spring Batch&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Java 기반, 대규모 배치 처리 표준 프레임워크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Quartz&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Java 기반, 유연한 스케줄링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Cron&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Unix/Linux 기반, 시간 기반 작업 자동화 (&lt;code&gt;0 0 * * *&lt;/code&gt; 형태의 표현식)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# Cron 표현식 예시
# 분 시 일 월 요일
0 2 * * *    # 매일 새벽 2시에 실행
0 9 * * 1    # 매주 월요일 오전 9시에 실행
0 0 1 * *    # 매월 1일 자정에 실행&lt;/code&gt;&lt;/pre&gt;</description>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/29</guid>
      <comments>https://revivalearth.tistory.com/entry/%EC%9B%B9-%EC%84%9C%EB%B2%84-%EB%B0%8F-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B5%AC%EC%A1%B0-%EC%9D%B4%ED%95%B4-Web-DB#entry29comment</comments>
      <pubDate>Mon, 25 May 2026 12:05:39 +0900</pubDate>
    </item>
    <item>
      <title>데이터와 DBMS 핵심 정리</title>
      <link>https://revivalearth.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-DBMS-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC</link>
      <description>&lt;h1&gt;1. 데이터 전환과 검증&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 전환이란 기존 시스템의 데이터를 추출해 새 정보 시스템이 운영할 수 있는 형태로 변환한 뒤 적재하는 전 과정을 말한다. 단순 복사가 아니라 구조 변환과 품질 검증까지 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 검증&lt;/b&gt;은 원본 데이터가 목적 시스템에 정상적으로 옮겨졌는지 확인하는 단계다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류 데이터 처리는 아래 순서로 진행한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터 품질 분석&lt;/li&gt;
&lt;li&gt;오류 데이터 측정&lt;/li&gt;
&lt;li&gt;오류 데이터 정제&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;2. 데이터베이스&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기본 개념&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스는 공동으로 사용될 데이터를 중복 없이 통합하고, 저장 장치에 보관하여 항상 접근 가능하도록 운영하는 데이터 집합이다. 네 가지 특성으로 요약된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;통합된 데이터&lt;/b&gt;: 중복을 제거하여 하나로 관리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저장된 데이터&lt;/b&gt;: 물리적 저장 매체에 보관&lt;/li&gt;
&lt;li&gt;&lt;b&gt;운영 데이터&lt;/b&gt;: 조직의 업무 수행에 반드시 필요한 데이터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공용 데이터&lt;/b&gt;: 여러 사용자가 함께 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS는 사용자 요구에 따라 데이터를 생성하고 데이터베이스를 관리하는 소프트웨어다. 세 가지 기능을 제공한다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;언어&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;정의 기능&lt;/td&gt;
&lt;td&gt;DDL&lt;/td&gt;
&lt;td&gt;구조 생성&amp;middot;변경&amp;middot;삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;조작 기능&lt;/td&gt;
&lt;td&gt;DML&lt;/td&gt;
&lt;td&gt;데이터 삽입&amp;middot;조회&amp;middot;수정&amp;middot;삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제어 기능&lt;/td&gt;
&lt;td&gt;DCL&lt;/td&gt;
&lt;td&gt;접근 권한&amp;middot;무결성&amp;middot;보안&amp;middot;회복&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스키마 3단계 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스키마는 데이터베이스의 구조와 제약 조건에 관한 전반적인 명세다. 외부&amp;middot;개념&amp;middot;내부 3단계로 나뉜다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02_schema_3tier.png&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bikOuO/dJMcab5oahA/gdrLcY7QBx0Mq9JBDkYxlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bikOuO/dJMcab5oahA/gdrLcY7QBx0Mq9JBDkYxlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bikOuO/dJMcab5oahA/gdrLcY7QBx0Mq9JBDkYxlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbikOuO%2FdJMcab5oahA%2FgdrLcY7QBx0Mq9JBDkYxlk%2Fimg.png&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;427&quot; height=&quot;440&quot; data-filename=&quot;02_schema_3tier.png&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;외부 스키마&lt;/b&gt;: 각 사용자가 필요로 하는 DB의 논리적 구조 정의. 여러 개 존재 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개념 스키마&lt;/b&gt;: DB 전체의 논리적 구조. 조직 전체의 관점. 단 하나만 존재.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내부 스키마&lt;/b&gt;: 물리적 저장 장치 관점의 DB 구조. 실제 저장 방식을 기술.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DB 설계 순서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요구 조건 분석부터 구현까지 5단계로 진행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01_db_design_process.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cO1a7x/dJMcahkhKwz/j532EbyQaWMJhCkWtLsMqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cO1a7x/dJMcahkhKwz/j532EbyQaWMJhCkWtLsMqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cO1a7x/dJMcahkhKwz/j532EbyQaWMJhCkWtLsMqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcO1a7x%2FdJMcahkhKwz%2Fj532EbyQaWMJhCkWtLsMqk%2Fimg.png&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;1568&quot; height=&quot;482&quot; data-filename=&quot;01_db_design_process.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;핵심 활동&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;요구 조건 분석&lt;/td&gt;
&lt;td&gt;사용자 요구 파악&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;개념적 설계&lt;/td&gt;
&lt;td&gt;현실을 추상적 개념으로 표현. E-R 모델 작성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;논리적 설계&lt;/td&gt;
&lt;td&gt;DBMS가 지원하는 구조로 변환 (Mapping)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;물리적 설계&lt;/td&gt;
&lt;td&gt;논리 구조를 물리 구조로 변환. 저장 방식 결정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;구현&lt;/td&gt;
&lt;td&gt;SQL로 실제 DB 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;E-R 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실 세계의 데이터를 개념적 논리 구조로 표현하기 위한 모델이다. 아래 기호를 사용한다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기호&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;사각형&lt;/td&gt;
&lt;td&gt;개체(Entity)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;마름모&lt;/td&gt;
&lt;td&gt;관계(Relationship)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;타원&lt;/td&gt;
&lt;td&gt;속성(Attribute)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이중 타원&lt;/td&gt;
&lt;td&gt;다중값 속성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;밑줄 타원&lt;/td&gt;
&lt;td&gt;기본키 속성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;복수 타원&lt;/td&gt;
&lt;td&gt;복합 속성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선/링크&lt;/td&gt;
&lt;td&gt;연결&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개체(Entity)는 DB에 표현하려는 현실 세계의 대상체로, 유일한 식별자로 구분된다. 관계는 개체 간의 연관성을 나타내며 1:1, 1:N, N:M 세 가지로 구분한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;릴레이션 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계형 DB에서 테이블(릴레이션)을 구성하는 요소들이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;┌──────┬────────┬──────┬──────────┐  &amp;larr; 릴레이션 스키마 (속성의 집합)
│ 학번 │  이름  │ 학년 │  전공    │
├──────┼────────┼──────┼──────────┤
│ 1001 │ 홍길동 │  2   │ 컴퓨터   │  &amp;larr; 튜플 (행 하나)
│ 1002 │ 이순신 │  3   │ 소프트웨어│  &amp;larr; 튜플
└──────┴────────┴──────┴──────────┘
  &amp;uarr; 속성(Attribute) / 도메인: 각 속성이 취할 수 있는 값의 집합&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;카디널리티(기수)&lt;/b&gt;: 튜플의 수 (행의 수)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디그리(차수)&lt;/b&gt;: 속성의 수 (열의 수)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;키의 종류&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;03_key_hierarchy.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1052&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDv97J/dJMcaaSXTaW/8GcqgqKMKYztY9kjbephg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDv97J/dJMcaaSXTaW/8GcqgqKMKYztY9kjbephg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDv97J/dJMcaaSXTaW/8GcqgqKMKYztY9kjbephg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDv97J%2FdJMcaaSXTaW%2F8GcqgqKMKYztY9kjbephg1%2Fimg.png&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;516&quot; height=&quot;464&quot; data-filename=&quot;03_key_hierarchy.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1052&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;후보키&lt;/b&gt;: 유일성 + 최소성 모두 만족&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본키&lt;/b&gt;: 후보키 중 대표로 선택한 키. Not Null, 중복 불가.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대체키&lt;/b&gt;: 기본키로 선택되지 않은 나머지 후보키&lt;/li&gt;
&lt;li&gt;&lt;b&gt;슈퍼키&lt;/b&gt;: 유일성은 만족하지만 최소성은 만족하지 않는 키&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외래키&lt;/b&gt;: 다른 릴레이션의 기본키를 참조하는 속성&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무결성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 정확성과 일관성을 유지하기 위한 제약 조건이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개체 무결성&lt;/b&gt;: 기본키는 NULL이 될 수 없고, 중복될 수 없다.&lt;br /&gt;&lt;b&gt;참조 무결성&lt;/b&gt;: 외래키 값은 NULL이거나, 참조하는 릴레이션의 기본키 값과 동일해야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;-- 개체 무결성 예시
CREATE TABLE Student (
    student_id INT PRIMARY KEY,  -- NOT NULL + UNIQUE 자동 적용
    name       VARCHAR(50)
);

-- 참조 무결성 예시
CREATE TABLE Enrollment (
    enroll_id  INT PRIMARY KEY,
    student_id INT,
    FOREIGN KEY (student_id) REFERENCES Student(student_id)
    -- Student 테이블에 없는 student_id는 삽입 불가
);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;관계 대수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 데이터를 어떻게 유도할지 절차적으로 기술하는 언어다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산자&lt;/th&gt;
&lt;th&gt;기호&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Select&lt;/td&gt;
&lt;td&gt;&amp;sigma; (시그마)&lt;/td&gt;
&lt;td&gt;조건을 만족하는 튜플 추출 (수평 연산)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project&lt;/td&gt;
&lt;td&gt;&amp;pi; (파이)&lt;/td&gt;
&lt;td&gt;원하는 속성만 추출 (수직 연산)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Join&lt;/td&gt;
&lt;td&gt;⋈&lt;/td&gt;
&lt;td&gt;두 릴레이션을 결합 (카티션 프로덕트 + 셀렉트)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Division&lt;/td&gt;
&lt;td&gt;&amp;divide;&lt;/td&gt;
&lt;td&gt;R &amp;divide; S: R에서 S의 속성을 제외한 나머지를 구함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;합집합&lt;/td&gt;
&lt;td&gt;&amp;cup;&lt;/td&gt;
&lt;td&gt;두 릴레이션의 합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;교집합&lt;/td&gt;
&lt;td&gt;&amp;cap;&lt;/td&gt;
&lt;td&gt;두 릴레이션의 공통 튜플&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;차집합&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;R에서 S에 있는 튜플 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;교차곱&lt;/td&gt;
&lt;td&gt;&amp;times;&lt;/td&gt;
&lt;td&gt;모든 가능한 튜플의 조합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;-- Select (&amp;sigma;): 학년이 2인 학생만 조회
SELECT * FROM Student WHERE grade = 2;

-- Project (&amp;pi;): 이름과 전공만 조회
SELECT name, major FROM Student;

-- Join (⋈): 두 테이블 결합
SELECT * FROM Student JOIN Enrollment
    ON Student.student_id = Enrollment.student_id;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이상(Anomaly)과 정규화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화되지 않은 테이블에서는 삽입&amp;middot;삭제&amp;middot;갱신 시 이상 현상이 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;삽입 이상&lt;/b&gt;: 불필요한 데이터를 함께 입력해야만 삽입 가능한 현상&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 이상&lt;/b&gt;: 하나의 데이터를 삭제하면 관련 없는 데이터도 함께 사라지는 현상&lt;/li&gt;
&lt;li&gt;&lt;b&gt;갱신 이상&lt;/b&gt;: 일부 튜플만 수정되어 데이터 불일치가 생기는 현상&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화는 이 이상 현상을 단계적으로 제거하는 과정이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;04_normalization.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biikNR/dJMcahkhKBh/xqdaIpJVEFCrDFQ1kAleH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biikNR/dJMcahkhKBh/xqdaIpJVEFCrDFQ1kAleH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biikNR/dJMcahkhKBh/xqdaIpJVEFCrDFQ1kAleH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiikNR%2FdJMcahkhKBh%2FxqdaIpJVEFCrDFQ1kAleH0%2Fimg.png&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;1568&quot; height=&quot;96&quot; data-filename=&quot;04_normalization.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;조건&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;제 1 정규형 (1NF)&lt;/td&gt;
&lt;td&gt;모든 도메인이 원자값(더 이상 분해 불가)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제 2 정규형 (2NF)&lt;/td&gt;
&lt;td&gt;1NF + 부분 함수 종속 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제 3 정규형 (3NF)&lt;/td&gt;
&lt;td&gt;2NF + 이행적 함수 종속 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BCNF&lt;/td&gt;
&lt;td&gt;3NF + 결정자이면서 후보키가 아닌 속성 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제 4 정규형 (4NF)&lt;/td&gt;
&lt;td&gt;BCNF + 다치 종속 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제 5 정규형 (5NF)&lt;/td&gt;
&lt;td&gt;4NF + 조인 종속성 이용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수 종속&lt;/b&gt;: 속성 A의 값이 결정되면 속성 B의 값도 결정될 때, B는 A에 함수적으로 종속된다고 한다. (A &amp;rarr; B)&lt;br /&gt;&lt;b&gt;이행적 함수 종속&lt;/b&gt;: A &amp;rarr; B이고 B &amp;rarr; C이면, A &amp;rarr; C가 성립하는 관계.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;반정규화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화된 모델을 의도적으로 역행시켜 성능을 높이는 기법이다. 조회 성능이 중요한 상황에서 쓰인다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;중복 테이블 추가&lt;/b&gt;: 자주 조인하는 테이블을 미리 합쳐서 별도로 관리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;집계 테이블 추가&lt;/b&gt;: 합계&amp;middot;평균 같은 집계 데이터를 위한 테이블 생성 + 트리거로 자동 갱신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;진행 테이블 추가&lt;/b&gt;: 이력 관리 목적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특정 부분 테이블 추가&lt;/b&gt;: 조건에 해당하는 행만 별도 테이블로 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시스템 카탈로그&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 내 다양한 객체(테이블, 뷰, 인덱스, 사용자 등)에 관한 메타데이터를 담는 시스템 DB다. DBMS가 자동으로 관리하며, 사용자는 조회만 가능하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;트랜잭션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리적 기능을 수행하기 위한 작업 단위로, 한꺼번에 모두 수행되어야 할 일련의 연산이다. 네 가지 특성(ACID)을 가진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;08_acid.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CPs4E/dJMcacwt2B8/8RQfqOs7WefozJ95VXc3S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CPs4E/dJMcacwt2B8/8RQfqOs7WefozJ95VXc3S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CPs4E/dJMcacwt2B8/8RQfqOs7WefozJ95VXc3S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCPs4E%2FdJMcacwt2B8%2F8RQfqOs7WefozJ95VXc3S1%2Fimg.png&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;1568&quot; height=&quot;436&quot; data-filename=&quot;08_acid.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;특성&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;원자성 (Atomicity)&lt;/td&gt;
&lt;td&gt;모두 실행되거나, 모두 실행되지 않아야 한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일관성 (Consistency)&lt;/td&gt;
&lt;td&gt;트랜잭션 완료 후에도 DB는 일관된 상태를 유지한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;독립성 (Isolation)&lt;/td&gt;
&lt;td&gt;트랜잭션 수행 중 다른 트랜잭션이 끼어들 수 없다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;영속성 (Durability)&lt;/td&gt;
&lt;td&gt;완료된 트랜잭션 결과는 영구 반영된다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;-- 트랜잭션 예시: 계좌 이체
BEGIN TRANSACTION;
    UPDATE Account SET balance = balance - 10000 WHERE id = 'A';
    UPDATE Account SET balance = balance + 10000 WHERE id = 'B';
COMMIT;  -- 둘 다 성공해야 반영
-- 중간에 오류 발생 시 ROLLBACK으로 전체 취소&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CRUD 분석&lt;/b&gt;은 프로세스와 테이블 간의 Create&amp;middot;Read&amp;middot;Update&amp;middot;Delete 관계를 매트릭스로 정리해 트랜잭션 패턴을 파악하는 기법이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인덱스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 레코드에 빠르게 접근하기 위해 &lt;code&gt;&amp;lt;키 값, 포인터&amp;gt;&lt;/code&gt; 쌍으로 구성하는 데이터 구조다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;클러스터드 인덱스&lt;/td&gt;
&lt;td&gt;키 순서에 따라 데이터 자체도 물리적으로 정렬. 테이블당 1개만 가능.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;넌 클러스터드 인덱스&lt;/td&gt;
&lt;td&gt;키 값만 정렬. 실제 데이터 위치는 포인터로 참조. 여러 개 생성 가능.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;뷰 (View)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나 이상의 기본 테이블로부터 유도된 가상 테이블이다. 실제 데이터를 저장하지 않고 쿼리 결과를 논리적으로 보여준다. &lt;code&gt;CREATE VIEW&lt;/code&gt;와 &lt;code&gt;DROP VIEW&lt;/code&gt;로 관리한다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;-- 뷰 생성 예시
CREATE VIEW cs_students AS
    SELECT name, grade FROM Student WHERE major = '컴퓨터';

-- 뷰 조회 (일반 테이블처럼 사용)
SELECT * FROM cs_students;

-- 뷰 삭제
DROP VIEW cs_students;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;파티션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대용량 테이블이나 인덱스를 작은 논리 단위로 나누는 기법이다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;적합한 경우&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;범위 분할&lt;/td&gt;
&lt;td&gt;값의 범위 기준으로 분할&lt;/td&gt;
&lt;td&gt;월별&amp;middot;일별 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;해시 분할&lt;/td&gt;
&lt;td&gt;해시 함수로 균등 분산&lt;/td&gt;
&lt;td&gt;고객번호&amp;middot;주민번호처럼 데이터가 고른 컬럼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;조합 분할&lt;/td&gt;
&lt;td&gt;범위 분할 후 다시 해시 함수 적용&lt;/td&gt;
&lt;td&gt;두 기준을 혼합해야 하는 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;분산 데이터베이스의 투명성 목표&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분산 환경에서 사용자가 내부 구조를 의식하지 않아도 되도록 보장하는 4가지 목표다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;목표&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;위치 투명성&lt;/td&gt;
&lt;td&gt;데이터가 어디 있는지 몰라도 논리적 명칭으로 접근 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;중복 투명성&lt;/td&gt;
&lt;td&gt;데이터가 여러 곳에 복제되어 있어도 하나처럼 보임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;병행 투명성&lt;/td&gt;
&lt;td&gt;다수 트랜잭션이 동시에 실행되어도 결과에 영향 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;장애 투명성&lt;/td&gt;
&lt;td&gt;일부 노드에 장애가 생겨도 트랜잭션이 정상 처리됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;3. 데이터 복구 및 보안&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RTO / RPO&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장애 발생 시 복구 목표를 정량화하는 두 가지 지표다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;RTO&lt;/b&gt; (Recovery Time Objective, 목표 복구 시간): 장애 발생 후 시스템이 정상 복구되기까지 허용되는 최대 시간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RPO&lt;/b&gt; (Recovery Point Objective, 목표 복구 시점): 장애 발생 시 어느 시점의 데이터까지 복구할 수 있어야 하는지의 기준&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RTO가 짧을수록 빠른 복구를 보장해야 하고, RPO가 짧을수록 최신 데이터에 가깝게 복구해야 한다. 두 값이 모두 작을수록 복구 인프라 비용은 올라간다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;암호화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평문을 암호화(Encryption)하여 보호하고, 필요 시 복호화(Decryption)하여 원래 값을 복원하는 방식이다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;키 구조&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;개인키 암호화 (대칭키)&lt;/td&gt;
&lt;td&gt;암호화&amp;middot;복호화에 같은 키 사용&lt;/td&gt;
&lt;td&gt;속도 빠름. 키 배포 문제 있음.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공개키 암호화 (비대칭키)&lt;/td&gt;
&lt;td&gt;공개키로 암호화, 개인키로 복호화&lt;/td&gt;
&lt;td&gt;키 배포 안전. 속도 느림.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;접근 통제&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;영문&lt;/th&gt;
&lt;th&gt;기준&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;임의 접근 통제&lt;/td&gt;
&lt;td&gt;DAC (Discretionary AC)&lt;/td&gt;
&lt;td&gt;사용자 신원에 따라 접근 권한 부여&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;강제 접근 통제&lt;/td&gt;
&lt;td&gt;MAC (Mandatory AC)&lt;/td&gt;
&lt;td&gt;주체와 객체의 보안 등급 비교 후 접근 허용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;역할 기반 접근 통제&lt;/td&gt;
&lt;td&gt;RBAC (Role-Based AC)&lt;/td&gt;
&lt;td&gt;사용자의 역할에 따라 권한 부여&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스토리지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대용량 데이터를 저장하기 위해 서버와 저장 장치를 연결하는 기술이다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;연결 방식&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DAS (Direct Attached Storage)&lt;/td&gt;
&lt;td&gt;전용 케이블로 직접 연결&lt;/td&gt;
&lt;td&gt;단순하지만 공유 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NAS (Network Attached Storage)&lt;/td&gt;
&lt;td&gt;네트워크를 통해 연결&lt;/td&gt;
&lt;td&gt;파일 공유에 유리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SAN (Storage Area Network)&lt;/td&gt;
&lt;td&gt;별도 전용 네트워크 구성&lt;/td&gt;
&lt;td&gt;DAS의 속도 + NAS의 공유 장점 혼합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;4. 자료구조&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;선형 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 일렬로 나열된 구조다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;자료구조&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;배열&lt;/td&gt;
&lt;td&gt;크기와 형이 동일. 인덱스로 접근. 정적 자료구조.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선형 리스트&lt;/td&gt;
&lt;td&gt;순서 있는 연속 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스택&lt;/td&gt;
&lt;td&gt;LIFO (Last In, First Out). 함수 호출 스택, 괄호 검사 등에 활용.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;큐&lt;/td&gt;
&lt;td&gt;FIFO (First In, First Out). 프린터 스풀, 프로세스 스케줄링 등에 활용.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데크 (Deque)&lt;/td&gt;
&lt;td&gt;양쪽 끝에서 삽입&amp;middot;삭제 모두 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 스택 (LIFO)
stack = []
stack.append(1)  # push
stack.append(2)
stack.append(3)
print(stack.pop())  # 3 &amp;mdash; 마지막에 넣은 것이 먼저 나옴

# 큐 (FIFO)
from collections import deque
queue = deque()
queue.append(1)  # enqueue
queue.append(2)
queue.append(3)
print(queue.popleft())  # 1 &amp;mdash; 처음에 넣은 것이 먼저 나옴&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비선형 구조&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그래프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정점(Vertex)과 간선(Edge)으로 구성된 자료구조다. 방향&amp;middot;무방향 그래프로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 간선 수:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;방향 그래프: N(N-1)&lt;/li&gt;
&lt;li&gt;무방향 그래프: N(N-1) / 2&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이클이 없는 그래프다. 계층적 구조를 표현하는 데 적합하다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;용어&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;루트 노드&lt;/td&gt;
&lt;td&gt;트리의 최상위 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;디그리&lt;/td&gt;
&lt;td&gt;각 노드에서 뻗어나온 가지(자식)의 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;단말 노드&lt;/td&gt;
&lt;td&gt;자식이 없는 노드 (리프 노드)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;레벨&lt;/td&gt;
&lt;td&gt;루트 노드가 레벨 1, 아래로 내려갈수록 증가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;깊이&lt;/td&gt;
&lt;td&gt;트리에서 노드가 가질 수 있는 최대 레벨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이진 트리 순회 3가지&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;05_tree_traversal.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4j0N1/dJMcabj31aV/oPU2wbIJNqKtnKIev7k8D1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4j0N1/dJMcabj31aV/oPU2wbIJNqKtnKIev7k8D1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4j0N1/dJMcabj31aV/oPU2wbIJNqKtnKIev7k8D1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4j0N1%2FdJMcabj31aV%2FoPU2wbIJNqKtnKIev7k8D1%2Fimg.png&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;1568&quot; height=&quot;608&quot; data-filename=&quot;05_tree_traversal.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;순회&lt;/th&gt;
&lt;th&gt;순서&lt;/th&gt;
&lt;th&gt;위 트리 결과&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Preorder (전위)&lt;/td&gt;
&lt;td&gt;루트 &amp;rarr; 왼 &amp;rarr; 오른&lt;/td&gt;
&lt;td&gt;A B D E C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inorder (중위)&lt;/td&gt;
&lt;td&gt;왼 &amp;rarr; 루트 &amp;rarr; 오른&lt;/td&gt;
&lt;td&gt;D B E A C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postorder (후위)&lt;/td&gt;
&lt;td&gt;왼 &amp;rarr; 오른 &amp;rarr; 루트&lt;/td&gt;
&lt;td&gt;D E B C A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;class Node:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

def preorder(node):
    if node:
        print(node.val, end=' ')  # 루트
        preorder(node.left)        # 왼
        preorder(node.right)       # 오른

def inorder(node):
    if node:
        inorder(node.left)         # 왼
        print(node.val, end=' ')  # 루트
        inorder(node.right)        # 오른

def postorder(node):
    if node:
        postorder(node.left)       # 왼
        postorder(node.right)      # 오른
        print(node.val, end=' ')  # 루트&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정렬 알고리즘&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 정렬 개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬(Sort)은 데이터를 특정 기준에 따라 순서대로 나열하는 연산이다. 알고리즘마다 시간 복잡도, 공간 복잡도, 안정성이 다르기 때문에 상황에 따라 선택 기준이 달라진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01_sort_taxonomy.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YGsls/dJMcahEu8fw/gWb5nMKWmcyOSCOtKxogm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YGsls/dJMcahEu8fw/gWb5nMKWmcyOSCOtKxogm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YGsls/dJMcahEu8fw/gWb5nMKWmcyOSCOtKxogm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYGsls%2FdJMcahEu8fw%2FgWb5nMKWmcyOSCOtKxogm1%2Fimg.png&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;1568&quot; height=&quot;278&quot; data-filename=&quot;01_sort_taxonomy.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;안정 정렬(Stable Sort)&lt;/b&gt;: 동일한 키 값을 가진 요소들의 상대적 순서가 정렬 후에도 유지되는 정렬.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도 요약:&lt;/p&gt;
&lt;table style=&quot;width: 586px; height: 468px;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 72px;&quot;&gt;정렬&lt;/th&gt;
&lt;th style=&quot;width: 84px;&quot;&gt;최선&lt;/th&gt;
&lt;th style=&quot;width: 84px;&quot;&gt;평균&lt;/th&gt;
&lt;th style=&quot;width: 84px;&quot;&gt;최악&lt;/th&gt;
&lt;th style=&quot;width: 72px;&quot;&gt;공간&lt;/th&gt;
&lt;th style=&quot;width: 50px;&quot;&gt;안정&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;버블 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✓&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;선택 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✗&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;삽입 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✓&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;셸 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n^1.5)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✗&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;퀵 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(log n)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✗&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;합병 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✓&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;힙 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✗&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;&lt;b&gt;기수 정렬&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(kn)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(kn)&lt;/td&gt;
&lt;td style=&quot;width: 84px;&quot;&gt;O(kn)&lt;/td&gt;
&lt;td style=&quot;width: 72px;&quot;&gt;O(n+k)&lt;/td&gt;
&lt;td style=&quot;width: 50px;&quot;&gt;&lt;b&gt;✓&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02_complexity_groups.png&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;1508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X0HOB/dJMcafta4pM/fELTnrGvfAIdxgT7HqCCE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X0HOB/dJMcafta4pM/fELTnrGvfAIdxgT7HqCCE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X0HOB/dJMcafta4pM/fELTnrGvfAIdxgT7HqCCE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX0HOB%2FdJMcafta4pM%2FfELTnrGvfAIdxgT7HqCCE0%2Fimg.png&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;530&quot; height=&quot;580&quot; data-filename=&quot;02_complexity_groups.png&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;1508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 교환 기반 정렬&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;버블 정렬 (Bubble Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인접한 두 원소를 비교해 순서가 맞지 않으면 교환한다. 한 패스가 끝날 때마다 가장 큰 값이 맨 뒤로 이동한다. 구현이 단순하지만 효율은 낮은 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 정렬된 배열에서는 교환이 발생하지 않으면 조기 종료할 수 있어 최선의 경우 O(n)이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;03_bubble_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ewwqMT/dJMcabj31gf/kLpGkPk0TOphxnqJ8KFts0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ewwqMT/dJMcabj31gf/kLpGkPk0TOphxnqJ8KFts0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ewwqMT/dJMcabj31gf/kLpGkPk0TOphxnqJ8KFts0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FewwqMT%2FdJMcabj31gf%2FkLpGkPk0TOphxnqJ8KFts0%2Fimg.png&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;1568&quot; height=&quot;160&quot; data-filename=&quot;03_bubble_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [5, 3, 8, 1, 2]

1패스:
[3, 5, 8, 1, 2]  &amp;rarr; 5&amp;harr;3
[3, 5, 8, 1, 2]  &amp;rarr; 5&amp;lt;8, 유지
[3, 5, 1, 8, 2]  &amp;rarr; 8&amp;harr;1
[3, 5, 1, 2, 8]  &amp;rarr; 8&amp;harr;2  &amp;larr; 8이 맨 뒤로 확정

2패스:
[3, 5, 1, 2, 8]  &amp;rarr; 3&amp;lt;5, 유지
[3, 1, 5, 2, 8]  &amp;rarr; 5&amp;harr;1
[3, 1, 2, 5, 8]  &amp;rarr; 5&amp;harr;2  &amp;larr; 5 확정
...&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;def bubble_sort(arr):
    n = len(arr)
    for i in range(n - 1):
        swapped = False
        for j in range(n - 1 - i):   # 이미 정렬된 뒷부분은 건너뜀
            if arr[j] &amp;gt; arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
        if not swapped:               # 교환 없으면 이미 정렬된 상태
            break
    return arr&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;선택 정렬 (Selection Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체에서 가장 작은(또는 큰) 원소를 찾아 맨 앞 원소와 교환한다. 패스마다 정렬 범위가 하나씩 줄어든다. 비교 횟수는 항상 동일하므로 최선&amp;middot;최악 모두 O(n&amp;sup2;)다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;07_selection_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q9Ob2/dJMcaiKapxq/YpJLfvmFzwk4YHfDdthUs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q9Ob2/dJMcaiKapxq/YpJLfvmFzwk4YHfDdthUs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q9Ob2/dJMcaiKapxq/YpJLfvmFzwk4YHfDdthUs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ9Ob2%2FdJMcaiKapxq%2FYpJLfvmFzwk4YHfDdthUs0%2Fimg.png&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;1568&quot; height=&quot;128&quot; data-filename=&quot;07_selection_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;128&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [5, 3, 8, 1, 2]

1패스: 최솟값 1 &amp;rarr; 인덱스 0의 5와 교환
[1, 3, 8, 5, 2]

2패스: 나머지 [3,8,5,2]에서 최솟값 2 &amp;rarr; 인덱스 1의 3과 교환
[1, 2, 8, 5, 3]

3패스: [8,5,3]에서 최솟값 3 &amp;rarr; 8과 교환
[1, 2, 3, 5, 8]

4패스: [5,8]에서 최솟값 5 &amp;rarr; 유지
[1, 2, 3, 5, 8]  &amp;larr; 완료&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;def selection_sort(arr):
    n = len(arr)
    for i in range(n - 1):
        min_idx = i
        for j in range(i + 1, n):      # 남은 범위에서 최솟값 탐색
            if arr[j] &amp;lt; arr[min_idx]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]  # 최솟값을 앞으로
    return arr&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;퀵 정렬 (Quick Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피벗(pivot)을 기준으로 피벗보다 작은 것은 왼쪽, 큰 것은 오른쪽으로 분할한 뒤, 각 부분을 재귀적으로 정렬한다. 평균적으로 가장 빠른 정렬 중 하나이나, 피벗 선택이 나쁘면 최악 O(n&amp;sup2;)이 될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;04_quick_sort.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;1212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OHHD2/dJMb99T15rO/ivFSBm1YkdeqWgCoHdKnj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OHHD2/dJMb99T15rO/ivFSBm1YkdeqWgCoHdKnj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OHHD2/dJMb99T15rO/ivFSBm1YkdeqWgCoHdKnj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOHHD2%2FdJMb99T15rO%2FivFSBm1YkdeqWgCoHdKnj0%2Fimg.png&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;636&quot; height=&quot;493&quot; data-filename=&quot;04_quick_sort.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;1212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [5, 3, 8, 1, 2]  &amp;larr; 피벗: 5

분할:
좌: [3, 1, 2]  (5보다 작은 것)
피벗: [5]
우: [8]        (5보다 큰 것)

좌측 [3, 1, 2] 재귀 정렬 &amp;larr; 피벗: 3
  좌: [1, 2] &amp;rarr; 피벗: 1 &amp;rarr; [1, 2]
  피벗: [3]
  우: []

결과 조합: [1, 2, 3, 5, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;def quick_sort(arr):
    if len(arr) &amp;lt;= 1:
        return arr
    pivot = arr[len(arr) // 2]          # 중간값을 피벗으로 선택
    left  = [x for x in arr if x &amp;lt; pivot]
    mid   = [x for x in arr if x == pivot]
    right = [x for x in arr if x &amp;gt; pivot]
    return quick_sort(left) + mid + quick_sort(right)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 삽입 기반 정렬&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;삽입 정렬 (Insertion Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 원소를 이미 정렬된 앞부분의 적절한 위치에 삽입한다. 데이터가 거의 정렬된 상태라면 매우 효율적이고, 소규모 데이터에서 실용적인 편이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;08_insertion_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5qOhM/dJMcaicqebI/6N5zhqgMAWjCk0uiJR9J51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5qOhM/dJMcaicqebI/6N5zhqgMAWjCk0uiJR9J51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5qOhM/dJMcaicqebI/6N5zhqgMAWjCk0uiJR9J51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5qOhM%2FdJMcaicqebI%2F6N5zhqgMAWjCk0uiJR9J51%2Fimg.png&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;1568&quot; height=&quot;148&quot; data-filename=&quot;08_insertion_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [5, 3, 8, 1, 2]

i=1: 3을 [5] 사이에 삽입 &amp;rarr; [3, 5, 8, 1, 2]
i=2: 8은 5보다 크므로 유지 &amp;rarr; [3, 5, 8, 1, 2]
i=3: 1을 [3,5,8] 앞에 삽입 &amp;rarr; [1, 3, 5, 8, 2]
i=4: 2를 [1,3,5,8] 사이에 삽입 &amp;rarr; [1, 2, 3, 5, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j &amp;gt;= 0 and arr[j] &amp;gt; key:  # 정렬된 부분을 오른쪽으로 밀기
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key                # 적절한 위치에 삽입
    return arr&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;셸 정렬 (Shell Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삽입 정렬의 개선판이다. 간격(gap)을 두고 떨어진 원소들끼리 먼저 정렬한 다음, 간격을 줄여가며 최종적으로 gap=1인 삽입 정렬로 마무리한다. 삽입 정렬의 단점인 &quot;먼 거리 이동&quot;을 줄이는 것이 핵심이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;09_shell_sort.png&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;1376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qz3kP/dJMcaarT6PM/SSkNnpphvd8KLm4WTSlEi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qz3kP/dJMcaarT6PM/SSkNnpphvd8KLm4WTSlEi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qz3kP/dJMcaarT6PM/SSkNnpphvd8KLm4WTSlEi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqz3kP%2FdJMcaarT6PM%2FSSkNnpphvd8KLm4WTSlEi0%2Fimg.png&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;472&quot; height=&quot;566&quot; data-filename=&quot;09_shell_sort.png&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;1376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [8, 3, 5, 1, 9, 2, 7, 4]  gap=4

gap=4: [8,9], [3,2], [5,7], [1,4] 각각 정렬
&amp;rarr; [8, 2, 5, 1, 9, 3, 7, 4]

gap=2: [8,5,9,7], [2,1,3,4] 각각 정렬
&amp;rarr; [5, 1, 7, 2, 8, 3, 9, 4]

gap=1: 일반 삽입 정렬
&amp;rarr; [1, 2, 3, 4, 5, 7, 8, 9]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;def shell_sort(arr):
    n = len(arr)
    gap = n // 2
    while gap &amp;gt; 0:
        for i in range(gap, n):
            temp = arr[i]
            j = i
            while j &amp;gt;= gap and arr[j - gap] &amp;gt; temp:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = temp
        gap //= 2
    return arr&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 분할 정복 / 트리 기반 정렬&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;합병 정렬 (Merge Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열을 절반으로 계속 나누고, 정렬된 부분을 합치는(Merge) 방식이다. 항상 O(n log n)을 보장하고 안정 정렬이지만, 합치는 과정에서 추가 메모리 O(n)이 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;05_merge_sort.png&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R4sg0/dJMcacXwzZg/Ec2kkCUoFrFMoWVAv1gdt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R4sg0/dJMcacXwzZg/Ec2kkCUoFrFMoWVAv1gdt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R4sg0/dJMcacXwzZg/Ec2kkCUoFrFMoWVAv1gdt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR4sg0%2FdJMcacXwzZg%2FEc2kkCUoFrFMoWVAv1gdt1%2Fimg.png&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;603&quot; height=&quot;593&quot; data-filename=&quot;05_merge_sort.png&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [5, 3, 8, 1, 2]

분할:
[5, 3] [8, 1, 2]
[5][3] [8][1, 2]
       [8][1][2]

합병:
[3, 5]    [1, 2] &amp;rarr; [1, 2, 8]
[1, 2, 3, 5, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;def merge_sort(arr):
    if len(arr) &amp;lt;= 1:
        return arr
    mid = len(arr) // 2
    left  = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0
    while i &amp;lt; len(left) and j &amp;lt; len(right):
        if left[i] &amp;lt;= right[j]:     # &amp;lt;= 이므로 안정 정렬
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;힙 정렬 (Heap Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 힙(Max Heap) 자료구조를 이용한다. 전체를 힙으로 만든 뒤, 루트(최댓값)를 맨 뒤로 보내고 힙을 재구성하는 과정을 반복한다. 추가 메모리 없이 O(n log n)을 보장하지만 안정 정렬은 아니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10_heap_sort.png&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;2388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/naKDf/dJMcabK9fdt/QB27cAIOoKbTXVhYPVi0Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/naKDf/dJMcabK9fdt/QB27cAIOoKbTXVhYPVi0Nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/naKDf/dJMcabK9fdt/QB27cAIOoKbTXVhYPVi0Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnaKDf%2FdJMcabK9fdt%2FQB27cAIOoKbTXVhYPVi0Nk%2Fimg.png&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;462&quot; height=&quot;1014&quot; data-filename=&quot;10_heap_sort.png&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;2388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [5, 3, 8, 1, 2]

힙 구성(heapify):
        8
       / \
      3   5
     / \
    1   2

루트(8) 추출 &amp;rarr; 맨 뒤로:
[3, 2, 5, 1, | 8]

다시 힙 구성 &amp;rarr; 루트(5) 추출:
[3, 2, 1, | 5, 8]

반복 후 결과: [1, 2, 3, 5, 8]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;def heap_sort(arr):
    n = len(arr)

    # 최대 힙 구성
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)

    # 루트를 맨 뒤로 보내며 반복
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]   # 최댓값을 맨 뒤로
        heapify(arr, i, 0)                 # 나머지를 다시 힙으로

    return arr

def heapify(arr, n, i):
    largest = i
    left    = 2 * i + 1
    right   = 2 * i + 2
    if left  &amp;lt; n and arr[left]  &amp;gt; arr[largest]: largest = left
    if right &amp;lt; n and arr[right] &amp;gt; arr[largest]: largest = right
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 비교 없는 정렬&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;기수 정렬 (Radix Sort)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원소를 직접 비교하지 않고, 자릿수(1의 자리 &amp;rarr; 10의 자리 &amp;rarr; &amp;hellip;) 순서로 정렬을 반복한다. 키의 자릿수 k와 데이터 수 n에 따라 O(kn)의 시간 복잡도를 가진다. 정수나 고정 길이 문자열에 효과적이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;06_radix_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXkXxi/dJMcajvzWH1/lSTkHGTee1J906Cc3CPKrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXkXxi/dJMcajvzWH1/lSTkHGTee1J906Cc3CPKrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXkXxi/dJMcajvzWH1/lSTkHGTee1J906Cc3CPKrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXkXxi%2FdJMcajvzWH1%2FlSTkHGTee1J906Cc3CPKrK%2Fimg.png&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;1568&quot; height=&quot;130&quot; data-filename=&quot;06_radix_sort.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;초기: [170, 45, 75, 90, 802, 24, 2, 66]

1의 자리 기준 정렬:
[170, 90, 802, 2, 24, 45, 75, 66]

10의 자리 기준 정렬:
[802, 2, 24, 45, 66, 170, 75, 90]

100의 자리 기준 정렬:
[2, 24, 45, 66, 75, 90, 170, 802]  &amp;larr; 완료&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;def radix_sort(arr):
    max_val = max(arr)
    exp = 1                          # 1의 자리부터 시작
    while max_val // exp &amp;gt; 0:
        counting_sort_by_digit(arr, exp)
        exp *= 10
    return arr

def counting_sort_by_digit(arr, exp):
    n = len(arr)
    output  = [0] * n
    count   = [0] * 10              # 0~9 자릿수 버킷

    for i in range(n):
        digit = (arr[i] // exp) % 10
        count[digit] += 1

    for i in range(1, 10):          # 누적 합
        count[i] += count[i - 1]

    for i in range(n - 1, -1, -1):  # 뒤에서부터 채워야 안정 정렬 유지
        digit = (arr[i] // exp) % 10
        output[count[digit] - 1] = arr[i]
        count[digit] -= 1

    for i in range(n):
        arr[i] = output[i]&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;5. 통합 구현&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통합 구현은 송수신 모듈과 중계 모듈 간의 연계를 구현하는 것이다. 구성 요소는 송수신 시스템, 모듈, 중계 시스템, 연계 데이터, 네트워크다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;연계 메커니즘 흐름&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;06_integration_mechanism.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJdsDI/dJMcacDgxan/hFx2OnnGUzF4KYnV58wDA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJdsDI/dJMcacDgxan/hFx2OnnGUzF4KYnV58wDA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJdsDI/dJMcacDgxan/hFx2OnnGUzF4KYnV58wDA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJdsDI%2FdJMcacDgxan%2FhFx2OnnGUzF4KYnV58wDA0%2Fimg.png&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;1568&quot; height=&quot;134&quot; data-filename=&quot;06_integration_mechanism.png&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 생성 및 추출 &amp;rarr; 코드 매핑 및 데이터 변환 &amp;rarr; 인터페이스 테이블 또는 파일 생성 &amp;rarr; 연계 서버 또는 송신 어댑터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연계 방식은 &lt;b&gt;직접 연계&lt;/b&gt;와 &lt;b&gt;간접 연계&lt;/b&gt; 두 가지로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시스템별 역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;송신 시스템&lt;/b&gt;: 인터페이스 테이블 또는 파일의 데이터를 전송 형식에 맞게 변환하고 송신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수신 시스템&lt;/b&gt;: 수신한 데이터를 인터페이스 테이블이나 파일로 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연계 서버&lt;/b&gt;: 모든 중계 처리를 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연계 테스트 순서: 케이스 작성 &amp;rarr; 환경 구축 &amp;rarr; 수행 &amp;rarr; 검증&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연계 데이터 보안은 &lt;b&gt;전송 구간 보안&lt;/b&gt;과 &lt;b&gt;데이터 자체 보안&lt;/b&gt; 두 축으로 관리한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;관련 기술&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;XML&lt;/b&gt; (eXtensible Markup Language)은 특수한 목적의 마크업 언어를 만들기 위한 다목적 마크업 언어다. 웹 브라우저 간 HTML 호환 문제와 SGML의 복잡함을 해결하기 위해 개발되었다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!-- XML 예시: 학생 데이터 --&amp;gt;
&amp;lt;students&amp;gt;
    &amp;lt;student id=&quot;1001&quot;&amp;gt;
        &amp;lt;name&amp;gt;홍길동&amp;lt;/name&amp;gt;
        &amp;lt;grade&amp;gt;2&amp;lt;/grade&amp;gt;
        &amp;lt;major&amp;gt;컴퓨터&amp;lt;/major&amp;gt;
    &amp;lt;/student&amp;gt;
&amp;lt;/students&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SOAP&lt;/b&gt; (Simple Object Access Protocol)는 HTTP/HTTPS, SMTP 등을 통해 XML 메시지를 교환하는 통신 규약이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WSDL&lt;/b&gt; (Web Services Description Language)은 웹 서비스의 서식과 프로토콜을 표준 방식으로 기술하고 게시하기 위한 언어다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;WSDL: 서비스 명세 정의 (무엇을, 어떻게 제공하는지)
SOAP: 실제 데이터 교환 (XML 기반 통신 규약)
XML:  데이터 표현 형식&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;부록 &amp;mdash; 키 개념 비교 정리&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정규화 단계 요약&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;제거 대상&lt;/th&gt;
&lt;th&gt;키워드&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1NF&lt;/td&gt;
&lt;td&gt;비원자값&lt;/td&gt;
&lt;td&gt;원자값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2NF&lt;/td&gt;
&lt;td&gt;부분 함수 종속&lt;/td&gt;
&lt;td&gt;완전 함수 종속&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3NF&lt;/td&gt;
&lt;td&gt;이행적 함수 종속&lt;/td&gt;
&lt;td&gt;A&amp;rarr;B&amp;rarr;C 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BCNF&lt;/td&gt;
&lt;td&gt;결정자 &amp;ne; 후보키&lt;/td&gt;
&lt;td&gt;모든 결정자가 후보키&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4NF&lt;/td&gt;
&lt;td&gt;다치 종속&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5NF&lt;/td&gt;
&lt;td&gt;조인 종속&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;분산 DB 투명성 암기 포인트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치&amp;middot;중복&amp;middot;병행&amp;middot;장애 &amp;mdash; &lt;b&gt;&quot;위중병장&quot;&lt;/b&gt; 으로 묶어 기억하면 편하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스토리지 3종 비교&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OCIGf/dJMcab5oaI5/V0aMpGYuyCrgb8yqKCe651/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OCIGf/dJMcab5oaI5/V0aMpGYuyCrgb8yqKCe651/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OCIGf/dJMcab5oaI5/V0aMpGYuyCrgb8yqKCe651/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOCIGf%2FdJMcab5oaI5%2FV0aMpGYuyCrgb8yqKCe651%2Fimg.png&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;332&quot; height=&quot;147&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv8N1S/dJMcahq17yj/zdqFJKa3ChUCzOFCqEOjsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv8N1S/dJMcahq17yj/zdqFJKa3ChUCzOFCqEOjsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv8N1S/dJMcahq17yj/zdqFJKa3ChUCzOFCqEOjsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv8N1S%2FdJMcahq17yj%2FzdqFJKa3ChUCzOFCqEOjsK%2Fimg.png&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;513&quot; height=&quot;164&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAmvFJ/dJMb99NerNt/NTy4AKQ98vmetZISQRMZJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAmvFJ/dJMb99NerNt/NTy4AKQ98vmetZISQRMZJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAmvFJ/dJMb99NerNt/NTy4AKQ98vmetZISQRMZJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAmvFJ%2FdJMb99NerNt%2FNTy4AKQ98vmetZISQRMZJK%2Fimg.png&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;404&quot; height=&quot;194&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;부록 &amp;mdash; 정렬 선택 가이드&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상황별 권장 정렬&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;상황&lt;/th&gt;
&lt;th&gt;권장 정렬&lt;/th&gt;
&lt;th&gt;이유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;데이터가 거의 정렬되어 있음&lt;/td&gt;
&lt;td&gt;삽입 정렬&lt;/td&gt;
&lt;td&gt;최선 O(n), 구현 단순&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;범용&amp;middot;대규모 데이터&lt;/td&gt;
&lt;td&gt;퀵 정렬&lt;/td&gt;
&lt;td&gt;평균 O(n log n), 캐시 효율 좋음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최악도 O(n log n) 보장 필요&lt;/td&gt;
&lt;td&gt;합병 정렬 / 힙 정렬&lt;/td&gt;
&lt;td&gt;항상 O(n log n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;안정 정렬이 필요&lt;/td&gt;
&lt;td&gt;합병 정렬&lt;/td&gt;
&lt;td&gt;안정 + O(n log n) 보장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정수&amp;middot;고정 길이 키&lt;/td&gt;
&lt;td&gt;기수 정렬&lt;/td&gt;
&lt;td&gt;O(kn), 비교 불필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메모리 제약 있음&lt;/td&gt;
&lt;td&gt;힙 정렬&lt;/td&gt;
&lt;td&gt;추가 메모리 O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 암기 포인트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;버블&amp;middot;선택&amp;middot;삽입&lt;/b&gt;: 단순 정렬. 평균 O(n&amp;sup2;). 소규모에 적합.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;퀵&amp;middot;합병&amp;middot;힙&lt;/b&gt;: 고급 정렬. 평균 O(n log n).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;합병 정렬만&lt;/b&gt; 안정 + O(n log n) 최악 보장을 동시에 만족.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;힙 정렬만&lt;/b&gt; 추가 메모리 없이 O(n log n) 최악 보장.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기수 정렬&lt;/b&gt;: 비교 없이 정렬. 조건(정수 or 고정 키)이 맞으면 가장 빠를 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Backend &amp;amp; Infra</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/28</guid>
      <comments>https://revivalearth.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-DBMS-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC#entry28comment</comments>
      <pubDate>Mon, 25 May 2026 11:59:40 +0900</pubDate>
    </item>
    <item>
      <title>소프트웨어 디자인 패턴 핵심 정리 (with Python)</title>
      <link>https://revivalearth.tistory.com/entry/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC-with-Python</link>
      <description>&lt;h1&gt;디자인 패턴 정리&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 생성 패턴 (Creational Patterns)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 생성 방식을 추상화해서 코드와 생성 로직을 분리한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. 추상 팩토리 (Abstract Factory)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로 연관&amp;middot;의존하는 객체 그룹을 하나의 팩토리로 묶어 생성한다.&lt;br /&gt;구체 클래스를 지정하지 않고 인터페이스만으로 객체 집합을 교체할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01_1_1_추상_팩토리_Abstract_Factory.png&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddl21t/dJMcadWpFvN/YeJN35DA54cfIuAta7jcqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddl21t/dJMcadWpFvN/YeJN35DA54cfIuAta7jcqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddl21t/dJMcadWpFvN/YeJN35DA54cfIuAta7jcqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fddl21t%2FdJMcadWpFvN%2FYeJN35DA54cfIuAta7jcqk%2Fimg.png&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;577&quot; height=&quot;390&quot; data-filename=&quot;01_1_1_추상_팩토리_Abstract_Factory.png&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Button(ABC):
    @abstractmethod
    def render(self): ...

class Checkbox(ABC):
    @abstractmethod
    def render(self): ...

class WindowsButton(Button):
    def render(self): return &quot;Windows Button&quot;

class WindowsCheckbox(Checkbox):
    def render(self): return &quot;Windows Checkbox&quot;

class MacButton(Button):
    def render(self): return &quot;Mac Button&quot;

class MacCheckbox(Checkbox):
    def render(self): return &quot;Mac Checkbox&quot;

class GUIFactory(ABC):
    @abstractmethod
    def create_button(self) -&amp;gt; Button: ...
    @abstractmethod
    def create_checkbox(self) -&amp;gt; Checkbox: ...

class WindowsFactory(GUIFactory):
    def create_button(self): return WindowsButton()
    def create_checkbox(self): return WindowsCheckbox()

class MacFactory(GUIFactory):
    def create_button(self): return MacButton()
    def create_checkbox(self): return MacCheckbox()

# 사용
factory: GUIFactory = WindowsFactory()
print(factory.create_button().render())    # Windows Button
print(factory.create_checkbox().render())  # Windows Checkbox&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. 빌더 (Builder)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 객체의 생성 과정을 단계별로 분리한다.&lt;br /&gt;같은 생성 절차로 다른 표현의 객체를 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02_1_2_빌더_Builder.png&quot; data-origin-width=&quot;262&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTtPyU/dJMb99T13EY/kJZTKCCUtnDWYHOkkZ0Ynk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTtPyU/dJMb99T13EY/kJZTKCCUtnDWYHOkkZ0Ynk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTtPyU/dJMb99T13EY/kJZTKCCUtnDWYHOkkZ0Ynk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTtPyU%2FdJMb99T13EY%2FkJZTKCCUtnDWYHOkkZ0Ynk%2Fimg.png&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;198&quot; height=&quot;464&quot; data-filename=&quot;02_1_2_빌더_Builder.png&quot; data-origin-width=&quot;262&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Car:
    def __init__(self):
        self.engine = None
        self.seats = None

    def __repr__(self):
        return f&quot;Car(engine={self.engine}, seats={self.seats})&quot;

class CarBuilder:
    def __init__(self):
        self._car = Car()

    def set_engine(self, engine: str):
        self._car.engine = engine
        return self  # 메서드 체이닝 지원

    def set_seats(self, seats: int):
        self._car.seats = seats
        return self

    def build(self) -&amp;gt; Car:
        return self._car

# 사용
car = CarBuilder().set_engine(&quot;V8&quot;).set_seats(4).build()
print(car)  # Car(engine=V8, seats=4)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-3. 팩토리 메소드 (Factory Method)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 생성을 서브클래스에 위임한다.&lt;br /&gt;상위 클래스는 인터페이스만 정의하고, 실제 인스턴스화는 서브클래스가 담당한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;03_1_3_팩토리_메소드_Factory_Method.png&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SiEmY/dJMcagezhdu/5aqkf8yVA5dqAwO68j0211/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SiEmY/dJMcagezhdu/5aqkf8yVA5dqAwO68j0211/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SiEmY/dJMcagezhdu/5aqkf8yVA5dqAwO68j0211/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSiEmY%2FdJMcagezhdu%2F5aqkf8yVA5dqAwO68j0211%2Fimg.png&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;824&quot; height=&quot;566&quot; data-filename=&quot;03_1_3_팩토리_메소드_Factory_Method.png&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Transport(ABC):
    @abstractmethod
    def deliver(self) -&amp;gt; str: ...

class Truck(Transport):
    def deliver(self): return &quot;트럭으로 육상 배송&quot;

class Ship(Transport):
    def deliver(self): return &quot;배로 해상 배송&quot;

class Logistics(ABC):
    @abstractmethod
    def create_transport(self) -&amp;gt; Transport: ...

    def plan_delivery(self):
        transport = self.create_transport()
        return transport.deliver()

class RoadLogistics(Logistics):
    def create_transport(self): return Truck()

class SeaLogistics(Logistics):
    def create_transport(self): return Ship()

# 사용
for logistics in [RoadLogistics(), SeaLogistics()]:
    print(logistics.plan_delivery())
# 트럭으로 육상 배송
# 배로 해상 배송&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-4. 프로토타입 (Prototype)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 객체를 복제해서 새 객체를 만든다.&lt;br /&gt;초기화 비용이 크거나 외부 의존성이 많은 객체에 유용하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;04_1_4_프로토타입_Prototype.png&quot; data-origin-width=&quot;204&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTdevU/dJMcahdtTk2/KPoLddiPqyHVn9k5kkJ561/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTdevU/dJMcahdtTk2/KPoLddiPqyHVn9k5kkJ561/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTdevU/dJMcahdtTk2/KPoLddiPqyHVn9k5kkJ561/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTdevU%2FdJMcahdtTk2%2FKPoLddiPqyHVn9k5kkJ561%2Fimg.png&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;204&quot; height=&quot;360&quot; data-filename=&quot;04_1_4_프로토타입_Prototype.png&quot; data-origin-width=&quot;204&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;import copy

class DatabaseConnection:
    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port
        # 실제로는 여기서 무거운 초기화 작업이 일어난다고 가정
        self.config = {&quot;timeout&quot;: 30, &quot;retry&quot;: 3}

    def clone(self):
        return copy.deepcopy(self)

    def __repr__(self):
        return f&quot;DB({self.host}:{self.port}, config={self.config})&quot;

# 무거운 초기화는 최초 1회만
original = DatabaseConnection(&quot;localhost&quot;, 5432)

# 이후에는 복제로 비용 절감
replica = original.clone()
replica.port = 5433
replica.config[&quot;timeout&quot;] = 60

print(original)  # DB(localhost:5432, config={'timeout': 30, 'retry': 3})
print(replica)   # DB(localhost:5433, config={'timeout': 60, 'retry': 3})&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-5. 싱글톤 (Singleton)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 인스턴스가 단 하나만 존재하도록 보장한다.&lt;br /&gt;전역 접근점을 제공하며, 설정 관리자&amp;middot;로거&amp;middot;DB 커넥션 풀에서 자주 쓰인다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;05_1_5_싱글톤_Singleton.png&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmapvi/dJMcahR2Ije/OM2xEfKJCRVYdQA5n55XS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmapvi/dJMcahR2Ije/OM2xEfKJCRVYdQA5n55XS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmapvi/dJMcahR2Ije/OM2xEfKJCRVYdQA5n55XS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmapvi%2FdJMcahR2Ije%2FOM2xEfKJCRVYdQA5n55XS0%2Fimg.png&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;228&quot; height=&quot;184&quot; data-filename=&quot;05_1_5_싱글톤_Singleton.png&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class AppConfig:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance.settings = {}
        return cls._instance

    def set(self, key, value):
        self.settings[key] = value

    def get(self, key):
        return self.settings.get(key)

# 사용
config1 = AppConfig()
config1.set(&quot;debug&quot;, True)

config2 = AppConfig()
print(config2.get(&quot;debug&quot;))      # True &amp;mdash; 같은 인스턴스
print(config1 is config2)        # True&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 구조 패턴 (Structural Patterns)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스와 객체를 조합해서 더 큰 구조를 만든다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 어댑터 (Adapter)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호환되지 않는 인터페이스를 클라이언트가 기대하는 형태로 변환한다.&lt;br /&gt;기존 코드를 수정하지 않고 새 인터페이스에 맞게 연결할 때 쓴다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;06_2_1_어댑터_Adapter.png&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn4cUi/dJMcahEu6Ba/dLgAQpPZEKqll6UIvPfnwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn4cUi/dJMcahEu6Ba/dLgAQpPZEKqll6UIvPfnwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn4cUi/dJMcahEu6Ba/dLgAQpPZEKqll6UIvPfnwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn4cUi%2FdJMcahEu6Ba%2FdLgAQpPZEKqll6UIvPfnwk%2Fimg.png&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;257&quot; height=&quot;536&quot; data-filename=&quot;06_2_1_어댑터_Adapter.png&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class KoreanPayment:
    &quot;&quot;&quot;기존 한국 결제 모듈 &amp;mdash; 인터페이스가 다름&quot;&quot;&quot;
    def korean_pay(self, amount: int) -&amp;gt; str:
        return f&quot;한국 결제: {amount}원&quot;

class PaymentGateway:
    &quot;&quot;&quot;클라이언트가 기대하는 인터페이스&quot;&quot;&quot;
    def pay(self, amount: float) -&amp;gt; str: ...

class PaymentAdapter(PaymentGateway):
    def __init__(self, korean_payment: KoreanPayment):
        self._payment = korean_payment

    def pay(self, amount: float) -&amp;gt; str:
        krw = int(amount * 1350)  # USD &amp;rarr; KRW 변환
        return self._payment.korean_pay(krw)

# 사용
adapter = PaymentAdapter(KoreanPayment())
print(adapter.pay(10.0))  # 한국 결제: 13500원&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 브리지 (Bridge)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상화(Abstraction)와 구현(Implementation)을 독립적으로 변경할 수 있도록 분리한다.&lt;br /&gt;상속 대신 합성을 사용해서 두 축의 변화를 각자 확장한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;07_2_2_브리지_Bridge.png&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxH9mM/dJMcacwt0mV/kbwpNTrLg2tJDOSG9EE7f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxH9mM/dJMcacwt0mV/kbwpNTrLg2tJDOSG9EE7f1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxH9mM/dJMcacwt0mV/kbwpNTrLg2tJDOSG9EE7f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxH9mM%2FdJMcacwt0mV%2FkbwpNTrLg2tJDOSG9EE7f1%2Fimg.png&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;729&quot; height=&quot;536&quot; data-filename=&quot;07_2_2_브리지_Bridge.png&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Renderer(ABC):
    @abstractmethod
    def render_shape(self, name: str) -&amp;gt; str: ...

class VectorRenderer(Renderer):
    def render_shape(self, name): return f&quot;벡터로 {name} 렌더링&quot;

class RasterRenderer(Renderer):
    def render_shape(self, name): return f&quot;래스터로 {name} 렌더링&quot;

class Shape(ABC):
    def __init__(self, renderer: Renderer):
        self.renderer = renderer

    @abstractmethod
    def draw(self) -&amp;gt; str: ...

class Circle(Shape):
    def draw(self): return self.renderer.render_shape(&quot;원&quot;)

class Square(Shape):
    def draw(self): return self.renderer.render_shape(&quot;사각형&quot;)

# 사용 &amp;mdash; 추상(도형)과 구현(렌더러)을 독립적으로 조합
print(Circle(VectorRenderer()).draw())   # 벡터로 원 렌더링
print(Square(RasterRenderer()).draw())   # 래스터로 사각형 렌더링&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 컴포지트 (Composite)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 객체와 복합 객체를 동일한 인터페이스로 다룬다.&lt;br /&gt;파일 시스템처럼 트리 구조로 구성된 대상에 적합하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;08_2_3_컴포지트_Composite.png&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FtBXe/dJMcaiKanIW/keCxFxZwkFlmsEJoXSyqFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FtBXe/dJMcaiKanIW/keCxFxZwkFlmsEJoXSyqFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FtBXe/dJMcaiKanIW/keCxFxZwkFlmsEJoXSyqFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFtBXe%2FdJMcaiKanIW%2FkeCxFxZwkFlmsEJoXSyqFK%2Fimg.png&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;389&quot; height=&quot;402&quot; data-filename=&quot;08_2_3_컴포지트_Composite.png&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class FileSystemItem(ABC):
    def __init__(self, name: str):
        self.name = name

    @abstractmethod
    def size(self) -&amp;gt; int: ...

class File(FileSystemItem):
    def __init__(self, name: str, size: int):
        super().__init__(name)
        self._size = size

    def size(self): return self._size

class Directory(FileSystemItem):
    def __init__(self, name: str):
        super().__init__(name)
        self._children: list[FileSystemItem] = []

    def add(self, item: FileSystemItem):
        self._children.append(item)
        return self

    def size(self): return sum(c.size() for c in self._children)

# 사용 &amp;mdash; 파일과 디렉토리를 구분 없이 처리
root = Directory(&quot;root&quot;)
root.add(File(&quot;README.md&quot;, 10))
src = Directory(&quot;src&quot;)
src.add(File(&quot;main.py&quot;, 50)).add(File(&quot;utils.py&quot;, 30))
root.add(src)

print(root.size())   # 90
print(src.size())    # 80&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-4. 퍼케이드 (Facade)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 서브시스템 위에 단순한 인터페이스를 제공한다.&lt;br /&gt;내부 구조를 숨기고 클라이언트가 쉽게 사용할 수 있도록 창구 역할을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;09_2_4_퍼케이드_Facade.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u7i1V/dJMcabEjIE3/ZD3ixObXLksRSwIi12kYL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u7i1V/dJMcabEjIE3/ZD3ixObXLksRSwIi12kYL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u7i1V/dJMcabEjIE3/ZD3ixObXLksRSwIi12kYL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu7i1V%2FdJMcabEjIE3%2FZD3ixObXLksRSwIi12kYL1%2Fimg.png&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;612&quot; height=&quot;366&quot; data-filename=&quot;09_2_4_퍼케이드_Facade.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Projector:
    def on(self): print(&quot;프로젝터 켜짐&quot;)
    def off(self): print(&quot;프로젝터 꺼짐&quot;)

class SoundSystem:
    def on(self): print(&quot;사운드 시스템 켜짐&quot;)
    def set_volume(self, v): print(f&quot;볼륨 {v}으로 설정&quot;)

class StreamingPlayer:
    def play(self, title): print(f&quot;'{title}' 재생 시작&quot;)
    def stop(self): print(&quot;재생 중지&quot;)

class HomeTheaterFacade:
    &quot;&quot;&quot;복잡한 초기화를 한 메서드로 압축&quot;&quot;&quot;
    def __init__(self):
        self._proj = Projector()
        self._sound = SoundSystem()
        self._player = StreamingPlayer()

    def watch_movie(self, title: str):
        self._proj.on()
        self._sound.on()
        self._sound.set_volume(30)
        self._player.play(title)

    def end_movie(self):
        self._player.stop()
        self._proj.off()

# 사용
theater = HomeTheaterFacade()
theater.watch_movie(&quot;Inception&quot;)
theater.end_movie()&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-5. 플라이웨이트 (Flyweight)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대량의 유사 객체에서 공유 가능한 상태를 분리해 메모리를 절약한다.&lt;br /&gt;불변 데이터(내재적 상태)를 공유하고, 가변 데이터(외재적 상태)는 외부에서 전달한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10_2_5_플라이웨이트_Flyweight.png&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbNF6R/dJMcabEjIFm/M026U2xUiVcmkQukvFCRcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbNF6R/dJMcabEjIFm/M026U2xUiVcmkQukvFCRcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbNF6R/dJMcabEjIFm/M026U2xUiVcmkQukvFCRcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbNF6R%2FdJMcabEjIFm%2FM026U2xUiVcmkQukvFCRcK%2Fimg.png&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;659&quot; height=&quot;426&quot; data-filename=&quot;10_2_5_플라이웨이트_Flyweight.png&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class TreeType:
    &quot;&quot;&quot;공유되는 내재적 상태 &amp;mdash; 무거운 텍스처 데이터&quot;&quot;&quot;
    def __init__(self, name: str, texture: str):
        self.name = name
        self.texture = texture  # 실제로는 수 MB의 이미지 데이터

    def draw(self, x: int, y: int):
        print(f&quot;[{self.name}] 텍스처로 ({x},{y})에 그리기&quot;)

class TreeFactory:
    _cache: dict[str, TreeType] = {}

    @classmethod
    def get(cls, name: str, texture: str) -&amp;gt; TreeType:
        key = f&quot;{name}:{texture}&quot;
        if key not in cls._cache:
            cls._cache[key] = TreeType(name, texture)
            print(f&quot;새 TreeType 생성: {name}&quot;)
        return cls._cache[key]

class Tree:
    &quot;&quot;&quot;외재적 상태(좌표)만 보유&quot;&quot;&quot;
    def __init__(self, x: int, y: int, tree_type: TreeType):
        self.x = x
        self.y = y
        self.tree_type = tree_type

    def draw(self):
        self.tree_type.draw(self.x, self.y)

# 사용 &amp;mdash; 1000그루를 심어도 TreeType은 2개만 생성
oak_type = TreeFactory.get(&quot;oak&quot;, &quot;oak_texture.png&quot;)
pine_type = TreeFactory.get(&quot;pine&quot;, &quot;pine_texture.png&quot;)

trees = [
    Tree(i * 10, i * 5, oak_type if i % 2 == 0 else pine_type)
    for i in range(10)
]
trees[0].draw()
trees[1].draw()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-6. 프록시 (Proxy)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 객체 앞에 대리 객체를 두어 접근을 제어한다.&lt;br /&gt;지연 초기화, 접근 권한 제어, 캐싱, 로깅 등에 활용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11_2_6_프록시_Proxy.png&quot; data-origin-width=&quot;287&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BCurh/dJMcagMrdL0/WToAc1alpTN5w6QDRFzjB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BCurh/dJMcagMrdL0/WToAc1alpTN5w6QDRFzjB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BCurh/dJMcagMrdL0/WToAc1alpTN5w6QDRFzjB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBCurh%2FdJMcagMrdL0%2FWToAc1alpTN5w6QDRFzjB1%2Fimg.png&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;287&quot; height=&quot;536&quot; data-filename=&quot;11_2_6_프록시_Proxy.png&quot; data-origin-width=&quot;287&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Database(ABC):
    @abstractmethod
    def query(self, sql: str) -&amp;gt; str: ...

class RealDatabase(Database):
    def query(self, sql: str) -&amp;gt; str:
        return f&quot;결과: {sql} 실행 완료&quot;

class CachingProxy(Database):
    &quot;&quot;&quot;캐싱 + 접근 로깅&quot;&quot;&quot;
    def __init__(self):
        self._real = RealDatabase()
        self._cache: dict[str, str] = {}

    def query(self, sql: str) -&amp;gt; str:
        if sql in self._cache:
            print(f&quot;[캐시 히트] {sql}&quot;)
            return self._cache[sql]
        print(f&quot;[DB 조회] {sql}&quot;)
        result = self._real.query(sql)
        self._cache[sql] = result
        return result

# 사용
db = CachingProxy()
print(db.query(&quot;SELECT * FROM users&quot;))  # [DB 조회]
print(db.query(&quot;SELECT * FROM users&quot;))  # [캐시 히트]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 행위 패턴 (Behavioral Patterns)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 간의 책임 분배와 알고리즘 캡슐화를 다룬다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. 책임 연쇄 (Chain of Responsibility)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 처리할 수 있는 객체들을 체인으로 연결한다.&lt;br /&gt;각 핸들러는 처리하거나 다음 핸들러로 넘긴다. HTTP 미들웨어, 이벤트 버블링이 대표적이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12_3_1_책임_연쇄_Chain_of_Responsibility.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXAAj2/dJMcafGKzS1/kYpcGoUEuVEQ7vK6YsZyk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXAAj2/dJMcafGKzS1/kYpcGoUEuVEQ7vK6YsZyk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXAAj2/dJMcafGKzS1/kYpcGoUEuVEQ7vK6YsZyk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXAAj2%2FdJMcafGKzS1%2FkYpcGoUEuVEQ7vK6YsZyk1%2Fimg.png&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;884&quot; height=&quot;444&quot; data-filename=&quot;12_3_1_책임_연쇄_Chain_of_Responsibility.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Handler(ABC):
    def __init__(self):
        self._next: Handler | None = None

    def set_next(self, handler: &quot;Handler&quot;) -&amp;gt; &quot;Handler&quot;:
        self._next = handler
        return handler  # 체이닝용

    @abstractmethod
    def handle(self, request: dict) -&amp;gt; str | None: ...

class AuthHandler(Handler):
    def handle(self, request):
        if not request.get(&quot;token&quot;):
            return &quot;인증 실패&quot;
        return self._next.handle(request) if self._next else None

class LogHandler(Handler):
    def handle(self, request):
        print(f&quot;[LOG] 요청 수신: {request.get('action')}&quot;)
        return self._next.handle(request) if self._next else None

class BusinessHandler(Handler):
    def handle(self, request):
        return f&quot;처리 완료: {request.get('action')}&quot;

# 체인 구성
auth = AuthHandler()
log = LogHandler()
biz = BusinessHandler()
auth.set_next(log).set_next(biz)

print(auth.handle({&quot;action&quot;: &quot;create&quot;, &quot;token&quot;: &quot;abc&quot;}))
# [LOG] 요청 수신: create
# 처리 완료: create

print(auth.handle({&quot;action&quot;: &quot;create&quot;}))
# 인증 실패&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. 커맨드 (Command)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 객체로 캡슐화한다.&lt;br /&gt;요청의 큐잉, 로깅, 실행 취소(undo)가 필요할 때 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13_3_2_커맨드_Command.png&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cywSFH/dJMcahdtTvq/v4MdldmiwohuxIVKO45T0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cywSFH/dJMcahdtTvq/v4MdldmiwohuxIVKO45T0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cywSFH/dJMcahdtTvq/v4MdldmiwohuxIVKO45T0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcywSFH%2FdJMcahdtTvq%2Fv4MdldmiwohuxIVKO45T0K%2Fimg.png&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;277&quot; height=&quot;808&quot; data-filename=&quot;13_3_2_커맨드_Command.png&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;808&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self): ...
    @abstractmethod
    def undo(self): ...

class Light:
    def on(self): print(&quot;조명 켜짐&quot;)
    def off(self): print(&quot;조명 꺼짐&quot;)

class LightOnCommand(Command):
    def __init__(self, light: Light):
        self._light = light
    def execute(self): self._light.on()
    def undo(self): self._light.off()

class RemoteControl:
    def __init__(self):
        self._history: list[Command] = []

    def press(self, cmd: Command):
        cmd.execute()
        self._history.append(cmd)

    def undo(self):
        if self._history:
            self._history.pop().undo()

# 사용
remote = RemoteControl()
light = Light()
remote.press(LightOnCommand(light))  # 조명 켜짐
remote.undo()                        # 조명 꺼짐&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-3. 이터레이터 (Iterator)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션의 내부 구조를 노출하지 않고 순회한다.&lt;br /&gt;Python의 &lt;code&gt;__iter__&lt;/code&gt; / &lt;code&gt;__next__&lt;/code&gt; 프로토콜이 이 패턴의 언어 수준 구현이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;14_3_3_이터레이터_Iterator.png&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5CcQ9/dJMcadhQTBE/J2a2ok9HKGiFAhqa7LUtK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5CcQ9/dJMcadhQTBE/J2a2ok9HKGiFAhqa7LUtK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5CcQ9/dJMcadhQTBE/J2a2ok9HKGiFAhqa7LUtK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5CcQ9%2FdJMcadhQTBE%2FJ2a2ok9HKGiFAhqa7LUtK1%2Fimg.png&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;171&quot; height=&quot;456&quot; data-filename=&quot;14_3_3_이터레이터_Iterator.png&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class NumberRange:
    &quot;&quot;&quot;짝수만 반환하는 이터레이터&quot;&quot;&quot;
    def __init__(self, start: int, end: int):
        self.start = start
        self.end = end
        self.current = start

    def __iter__(self):
        self.current = self.start
        return self

    def __next__(self):
        while self.current &amp;lt;= self.end:
            val = self.current
            self.current += 1
            if val % 2 == 0:
                return val
        raise StopIteration

# 사용
for n in NumberRange(1, 10):
    print(n, end=&quot; &quot;)
# 2 4 6 8 10&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-4. 중재자 (Mediator)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체들이 서로 직접 참조하지 않고 중재자를 통해 통신한다.&lt;br /&gt;채팅 서버, UI 컴포넌트 간 조율, 항공 관제 시스템이 대표적이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;15_3_4_중재자_Mediator.png&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;626&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQACRt/dJMcabxw2D3/4Ul4BN0N6x1Fwy7sjs1T7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQACRt/dJMcabxw2D3/4Ul4BN0N6x1Fwy7sjs1T7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQACRt/dJMcabxw2D3/4Ul4BN0N6x1Fwy7sjs1T7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQACRt%2FdJMcabxw2D3%2F4Ul4BN0N6x1Fwy7sjs1T7K%2Fimg.png&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;305&quot; height=&quot;626&quot; data-filename=&quot;15_3_4_중재자_Mediator.png&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;626&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from __future__ import annotations

class ChatRoom:
    def __init__(self):
        self._users: list[User] = []

    def add_user(self, user: User):
        user.mediator = self
        self._users.append(user)

    def broadcast(self, message: str, sender: User):
        for user in self._users:
            if user is not sender:
                user.receive(f&quot;[{sender.name}] {message}&quot;)

class User:
    def __init__(self, name: str):
        self.name = name
        self.mediator: ChatRoom | None = None

    def send(self, message: str):
        self.mediator.broadcast(message, self)

    def receive(self, message: str):
        print(f&quot;{self.name} 수신: {message}&quot;)

# 사용
room = ChatRoom()
alice, bob, charlie = User(&quot;Alice&quot;), User(&quot;Bob&quot;), User(&quot;Charlie&quot;)
for u in [alice, bob, charlie]:
    room.add_user(u)

alice.send(&quot;안녕하세요!&quot;)
# Bob 수신: [Alice] 안녕하세요!
# Charlie 수신: [Alice] 안녕하세요!&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-5. 메멘토 (Memento)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 내부 상태를 캡슐화해서 저장하고, 나중에 복원한다.&lt;br /&gt;실행 취소(undo), 스냅샷, 게임 세이브 포인트에 활용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;16_3_5_메멘토_Memento.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ETdqR/dJMcadhQTB1/PuSscFBjE8FGKBLQkH2HN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ETdqR/dJMcadhQTB1/PuSscFBjE8FGKBLQkH2HN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ETdqR/dJMcadhQTB1/PuSscFBjE8FGKBLQkH2HN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FETdqR%2FdJMcadhQTB1%2FPuSscFBjE8FGKBLQkH2HN0%2Fimg.png&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;495&quot; height=&quot;402&quot; data-filename=&quot;16_3_5_메멘토_Memento.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Memento:
    def __init__(self, state: str):
        self._state = state

    def get_state(self) -&amp;gt; str:
        return self._state

class Editor:
    def __init__(self):
        self.content = &quot;&quot;

    def write(self, text: str):
        self.content += text

    def save(self) -&amp;gt; Memento:
        return Memento(self.content)

    def restore(self, memento: Memento):
        self.content = memento.get_state()

class History:
    def __init__(self):
        self._stack: list[Memento] = []

    def push(self, m: Memento): self._stack.append(m)
    def pop(self) -&amp;gt; Memento | None:
        return self._stack.pop() if self._stack else None

# 사용
editor = Editor()
history = History()

editor.write(&quot;첫 번째 문장. &quot;)
history.push(editor.save())

editor.write(&quot;두 번째 문장. &quot;)
history.push(editor.save())

editor.write(&quot;잘못된 내용...&quot;)
print(editor.content)  # 첫 번째 문장. 두 번째 문장. 잘못된 내용...

editor.restore(history.pop())
print(editor.content)  # 첫 번째 문장. 두 번째 문장.&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-6. 옵저버 (Observer)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 객체(Subject)의 상태 변화를 여러 객체(Observer)에게 자동으로 알린다.&lt;br /&gt;이벤트 시스템, 데이터 바인딩, pub-sub 아키텍처의 기반이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;17_3_6_옵저버_Observer.png&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIBOWI/dJMcadhQTB4/rXMlaGyHRo4K3ts8C0HSik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIBOWI/dJMcadhQTB4/rXMlaGyHRo4K3ts8C0HSik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIBOWI/dJMcadhQTB4/rXMlaGyHRo4K3ts8C0HSik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIBOWI%2FdJMcadhQTB4%2FrXMlaGyHRo4K3ts8C0HSik%2Fimg.png&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;509&quot; height=&quot;584&quot; data-filename=&quot;17_3_6_옵저버_Observer.png&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Observer(ABC):
    @abstractmethod
    def update(self, event: str): ...

class EventBus:
    def __init__(self):
        self._observers: list[Observer] = []

    def subscribe(self, observer: Observer):
        self._observers.append(observer)

    def unsubscribe(self, observer: Observer):
        self._observers.remove(observer)

    def notify(self, event: str):
        for obs in self._observers:
            obs.update(event)

class EmailNotifier(Observer):
    def update(self, event): print(f&quot;[이메일] 이벤트 발생: {event}&quot;)

class SlackNotifier(Observer):
    def update(self, event): print(f&quot;[슬랙] 이벤트 발생: {event}&quot;)

# 사용
bus = EventBus()
bus.subscribe(EmailNotifier())
bus.subscribe(SlackNotifier())
bus.notify(&quot;주문 완료&quot;)
# [이메일] 이벤트 발생: 주문 완료
# [슬랙] 이벤트 발생: 주문 완료&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-7. 상태 (State)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 내부 상태에 따라 행동을 바꾼다.&lt;br /&gt;조건문 분기 대신 상태 클래스를 교체하는 방식으로 동작한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;18_3_7_상태_State.png&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch1DSU/dJMcadhQTB8/vfpXoKWuQMK39sZe2RwKZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch1DSU/dJMcadhQTB8/vfpXoKWuQMK39sZe2RwKZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch1DSU/dJMcadhQTB8/vfpXoKWuQMK39sZe2RwKZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch1DSU%2FdJMcadhQTB8%2FvfpXoKWuQMK39sZe2RwKZk%2Fimg.png&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;306&quot; height=&quot;412&quot; data-filename=&quot;18_3_7_상태_State.png&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class OrderState(ABC):
    @abstractmethod
    def next(self, order: &quot;Order&quot;): ...

    @abstractmethod
    def status(self) -&amp;gt; str: ...

class IdleState(OrderState):
    def next(self, order):
        order.state = ProcessingState()
    def status(self): return &quot;대기 중&quot;

class ProcessingState(OrderState):
    def next(self, order):
        order.state = CompletedState()
    def status(self): return &quot;처리 중&quot;

class CompletedState(OrderState):
    def next(self, order):
        print(&quot;이미 완료된 주문&quot;)
    def status(self): return &quot;완료&quot;

class Order:
    def __init__(self):
        self.state: OrderState = IdleState()

    def next(self):
        self.state.next(self)

    def status(self) -&amp;gt; str:
        return self.state.status()

# 사용
order = Order()
print(order.status())  # 대기 중
order.next()
print(order.status())  # 처리 중
order.next()
print(order.status())  # 완료&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-8. 전략 (Strategy)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘을 별도 클래스로 캡슐화하고 런타임에 교체할 수 있도록 한다.&lt;br /&gt;정렬 알고리즘, 결제 방법, 압축 방식처럼 &quot;어떻게 할지&quot;를 바꿔야 할 때 쓴다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;19_3_8_전략_Strategy.png&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T659l/dJMcaaZHN1p/sPrsCeFxg57MQGkWZacMSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T659l/dJMcaaZHN1p/sPrsCeFxg57MQGkWZacMSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T659l/dJMcaaZHN1p/sPrsCeFxg57MQGkWZacMSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT659l%2FdJMcaaZHN1p%2FsPrsCeFxg57MQGkWZacMSK%2Fimg.png&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;418&quot; height=&quot;560&quot; data-filename=&quot;19_3_8_전략_Strategy.png&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class SortStrategy(ABC):
    @abstractmethod
    def sort(self, data: list) -&amp;gt; list: ...

class BubbleSort(SortStrategy):
    def sort(self, data):
        d = data[:]
        for i in range(len(d)):
            for j in range(len(d) - i - 1):
                if d[j] &amp;gt; d[j+1]:
                    d[j], d[j+1] = d[j+1], d[j]
        return d

class QuickSort(SortStrategy):
    def sort(self, data):
        if len(data) &amp;lt;= 1:
            return data
        pivot = data[0]
        left = [x for x in data[1:] if x &amp;lt;= pivot]
        right = [x for x in data[1:] if x &amp;gt; pivot]
        return self.sort(left) + [pivot] + self.sort(right)

class Sorter:
    def __init__(self, strategy: SortStrategy):
        self.strategy = strategy

    def sort(self, data: list) -&amp;gt; list:
        return self.strategy.sort(data)

# 런타임에 알고리즘 교체
data = [5, 3, 1, 4, 2]
sorter = Sorter(BubbleSort())
print(sorter.sort(data))  # [1, 2, 3, 4, 5]

sorter.strategy = QuickSort()
print(sorter.sort(data))  # [1, 2, 3, 4, 5]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-9. 템플릿 메소드 (Template Method)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘의 골격을 상위 클래스에서 정의하고, 세부 단계는 서브클래스가 구현한다.&lt;br /&gt;전체 흐름은 변하지 않고 일부 단계만 교체할 때 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20_3_9_템플릿_메소드_Template_Method.png&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AYKHh/dJMcabROltb/6akwKPSFlnyFZ6KVWKG9UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AYKHh/dJMcabROltb/6akwKPSFlnyFZ6KVWKG9UK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AYKHh/dJMcabROltb/6akwKPSFlnyFZ6KVWKG9UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAYKHh%2FdJMcabROltb%2F6akwKPSFlnyFZ6KVWKG9UK%2Fimg.png&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;485&quot; height=&quot;438&quot; data-filename=&quot;20_3_9_템플릿_메소드_Template_Method.png&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class DataProcessor(ABC):
    def process(self):
        &quot;&quot;&quot;골격 &amp;mdash; 순서는 고정&quot;&quot;&quot;
        data = self.read_data()
        result = self.transform(data)
        self.write_data(result)

    @abstractmethod
    def read_data(self) -&amp;gt; list: ...

    @abstractmethod
    def transform(self, data: list) -&amp;gt; list: ...

    @abstractmethod
    def write_data(self, data: list): ...

class CsvProcessor(DataProcessor):
    def read_data(self):
        print(&quot;CSV 파일 읽기&quot;)
        return [1, 2, 3]

    def transform(self, data):
        return [x * 2 for x in data]

    def write_data(self, data):
        print(f&quot;CSV 저장: {data}&quot;)

class JsonProcessor(DataProcessor):
    def read_data(self):
        print(&quot;JSON 파일 읽기&quot;)
        return [10, 20, 30]

    def transform(self, data):
        return [x + 1 for x in data]

    def write_data(self, data):
        print(f&quot;JSON 저장: {data}&quot;)

# 사용
CsvProcessor().process()
# CSV 파일 읽기 &amp;rarr; CSV 저장: [2, 4, 6]

JsonProcessor().process()
# JSON 파일 읽기 &amp;rarr; JSON 저장: [11, 21, 31]&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-10. 방문자 (Visitor)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조는 그대로 두고 새로운 연산을 추가한다.&lt;br /&gt;기존 클래스를 수정하지 않고 외부에서 기능을 붙일 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;21_3_10_방문자_Visitor.png&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Iqe33/dJMcagMrdPI/pKpKNuE9kpmGPeawzMBmk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Iqe33/dJMcagMrdPI/pKpKNuE9kpmGPeawzMBmk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Iqe33/dJMcagMrdPI/pKpKNuE9kpmGPeawzMBmk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIqe33%2FdJMcagMrdPI%2FpKpKNuE9kpmGPeawzMBmk1%2Fimg.png&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;524&quot; height=&quot;766&quot; data-filename=&quot;21_3_10_방문자_Visitor.png&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Visitor(ABC):
    @abstractmethod
    def visit_file(self, file: &quot;FileNode&quot;): ...
    @abstractmethod
    def visit_directory(self, directory: &quot;DirectoryNode&quot;): ...

class FileNode:
    def __init__(self, name: str, size: int):
        self.name = name
        self.size = size

    def accept(self, visitor: Visitor):
        visitor.visit_file(self)

class DirectoryNode:
    def __init__(self, name: str):
        self.name = name
        self.children = []

    def add(self, node): self.children.append(node)

    def accept(self, visitor: Visitor):
        visitor.visit_directory(self)
        for child in self.children:
            child.accept(visitor)

class SizeCalculator(Visitor):
    def __init__(self):
        self.total = 0

    def visit_file(self, file):
        self.total += file.size
        print(f&quot;  파일: {file.name} ({file.size}KB)&quot;)

    def visit_directory(self, directory):
        print(f&quot;디렉토리: {directory.name}&quot;)

# 사용
root = DirectoryNode(&quot;root&quot;)
root.add(FileNode(&quot;README.md&quot;, 10))
src = DirectoryNode(&quot;src&quot;)
src.add(FileNode(&quot;main.py&quot;, 50))
root.add(src)

calc = SizeCalculator()
root.accept(calc)
print(f&quot;총 크기: {calc.total}KB&quot;)
# 총 크기: 60KB&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-11. 인터프리터 (Interpreter)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어의 문법을 클래스 계층으로 표현하고, 해당 언어의 문장을 해석한다.&lt;br /&gt;간단한 DSL, 쿼리 파서, 수식 계산기에서 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;22_3_11_인터프리터_Interpreter.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/toYz0/dJMcab5n8Ri/4JvBOdcpsMgwyEnrZk874K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/toYz0/dJMcab5n8Ri/4JvBOdcpsMgwyEnrZk874K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/toYz0/dJMcab5n8Ri/4JvBOdcpsMgwyEnrZk874K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtoYz0%2FdJMcab5n8Ri%2F4JvBOdcpsMgwyEnrZk874K%2Fimg.png&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;884&quot; height=&quot;314&quot; data-filename=&quot;22_3_11_인터프리터_Interpreter.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from abc import ABC, abstractmethod

class Expression(ABC):
    @abstractmethod
    def interpret(self) -&amp;gt; int: ...

class NumberExpression(Expression):
    def __init__(self, value: int):
        self.value = value

    def interpret(self) -&amp;gt; int:
        return self.value

class AddExpression(Expression):
    def __init__(self, left: Expression, right: Expression):
        self.left = left
        self.right = right

    def interpret(self) -&amp;gt; int:
        return self.left.interpret() + self.right.interpret()

class MultiplyExpression(Expression):
    def __init__(self, left: Expression, right: Expression):
        self.left = left
        self.right = right

    def interpret(self) -&amp;gt; int:
        return self.left.interpret() * self.right.interpret()

# (3 + 4) * 2
expr = MultiplyExpression(
    AddExpression(NumberExpression(3), NumberExpression(4)),
    NumberExpression(2)
)
print(expr.interpret())  # 14&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패턴 선택 가이드&lt;/h2&gt;
&lt;table style=&quot;width: 676px;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 379px;&quot;&gt;상황&lt;/th&gt;
&lt;th style=&quot;width: 297px;&quot;&gt;추천 패턴&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;객체 생성 방식을 바꿔야 함&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;팩토리 메소드 / 추상 팩토리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;복잡한 객체를 단계별로 조립&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;빌더&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;초기화 비용이 큰 객체가 많이 필요&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;프로토타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;전역 단일 인스턴스 필요&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;싱글톤&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;인터페이스가 맞지 않는 기존 코드 재사용&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;어댑터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;기능과 구현을 독립적으로 확장&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;브리지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;트리 구조를 단일 인터페이스로 처리&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;컴포지트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;복잡한 서브시스템을 단순하게 노출&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;퍼케이드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;대량의 유사 객체로 메모리 절감&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;플라이웨이트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;접근 제어 / 캐싱 / 지연 초기화&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;프록시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;요청을 여러 핸들러 중 하나가 처리&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;책임 연쇄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;요청을 객체화해 undo/큐잉 필요&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;커맨드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;컬렉션 순회 방식을 캡슐화&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;이터레이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;객체 간 직접 참조를 없애고 싶음&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;중재자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;상태 저장 / 복원이 필요&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;메멘토&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;상태 변화를 여러 객체에 자동 전파&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;옵저버&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;상태에 따라 동작이 달라짐&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;알고리즘을 런타임에 교체&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;전략&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;알고리즘 골격은 고정, 세부만 변경&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;템플릿 메소드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;구조 변경 없이 새 연산 추가&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;방문자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 379px;&quot;&gt;간단한 언어/문법 해석&lt;/td&gt;
&lt;td style=&quot;width: 297px;&quot;&gt;인터프리터&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>Software</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/27</guid>
      <comments>https://revivalearth.tistory.com/entry/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC-with-Python#entry27comment</comments>
      <pubDate>Mon, 25 May 2026 10:52:55 +0900</pubDate>
    </item>
    <item>
      <title>Software 공학 핵심 정리 - 생명주기(SDLC) 및 방법론 등</title>
      <link>https://revivalearth.tistory.com/entry/Software-%EA%B3%B5%ED%95%99-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0SDLC-%EB%B0%8F-%EB%B0%A9%EB%B2%95%EB%A1%A0-%EB%93%B1</link>
      <description>&lt;h1&gt;소프트웨어 공학 핵심 정리&lt;/h1&gt;
&lt;h1&gt;1. 소프트웨어 생명 주기 (SDLC)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 개발 과정을 체계적으로 나눈 것이다. 어떤 모형을 선택하느냐에 따라 팀 구조, 문서화 방식, 일정 산정 방식이 달라진다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4가지 주요 모형 비교&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 123px;&quot;&gt;모형&lt;/th&gt;
&lt;th style=&quot;width: 371px;&quot;&gt;핵심 특징&lt;/th&gt;
&lt;th style=&quot;width: 199px;&quot;&gt;단점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 123px;&quot;&gt;&lt;b&gt;폭포수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 371px;&quot;&gt;단계가 순차적으로 진행, 이전 단계로 되돌아가기 어렵다&lt;/td&gt;
&lt;td style=&quot;width: 199px;&quot;&gt;요구 변화에 경직됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 123px;&quot;&gt;&lt;b&gt;프로토타입&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 371px;&quot;&gt;견본품을 먼저 만들어 최종 결과를 미리 확인한다&lt;/td&gt;
&lt;td style=&quot;width: 199px;&quot;&gt;프로토타입을 실제 제품으로 오해할 수 있다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 123px;&quot;&gt;&lt;b&gt;나선형&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 371px;&quot;&gt;위험 분석을 반복하며 점진적으로 완성한다&lt;/td&gt;
&lt;td style=&quot;width: 199px;&quot;&gt;관리가 복잡하다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 123px;&quot;&gt;&lt;b&gt;애자일&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 371px;&quot;&gt;짧은 반복 주기로 변화에 유연하게 대응한다&lt;/td&gt;
&lt;td style=&quot;width: 199px;&quot;&gt;문서화가 부족해질 수 있다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6eOXO/dJMcaiKanAG/vvv1gBXqRIKSp8jtzVgKv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6eOXO/dJMcaiKanAG/vvv1gBXqRIKSp8jtzVgKv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6eOXO/dJMcaiKanAG/vvv1gBXqRIKSp8jtzVgKv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6eOXO%2FdJMcaiKanAG%2Fvvv1gBXqRIKSp8jtzVgKv0%2Fimg.png&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;1512&quot; height=&quot;140&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;폭포수 모형&lt;/b&gt;은 이처럼 단계가 한 방향으로 흐른다. 이전 단계로 되돌아가는 것이 구조적으로 어렵다는 점이 핵심 단점이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;애자일 상세&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애자일은 특정 방법론이 아니라 일종의 철학이다. 그 아래에 스크럼, XP, 칸반, 린, FDD 같은 구체적인 방법론들이 존재한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스크럼 (Scrum)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;PO&lt;/code&gt; (Product Owner): 제품 백로그 관리, 우선순위 결정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SM&lt;/code&gt; (Scrum Master): 팀의 장애물 제거, 프로세스 가이드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DT&lt;/code&gt; (Development Team): 실제 개발을 담당하는 팀원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;진행 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coRr7d/dJMcahxMQA5/L1htJmHWrwJ71OR0syCCD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coRr7d/dJMcahxMQA5/L1htJmHWrwJ71OR0syCCD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coRr7d/dJMcahxMQA5/L1htJmHWrwJ71OR0syCCD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoRr7d%2FdJMcahxMQA5%2FL1htJmHWrwJ71OR0syCCD0%2Fimg.png&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;1568&quot; height=&quot;512&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프린트는 보통 1~4주 단위로 진행되며, 이 주기 안에서 계획, 개발, 검토, 회고가 모두 이루어진다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;XP (eXtreme Programming)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XP는 다섯 가지 가치를 기반으로 한다: &lt;b&gt;의사소통, 단순성, 용기, 존중, 피드백&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 실천 방법은 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;페어 프로그래밍&lt;/b&gt;: 두 명이 한 컴퓨터로 함께 코드를 작성한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TDD (테스트 주도 개발)&lt;/b&gt;: 코드보다 테스트를 먼저 작성한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공동 코드 소유&lt;/b&gt;: 팀원 누구나 코드를 수정할 수 있다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지속적 통합 (CI)&lt;/b&gt;: 코드를 자주 통합해 충돌을 미리 발견한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리팩토링&lt;/b&gt;: 기능을 유지하면서 코드 구조를 지속적으로 개선한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소규모 릴리즈&lt;/b&gt;: 작은 단위로 자주 배포한다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# TDD 예시: 테스트 먼저 작성
def test_add():
    assert add(2, 3) == 5  # 아직 add 함수가 없어도 테스트를 먼저 정의한다

# 그 다음 구현
def add(a, b):
    return a + b&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;2. 관리 시스템 선택 기준&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 선택 시 고려할 기준을 정리하면 아래와 같다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시스템&lt;/th&gt;
&lt;th&gt;주요 고려 요소&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DBMS&lt;/td&gt;
&lt;td&gt;가용성, 성능, 기술 지원, 구축 비용, 상호 호환성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WAS&lt;/td&gt;
&lt;td&gt;가용성, 성능, 기술 지원, 구축 비용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;오픈소스&lt;/td&gt;
&lt;td&gt;라이선스 종류, 사용자 수, 기술의 지속 가능성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS는 WAS에 비해 &lt;b&gt;상호 호환성&lt;/b&gt;이 추가된다는 점이 차이다. 다른 시스템과의 연동 가능성까지 확인해야 한다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;3. 요구사항&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기능 vs 비기능&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능 요구사항&lt;/b&gt;: 시스템이 &lt;b&gt;무엇을 해야 하는지&lt;/b&gt;에 대한 것. &quot;로그인 기능을 제공한다&quot;, &quot;검색 결과를 10개씩 보여준다&quot; 같은 것들이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비기능 요구사항&lt;/b&gt;: &lt;b&gt;품질과 제약&lt;/b&gt;에 관한 것. &quot;응답 시간이 1초 이내여야 한다&quot;, &quot;HTTPS를 사용해야 한다&quot; 같은 것들이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개발 프로세스&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vp51n/dJMcahLjzwl/1EV7XF9iP2IRQRMVYUPCA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vp51n/dJMcahLjzwl/1EV7XF9iP2IRQRMVYUPCA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vp51n/dJMcahLjzwl/1EV7XF9iP2IRQRMVYUPCA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVp51n%2FdJMcahLjzwl%2F1EV7XF9iP2IRQRMVYUPCA1%2Fimg.png&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;1068&quot; height=&quot;140&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;분석 단계: DFD와 자료 사전&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DFD (Data Flow Diagram)&lt;/b&gt;는 데이터의 흐름과 변환 과정을 도형으로 표현하는 도구다. 구조적 분석에 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFD의 4가지 구성 요소:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로세스&lt;/b&gt;: 데이터를 변환하는 처리 단위 (원으로 표현)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자료 흐름&lt;/b&gt;: 데이터의 이동 경로 (화살표)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자료 저장소&lt;/b&gt;: 데이터가 보관되는 곳 (이중 선)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단말&lt;/b&gt;: 시스템 외부의 입출력 주체 (사각형)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자료 사전&lt;/b&gt; 기호 요약:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기호&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;정의&lt;/td&gt;
&lt;td&gt;주문 = 고객명 + 상품명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;연결 (AND)&lt;/td&gt;
&lt;td&gt;이름 + 전화번호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;( )&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;생략 가능&lt;/td&gt;
&lt;td&gt;(주소)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[ ]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;선택 (OR)&lt;/td&gt;
&lt;td&gt;[현금|카드]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{ }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;반복&lt;/td&gt;
&lt;td&gt;{주문 항목}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;** **&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;설명/주석&lt;/td&gt;
&lt;td&gt;&lt;b&gt;배송 상태 코드&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;명세 단계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정형 명세 기법&lt;/b&gt;: VDM, Z, Petri-net, CSP. 수학적 표기를 사용해 정밀하게 표현한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비정형 명세 기법&lt;/b&gt;: FSM, Decision Table, ER 모델링, State Chart. 더 직관적이며 현업에서 자주 쓰인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;4. UML&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UML은 객체지향 설계를 시각적으로 표현하기 위한 표준 모델링 언어다. 럼바우, 부치, 제이콥슨의 방법론을 통합해서 만들어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지 구성 요소는 &lt;b&gt;사물(Things), 다이어그램(Diagram), 관계(Relationships)&lt;/b&gt;다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다이어그램 분류&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bswkmp/dJMcagFFLUx/KyUkv5yPHUzH89cJsIjKiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bswkmp/dJMcagFFLUx/KyUkv5yPHUzH89cJsIjKiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bswkmp/dJMcagFFLUx/KyUkv5yPHUzH89cJsIjKiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbswkmp%2FdJMcagFFLUx%2FKyUkv5yPHUzH89cJsIjKiK%2Fimg.png&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;1568&quot; height=&quot;278&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 다이어그램 정리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;유스케이스 다이어그램&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;포함 관계 (include)&lt;/b&gt;: 기존 유스케이스에서 새로 만든 유스케이스로 점선 화살표가 향한다. &quot;반드시 포함된다&quot;는 의미다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장 관계 (extend)&lt;/b&gt;: 확장하는 유스케이스에서 원래 유스케이스 방향으로 점선 화살표가 향한다. &quot;조건에 따라 추가된다&quot;는 의미다.&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;568&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c11nDk/dJMcag6G4Nd/WsXXS7kduztgZGTPYpSIH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c11nDk/dJMcag6G4Nd/WsXXS7kduztgZGTPYpSIH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c11nDk/dJMcag6G4Nd/WsXXS7kduztgZGTPYpSIH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc11nDk%2FdJMcag6G4Nd%2FWsXXS7kduztgZGTPYpSIH1%2Fimg.png&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;391&quot; height=&quot;307&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시퀀스 vs 커뮤니케이션&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 객체 간 메시지 흐름을 표현하지만, 시퀀스는 &lt;b&gt;시간 순서&lt;/b&gt;를, 커뮤니케이션은 &lt;b&gt;객체 간 연관 관계&lt;/b&gt;를 더 강조한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;활동 다이어그램의 노드 구분&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 이름이 비슷해 헷갈리기 쉽다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;노드&lt;/th&gt;
&lt;th&gt;모양&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;조건 노드&lt;/td&gt;
&lt;td&gt;마름모&lt;/td&gt;
&lt;td&gt;나가는 흐름이 2개 이상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;병합 노드&lt;/td&gt;
&lt;td&gt;마름모&lt;/td&gt;
&lt;td&gt;들어오는 흐름이 2개 이상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;포크 노드&lt;/td&gt;
&lt;td&gt;두꺼운 가로선&lt;/td&gt;
&lt;td&gt;병렬 분기 시작 (나가는 흐름 2+)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;조인 노드&lt;/td&gt;
&lt;td&gt;두꺼운 가로선&lt;/td&gt;
&lt;td&gt;병렬 흐름 합류 (들어오는 흐름 2+)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스윔 레인&lt;/td&gt;
&lt;td&gt;구분선&lt;/td&gt;
&lt;td&gt;행위 주체를 구분하는 영역&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;관계 정리&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YoHFf/dJMcadWpFqE/IERXYBRMACrSkkEjgUik6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YoHFf/dJMcadWpFqE/IERXYBRMACrSkkEjgUik6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YoHFf/dJMcadWpFqE/IERXYBRMACrSkkEjgUik6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYoHFf%2FdJMcadWpFqE%2FIERXYBRMACrSkkEjgUik6k%2Fimg.png&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;1196&quot; height=&quot;516&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계를 정리하면 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;연관&lt;/b&gt;: 서로 관련된 관계. 실선.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;집합&lt;/b&gt;: 부분이 전체에 포함되지만, 독립적으로 존재 가능. 속이 빈 마름모.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포함(Composition)&lt;/b&gt;: 부분이 전체에 종속됨. 전체가 사라지면 부분도 사라진다. 속이 찬 마름모.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일반화&lt;/b&gt;: 상속 관계. 속이 빈 실선 화살표.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의존&lt;/b&gt;: 짧은 시간만 연관. 점선 화살표.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실체화&lt;/b&gt;: 인터페이스 구현. 속이 빈 점선 화살표.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;5. 개발 방법론 및 비용 산정&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;방법론 비교&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방법론&lt;/th&gt;
&lt;th&gt;핵심 개념&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;객체지향&lt;/td&gt;
&lt;td&gt;객체를 조립해 시스템 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;컴포넌트 기반 (CBD)&lt;/td&gt;
&lt;td&gt;기존 컴포넌트를 재조합해 새 시스템 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;소프트웨어 재사용&lt;/td&gt;
&lt;td&gt;검증된 SW를 다른 개발에 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;소프트웨어 재공학&lt;/td&gt;
&lt;td&gt;기존 시스템을 분석해 더 나은 시스템으로 재구성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 재사용은 두 가지 방식이 있다. &lt;b&gt;합성 중심&lt;/b&gt;은 블록을 조립하듯 완성하고, &lt;b&gt;생성 중심&lt;/b&gt;은 추상화된 명세를 구체화해 생성한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비용 산정 기법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SC4Nw/dJMcadWpFqQ/KR7lBCBm2yWPBbfoL396dK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SC4Nw/dJMcadWpFqQ/KR7lBCBm2yWPBbfoL396dK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SC4Nw/dJMcadWpFqQ/KR7lBCBm2yWPBbfoL396dK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSC4Nw%2FdJMcadWpFqQ%2FKR7lBCBm2yWPBbfoL396dK%2Fimg.png&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;1568&quot; height=&quot;374&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LOC 공식&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-05-25 10.37.48.png&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zcg5Z/dJMcai4r3pt/DbnQxAptPI0drt8YscTRKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zcg5Z/dJMcai4r3pt/DbnQxAptPI0drt8YscTRKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zcg5Z/dJMcai4r3pt/DbnQxAptPI0drt8YscTRKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzcg5Z%2FdJMcai4r3pt%2FDbnQxAptPI0drt8YscTRKK%2Fimg.png&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;378&quot; height=&quot;68&quot; data-filename=&quot;스크린샷 2026-05-25 10.37.48.png&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;COCOMO 유형&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;조직형&lt;/b&gt;: 5만 라인 이하, 소규모 팀&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반분리형&lt;/b&gt;: 30만 라인 이하, 중간 규모&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임베디드형&lt;/b&gt;: 30만 라인 초과, 복잡한 하드웨어 연계 환경&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;일정 관리 도구&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PERT&lt;/b&gt;: 불확실한 상황에서 완료 시기를 확률적으로 예측한다. 낙관, 가능성, 비관 세 가지 시나리오를 활용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPM&lt;/b&gt;: 전체 작업 네트워크에서 가장 긴 경로(임계 경로)를 찾는다. 이 경로가 전체 프로젝트 기간을 결정한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간트 차트&lt;/b&gt;: 작업별 일정을 막대 형태로 시각화한 표다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;소프트웨어 품질 및 평가 모델&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;모델&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ISO/IEC 12207&lt;/td&gt;
&lt;td&gt;생명 주기 프로세스 표준. 기본/지원/조직 프로세스로 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CMMI&lt;/td&gt;
&lt;td&gt;조직의 프로세스 성숙도를 5단계로 평가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SPICE (ISO/IEC 15504)&lt;/td&gt;
&lt;td&gt;소프트웨어 프로세스 수행 능력을 6단계로 평가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CMMI 5단계&lt;/b&gt; (초관정정최): 초기 &amp;rarr; 관리 &amp;rarr; 정의 &amp;rarr; 정량적 관리 &amp;rarr; 최적화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SPICE 6단계&lt;/b&gt;: 불완전 &amp;rarr; 수행 &amp;rarr; 관리 &amp;rarr; 확립 &amp;rarr; 예측 &amp;rarr; 최적화&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스테레오 타입&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UML 기본 표기 외에 추가 의미를 부여할 때 사용한다. &lt;code&gt;&amp;lt;&amp;lt;interface&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;abstract&amp;gt;&amp;gt;&lt;/code&gt; 같은 형식으로 표현한다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;&amp;lt;&amp;lt;interface&amp;gt;&amp;gt;
PaymentGateway&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;부록 &amp;mdash; 개발 프레임워크와 CASE&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CASE (Computer-Aided Software Engineering)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SW 개발 과정의 전부 또는 일부를 자동화하는 도구다. 분석 단계에서 쓰이는 CASE 도구로는 SADT, SREM, PSL/PSA, TAGS 등이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SADT&lt;/b&gt;: SoftTech 사가 개발. 시스템 정의와 요구사항 분석에 활용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HIPO&lt;/b&gt;: 입력-처리-출력 기능을 계층 구조로 표현. 하향식 개발의 문서화 도구.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링 프레임워크&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 기반의 오픈소스 경량형 애플리케이션 프레임워크다. 핵심 특성은 &lt;b&gt;모듈화, 재사용성, 확장성, 제어의 역흐름(IoC)&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;// IoC (제어의 역흐름) 예시
// 직접 객체를 생성하는 대신, 스프링이 의존성을 주입해준다
@Service
public class OrderService {
    private final PaymentService paymentService;

    // 스프링이 PaymentService를 자동으로 주입한다 (생성자 주입)
    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 객체의 생성과 생명 주기를 직접 제어하는 대신, 프레임워크가 그 제어권을 가져가는 방식이다. 이것이 &quot;제어의 역흐름&quot;이라는 이름의 유래다.&lt;/p&gt;</description>
      <category>Software</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/26</guid>
      <comments>https://revivalearth.tistory.com/entry/Software-%EA%B3%B5%ED%95%99-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0SDLC-%EB%B0%8F-%EB%B0%A9%EB%B2%95%EB%A1%A0-%EB%93%B1#entry26comment</comments>
      <pubDate>Mon, 25 May 2026 10:38:35 +0900</pubDate>
    </item>
    <item>
      <title>[ML] 군집화 알고리즘을 Azure ML에서 구현</title>
      <link>https://revivalearth.tistory.com/entry/ML-PCA%EC%99%80-K-%EA%B5%B0%EC%A7%91%ED%99%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;군집화 알고리즘&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;군집화&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;회기 모델에서 &lt;code&gt;오차&lt;/code&gt; 개념을 사용하였다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;군집이 잘 뭉쳐있는지, 넓게 퍼져있는지를 볼 때 &lt;b&gt;오차&lt;/b&gt;를 &lt;b&gt;거리&lt;/b&gt; 개념으로 사용한다. 각 군집 간의 거리도 지표로 사용 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;거리에 대한 것은 Manhattan distance와 Euclidian distance가 있으며, 그 외에&amp;nbsp;Minkowski, Mahlanobis, Jacaard 개념 등이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;군집화 알고리즘의 종류&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;분할적 군집화&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;K-MEANS Clustering, DBSCAN 등이 있으며, 계층 관계가 없고 직관적인 방법이 특징.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;중심점(Centroid)이 거리의 평균. K(클러스터링 수)를 미리 정하고 초기 중심점 설정 이후 그 갱신을 반복한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bskyvision.com/entry/%EA%B0%80%EC%9E%A5-%EA%B0%84%EB%8B%A8%ED%95%9C-%EA%B5%B0%EC%A7%91-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-K-means-%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%A7%81&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;추가 참고 자료: 군집 클러스터링 (bskyvision)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;* K-Means&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;알고리즘&lt;/b&gt;은 경계가 선으로 구분된다. 그러기 때문에 기하학적 모양의 군집은 제대로 되지 않을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;계층적 군집화&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;군집 간에 상하 계층적 구조로 형성 된다. (Dendrogram) 거리에 따라 계층을 형성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;덴드로그램의 단점은 데이터 추가 제거에 대해 전체 연산량 부하가 많을 수도 있다.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DBSCAN Clustering (Density-Based Spatial CLustering of Applications with Noise)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밀도의 개념으로 군집을 형성하며, 그 결과를 통해 Noise 제거가 가능하다. 클러스터에 할당되지 않는 데이터도 있으며, 이러한 형태의 Noise를 제거할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Core Point, Border Point, Noise Point가 주요 항목이며, 하이퍼 파라미터로 Epsilon(이웃 반경), minPts(최소 샘플 수)가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;K-MEANS 클러스터링의 초기화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Random Seed 방법은 임의로 초기화점을 선택하며, 이로 인해 간혹 잘못된 결과가 나오기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;b&gt;K-Means ++&lt;/b&gt;는 초기 Centroid가 최대한 서로 멀리 떨어지도록 선택하는 방법이며, 랜덤 시드 초기화보다 빠르게 수렴한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;군집수 결정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오차제곱합(SSE, Sum of Squared Error)&lt;/b&gt;: 군집 내 유사도 최대화&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-24 17.13.11.png&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sLVut/dJMcagw99yz/kBfjrRwVd0qhS36g1lNxUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sLVut/dJMcagw99yz/kBfjrRwVd0qhS36g1lNxUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sLVut/dJMcagw99yz/kBfjrRwVd0qhS36g1lNxUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsLVut%2FdJMcagw99yz%2FkBfjrRwVd0qhS36g1lNxUk%2Fimg.png&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;369&quot; height=&quot;218&quot; data-filename=&quot;스크린샷 2025-11-24 17.13.11.png&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실루엣 (Silhouette)&lt;/b&gt;: 군집 내 유사도 최대화 + 군집 간 유사도 최소화&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;CodeCogsEqn.png&quot; data-origin-width=&quot;217&quot; data-origin-height=&quot;75&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjzVaG/dJMcahv4zEm/7wE9kRk2ENg3kyUCe7ap80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjzVaG/dJMcahv4zEm/7wE9kRk2ENg3kyUCe7ap80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjzVaG/dJMcahv4zEm/7wE9kRk2ENg3kyUCe7ap80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjzVaG%2FdJMcahv4zEm%2F7wE9kRk2ENg3kyUCe7ap80%2Fimg.png&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;217&quot; height=&quot;75&quot; data-filename=&quot;CodeCogsEqn.png&quot; data-origin-width=&quot;217&quot; data-origin-height=&quot;75&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #777777; text-align: center;&quot;&gt;a(i): 동일한 클러스터 내 데이터들과의 평균 거리 (응집도), &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #777777; text-align: center;&quot;&gt;b(i): 가장 가까운 다른 클러스터 데이터들과의 평균거리 (분리도)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실루엣의 경우 응집도와 분리도를 함께 보아야 한다. 실루엣의 가파른 정도에 따라 군집화가 잘 구성되었는지 판단할 수 있으며, &lt;b&gt;실루엣 계수 평균 선&lt;/b&gt; 또한 이와 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hyunse0.tistory.com/49&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고 자료: 군집 분석 (ML)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Azure ML을 통한 시각화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 클러스터 머신 러닝 분석은 아래 단계와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 전처리와 병합&lt;/li&gt;
&lt;li&gt;정규화 (Normalization)&lt;/li&gt;
&lt;li&gt;주성분분석 (PCA)&lt;/li&gt;
&lt;li&gt;데이터 분리 및 학습&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-25 10.13.02.png&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;877&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPiKvi/dJMcaaDIsJ8/Z7FG50TqO6BIPvYzTV0kr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPiKvi/dJMcaaDIsJ8/Z7FG50TqO6BIPvYzTV0kr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPiKvi/dJMcaaDIsJ8/Z7FG50TqO6BIPvYzTV0kr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPiKvi%2FdJMcaaDIsJ8%2FZ7FG50TqO6BIPvYzTV0kr1%2Fimg.png&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;513&quot; height=&quot;627&quot; data-filename=&quot;스크린샷 2025-11-25 10.13.02.png&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;877&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`Execute Python Script` 블럭에서는 PCA를 수행하며, 별도의 코드를 삽입해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Data &amp;amp; Science</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/17</guid>
      <comments>https://revivalearth.tistory.com/entry/ML-PCA%EC%99%80-K-%EA%B5%B0%EC%A7%91%ED%99%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98#entry17comment</comments>
      <pubDate>Mon, 24 Nov 2025 17:23:12 +0900</pubDate>
    </item>
    <item>
      <title>Designing a Real-Time Data Streaming Architecture on Azure</title>
      <link>https://revivalearth.tistory.com/entry/Azure%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%98%EC%97%AC-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;eventhub.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btoVCS/dJMcahQfOe5/O7durPIBFeEcS38Aa5rRu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btoVCS/dJMcahQfOe5/O7durPIBFeEcS38Aa5rRu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btoVCS/dJMcahQfOe5/O7durPIBFeEcS38Aa5rRu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtoVCS%2FdJMcahQfOe5%2FO7durPIBFeEcS38Aa5rRu1%2Fimg.png&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;1024&quot; height=&quot;768&quot; data-filename=&quot;eventhub.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;difficulty.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dduXsL/dJMcaacwuhl/68qhsMCmnKgkHNMlhzXfQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dduXsL/dJMcaacwuhl/68qhsMCmnKgkHNMlhzXfQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dduXsL/dJMcaacwuhl/68qhsMCmnKgkHNMlhzXfQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdduXsL%2FdJMcaacwuhl%2F68qhsMCmnKgkHNMlhzXfQk%2Fimg.png&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;573&quot; height=&quot;154&quot; data-filename=&quot;difficulty.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Azure Cloud is a PaaS platform that helps developers build applications without managing infrastructure.&lt;br /&gt;It also enables real-time data streaming using open-source technologies such as &lt;b&gt;Kafka&lt;/b&gt; and &lt;b&gt;Elasticsearch&lt;/b&gt;.&lt;br /&gt;Additionally, Azure provides a large-scale message pipeline service called &lt;b&gt;Azure Event Hub&lt;/b&gt;, which works similarly to Kafka.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Azure Event Hub&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Azure Event Hub helps process massive real-time data streams, handling millions of events per second.&lt;br /&gt;It is similar to Kafka, but if you prefer an open-source and self-managed architecture, you can use Kafka instead.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Why use Event Hub?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;If your workflow focuses on batch processing&amp;mdash;collecting, cleaning, and loading data in bulk&amp;mdash;you don&amp;rsquo;t necessarily need to use Event Hub.&lt;br /&gt;However, Event Hub is optimized for real-time streaming, capable of handling a massive number of concurrent events and routing them to multiple independent microservices.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Azure Functions&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Azure Functions is a serverless computing service that allows you to run small, single-purpose pieces of code.&lt;br /&gt;It can handle business logic, data processing or transformation, and API requests.&lt;br /&gt;It is simple, lightweight, fast, and flexible.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Currently, the function only logs messages, but you can implement any business logic or custom functionality you want inside it.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;import azure.functions as func
import logging

app = func.FunctionApp()

@app.event_hub_message_trigger(arg_name=&quot;azeventhub&quot;, event_hub_name=&quot;myeventhub&quot;,
                               connection=&quot;exampleEventhub_RootManageSharedAccessKey_EVENTHUB&quot;) 
def eventhub_trigger(azeventhub: func.EventHubEvent):
    logging.info('Python EventHub trigger processed an event: %s',
                azeventhub.get_body().decode('utf-8'))


@app.function_name(name=&quot;eventhub_output&quot;)
@app.route(route=&quot;eventhub_output&quot;, methods=[&quot;POST&quot;])
@app.event_hub_output(arg_name=&quot;event&quot;, 
                      event_hub_name='myeventhub',
                      connection=&quot;exampleEventhub_RootManageSharedAccessKey_EVENTHUB&quot;)
def eventhub_output(req: func.HttpRequest, event: func.Out[str]) -&amp;gt; func.HttpResponse:
    req_body = req.get_body().decode('utf-8')
    event.set(req_body)
    logging.info(&quot;HTTP trigger function received a request: %s&quot;, req_body)

    return func.HttpResponse(&quot;Event Hub output function executed successfully.&quot;, status_code=200)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Tip] For more information on how to build an Azure Function, see: &lt;a href=&quot;https://revivalearth.tistory.com/entry/How-can-I-build-an-Event-Hub-in-Azure-and-integrate-it-with-a-webhook-for-Microsoft-Teams&quot;&gt;How-can-I-build-an-Event-Hub-in-Azure-and-integrate-it-with-a-webhook-for-Microsoft-Teams&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Simple Diagram&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Mermaid Chart - Create complex, visual diagrams with text.-2025-11-04-024727.png&quot; data-origin-width=&quot;2150&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIL09a/dJMcahW1lJu/3AqFu1Uv9b3krkKTQW6c81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIL09a/dJMcahW1lJu/3AqFu1Uv9b3krkKTQW6c81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIL09a/dJMcahW1lJu/3AqFu1Uv9b3krkKTQW6c81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIL09a%2FdJMcahW1lJu%2F3AqFu1Uv9b3krkKTQW6c81%2Fimg.png&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;2150&quot; height=&quot;942&quot; data-filename=&quot;Mermaid Chart - Create complex, visual diagrams with text.-2025-11-04-024727.png&quot; data-origin-width=&quot;2150&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;When a client makes a &lt;b&gt;POST&lt;/b&gt; request to &lt;code&gt;/api/eventhub_output&lt;/code&gt;, the Azure Function forwards the data to an &lt;b&gt;Event Hub&lt;/b&gt; that it&amp;rsquo;s already connected to.&lt;br /&gt;The &lt;b&gt;Event Hub&lt;/b&gt; then triggers another function by publishing a new message.&lt;br /&gt;This triggered function runs the logic defined by the user.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Mermaid Chart - Create complex, visual diagrams with text.-2025-11-04-024723.png&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;1484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/batoH6/dJMcadAjMhk/N4GwUj4K54roOJacPyX8w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/batoH6/dJMcadAjMhk/N4GwUj4K54roOJacPyX8w1/img.png&quot; data-alt=&quot;Very simple diagram for EventHub &amp;amp;amp; Function&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/batoH6/dJMcadAjMhk/N4GwUj4K54roOJacPyX8w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbatoH6%2FdJMcadAjMhk%2FN4GwUj4K54roOJacPyX8w1%2Fimg.png&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;234&quot; height=&quot;546&quot; data-filename=&quot;Mermaid Chart - Create complex, visual diagrams with text.-2025-11-04-024723.png&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;1484&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Very simple diagram for EventHub &amp;amp; Function&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Event Hub can be connected to other microservices, as it is capable of processing massive amounts of data concurrently in real time.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JmM6Z/dJMb99YZjbD/eyZMT77T4kJ3fvnx6s0T41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JmM6Z/dJMb99YZjbD/eyZMT77T4kJ3fvnx6s0T41/img.png&quot; data-alt=&quot;An example diagram for Data Processing&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JmM6Z/dJMb99YZjbD/eyZMT77T4kJ3fvnx6s0T41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJmM6Z%2FdJMb99YZjbD%2FeyZMT77T4kJ3fvnx6s0T41%2Fimg.png&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;736&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;736&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;An example diagram for Data Processing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The purpose of using Event Hub is not just to collect massive amounts of data, but to enable automatic scale-out and flexible customization in response to incoming data from producers.&lt;br /&gt;Developers can also build a real-time, large-scale data streaming architecture without worrying about infrastructure, allowing them to focus on implementing business logic and core project features.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Build the services on Azure Portal&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Once you have created an Event Hub, you will see a screen where you can manage your Event Hub instances, as shown below.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-04 15.57.26.png&quot; data-origin-width=&quot;1506&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ecfh26/dJMcaeTwSIa/4rMA4rXuNArGF2pjbkv6Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ecfh26/dJMcaeTwSIa/4rMA4rXuNArGF2pjbkv6Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ecfh26/dJMcaeTwSIa/4rMA4rXuNArGF2pjbkv6Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fecfh26%2FdJMcaeTwSIa%2F4rMA4rXuNArGF2pjbkv6Hk%2Fimg.png&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;773&quot; height=&quot;429&quot; data-filename=&quot;스크린샷 2025-11-04 15.57.26.png&quot; data-origin-width=&quot;1506&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The &lt;code&gt;Data Explorer&lt;/code&gt; tab allows you to view the list of events received from producers and send dummy events for testing.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-04 16.00.41.png&quot; data-origin-width=&quot;1669&quot; data-origin-height=&quot;841&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IsVBC/dJMcacOWE4s/lZPZC9Hrrj7YrOWxXdKqzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IsVBC/dJMcacOWE4s/lZPZC9Hrrj7YrOWxXdKqzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IsVBC/dJMcacOWE4s/lZPZC9Hrrj7YrOWxXdKqzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIsVBC%2FdJMcacOWE4s%2FlZPZC9Hrrj7YrOWxXdKqzk%2Fimg.png&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;759&quot; height=&quot;382&quot; data-filename=&quot;스크린샷 2025-11-04 16.00.41.png&quot; data-origin-width=&quot;1669&quot; data-origin-height=&quot;841&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Logging and Test in Azure Function&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You can check logs and test whether your functions work properly.&lt;br /&gt;But be sure to configure security tokens and authentication settings correctly when your Azure Function is accessed externally.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-04 16.03.59.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lCILu/dJMcafkBduy/42xtBGwG2ulNisIbEjM870/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lCILu/dJMcafkBduy/42xtBGwG2ulNisIbEjM870/img.png&quot; data-alt=&quot;Function App ➣ An event hub we created before &amp;amp;gt; Tab 'Logs'&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lCILu/dJMcafkBduy/42xtBGwG2ulNisIbEjM870/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlCILu%2FdJMcafkBduy%2F42xtBGwG2ulNisIbEjM870%2Fimg.png&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;1682&quot; height=&quot;548&quot; data-filename=&quot;스크린샷 2025-11-04 16.03.59.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Function App ➣ An event hub we created before &amp;gt; Tab 'Logs'&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Tip] You can test your deployed Azure Function with the following command:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;curl -X POST -d https://&amp;lt;Your App Name&amp;gt;.azurewebsites.net/api/&amp;lt;Function Name&amp;gt;?code=&amp;lt;Function Token&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Note] If the &lt;b&gt;Authorization Level&lt;/b&gt; is set to function or admin, you must include the code parameter in the URL.&lt;br /&gt;However, if it is set to anonymous, no token is required, and the &lt;b&gt;Authorization Level&lt;/b&gt; can be configured when you create or initialize the function.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Cloud Infra/Azure</category>
      <category>azure</category>
      <category>Azure Event Hub</category>
      <category>Beginner</category>
      <category>Data Streaming</category>
      <category>Event Hub</category>
      <category>kafka</category>
      <category>실시간 데이터 스트리밍</category>
      <category>이벤트 허브</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/12</guid>
      <comments>https://revivalearth.tistory.com/entry/Azure%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%98%EC%97%AC-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0#entry12comment</comments>
      <pubDate>Tue, 4 Nov 2025 15:06:55 +0900</pubDate>
    </item>
    <item>
      <title>Building a RAG Model with Azure OpenAI and NoSQL (1)</title>
      <link>https://revivalearth.tistory.com/entry/Building-a-RAG-Model-with-Azure-OpenAI-and-Azure-Cosmos-DB</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;rag model.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9rFQf/dJMb99SczIX/A4AdXGXnPyHkdFhydPa9uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9rFQf/dJMb99SczIX/A4AdXGXnPyHkdFhydPa9uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9rFQf/dJMb99SczIX/A4AdXGXnPyHkdFhydPa9uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9rFQf%2FdJMb99SczIX%2FA4AdXGXnPyHkdFhydPa9uK%2Fimg.png&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;1024&quot; height=&quot;768&quot; data-filename=&quot;rag model.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;difficulty-intermediate.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVbca4/dJMcahQf0XG/7Z4ZUxl2UQyCkvxGmtpyl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVbca4/dJMcahQf0XG/7Z4ZUxl2UQyCkvxGmtpyl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVbca4/dJMcahQf0XG/7Z4ZUxl2UQyCkvxGmtpyl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVbca4%2FdJMcahQf0XG%2F7Z4ZUxl2UQyCkvxGmtpyl0%2Fimg.png&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;603&quot; height=&quot;162&quot; data-filename=&quot;difficulty-intermediate.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The RAG model is useful for improving the search performance and reliability of artificial intelligence systems.&lt;br /&gt;As you may know, Azure Cloud provides OpenAI services and also supports NoSQL databases such as Azure Cosmos DB.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ready to start:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;You need one resource group.&lt;/li&gt;
&lt;li&gt;Make sure your subscription has valid payment information registered.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ Create an Azure Open AI&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You can find &lt;b&gt;Azure OpenAI&lt;/b&gt; in the &lt;b&gt;Azure Marketplace&lt;/b&gt;.&lt;br /&gt;Click &lt;b&gt;Create&lt;/b&gt; to start setting up a new &lt;b&gt;Azure OpenAI instance&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-1.png&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bapzUO/dJMcaj8ngwZ/127RQu5wLccMXwNT0INUZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bapzUO/dJMcaj8ngwZ/127RQu5wLccMXwNT0INUZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bapzUO/dJMcaj8ngwZ/127RQu5wLccMXwNT0INUZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbapzUO%2FdJMcaj8ngwZ%2F127RQu5wLccMXwNT0INUZ0%2Fimg.png&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;608&quot; height=&quot;493&quot; data-filename=&quot;az-2-openai-1.png&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Select your &lt;b&gt;subscription type&lt;/b&gt; and the &lt;b&gt;resource group&lt;/b&gt; you created earlier.&lt;br /&gt;Then, configure any other settings according to your preferences.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-2.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;879&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lV5lF/dJMcafkBfKX/EnozcJjg2CBVlVPmDxksW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lV5lF/dJMcafkBfKX/EnozcJjg2CBVlVPmDxksW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lV5lF/dJMcafkBfKX/EnozcJjg2CBVlVPmDxksW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlV5lF%2FdJMcafkBfKX%2FEnozcJjg2CBVlVPmDxksW1%2Fimg.png&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;596&quot; height=&quot;540&quot; data-filename=&quot;az-2-openai-2.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;879&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Once the instance has been created, you will see a &lt;b&gt;dashboard&lt;/b&gt; similar to the image below.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1691&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GzgCO/dJMcacg6Tlw/GEkoOfEcp5IAwjjN33mOhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GzgCO/dJMcacg6Tlw/GEkoOfEcp5IAwjjN33mOhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GzgCO/dJMcacg6Tlw/GEkoOfEcp5IAwjjN33mOhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGzgCO%2FdJMcacg6Tlw%2FGEkoOfEcp5IAwjjN33mOhK%2Fimg.png&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;1691&quot; height=&quot;858&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1691&quot; data-origin-height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ Azure AI Foundry&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Creating a LLM Instance&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;If you click &lt;b&gt;Go to Azure AI Foundry portal&lt;/b&gt;, a page will appear where you can configure your preferences and create AI instances.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-4.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc44db/dJMb99LsmyS/MNGIv66GEUA2NFQolHQkt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc44db/dJMb99LsmyS/MNGIv66GEUA2NFQolHQkt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc44db/dJMb99LsmyS/MNGIv66GEUA2NFQolHQkt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc44db%2FdJMb99LsmyS%2FMNGIv66GEUA2NFQolHQkt0%2Fimg.png&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;1920&quot; height=&quot;912&quot; data-filename=&quot;az-2-openai-4.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Find the tab named &lt;b&gt;Deployments&lt;/b&gt; below, then click &lt;b&gt;+ Deploy model&lt;/b&gt; and select &lt;b&gt;Deploy base model&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-5.png&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qi89u/dJMcae64guM/YFX8EKpLtDkpkycZeg5rJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qi89u/dJMcae64guM/YFX8EKpLtDkpkycZeg5rJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qi89u/dJMcae64guM/YFX8EKpLtDkpkycZeg5rJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqi89u%2FdJMcae64guM%2FYFX8EKpLtDkpkycZeg5rJk%2Fimg.png&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;919&quot; height=&quot;920&quot; data-filename=&quot;az-2-openai-5.png&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;920&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You can search for many AI models. For this example, we will search for &lt;code&gt;**gpt-4o-mini**&lt;/code&gt;, or you can choose another model you want to use.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-6.png&quot; data-origin-width=&quot;1605&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5HqY5/dJMcaaKmCDt/MSP8yUT5kv6hpXvgsKHtLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5HqY5/dJMcaaKmCDt/MSP8yUT5kv6hpXvgsKHtLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5HqY5/dJMcaaKmCDt/MSP8yUT5kv6hpXvgsKHtLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5HqY5%2FdJMcaaKmCDt%2FMSP8yUT5kv6hpXvgsKHtLk%2Fimg.png&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;1605&quot; height=&quot;900&quot; data-filename=&quot;az-2-openai-6.png&quot; data-origin-width=&quot;1605&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;If you find the AI model you want to use, click &lt;b&gt;Confirm&lt;/b&gt; to continue creating the instance.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-7-model.png&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;609&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YOc5I/dJMcahJuqhH/y5wASBkksV9kNwGEvF9yRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YOc5I/dJMcahJuqhH/y5wASBkksV9kNwGEvF9yRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YOc5I/dJMcahJuqhH/y5wASBkksV9kNwGEvF9yRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYOc5I%2FdJMcahJuqhH%2Fy5wASBkksV9kNwGEvF9yRk%2Fimg.png&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;635&quot; height=&quot;609&quot; data-filename=&quot;az-2-openai-7-model.png&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;609&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Then, you can click `&lt;b&gt;Customize`&lt;/b&gt; to set up the preferences as you like.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-8-model.png&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;866&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OsOkD/dJMcagqhkfy/T3MjUQRLnrPsqwkiBsWpOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OsOkD/dJMcagqhkfy/T3MjUQRLnrPsqwkiBsWpOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OsOkD/dJMcagqhkfy/T3MjUQRLnrPsqwkiBsWpOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOsOkD%2FdJMcagqhkfy%2FT3MjUQRLnrPsqwkiBsWpOK%2Fimg.png&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;642&quot; height=&quot;866&quot; data-filename=&quot;az-2-openai-8-model.png&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Adjust the &lt;b&gt;slider bar&lt;/b&gt; to set the &lt;b&gt;Maximum Token Rate&lt;/b&gt; in the detailed settings panel.&lt;br /&gt;When you finish configuring the settings, click &lt;b&gt;Deploy&lt;/b&gt; to continue creating the instance.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ Creating a Text Embedding Model Instance&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Just like you created the LLM instance earlier, you also need to create a text embedding model instance.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enter &lt;code&gt;text-embedding&lt;/code&gt; in the search bar to find the Embeddings model, then click it to continue creating the instance.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-9-embedding.png&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;787&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8ShF6/dJMcain5Wpo/kRkOW9hPVgiDH0o0Z9FJv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8ShF6/dJMcain5Wpo/kRkOW9hPVgiDH0o0Z9FJv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8ShF6/dJMcain5Wpo/kRkOW9hPVgiDH0o0Z9FJv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8ShF6%2FdJMcain5Wpo%2FkRkOW9hPVgiDH0o0Z9FJv1%2Fimg.png&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;1023&quot; height=&quot;787&quot; data-filename=&quot;az-2-openai-9-embedding.png&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;787&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;And configure the settings in the panel like earlier.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-10-embedding.png&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;911&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYE9jG/dJMcaawPtKB/xSyUQHHKfncU1Yns4NKiK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYE9jG/dJMcaawPtKB/xSyUQHHKfncU1Yns4NKiK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYE9jG/dJMcaawPtKB/xSyUQHHKfncU1Yns4NKiK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYE9jG%2FdJMcaawPtKB%2FxSyUQHHKfncU1Yns4NKiK1%2Fimg.png&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;631&quot; height=&quot;911&quot; data-filename=&quot;az-2-openai-10-embedding.png&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;911&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ Start a project to build a &lt;b&gt;RAG&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Access Key&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;If you want to make this model accessible from requests by external clients, deploy the API key and store it in environment variables, such as in a .&lt;b&gt;env&lt;/b&gt; or &lt;b&gt;.json&lt;/b&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-11-create-key.png&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SBUV0/dJMcafkBqW8/XnEIBfNvQRfbFgymqpgltk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SBUV0/dJMcafkBqW8/XnEIBfNvQRfbFgymqpgltk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SBUV0/dJMcafkBqW8/XnEIBfNvQRfbFgymqpgltk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSBUV0%2FdJMcafkBqW8%2FXnEIBfNvQRfbFgymqpgltk%2Fimg.png&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;1149&quot; height=&quot;862&quot; data-filename=&quot;az-2-openai-11-create-key.png&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Backend System&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You may need to set up your project as shown below. I have already created an &lt;b&gt;Azure Function App Project&lt;/b&gt; for testing in my VS Code workspace, but I want to create a new example using &lt;b&gt;FastAPI&lt;/b&gt; in the next time.&lt;br /&gt;(You can set up the API backend system using your preferred framework, such as &lt;b&gt;Azure Functions&lt;/b&gt;, &lt;b&gt;FastAPI&lt;/b&gt;, &lt;b&gt;Express.js&lt;/b&gt;, and more.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-2-openai-13-vscode-prj-dir.png&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZlknz/dJMcajUQdhn/AnKKDnCk9TBo06Dm925lrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZlknz/dJMcajUQdhn/AnKKDnCk9TBo06Dm925lrk/img.png&quot; data-alt=&quot;Azure Function Project Directory&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZlknz/dJMcajUQdhn/AnKKDnCk9TBo06Dm925lrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZlknz%2FdJMcajUQdhn%2FAnKKDnCk9TBo06Dm925lrk%2Fimg.png&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;278&quot; height=&quot;180&quot; data-filename=&quot;az-2-openai-13-vscode-prj-dir.png&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Azure Function Project Directory&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Note] This topic will be continued in the next post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Azure Cosmos DB (NoSQL)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Now, we will create a NoSQL database using &lt;b&gt;Azure Cosmos DB&lt;/b&gt;. Search for &lt;b&gt;Cosmos DB&lt;/b&gt; to find it.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-cosmosdb-init-market.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boHsa4/dJMcafkBrv8/a8R6AI57qAkCTQKYIkz8C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boHsa4/dJMcafkBrv8/a8R6AI57qAkCTQKYIkz8C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boHsa4/dJMcafkBrv8/a8R6AI57qAkCTQKYIkz8C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboHsa4%2FdJMcafkBrv8%2Fa8R6AI57qAkCTQKYIkz8C0%2Fimg.png&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;514&quot; height=&quot;520&quot; data-filename=&quot;az-cosmosdb-init-market.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Click &lt;b&gt;Create&lt;/b&gt; on the card named &lt;b&gt;Azure Cosmos DB for NoSQL&lt;/b&gt; to continue.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-cosmosdb-create-1.png&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;907&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVOqC5/dJMcafkBrv7/IGHVCZ7yThMrYvSXx3z1Gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVOqC5/dJMcafkBrv7/IGHVCZ7yThMrYvSXx3z1Gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVOqC5/dJMcafkBrv7/IGHVCZ7yThMrYvSXx3z1Gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVOqC5%2FdJMcafkBrv7%2FIGHVCZ7yThMrYvSXx3z1Gk%2Fimg.png&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;1344&quot; height=&quot;907&quot; data-filename=&quot;az-cosmosdb-create-1.png&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;907&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You can configure your instance according to your preferences.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;az-cosmosdb-create-instance-severless-.png&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj7utB/dJMcaiIoInV/8iKn432AHlGF9kq3ZKsXT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj7utB/dJMcaiIoInV/8iKn432AHlGF9kq3ZKsXT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj7utB/dJMcaiIoInV/8iKn432AHlGF9kq3ZKsXT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj7utB%2FdJMcaiIoInV%2F8iKn432AHlGF9kq3ZKsXT1%2Fimg.png&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;1694&quot; height=&quot;564&quot; data-filename=&quot;az-cosmosdb-create-instance-severless-.png&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Once your Cosmos DB instance is created, go to the &lt;b&gt;Settings&lt;/b&gt; section and find the &lt;b&gt;Features&lt;/b&gt; tab.&lt;br /&gt;Then, select &lt;b&gt;Vector Search for NoSQL API&lt;/b&gt; and enable it, so the status shows &lt;b&gt;On&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1693&quot; data-origin-height=&quot;873&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k5Sh8/dJMcai2HuKQ/sj2cUqM6hVPYEfsY2J6z80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k5Sh8/dJMcai2HuKQ/sj2cUqM6hVPYEfsY2J6z80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k5Sh8/dJMcai2HuKQ/sj2cUqM6hVPYEfsY2J6z80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5Sh8%2FdJMcai2HuKQ%2Fsj2cUqM6hVPYEfsY2J6z80%2Fimg.png&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;1693&quot; height=&quot;873&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1693&quot; data-origin-height=&quot;873&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;875&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FSArC/dJMcabCvl3V/gBAfLv7VsOAmqVM50aozY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FSArC/dJMcabCvl3V/gBAfLv7VsOAmqVM50aozY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FSArC/dJMcabCvl3V/gBAfLv7VsOAmqVM50aozY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFSArC%2FdJMcabCvl3V%2FgBAfLv7VsOAmqVM50aozY1%2Fimg.png&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;1422&quot; height=&quot;875&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;875&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;We will continue in the next post.  &lt;/b&gt;&lt;/p&gt;</description>
      <category>Cloud Infra/Azure</category>
      <category>AI rag</category>
      <category>Azure Cosmos DB</category>
      <category>Azure NoSQL</category>
      <category>Azure OpenAI</category>
      <category>ChatGPT</category>
      <category>intermediate</category>
      <category>LLM</category>
      <category>Rag</category>
      <category>RAG model</category>
      <category>vector embedding</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/9</guid>
      <comments>https://revivalearth.tistory.com/entry/Building-a-RAG-Model-with-Azure-OpenAI-and-Azure-Cosmos-DB#entry9comment</comments>
      <pubDate>Fri, 31 Oct 2025 16:02:28 +0900</pubDate>
    </item>
    <item>
      <title>How to Use Windows on macOS with VMware Fusion</title>
      <link>https://revivalearth.tistory.com/entry/How-to-use-Windows-with-VMware-Fusion-in-macOS</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;vmware.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDJ12u/dJMcabia6mc/Rt53uYvVGSj5pRVKfYBvY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDJ12u/dJMcabia6mc/Rt53uYvVGSj5pRVKfYBvY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDJ12u/dJMcabia6mc/Rt53uYvVGSj5pRVKfYBvY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDJ12u%2FdJMcabia6mc%2FRt53uYvVGSj5pRVKfYBvY1%2Fimg.png&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;1024&quot; height=&quot;768&quot; data-filename=&quot;vmware.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;difficulty.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYoRyR/dJMcagKyuc0/9E1KZXh5dBYcVqJfEe7okk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYoRyR/dJMcagKyuc0/9E1KZXh5dBYcVqJfEe7okk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYoRyR/dJMcagKyuc0/9E1KZXh5dBYcVqJfEe7okk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYoRyR%2FdJMcagKyuc0%2F9E1KZXh5dBYcVqJfEe7okk%2Fimg.png&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;562&quot; height=&quot;151&quot; data-filename=&quot;difficulty.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Requirements&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;VMware Fusion (Free)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You need to &lt;b&gt;sign in to Broadcom&lt;/b&gt; and download &lt;b&gt;VMware Fusion&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion&quot;&gt;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1761813049798&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Fusion and Workstation | VMware&quot; data-og-description=&quot;VMware Workstation and VMware Fusion desktop hypervisors are the industry leaders in local virtualization. Learn how VMware&amp;rsquo;s local virtualization solutions provide an easier way to build, test and deliver any app for any device or cloud.&quot; data-og-host=&quot;www.vmware.com&quot; data-og-source-url=&quot;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion&quot; data-og-url=&quot;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jRtvp/hyZMhV0WO2/9aD3mStOcrZqYGEf47E0w1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jRtvp/hyZMhV0WO2/9aD3mStOcrZqYGEf47E0w1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Fusion and Workstation | VMware&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;VMware Workstation and VMware Fusion desktop hypervisors are the industry leaders in local virtualization. Learn how VMware&amp;rsquo;s local virtualization solutions provide an easier way to build, test and deliver any app for any device or cloud.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.vmware.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You&amp;rsquo;ve successfully installed the application if you see an icon like the one below.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;219&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAQMR7/dJMcagKyr7J/ZL67tGcDyAhuFkskqNhPK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAQMR7/dJMcagKyr7J/ZL67tGcDyAhuFkskqNhPK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAQMR7/dJMcagKyr7J/ZL67tGcDyAhuFkskqNhPK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAQMR7%2FdJMcagKyr7J%2FZL67tGcDyAhuFkskqNhPK0%2Fimg.png&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;219&quot; height=&quot;180&quot; data-origin-width=&quot;219&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Windows ISO file&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;To download a Windows ISO file, visit the official Microsoft website:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.microsoft.com/en-US/software-download/windows10ISO&quot;&gt;https://www.microsoft.com/en-US/software-download/windows10ISO&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1761813099005&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Windows 10 디스크 이미지(ISO 파일) 다운로드&quot; data-og-description=&quot;Windows를 설치할 때 동일한 언어를 선택해야 합니다. 현재 사용 중인 언어를 확인하려면 PC 설정에서 시간 및 언어 또는 제어판의 지역으로 이동합니다.&quot; data-og-host=&quot;www.microsoft.com&quot; data-og-source-url=&quot;https://www.microsoft.com/ko-kr/software-download/windows10ISO&quot; data-og-url=&quot;https://www.microsoft.com/ko-kr/software-download/windows10iso&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cIXJzu/hyZMjfeM6M/5xy7giE62ekAYZJgzJ7JZk/img.jpg?width=484&amp;amp;height=297&amp;amp;face=0_0_484_297&quot;&gt;&lt;a href=&quot;https://www.microsoft.com/ko-kr/software-download/windows10ISO&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.microsoft.com/ko-kr/software-download/windows10ISO&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cIXJzu/hyZMjfeM6M/5xy7giE62ekAYZJgzJ7JZk/img.jpg?width=484&amp;amp;height=297&amp;amp;face=0_0_484_297');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Windows 10 디스크 이미지(ISO 파일) 다운로드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Windows를 설치할 때 동일한 언어를 선택해야 합니다. 현재 사용 중인 언어를 확인하려면 PC 설정에서 시간 및 언어 또는 제어판의 지역으로 이동합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Installation&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;535&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TqHD7/dJMcafESyjd/uH0ModkWiCufeMFJHuPpR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TqHD7/dJMcafESyjd/uH0ModkWiCufeMFJHuPpR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TqHD7/dJMcafESyjd/uH0ModkWiCufeMFJHuPpR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTqHD7%2FdJMcafESyjd%2FuH0ModkWiCufeMFJHuPpR0%2Fimg.png&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;637&quot; height=&quot;535&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;535&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Select &lt;b&gt;Install from disk or image&lt;/b&gt;, then choose the ISO image you downloaded.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwEpdY/dJMcadG3Wj6/qYiHWpNKLoksYJ0wDikq40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwEpdY/dJMcadG3Wj6/qYiHWpNKLoksYJ0wDikq40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwEpdY/dJMcadG3Wj6/qYiHWpNKLoksYJ0wDikq40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwEpdY%2FdJMcadG3Wj6%2FqYiHWpNKLoksYJ0wDikq40%2Fimg.png&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;639&quot; height=&quot;448&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pick the version of Windows you want to install.&lt;br /&gt;If you don&amp;rsquo;t have a product key, you can skip it by closing or ignoring the warning dialog.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXO1sv/dJMcaklSVic/GWikkk8MZp2I94ulYukGb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXO1sv/dJMcaklSVic/GWikkk8MZp2I94ulYukGb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXO1sv/dJMcaklSVic/GWikkk8MZp2I94ulYukGb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXO1sv%2FdJMcaklSVic%2FGWikkk8MZp2I94ulYukGb1%2Fimg.png&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;635&quot; height=&quot;530&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvKjoV/dJMcaeeTT0F/luEXjgekSju5aQqoJuPXGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvKjoV/dJMcaeeTT0F/luEXjgekSju5aQqoJuPXGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvKjoV/dJMcaeeTT0F/luEXjgekSju5aQqoJuPXGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvKjoV%2FdJMcaeeTT0F%2FluEXjgekSju5aQqoJuPXGK%2Fimg.png&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;631&quot; height=&quot;534&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Click &lt;b&gt;Continue&lt;/b&gt; to begin setting up your virtual environment.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvsJd0/dJMcadUA7JI/OvZV7qCcIE7fSmRAa5bQFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvsJd0/dJMcadUA7JI/OvZV7qCcIE7fSmRAa5bQFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvsJd0/dJMcadUA7JI/OvZV7qCcIE7fSmRAa5bQFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvsJd0%2FdJMcadUA7JI%2FOvZV7qCcIE7fSmRAa5bQFK%2Fimg.png&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;639&quot; height=&quot;532&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Successful&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Once the installation is complete, click the &lt;b&gt;Start (►)&lt;/b&gt; button to run the Windows virtual environment.&lt;br /&gt;You should see the Windows logo appear on the screen.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Tip] Changes the volume size before starts the virtual environment. Default volume size is maybe sets to '40 ~ 60GB'.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;805&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zgA9S/dJMcaiIm4r4/BrYzeXnvwTWbZfax7QZfo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zgA9S/dJMcaiIm4r4/BrYzeXnvwTWbZfax7QZfo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zgA9S/dJMcaiIm4r4/BrYzeXnvwTWbZfax7QZfo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzgA9S%2FdJMcaiIm4r4%2FBrYzeXnvwTWbZfax7QZfo0%2Fimg.png&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;1024&quot; height=&quot;805&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;805&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Computer</category>
      <category>Beginner</category>
      <category>mac windows</category>
      <category>virtual machine</category>
      <category>VM 설치</category>
      <category>VMware</category>
      <category>vmware fusion</category>
      <category>Windows 가상머신</category>
      <category>맥 윈도우 설치</category>
      <category>맥에서 윈도우</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/6</guid>
      <comments>https://revivalearth.tistory.com/entry/How-to-use-Windows-with-VMware-Fusion-in-macOS#entry6comment</comments>
      <pubDate>Thu, 30 Oct 2025 17:28:48 +0900</pubDate>
    </item>
    <item>
      <title>Building a Data Pipeline for Heavy Tasks with Python, Celery, Django API, and Docker (1)</title>
      <link>https://revivalearth.tistory.com/entry/Python-Building-a-Data-Pipeline-for-Heavy-Tasks-with-Python-Celery-and-Django-API</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NKsKb/dJMcabvIeRb/lGXJiWILZmiNY0qRvtnktK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NKsKb/dJMcabvIeRb/lGXJiWILZmiNY0qRvtnktK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NKsKb/dJMcabvIeRb/lGXJiWILZmiNY0qRvtnktK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNKsKb%2FdJMcabvIeRb%2FlGXJiWILZmiNY0qRvtnktK%2Fimg.png&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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;difficulty-intermediate.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/11j60/dJMcacuCwvL/O7M9E5WfReOjWDpY8udPu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/11j60/dJMcacuCwvL/O7M9E5WfReOjWDpY8udPu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/11j60/dJMcacuCwvL/O7M9E5WfReOjWDpY8udPu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F11j60%2FdJMcacuCwvL%2FO7M9E5WfReOjWDpY8udPu1%2Fimg.png&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;454&quot; height=&quot;122&quot; data-filename=&quot;difficulty-intermediate.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sometimes, we need to handle multiple tasks such as data processing, data collection, and making API requests that are I/O-bound. Even if it's not about data, we still have to handle heavy tasks in a company or in various projects.&lt;br /&gt;However, I/O-bound tasks are not recommended with Celery, because Celery is optimized for heavy tasks, also known as CPU-bound tasks.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!TIP] What is &lt;code&gt;CPU-bound&lt;/code&gt;? A CPU-bound task primarily relies on the CPU for computation and consumes significant system resources. It is the opposite of I/O-bound tasks. Usually, I/O-bound tasks involve waiting for network responses, API requests, or user interactions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Architecture &amp;amp; Building an API overview&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ec3W5P/dJMcagX5rZX/ewKu68futfs7Okx68vGgg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ec3W5P/dJMcagX5rZX/ewKu68futfs7Okx68vGgg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ec3W5P/dJMcagX5rZX/ewKu68futfs7Okx68vGgg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fec3W5P%2FdJMcagX5rZX%2FewKu68futfs7Okx68vGgg1%2Fimg.png&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;802&quot; height=&quot;577&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Django&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Django is a powerful Python web framework, analogous to FastAPI and Flask, that supports ORM models and queries, provides an admin panel, and can be used to build REST APIs with many available libraries.&lt;br /&gt;By choosing Django, you can build scalable, well-supported, production-ready microservices.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# Create a virtual environment
python -m venv .venv
# Activate the virtual environment
source .venv/bin/activate        # linux, macOS

# Alternatively, if you want to use (mini)conda:
conda create -n my-env python=3.12
# It's recommended to check the Django version and Python version before creating the environment.
conda activate my-env&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Installation django:&lt;/b&gt;&lt;br /&gt;&lt;code&gt;pip install django==5.1.2&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;When you have completed installing Django, you can create your project and the apps you want to use.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Note] This article does not cover the details of the installation process. For installation instructions, please refer to &lt;a href=&quot;https://docs.djangoproject.com/en/5.2/intro/install/&quot;&gt;Django Installation&lt;/a&gt; .&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;What is PostgreSQL?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL is compatible with ACID and ensures data integrity. It supports JSONField, ArrayField, HStoreField, and advanced queries. It can handle concurrent tasks efficiently, and the official Django documentation recommends it. However, you can also use other databases like MySQL, MariaDB, etc.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Tip] ACID stands for Atomicity, Consistency, Isolation, and Durability.&lt;br /&gt;In a DBMS, a transaction is a single logical unit of work in the database. It ensures that all SQL statements within the transaction are executed as a single unit, so that partial execution or failure does not leave the database in an inconsistent state. Transactions maintain the integrity of the database by committing all changes if successful, or rolling them back in case of failure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;There are two ways to deploy PostgreSQL:&lt;/b&gt; setting it up on the host machine or running it in a &lt;b&gt;Docker&lt;/b&gt; contianer.&lt;br /&gt;Also, we will build PostgreSQL using a &lt;b&gt;Docker&lt;/b&gt; container because it offers several advantages: flexibility, easy management, and impressive security performance.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Docker&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;First, you need to set up &lt;b&gt;Docker&lt;/b&gt; on your host machine using Linux commands.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# Ubuntu
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker&amp;rsquo;s official GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Add the Docker repository
echo \
&quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable&quot; | sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null

# Install Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Verify installation
docker --version
sudo docker run hello-world

# (Optional) Allow running Docker without sudo
sudo usermod -aG docker $USER
newgrp docker&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Note] This document primarily targets Linux environments, focusing on production server deployment rather than beginner-level setup.&lt;br /&gt;For Windows or macOS users, please refer to &lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;Installation Docker Desktop&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Setup PostgreSQL using Docker&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The following commands are basic Docker commands to set up the database.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# Select the version you prefer.
docker pull postgres:16

docker run --name my-postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mypassword \
  -e POSTGRES_DB=mydatabase \
  -p 5432:5432 \
  -v pgdata:/var/lib/postgresql/data \
  -d postgres:16

# After building the container: check the currently running Docker containers.
docker ps

# Access the psql shell of a running Docker container
docker exec -it my-postgres psql -U myuser -d mydatabase

# (Optional) Control running Docker containers
docker stop my-postgres
docker start my-postgres&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Note] &lt;b&gt;Docker Compose&lt;/b&gt; will be introduced later in the guide, along with how to use a &lt;code&gt;docker-compose.yml&lt;/code&gt; file to manage multiple containers efficiently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Gunicorn (or ASGI)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The command &lt;code&gt;python manage.py runserver&lt;/code&gt; starts a Django application, but it is not suitable for production. For production, you should use Gunicorn (WSGI) to serve all requests, or use ASGI with asynchronous views.&lt;br /&gt;However, We will now install Gunicorn.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;pip install gunicorn
gunicorn --version

# Default command to start
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 3&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!TIP] Django supports ASGI and asynchronous views and functions. However, you need to consider using an asynchronous system carefully, because some libraries may cause bugs or may not support asynchronous features.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Backend &amp;amp; Infra</category>
      <category>celery</category>
      <category>data pipeline</category>
      <category>Django</category>
      <category>Django REST framework</category>
      <category>DRF</category>
      <category>intermediate</category>
      <category>Python</category>
      <category>데이터 파이프라인</category>
      <category>셀러리</category>
      <category>파이썬</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/2</guid>
      <comments>https://revivalearth.tistory.com/entry/Python-Building-a-Data-Pipeline-for-Heavy-Tasks-with-Python-Celery-and-Django-API#entry2comment</comments>
      <pubDate>Wed, 29 Oct 2025 21:56:36 +0900</pubDate>
    </item>
    <item>
      <title>How can I build an Event Hub in Azure and integrate it with a webhook for Microsoft Teams?</title>
      <link>https://revivalearth.tistory.com/entry/How-can-I-build-an-Event-Hub-in-Azure-and-integrate-it-with-a-webhook-for-Microsoft-Teams</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;azure-event-hub-1.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oBhOy/dJMcajgc8zE/pMf4lcS1GuwUlBHU3Kx1c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oBhOy/dJMcajgc8zE/pMf4lcS1GuwUlBHU3Kx1c1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oBhOy/dJMcajgc8zE/pMf4lcS1GuwUlBHU3Kx1c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoBhOy%2FdJMcajgc8zE%2FpMf4lcS1GuwUlBHU3Kx1c1%2Fimg.png&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;1024&quot; height=&quot;768&quot; data-filename=&quot;azure-event-hub-1.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;difficulty.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be4ZJy/dJMcaiuPW9y/BPuvZGTCIVGB7sabYc8L60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be4ZJy/dJMcaiuPW9y/BPuvZGTCIVGB7sabYc8L60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be4ZJy/dJMcaiuPW9y/BPuvZGTCIVGB7sabYc8L60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe4ZJy%2FdJMcaiuPW9y%2FBPuvZGTCIVGB7sabYc8L60%2Fimg.png&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;510&quot; height=&quot;137&quot; data-filename=&quot;difficulty.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;What can you do with Azure Cloud?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Azure cloud enables you to build microservices-compatiable applications and focus on code development and processes during deployment.&lt;/p&gt;
&lt;h1&gt;What is Event hub?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Azure Event Hub&lt;/code&gt; is a fully managed, cloud-native data streaming platform ingests millions of events per second from any source, enabling real-time analytics and dynamic data pipelines.&lt;br /&gt;It offers low latency, high scalability, and is compatible with &lt;code&gt;Apache Kafka&lt;/code&gt;, allowing existing Kafka applications to run without code changes.&lt;br /&gt;Evenv hubs serves as a powerful event ingestion layer within Azure, facilitating immediate responses to business events, anomaly detection, and data archiving.&lt;/p&gt;
&lt;h1&gt;Compares with AWS kinesis&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Azure Event Hub&lt;/code&gt; is compatible with &lt;code&gt;Kafka&lt;/code&gt; and easily integrates with other Azure serivces.&lt;br /&gt;And &lt;code&gt;AWS Kinesis&lt;/code&gt; offers powerful serverless integration with &lt;code&gt;AWS Lambda&lt;/code&gt;, &lt;code&gt;Glue&lt;/code&gt;, and &lt;code&gt;Redshift&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Step by step&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Create a resource group (Azure Portal)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sign in to the Azure portal and create a resource group.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GyxO7/dJMcai9q5uE/EFX4yZgFFKsKykxBLFDxxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GyxO7/dJMcai9q5uE/EFX4yZgFFKsKykxBLFDxxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GyxO7/dJMcai9q5uE/EFX4yZgFFKsKykxBLFDxxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGyxO7%2FdJMcai9q5uE%2FEFX4yZgFFKsKykxBLFDxxk%2Fimg.png&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;1006&quot; height=&quot;796&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Left sidebar: &lt;code&gt;Resource groups&lt;/code&gt; &amp;rarr; &lt;code&gt;Create&lt;/code&gt; &amp;rarr; enter the resource group name &amp;rarr; choose Subscription and Region &amp;rarr; &lt;code&gt;Review + create&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;If you uses in CLI:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;  # create a resource group
  az group create --name MyResourceGroup --location eastus&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!NOTE] An &lt;code&gt;Azure Resource Group&lt;/code&gt; acts as a container that holds related Azure resources and services.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Create a Event Hub (Namespace)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;761&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4bvUF/dJMcake61Cx/IO7zXfnfz2pRilHghEtdNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4bvUF/dJMcake61Cx/IO7zXfnfz2pRilHghEtdNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4bvUF/dJMcake61Cx/IO7zXfnfz2pRilHghEtdNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4bvUF%2FdJMcake61Cx%2FIO7zXfnfz2pRilHghEtdNk%2Fimg.png&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;1149&quot; height=&quot;761&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;761&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Click &lt;code&gt;Create&lt;/code&gt;, and you will see the &lt;b&gt;Marketplace&lt;/b&gt;.&lt;br /&gt;Enter &quot;Event Hub&quot; in the search bar to find &lt;b&gt;Event Hubs&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1107&quot; data-origin-height=&quot;780&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XvDYh/dJMcahJsshD/4MyCXZ0s3oWDMQXMYKVtL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XvDYh/dJMcahJsshD/4MyCXZ0s3oWDMQXMYKVtL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XvDYh/dJMcahJsshD/4MyCXZ0s3oWDMQXMYKVtL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXvDYh%2FdJMcahJsshD%2F4MyCXZ0s3oWDMQXMYKVtL1%2Fimg.png&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;1107&quot; height=&quot;780&quot; data-origin-width=&quot;1107&quot; data-origin-height=&quot;780&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Once you find &lt;b&gt;Event Hubs&lt;/b&gt;, click the &lt;b&gt;Create&lt;/b&gt; button to start a new instance.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;First, create an &lt;code&gt;Event Hub Namspace&lt;/code&gt; for your hubs, and use a &lt;code&gt;Schema Registry&lt;/code&gt; to define a clear data structure between producers and consumers.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;780&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bToCXn/dJMcadfZjqF/N8qhzpmEyotp70MkorObXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bToCXn/dJMcadfZjqF/N8qhzpmEyotp70MkorObXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bToCXn/dJMcadfZjqF/N8qhzpmEyotp70MkorObXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbToCXn%2FdJMcadfZjqF%2FN8qhzpmEyotp70MkorObXK%2Fimg.png&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;1582&quot; height=&quot;780&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;780&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;When Event Hub Nampsace is created, you can add hubs on it.&lt;/p&gt;
&lt;h1&gt;Edit in Visual Studio Code for Azure Function App&lt;/h1&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;# function_app.py
import azure.functions as func
import pandas as pd
import json
import os
import requests
app = func.FunctionApp()

@app.event_hub_output(arg_name=&quot;event&quot;, 
                      event_hub_name= os.environ[&quot;SampleEventHubName&quot;], 
                      connection=&quot;SampleEventHubConnectionString&quot;
)
def sample_eventhubs_scheduler(timer: func.TimerRequest, event: func.Out[str]):
    df = pd.read_csv(&quot;sample_data/samples.csv&quot;, encoding=&quot;euc-kr&quot;)

    # Data preprocessing...

    sample_data_list = []
    for index, row in df.iterrows():
        # The code to process sample data and send an output to the event hub
        #
        ...

    event.set(sample_data_list)

    # A webhook request example
    whook_url = os.environ[&quot;AzureWebHookUrl&quot;]
    payload = {
        &quot;type&quot;: &quot;message&quot;,
        &quot;attachments&quot;: [
            {
                &quot;contentType&quot;: &quot;application/vnd.microsoft.card.adaptive&quot;,
                &quot;contentUrl&quot;: None,
                &quot;content&quot;: {
                    &quot;$schema&quot;: &quot;http://adaptivecards.io/schemas/adaptive-card.json&quot;,
                    &quot;type&quot;: &quot;AdaptiveCard&quot;,
                    &quot;version&quot;: &quot;1.2&quot;,
                    &quot;body&quot;: [
                        {
                            &quot;type&quot;: &quot;TextBlock&quot;,
                            &quot;text&quot;: &quot;Hello, An example web hook payload.&quot;
                        }
                    ]
                }
            }
        ]
    }
    response = requests.post(
        whook_url, 
        json=payload
    )
    response.raise_for_status()
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# Your requirements.txt 
# Maybe recommended to uses in Virtual Environment. (venv)

# DO NOT include azure-functions-worker in this file
# The Python Worker is managed by Azure Functions platform
# Manually managing azure-functions-worker may cause unexpected issues

azure-functions
requests
numpy
pytz
pandas&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You must have a &lt;code&gt;local.settings.json&lt;/code&gt; file in the root directory of your &lt;code&gt;Azure Function App&lt;/code&gt; project.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Note] This is a development settings for test &amp;amp; debugging.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
    &quot;IsEncrypted&quot;: false,
    &quot;Values&quot;: {
        &quot;AzureWebJobsStorage&quot;: &quot;UseDevelopmentStorage=true&quot;,
        &quot;FUNCTIONS_WORKER_RUNTIME&quot;: &quot;python&quot;,
        &quot;SampleEventHubName&quot;: &quot;&amp;lt;Your Hub Name&amp;gt;&quot;,
        &quot;SampleEventHubConnectionString&quot;: &quot;&amp;lt;Connection String of Event Hub namespace&amp;gt;&quot;,
        &quot;AzureWebHookUrl&quot;: &quot;&amp;lt;Web hook url you want to add&amp;gt;&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!Note] You can find the &lt;code&gt;...EventHubConnectionString&lt;/code&gt; in &lt;b&gt;Resource Group &amp;rarr; Your Event Hub Namespace &amp;rarr; Settings &amp;rarr; Shared access policies&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Make sure to create a policy named with &lt;code&gt;RootManageSharedAccessKey&lt;/code&gt;.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Copies your &lt;code&gt;Primary connection string&lt;/code&gt; in the policy you created and pastes it to &lt;code&gt;local.settings.json&lt;/code&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The &lt;code&gt;host.json&lt;/code&gt; file should also be located in the root directory of your project.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;version&quot;: &quot;2.0&quot;,
  &quot;logging&quot;: {
    &quot;applicationInsights&quot;: {
      &quot;samplingSettings&quot;: {
        &quot;isEnabled&quot;: true,
        &quot;excludedTypes&quot;: &quot;Request&quot;
      }
    }
  },
  &quot;extensionBundle&quot;: {
    &quot;id&quot;: &quot;Microsoft.Azure.Functions.ExtensionBundle&quot;,
    &quot;version&quot;: &quot;[4.*, 5.0.0)&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;It is recommended to install these VS Code extensions to help you build Azure Functions and other Azure services.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dko9YI/dJMcabP0FBW/RNKaCVYAJd5TDkSTJKmgRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dko9YI/dJMcabP0FBW/RNKaCVYAJd5TDkSTJKmgRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dko9YI/dJMcabP0FBW/RNKaCVYAJd5TDkSTJKmgRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdko9YI%2FdJMcabP0FBW%2FRNKaCVYAJd5TDkSTJKmgRK%2Fimg.png&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;641&quot; height=&quot;164&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kWf5E/dJMcae62mbI/9yidTX1j5HTVKJ1PVK14A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kWf5E/dJMcae62mbI/9yidTX1j5HTVKJ1PVK14A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kWf5E/dJMcae62mbI/9yidTX1j5HTVKJ1PVK14A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkWf5E%2FdJMcae62mbI%2F9yidTX1j5HTVKJ1PVK14A0%2Fimg.png&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;632&quot; height=&quot;168&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Main Points When Building an Azure Function App in VS Code&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Visual Studio Code supports many &lt;code&gt;Azure Cloud&lt;/code&gt; services through its extensions.&lt;br /&gt;It provides seamless integration that allows you to develop locally and deploy automatically to the cloud.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Deploy to the Cloud Easily with Azure Extensions&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;77&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cphodQ/dJMcaaXRUWG/wPeYNj2gMSlkAdfizYNGk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cphodQ/dJMcaaXRUWG/wPeYNj2gMSlkAdfizYNGk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cphodQ/dJMcaaXRUWG/wPeYNj2gMSlkAdfizYNGk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcphodQ%2FdJMcaaXRUWG%2FwPeYNj2gMSlkAdfizYNGk0%2Fimg.png&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;634&quot; height=&quot;77&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;77&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You can deploy your code to Azure Cloud directly once it&amp;rsquo;s ready.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!TIP] You may need to sign in to Azure using the CLI before deploying.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;az login
# A browser window will open for authentication.
# Make sure Azure CLI is installed on your device. (Compatible with Windows, macOS, and Linux)
# Installation instructions can be found in the official Microsoft documentation.&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Environment Variables in Azure Cloud&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You can check your environment variables in&lt;br /&gt;&lt;code&gt;Resource Group&lt;/code&gt; &amp;rarr; &lt;code&gt;Function App&lt;/code&gt; &amp;rarr; &lt;code&gt;Settings&lt;/code&gt; &amp;rarr; &lt;code&gt;Environment variables&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;762&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bObpdB/dJMcac9dJx0/kLzED9kg0G0HwYkUmY5GwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bObpdB/dJMcac9dJx0/kLzED9kg0G0HwYkUmY5GwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bObpdB/dJMcac9dJx0/kLzED9kg0G0HwYkUmY5GwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbObpdB%2FdJMcac9dJx0%2FkLzED9kg0G0HwYkUmY5GwK%2Fimg.png&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;802&quot; height=&quot;762&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;762&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Your local environment settings can be uploaded to Azure Cloud using:&lt;br /&gt;&lt;code&gt;Command Palette: Azure Functions: Upload Local Settings&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;83&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1bvfw/dJMcafkzv2u/CIUPaNwW8FWaTJGfp4qVU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1bvfw/dJMcafkzv2u/CIUPaNwW8FWaTJGfp4qVU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1bvfw/dJMcafkzv2u/CIUPaNwW8FWaTJGfp4qVU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1bvfw%2FdJMcafkzv2u%2FCIUPaNwW8FWaTJGfp4qVU0%2Fimg.png&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;602&quot; height=&quot;83&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;83&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Integrates with Microsoft Teams Web hook&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Microsoft teams support many services and hook, you can integrate them with Azure Cloud Services.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Search for &lt;code&gt;Workflow&lt;/code&gt; to find the &lt;b&gt;Teams Workflow app&lt;/b&gt;, where you can add a webhook, mailing system, bot messages, or any other automation you need for your project group or organization.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q5TCk/dJMcacg5yvB/e2ZZhkw7CmPbYkO94ut9z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q5TCk/dJMcacg5yvB/e2ZZhkw7CmPbYkO94ut9z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q5TCk/dJMcacg5yvB/e2ZZhkw7CmPbYkO94ut9z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq5TCk%2FdJMcacg5yvB%2Fe2ZZhkw7CmPbYkO94ut9z0%2Fimg.png&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;945&quot; height=&quot;702&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Once you've installed the Workflow app, open the workflow management dialog and modify it for your own customization.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1527&quot; data-origin-height=&quot;911&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZTzzF/dJMcabWMftA/bhnB4CTBmnV5kV787aGxf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZTzzF/dJMcabWMftA/bhnB4CTBmnV5kV787aGxf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZTzzF/dJMcabWMftA/bhnB4CTBmnV5kV787aGxf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZTzzF%2FdJMcabWMftA%2FbhnB4CTBmnV5kV787aGxf0%2Fimg.png&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;1527&quot; height=&quot;911&quot; data-origin-width=&quot;1527&quot; data-origin-height=&quot;911&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Here is an example of a webhook that triggers when an external Azure Function App has completed its task.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;teams hook.png&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;819&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxSvSp/dJMcakzqmo8/3dltxz0iC9IKKpqlmJ30Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxSvSp/dJMcakzqmo8/3dltxz0iC9IKKpqlmJ30Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxSvSp/dJMcakzqmo8/3dltxz0iC9IKKpqlmJ30Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxSvSp%2FdJMcakzqmo8%2F3dltxz0iC9IKKpqlmJ30Hk%2Fimg.png&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;1362&quot; height=&quot;819&quot; data-filename=&quot;teams hook.png&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;819&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Copyright &amp;copy; &lt;a href=&quot;https://revivalearth.tistory.com/&quot;&gt;RevivalEarth&lt;/a&gt; all rights reserved.&lt;/p&gt;</description>
      <category>Cloud Infra/Azure</category>
      <category>azure</category>
      <category>Azure Cloud</category>
      <category>Azure Event Hub</category>
      <category>Azure Function App</category>
      <category>Azure 이벤트 허브</category>
      <category>Beginner</category>
      <category>Cloud Engineering</category>
      <category>Python</category>
      <category>Teams Web hook</category>
      <category>webhook</category>
      <author>Seum Lee</author>
      <guid isPermaLink="true">https://revivalearth.tistory.com/1</guid>
      <comments>https://revivalearth.tistory.com/entry/How-can-I-build-an-Event-Hub-in-Azure-and-integrate-it-with-a-webhook-for-Microsoft-Teams#entry1comment</comments>
      <pubDate>Wed, 29 Oct 2025 14:47:40 +0900</pubDate>
    </item>
  </channel>
</rss>