<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>기록공간</title>
    <link>https://lipcoder.tistory.com/</link>
    <description>개인 공부를 위해 서적이나 사이트 수업 ppt 내용 등을 정리하며 부족한 부분은 새로 추가하며 포스팅하고 있습니다. 저작권 문제가 있을경우 개인 메시지를 남겨주세면 삭제하도록 하겠습니다.</description>
    <language>ko</language>
    <pubDate>Tue, 12 May 2026 13:33:26 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>입코딩</managingEditor>
    <image>
      <title>기록공간</title>
      <url>https://tistory1.daumcdn.net/tistory/3149806/attach/2ff4ae556aee4cb0ad9aa50612b0db54</url>
      <link>https://lipcoder.tistory.com</link>
    </image>
    <item>
      <title>[Effective Java] Item03. private 생성자나 열거 타입으로 싱글턴임을 보증하라</title>
      <link>https://lipcoder.tistory.com/547</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;싱글턴이란?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;싱글턴이란 디자인 패턴에서 생성 패턴 중 하나로 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;오직 하나의 인스턴스만 생성하도록 약속&lt;/span&gt;하는 패턴이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;보통 싱글턴 패턴은 무상태(Stateless) 객체나 시스템 객체같 유일해야 하는 객체를 생성하는데에 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;싱글턴 패턴의 한계는 그 특성에서도 알 수 있다. 하나의 인스턴스만 생성 가능 하다는 특성 말이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;싱글턴을 사용하려는 클라이언트를 테스트하기가 어려워 질 수 있다. 왜냐하면 테스트를 위한 가짜(mock)객체를 구현하는 것으로는 싱글턴을 대체 할 수 없기 때문이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;싱글턴 생성 방법&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;첫번째 방법&lt;/b&gt;&lt;/span&gt;은 &lt;u&gt;public 정적 final 멤버변수를 사용&lt;/u&gt;하는 방법이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648193200090&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    
    public void leaveTheBuilding() { ... }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;INSTANCE 멤버변수를 생성하여 Elvis 인스턴스를 선언과 동시에 초기화하고 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;생성자를 private으로 두었기 때문에 내부 클래스에서만 접근이 가능하다는 것도 주목해야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이렇게 하면 java는 클래스를 생성과 동시에 초기화 하면서 Elvis의 인스턴스가 딱 한 번 생성된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;때문에 Elvis는 전체 시스템에서 인스턴스가 하나임을 보장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 방법의 장점은 해당 클래스가 싱글턴임을 명백히 할 수 있다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;public static 필드가 final이니 다른 객체가 참조 할 수 없기 때문이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또 다른 장점은 간결하다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만, 이 방법은 리플렉션 API인 AccesibleObject.setAcceisible() 을 사용하여 private 생성자를 호출할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 공격은 예외 처리를 통해 막을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;두번째 방법&lt;/b&gt;&lt;/span&gt;은 &lt;u&gt;정적 팩터리 메서드를 사용&lt;/u&gt;하는 방법이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648193712667&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }
    
    public void leaveTheBuilding() { ... }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정적 팩터리 메서드를 통해서만 해당 변수를 반환하도록 변경되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;멤버변수는 private이므로 INSTANCE에 직접 접근할 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 방법의 장점은 API를 바꾸지 않아도 싱글턴이 아니게 변경 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;유일한 INSTANCE를 반환하던 팩터리 메서드를 호출 스레드별로 다른 인스턴스로 넘겨줄 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또 다른 장점은 정적 팩터리 메서드를 공급자로 사용 할 수 있다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Elvis::getInstance에서 Supplier&amp;lt;Elvis&amp;gt; 형식으로 변경하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 이러한 장점들이 필요 없는 경우에는 첫번째 방법을 사용하는 것이 더 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;세번째 방법&lt;/b&gt;&lt;/span&gt;은 &lt;u&gt;열거타입 방식의 싱글턴을 사용&lt;/u&gt;하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648194719925&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public enum Elvis {
    INSTANCE;
    
    public void leaveTheBuilding() { ... }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 두 방법보다 훨씬 더 간결하고 추가 노력을 하지 않아도 직렬화가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 복잡한 상황에서도 제 2의 인스턴스를 생성하는 상황을 막아준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점은 enum 외의 클래스를 상속받은 경우에 사용이 불가능 하다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java/Effective Java</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/547</guid>
      <comments>https://lipcoder.tistory.com/547#entry547comment</comments>
      <pubDate>Fri, 25 Mar 2022 17:02:23 +0900</pubDate>
    </item>
    <item>
      <title>개발 환경(Development Environment)</title>
      <link>https://lipcoder.tistory.com/546</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;일반적인 개발환경은 아래 그림과 같이 나뉘어 진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;각각 개발 과정에 따라, 각자의 역할과 목적이 다르고, 그에 따른 시스템의 크기도 다르다.&lt;/span&gt;&lt;/p&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-origin-width=&quot;1008&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWbBEk/btrrpFDqZ3y/fVzYmidLTLdZ6LguI9Lhi1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWbBEk/btrrpFDqZ3y/fVzYmidLTLdZ6LguI9Lhi1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWbBEk/btrrpFDqZ3y/fVzYmidLTLdZ6LguI9Lhi1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWbBEk%2FbtrrpFDqZ3y%2FfVzYmidLTLdZ6LguI9Lhi1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;389&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;꼭 모든 환경을 갖출 필요는 없기 때문에, 프로젝트에 따라서 각 환경을 합치거나 생략해도 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;각 환경에 대한 설명&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;로컬 개발 환경(Local)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발을 하기에 앞서, 개발자 개개인의 PC에 개발 및 테스트 환경이 셋업되어 있어야 한다. 각 &lt;span style=&quot;color: #006dd7;&quot;&gt;개발자마다, 설치된 서버 환경을 로컬 개발 환경&lt;/span&gt;이라고 한다. (ex. 각 PC에 MySQL(DB)과 Tomcat 등의 소프트웨어를 설치하고, Eclipse와 같은 통합 개발 환경(IDE)과 컴파일러 등이 설치된 환경)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;로컬 개발 환경을 구축할시 가장 주의해야 할 점은 &lt;span style=&quot;color: #ee2323;&quot;&gt;모든 개발자가 같은 개발 환경을 사용해야 한다&lt;/span&gt;는 것이다. 실제로 많이 일어나는 문제 중에서, 다른 버전의 JVM, Tomcat을 사용하거나 문자포맷을 서로 다르게 설정하여 코드를 합칠 때, 로컬에서 잘 작동하던 코드가 작동하지 않는 경우가 많다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발 환경을 표준화 하는 방법은 여러 가지가 있지만, 전체 개발 환경(앞서 언급한 모든 소프트웨어 등)을 압축 파일 형태로 묶어 사용하는 방법이 가장 일반적이다. maven을 사용하는 경우, 개발에 사용되는 라이브러리 버전 등을 지정할 수 있기 때문에 개발 환경 차이에서 오는 문제점을 상당 부분 해소할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;서버 개발 환경(Dev)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버 개발 환경은 각 개발자들이, &lt;span style=&quot;color: #006dd7;&quot;&gt;구현한 코드들을 합쳐 서버에서 테스트 해볼 수 있는 환경&lt;/span&gt;이다. 소스코드를 Git이나 SVN과 같은 형상관리 시스템(VCS)에서 Commit 하면, 코드는 서버 개발 환경에 자동으로 배포되고, 테스트를 해볼 수 있게 된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기능 개발을 위주로 하기 때문에, 서버 환경은 운영 환경 보다 훨씬 작다. 운영 환경이 클러스터링 환경으로 여러 개의 서버로 구성된다면, 개발 환경은 한 두개의 서버로 기능 구현이 가능한 정도로 구축하는 것이 일반적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;통합 개발 환경(Integration)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;통합 개발 환경은 여러개의 컴포넌트를 동시 개발하는 프로젝트가 있고, 각 컴포넌트가 다른 컴포넌트에 대해 의존성으로 가지고 있을 때,&amp;nbsp; &lt;span style=&quot;color: #006dd7;&quot;&gt;컴포넌트를 통합 및 테스트 하는 환경&lt;/span&gt;으로 사용한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 단말기와 서버를 같이 개발하는 환경의 경우 통합 환경에서 통합을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버 개발 환경과 마찬가지로 최소한의 설정으로 구성하되 서버 개발 환경에서 릴리즈되면 주기적으로 배치한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;테스팅 환경(QA)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 환경은 QA 엔지니어에 의해서 사용되는 환경으로, 배포 주기에 따라서 개발환경에서 테스팅 환경으로 배포된다. 여기서는 &lt;span style=&quot;color: #006dd7;&quot;&gt;기능 및 비기능 테스트&lt;/span&gt; 등을 QA 엔지니어가 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비기능 테스트를 수행할 시에는 운영 환경과 거의 유사한 환경을 만들어 놓고, 테스트를 수행한다. 경우에 따라서 비기능 테스트는 배포 전에, 운영 환경에서 직접 수행하는 경우도 있다. 이런 경우 배포 주기가 매우 길 때 주로 사용하는데, 기업의 내부 IT 시스템을 만들어서 몇 년씩 사용하는 경우 이런 방식을 이용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;스테이징 환경(Staging)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;운영환경과 거의 동일한 환경을 만들어 놓고, 운영 환경으로 넘어가기 전에 여러 가지 &lt;span style=&quot;color: #006dd7;&quot;&gt;비기능적인 부분(보안, 성능, 장애 등)을 검증&lt;/span&gt;하는 환경이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;운영 환경(Production)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실제 서비스를 위한 운영 환경이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대부분 개발환경은 별도로 운영하는 것이 일반적이고, 상황에 따라 통합, 테스팅, 스테이징 환경은 요구 사항에 따라 합치거나 별도로 운영한다. 환경이 많아지면 조금 더 다양한 형태의 검증과 각 역할별(테스터, 개발자, 사용자 등)로 테스트가 쉽지만, 반대로 각 환경을 유지 하는데 필요한 서버들과 운영 인력이 많이 소요되는 단점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래서 요즘과 같이 가상화 환경을 사용하는 경우에는 이미지를 만들어놨다가, 실제 테스트나 사용을 할 경우에만 가상 서버에 환경을 배치해서 사용하고, 사용이 끝나면 다시 이미지를 저장소에 저장해 놓는 전략을 많이 사용한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;본 내용의 출처는 &lt;a href=&quot;https://bcho.tistory.com/759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bcho.tistory.com/759&lt;/a&gt;&amp;nbsp;입니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Software Engineering</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/546</guid>
      <comments>https://lipcoder.tistory.com/546#entry546comment</comments>
      <pubDate>Mon, 24 Jan 2022 14:15:31 +0900</pubDate>
    </item>
    <item>
      <title>[HTTP 강의] 1. 인터넷 네트워크</title>
      <link>https://lipcoder.tistory.com/545</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;인터넷 통신&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP도 결국 인터넷 망을 통해서 동작하기 때문에 인터넷 통신에 대해서 알 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYa1aX/btrro58d8Te/alAqXZOBSNSZ7kM2mQAKVK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYa1aX/btrro58d8Te/alAqXZOBSNSZ7kM2mQAKVK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYa1aX/btrro58d8Te/alAqXZOBSNSZ7kM2mQAKVK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYa1aX%2Fbtrro58d8Te%2FalAqXZOBSNSZ7kM2mQAKVK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;133&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음과 같이 두 개의 컴퓨터가 있다. 둘은 어떻게 통신을 하게 되는 걸까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메시지를 주고받고 싶을 경우 선이 연결되어 있다면 단순하게 그냥 통신하면 될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzemk/btrrlTul8KY/R3vjsh7kfZDNxeZwmvzBx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzemk/btrrlTul8KY/R3vjsh7kfZDNxeZwmvzBx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzemk/btrrlTul8KY/R3vjsh7kfZDNxeZwmvzBx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkzemk%2FbtrrlTul8KY%2FR3vjsh7kfZDNxeZwmvzBx0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;165&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;282&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;920&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FjwYF/btrrjAWjUFJ/PTU9FXKkmFuiSqgVJ7m2B0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FjwYF/btrrjAWjUFJ/PTU9FXKkmFuiSqgVJ7m2B0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FjwYF/btrrjAWjUFJ/PTU9FXKkmFuiSqgVJ7m2B0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFjwYF%2FbtrrjAWjUFJ%2FPTU9FXKkmFuiSqgVJ7m2B0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;176&quot; data-origin-width=&quot;920&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 이게 인터넷을 통해야 한다면 말이 달라진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;920&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLmiLZ/btrroYalSOT/gvKDt2y4gv2XJDUXbOC7LK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLmiLZ/btrroYalSOT/gvKDt2y4gv2XJDUXbOC7LK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLmiLZ/btrroYalSOT/gvKDt2y4gv2XJDUXbOC7LK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLmiLZ%2FbtrroYalSOT%2FgvKDt2y4gv2XJDUXbOC7LK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;176&quot; data-origin-width=&quot;920&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인터넷 망은 단순히 선 하나를 통해 통신할 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인터넷에 연결된 컴퓨터는 수없이 많고, 목적지까지의 거리도 엄청나게 멀 수 있기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGhPDc/btrroGOx090/gSbKDE0zppNC7SvaILmhyK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGhPDc/btrroGOx090/gSbKDE0zppNC7SvaILmhyK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGhPDc/btrroGOx090/gSbKDE0zppNC7SvaILmhyK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGhPDc%2FbtrroGOx090%2FgSbKDE0zppNC7SvaILmhyK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;513&quot; height=&quot;247&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인터넷 망은 매우 복잡하다. 인터넷 안에 수많은 노드들이 선을 통해 서로 연결되어 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 선은 해저를 통하는 광케이블이 될 수도 있고, 심지어는 위성을 통할 수도 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그러면 이렇게 수많은 노드들을 거쳐서 목적지까지 도착하는 험난한 여정(?)을 위해서는 어떻게 해야 될까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 위해서 IP가 탄생하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;IP(Internet Protocol)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;PC끼리 통신을 가능하게 해주는 것은 IP 주소가 있기 때문이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;물론 전제 조건이 있는데, 통신을 해야 할 서로의 PC가 모두 IP 주소가 존재해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k30GU/btrrjAPBjxD/BFAvD4jR96BvTVFT5Hx7x0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k30GU/btrrjAPBjxD/BFAvD4jR96BvTVFT5Hx7x0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k30GU/btrrjAPBjxD/BFAvD4jR96BvTVFT5Hx7x0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk30GU%2FbtrrjAPBjxD%2FBFAvD4jR96BvTVFT5Hx7x0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;240&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본적으로 IP가 하는 역할은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;지정한 IP주소에 데이터 전달&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패킷이라는 통신 단위로 데이터 전달&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패킷을 통해 보낸다고 하지만, 패킷은 단순히 전송할 데이터만 담지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패킷 내에는 전송 데이터뿐만 아니라&lt;span style=&quot;color: #006dd7;&quot;&gt; 출발지와 목적지 IP&lt;/span&gt; 등을 담고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFWBHE/btrrodeWNzE/7MUvoKAFMWHYixYP5eoln0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFWBHE/btrrodeWNzE/7MUvoKAFMWHYixYP5eoln0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFWBHE/btrrodeWNzE/7MUvoKAFMWHYixYP5eoln0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFWBHE%2FbtrrodeWNzE%2F7MUvoKAFMWHYixYP5eoln0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;318&quot; height=&quot;168&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 정보들을 모두 담으면 클라이언트는 서버에 패킷을 전달하게 된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 패킷은 목적지 IP를 찾을 때까지 여러 노드들을 거치게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eyUbKs/btrrn2kkEwB/O6Eiv1dlOaEzv0Z5NteZAk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eyUbKs/btrrn2kkEwB/O6Eiv1dlOaEzv0Z5NteZAk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eyUbKs/btrrn2kkEwB/O6Eiv1dlOaEzv0Z5NteZAk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeyUbKs%2Fbtrrn2kkEwB%2FO6Eiv1dlOaEzv0Z5NteZAk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;555&quot; height=&quot;271&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패킷이 서버에 도착하여 클라이언트에게 다시 메시지를 보낸다고 했을 때, 패킷 내용은 도착과 목적지만 반대가 됐을 뿐 거의 비슷하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;물론 인터넷 망은 복잡하기 때문에 처음 클라이언트에서 보내온 경로와 다른 경로로 전송될 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t8770/btrroLCf0vW/iL7u28lzLMxMDXULkIHMd1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t8770/btrroLCf0vW/iL7u28lzLMxMDXULkIHMd1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t8770/btrroLCf0vW/iL7u28lzLMxMDXULkIHMd1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft8770%2FbtrroLCf0vW%2FiL7u28lzLMxMDXULkIHMd1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;272&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 IP 프로토콜에도 한계가 있는데, 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;비연결성&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;IP 프로토콜은 패킷을 받을 대상이 없거나 대상이 서비스 불능 상태여도 패킷을 전송한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트는 대상 서버가 패킷을 받을 수 있는 상태인지 모른다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzQUJ5/btrrospE8Qx/artIo0CDbzDC02R2WrE141/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzQUJ5/btrrospE8Qx/artIo0CDbzDC02R2WrE141/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzQUJ5/btrrospE8Qx/artIo0CDbzDC02R2WrE141/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzQUJ5%2FbtrrospE8Qx%2FartIo0CDbzDC02R2WrE141%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;641&quot; height=&quot;266&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;비신뢰성&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패킷을 보낼 때 여러 문제점이 생길 수 있는데, 첫 번째 문제점은 중간에 패킷이 사라지는 &lt;span style=&quot;color: #006dd7;&quot;&gt;패킷 소실이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패킷을 전송하는 과정에서 중간 노드가 꺼져있거나, 문제가 생긴다면 패킷이 소실될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qgNb6/btrrjA949gG/beGicfi2QmSIqYXX9DcD11/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qgNb6/btrrjA949gG/beGicfi2QmSIqYXX9DcD11/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qgNb6/btrrjA949gG/beGicfi2QmSIqYXX9DcD11/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqgNb6%2FbtrrjA949gG%2FbeGicfi2QmSIqYXX9DcD11%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;263&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;두 번째 문제점은 패킷이 순서대로 오지 않는 &lt;span style=&quot;color: #006dd7;&quot;&gt;전달 순서 문제&lt;/span&gt;이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;'Hello, world!'라는 메시지를 보낼 때 'Hello, '와 'world!'로 나누어 패킷을 전송한다고 가정하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;'world!' 패킷이 더 최적의 경로로 먼저 도착하게 될 수 있는데, 그러면 'worldHello, '라는 메시지로 목적지에 도착하게 된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m80UD/btrrjAPKCUp/zGkdNRaN2RIuMuW3Q2kfi1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m80UD/btrrjAPKCUp/zGkdNRaN2RIuMuW3Q2kfi1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m80UD/btrrjAPKCUp/zGkdNRaN2RIuMuW3Q2kfi1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm80UD%2FbtrrjAPKCUp%2FzGkdNRaN2RIuMuW3Q2kfi1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;652&quot; height=&quot;293&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다면 이러한 한계점을 어떻게 극복할 수 있을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 한계점을 해결해주는 것이 바로 TCP(UDP) 프로토콜이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;TCP(UDP)&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP(UDP)는 인터넷 프로토콜 스택 4 계층에서 전송 계층에 해당한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q7FYz/btrrj0m4ipJ/IkoJuj42OkXqxa1AUOlvjK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q7FYz/btrrj0m4ipJ/IkoJuj42OkXqxa1AUOlvjK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q7FYz/btrrj0m4ipJ/IkoJuj42OkXqxa1AUOlvjK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ7FYz%2Fbtrrj0m4ipJ%2FIkoJuj42OkXqxa1AUOlvjK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;333&quot; height=&quot;170&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP는 IP가 속하는 인터넷 계층의 상위 계층인 전송 계층에 속하여, 네트워크 통신에서 인터넷 계층의 한계점을 보완해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프로토콜 계층에 TCP, IP는 OS에 속하게 되며 전송 과정은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1064&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ru5go/btrrlSJdIdW/7Z6uEqAouK1tBAmEkZBXck/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ru5go/btrrlSJdIdW/7Z6uEqAouK1tBAmEkZBXck/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ru5go/btrrlSJdIdW/7Z6uEqAouK1tBAmEkZBXck/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fru5go%2FbtrrlSJdIdW%2F7Z6uEqAouK1tBAmEkZBXck%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;608&quot; height=&quot;285&quot; data-origin-width=&quot;1064&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이더넷 프레임(Ethernet frame) 개념의 경우 네트워크의 최하위 계층을 설명하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이는 MAC 주소와 같은 해당 하드웨어를 구분하는 정보이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;앞서 IP가 출발지와 도착지 IP를 설명했다고 한다면, TCP는 여기서 더 나아가 &lt;span style=&quot;color: #006dd7;&quot;&gt;출발지와 목적지 PORT 그리고 전송 제어와 순서 검증 정보&lt;/span&gt; 등이 들어오게 된다. 이를 가리켜 &lt;span style=&quot;color: #006dd7;&quot;&gt;TCP 세그먼트(Segment)&lt;/span&gt;라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1519&quot; data-origin-height=&quot;765&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvZSxP/btrrsmhZIhb/vMcTKuh7r5aBhkxMLQI0u1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvZSxP/btrrsmhZIhb/vMcTKuh7r5aBhkxMLQI0u1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvZSxP/btrrsmhZIhb/vMcTKuh7r5aBhkxMLQI0u1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvZSxP%2FbtrrsmhZIhb%2FvMcTKuh7r5aBhkxMLQI0u1%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;256&quot; data-origin-width=&quot;1519&quot; data-origin-height=&quot;765&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP 특징은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연결 지향 - TCP 3 way handshake&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 전송 보증&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;순서 보장&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이처럼 TCP는 대부분 신뢰성에 중점을 둔 프로토콜이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현재는 대부분이 TCP 프로토콜을 사용하고 있다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;TCP 3 way handshake&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP 3 way handshake는 데이터 전송에 앞서서 먼저 연결을 하는 과정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d9VAAp/btrroEXRV1A/C3NJ4ypVxZtyGQnTJq0My0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d9VAAp/btrroEXRV1A/C3NJ4ypVxZtyGQnTJq0My0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d9VAAp/btrroEXRV1A/C3NJ4ypVxZtyGQnTJq0My0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9VAAp%2FbtrroEXRV1A%2FC3NJ4ypVxZtyGQnTJq0My0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;535&quot; height=&quot;217&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 데이터 전송 전에 먼저 클라이언트 측에서 'SYN' 메시지를 보낸다. (SYN: 연결해줘)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 서버가 'SYN'을 받으면 'SYN' + 'ACK' 메시지를 보낸다. (ACK: 왔네. 알겠어. SYN: 나도 연결해줘)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 클라이언트는 응답을 받으면 'ACK' 메시지를 보낸다. (ACK: 알겠어)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp;(요즘은 기술이 발달하여 'ACK'와 함께 데이터도 보낸다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만, 이 과정은 개념적인(논리적인) 연결일 뿐이다. 컴퓨터끼리 서로 연결되었음을 약속하는 것이지 통신 과정에서 거치는 노드들은 연결되었다는 정보를 알지 못한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;데이터 전달 보증&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트에서 데이터 전송 시 서버는 데이터를 잘 받았다고 알려준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1323&quot; data-origin-height=&quot;409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UBEU7/btrrosxr4Sf/cJixhpU3d2npsmtAJ9z3q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UBEU7/btrrosxr4Sf/cJixhpU3d2npsmtAJ9z3q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UBEU7/btrrosxr4Sf/cJixhpU3d2npsmtAJ9z3q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUBEU7%2Fbtrrosxr4Sf%2FcJixhpU3d2npsmtAJ9z3q1%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;556&quot; height=&quot;172&quot; data-origin-width=&quot;1323&quot; data-origin-height=&quot;409&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;순서 보장&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트에서 패킷을 1, 2, 3 순서로 전송했다고 가정하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 서버에 패킷이 1, 3, 2 순서로 도착하였다면 서버는 패킷 2부터 다시 보내라고 응답한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kDcYX/btrrpUNhzzz/vtPwhbvh5Pb6xuvRJw6mWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kDcYX/btrrpUNhzzz/vtPwhbvh5Pb6xuvRJw6mWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kDcYX/btrrpUNhzzz/vtPwhbvh5Pb6xuvRJw6mWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkDcYX%2FbtrrpUNhzzz%2FvtPwhbvh5Pb6xuvRJw6mWk%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;590&quot; height=&quot;185&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 모든 기능은 TCP 세그먼트 안에 정보를 가지고 있기 때문에 가능하다는 것을 꼭 상기하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;UDP(User Datagram Protocol)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;UDP는 사용자 데이터그램 프로토콜의 약자로 기능이 거의 없는 것이 특징이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP에서 제공하는 3가지 기능(3way handshake, 데이터 전달 보증, 순서 보장)을 제공하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대신 단순하기 때문에 빠른 것이 특징이다. Port와 체크섬 정도만 추가되고, 나머지는 IP랑 거의 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP 프로토콜은 최적화를 위해 어떠한 작업을 할 수가 없다. 이미 전 세계에서 쓰고 있는 프로토콜을 어떻게 내 마음대로 바꿀 수 있을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래서 UDP는 TCP보다 빠른 속도를 요구하는 곳에서 필요하다. TCP에서 제공하는 기능을 사용하고 싶은 경우 UDP를 쓰되 애플리케이션 단에서 추가 작업을 하는 방향으로 개발한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실시간 인터넷 방송이나 온라인 격투 게임처럼 속도가 중요한 곳에서 많이 쓰이고 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아직까지 TCP 프로토콜이 90%의 점유율을 가지고 있지만, 최근에는 UDP가 각광받고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그 이유는 HTTP 3 기술에서 UDP 프로토콜을 사용하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Port&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Port는 말 그대로 항구라는 뜻이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트 PC가 인터넷을 통해 게임, 화상통화, 웹 브라우저 요청 등 많은 네트워크 서비스를 사용한다고 가정해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;683&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHYjoF/btrrqZAzvAT/QMLDickGUVM2jVkRJLiR2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHYjoF/btrrqZAzvAT/QMLDickGUVM2jVkRJLiR2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHYjoF/btrrqZAzvAT/QMLDickGUVM2jVkRJLiR2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHYjoF%2FbtrrqZAzvAT%2FQMLDickGUVM2jVkRJLiR2k%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;303&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;683&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이렇게 여러 애플리케이션을 사용하고 있는 경우, 전송하고 전송받을 때 어떤 IP주소로 데이터를 보내야 하고 어떤 애플리케이션으로 데이터를 받아야 하는지 알 수가 없다. 이러한 이유로 Port가 필요한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP 세그먼트에 있는 출발지와 도착지 Port를 이용하여 각 프로세스를 구분하고, 어느 주소로 할지를 구분할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1395&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4J88G/btrroWx5gZi/F72jNzhxU2TPf13j5ODYOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4J88G/btrroWx5gZi/F72jNzhxU2TPf13j5ODYOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4J88G/btrroWx5gZi/F72jNzhxU2TPf13j5ODYOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4J88G%2FbtrroWx5gZi%2FF72jNzhxU2TPf13j5ODYOk%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;353&quot; data-origin-width=&quot;1395&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 그림과 같이, 게임 정보를 게임 서버에 보낸다고 해보자. 게임 서버에도 여러 프로세스가 실행 중일 것이다. IP 주소는 알고 있지만 어느 프로세스로 보낼 것인지 알아야 할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이미 클라이언트에서는 도착지 Port(11220)를 알고 있기 때문에 해당 포트로 데이터를 전송할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그러면 서버에서는 요청을 받은 후 출발지 Port(8090)을 알고 있기 때문에 다시 해당 포트로 결과 데이터를 전송할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Port라는 항구를 통해서 통신 데이터라는 배를 입항시키고 출항시킬 수 있게 해 준다고 생각하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이처럼 Port는 하나의 IP주소를 가지고도 각 프로세스가 알맞은 통신할 수 있게 해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Port는 0 ~ 62235(2byte 범위)까지 할당이 가능하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;0 ~ 1023 Port는 잘 알려진 Port로 사용하지 않는 것이 권장된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주요 Port 번호를 나열하면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;FTP - 20, 21&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TELNET - 23&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP - 80&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTPS - 443&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DNS(Domain Name System)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;IP는 최대 12개의 숫자로 구성되어 있기 때문에 정말 기억하기 어렵다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한, IP 주소는 특정 사유로 변경될 수 있다. 해당 서버에 IP 주소를 내가 기억하고 있다 해도, 서버에서 IP 주소를 바꾸면 해당 서버에 더 이상 접속할 수 없게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 IP의 단점을 극복하기 위해 DNS가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DNS는 마치 전화번호부와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다른 점이 있다면 이름에는 도메인 주소가 오고 전화번호에는 IP 주소가 온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 도메인, IP 정보들은 DNS 서버에 등록되고, 클라이언트에서 도메인명을 DNS 서버에 요청하면 해당 IP 주소를 돌려준다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1598&quot; data-origin-height=&quot;943&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LRtFy/btrruzH7vgk/TPaKglmVqbWdWUmXQflVJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LRtFy/btrruzH7vgk/TPaKglmVqbWdWUmXQflVJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LRtFy/btrruzH7vgk/TPaKglmVqbWdWUmXQflVJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLRtFy%2FbtrruzH7vgk%2FTPaKglmVqbWdWUmXQflVJk%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;688&quot; height=&quot;406&quot; data-origin-width=&quot;1598&quot; data-origin-height=&quot;943&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이렇게 하면 도메인 명이 바뀌지 않는 한, IP 주소가 바뀌어도 아무런 문제가 생기지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 내용은 &quot;김영한 - &lt;span style=&quot;background-color: #ffffff;&quot;&gt;모든 개발자를 위한 HTTP 웹 기본 지식&quot;의 내용을 정리한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1642837920208&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;모든 개발자를 위한 HTTP 웹 기본 지식 - 인프런 | 강의&quot; data-og-description=&quot;실무에 꼭 필요한 HTTP 핵심 기능과 올바른 HTTP API 설계 방법을 학습합니다., 웹 기술을 사용하는 개발자라면 누구나 OK!꼭 필요한 HTTP의 핵심을 알려드립니다.   확인해주세요!본 강의는 자바 스&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://inf.run/pRaC&quot; data-og-url=&quot;https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WmlsR/hyNaxbmGxs/kOFXMNMYkdgKZAimthH8R1/img.jpg?width=768&amp;amp;height=500&amp;amp;face=0_0_768_500,https://scrap.kakaocdn.net/dn/hRS3P/hyNaqwycz3/nHNMTV6Zdov457I3Ul04hk/img.jpg?width=768&amp;amp;height=500&amp;amp;face=0_0_768_500,https://scrap.kakaocdn.net/dn/bMaN79/hyNayOTNRh/dostPZikoAKVulwOALu17k/img.jpg?width=1200&amp;amp;height=666&amp;amp;face=0_0_1200_666&quot;&gt;&lt;a href=&quot;https://inf.run/pRaC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inf.run/pRaC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WmlsR/hyNaxbmGxs/kOFXMNMYkdgKZAimthH8R1/img.jpg?width=768&amp;amp;height=500&amp;amp;face=0_0_768_500,https://scrap.kakaocdn.net/dn/hRS3P/hyNaqwycz3/nHNMTV6Zdov457I3Ul04hk/img.jpg?width=768&amp;amp;height=500&amp;amp;face=0_0_768_500,https://scrap.kakaocdn.net/dn/bMaN79/hyNayOTNRh/dostPZikoAKVulwOALu17k/img.jpg?width=1200&amp;amp;height=666&amp;amp;face=0_0_1200_666');&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;모든 개발자를 위한 HTTP 웹 기본 지식 - 인프런 | 강의&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;실무에 꼭 필요한 HTTP 핵심 기능과 올바른 HTTP API 설계 방법을 학습합니다., 웹 기술을 사용하는 개발자라면 누구나 OK!꼭 필요한 HTTP의 핵심을 알려드립니다.   확인해주세요!본 강의는 자바 스&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.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;</description>
      <category>Network/HTTP</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/545</guid>
      <comments>https://lipcoder.tistory.com/545#entry545comment</comments>
      <pubDate>Fri, 21 Jan 2022 15:42:55 +0900</pubDate>
    </item>
    <item>
      <title>소프트웨어 공학이란?</title>
      <link>https://lipcoder.tistory.com/544</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;소프트웨어 공학(Software Engineering)은 &lt;span style=&quot;color: #006dd7;&quot;&gt;소프트웨어를 개발하는데 있어서 필수적인 요소&lt;/span&gt;이다. 이를 전혀 고려하지 않고 무작정 개발에 뛰어들면 실패할 가능성이 매우 높다. 실제로 프로젝트에 대한 상세를 대충 구상하고 개발을 시작하면, 얼마안가 생각했던 방향과는 다른 방향으로 흘러간다. 이미 진행된 상황에서 이를 되돌리기는 매우 어렵다. 대규모 프로젝트를 진행하는 기업이 이런 상황이 발생하게 된다면 매우 큰 경제적, 시간적 손실이 발생한다. 이를 사전에 방지하고 좋은 소프트웨어를 효율적으로 개발하기 위해서는 소프트웨어 공학은 매우 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;소프트웨어를 개발하는 방법 중 하나인 애자일(Agile) 기법은 많은 유명 기업에서 채택하는 방법이다. 이러한 기업들이 왜 애자일 기법으로 개발하는지 이해할 필요가 있다. 이를 비롯해 효율적인 개발 방법과 구조, 윤리&lt;span style=&quot;color: #000000;&quot;&gt;&amp;middot;도덕적인 부분까지 다뤄본다.&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;소프트웨어 공학?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;소프트웨어 공학은 소프트웨어를 개발하는데 있어서 어떻게 개발할지?, 무엇을 개발할지? 에서부터 시작한다. 이러한 질문에 대한 효율적인 방법과 도구 그리고 이론을 모두 포함한 개념을 소프트웨어 공학이라고 부른다. 소프트웨어 공학을 통해 무작정 개발을 시작하지 않고 &lt;span style=&quot;color: #6164c6;&quot;&gt;기능적(Functional)&lt;/span&gt;, &lt;span style=&quot;color: #6164c6;&quot;&gt;비기능적(Non-Functional)&lt;/span&gt;인 부분을 고려하여 체계적으로 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;소프트웨어 공학 정의 : 시스템 개발의 초기 단계부터 시스템이 사용된 후 유지보수되기까지의 소프트웨어 개발과 관련된 모든 측면&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;소프트웨어와 관련된 모든 측면은 단순히 기술적인 개발과정만을 뜻하지 않고 프로젝트 관리, 개발 도구와 메소드 등과 같이 소프트웨어 제작에 있어 도움을 줄 수 있는 모든 것을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;소프트웨어 공학의 필요성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;크게 두가지로 나눠볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;비용의 문제&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현재 우리가 사용하는 PC 비용은 하드웨어보다 소프트웨어에 대한 비용이 더욱 커지고 있다. 여기서 말하는 비용이란 돈 뿐만 아니라 시간, 노력 등과 같은 개발에 필요한 모든 것을 뜻한다. 기술의 발전으로 소프트웨어 개발 비용 뿐만 아니라 유지 보수하는 비용도 꾸준히 증가하고 있는 추세이다. 소프트웨어 공학은 이같은 문제를 최소화하기 위해 효율적인 소프트웨어를 개발하는 것에 중심을 두고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;시스템 복잡도 향상&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;/u&gt;기술의 발전으로 시스템의 복잡도는 상당히 증가하고 있다. 이전에 불가능한 기술들이 지금은 가능한 시대가 되었다. 예를들어 인공지능이나 빅데이터 같은 복잡한 기술을 적용한 소프트웨어를 빠르게 개발하여 고객에게 전달해야한다. 더 커진 시스템을 고객에게 빠르게 전달하려니 완성도가 떨어지고 개발이 실패하는 상황이 발생하기도 한다. 이를 방지하기 위해 미리 계획을 세워놓고 체계적으로 진행할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 프로젝트에 같은 기술이 사용되지는 않는다. 새로운 기술을 적용하여 메소드를 작성하려면 그에 따른 비용이 발생한다. 시간이 지날수록 비용이 증가할 수밖에 없는 구조이다. 하지만, 고객은 더 싸고 오래 쓸 수 있는 소프트웨어를 원한다. 이런 상황에서 우리는 &lt;span style=&quot;color: #006dd7;&quot;&gt;소프트웨어 공학을 통해 빠르고 더 쉽게 개발할 수 있어야 한다&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋은 소프트웨어&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋은 소프트웨어는 고객에게 필요한 기능과 성능을 전달할 수 있다. 또한 유지보수가 가능해야 하고, 신뢰할 수 있어야 하며, 유용해야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특징을 알아보기에 앞서 우선 소프트웨어를 구체화 시킬 필요가 있다. 일반적으로 소프트웨어는 2가지 종류로 나눌 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;Generic products&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발되는 &lt;span style=&quot;color: #006dd7;&quot;&gt;소프트웨어가 어떤 것을 해야할지 개발자가 결정해서 개발하는 소프트웨어&lt;/span&gt;를 뜻한다. 당연히 유지보수도 개발자에 의해 진행된다. 개발되는 소프트웨어는 특정 사용자가 사용하는 것을 목표로 하는 것이 아닌 대중들이 사용하길 원하는 소프트웨어이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;Customized Products&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 고객의&lt;span style=&quot;color: #006dd7;&quot;&gt; 요구사항(Requirement)&lt;/span&gt;에 맞춰 개발되는 소프트웨어를 뜻한다. 유지보수 또한 고객의 요구사항에 맞추어 진행된다. 추후 프로그램이 업데이트 되면서 발생하는 변경사항들도 고객의 요구사항에 맞춰 진행한다. 이러한 소프트웨어는 개발 진행전에 고객과 충분한 커뮤니케이션이 필요하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;응용 프로그램은 다양한 종류로 분류할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Batch Processing System : 대용량 데이터를 처리하는 프로그램&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Entertainment System : 유저가 즐길 수 있는 프로그램 (게임 등)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;System for Modeling and Simulation : 시뮬레이션이나 모델링을 위한 시스템&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Data Collection System : 다른 시스템에서 전달 받은 데이터들을 수집하는 시스템&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;System of System : 다양한 시스템끼리 구성되어 상호작용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋&lt;b&gt;은 소프트웨어가 반드시 가져야 할 특성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋은 소프트웨어라는 것의 기준이 애매모호하기 때문에 여기서는 좋은 소프트웨어의 기준을 제시한다. 상황에 따라 속도가 빠른 소프트웨어가 좋을 수도 있고, 보안이 중요한 소프트웨어도 좋을 수 있다. 좋은 소프트웨어가 가져야 할 특성이라는 것은 특정 목적을 가진 소프트웨어가 가져야 할 특성과 다르다. 소프트웨어라면 가져야할 덕목이다. 소프트웨어 공학의 &lt;span style=&quot;color: #8a3db6;&quot;&gt;근복적인 원리&lt;/span&gt;를 확인해보도록 하자.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;유지가능성(Maintainability)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;소프트웨어는 변화하는 상황 속에서 고객의 요구사항에 맞춰 진화할 수 있어야 한다. 즉, 유지가 쉬워야 한다는 것이다. 그리고 빠른 업데이트를 진행할 수 있어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;신뢰성과 보안(Reliability and Security)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;소프트웨어의 &lt;span style=&quot;color: #8a3db6;&quot;&gt;신뢰성&lt;/span&gt;은 믿을 수 있는 것을 포함해 &lt;span style=&quot;color: #8a3db6;&quot;&gt;보안과&lt;/span&gt; &lt;span style=&quot;color: #8a3db6;&quot;&gt;안전&lt;/span&gt;을 모두 일컫는다. 소프트웨어는 절대 물리적, 경제적 손해를 유발하면 안된다. 어떤 이벤트에 대해 작동이 실패한 경우 경제적, 물리적 순해를 주면 안된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;효율성(Efficiency)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;소프트웨어가 작동할 때 메모리나 프로세서 같은 리소스를 사용하게 된다. 이 때, 리소스의 낭비를 유발해서는 안된다. 처리 시간, 메모리 사용에 있어서 효율적인 관리가 되어야 한다. 이말인 즉슨&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;복잡도를 관리&lt;/span&gt;해야 한다는 뜻이된다. 단순한 과정도 복잡한 프로세스를 거치게 되면 처리 시간이 올라가고 메모리를 많이 사용하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;접근가능성(Acceptability)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만들어진 소프트웨어를 아무도 사용하지 않으면 무용지물이다. 반대로 소프트웨어 사용자가 많아져도 너무 복잡하면 아무도 사용하지 않게 될것이다. 그래서 개발된 소프트웨어는 반드시 &lt;span style=&quot;color: #006dd7;&quot;&gt;이해할 수 있어야 하며, 유용해야 한다&lt;/span&gt;. 즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;시스템과 유저가 양립&lt;/span&gt;할 수 있어야한다. 이는 사용하기 쉬우며 다른 프로그램과의 충돌이 적은 소프트웨어를 뜻한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;출처 : &lt;a href=&quot;https://chanos.tistory.com/entry/Software-Engineering-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B3%B5%ED%95%99%EC%9D%B4%EB%9E%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B3%B5%ED%95%99%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1-%EC%A2%8B%EC%9D%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EC%9D%98-%ED%8A%B9%EC%84%B1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://chanos.tistory.com/entry/Software-Engineering-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B3%B5%ED%95%99%EC%9D%B4%EB%9E%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B3%B5%ED%95%99%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1-%EC%A2%8B%EC%9D%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EC%9D%98-%ED%8A%B9%EC%84%B1&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Software Engineering</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/544</guid>
      <comments>https://lipcoder.tistory.com/544#entry544comment</comments>
      <pubDate>Fri, 14 Jan 2022 16:42:19 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] Item02. 생성자의 매개변수가 많다면 빌더를 고려하라</title>
      <link>https://lipcoder.tistory.com/543</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정적 팩터리 메서드 혹은 생성자에는 서로 공통적인 제약이 하나 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;선택적 매개변수가 많을 경우 적절히 대응이 어렵다는 것이다.&amp;nbsp;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) 영양정보는 20개가 넘어가지만, 대다수의 값이 0인 경우&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 해결하기 위해 여러 대안이 있는데, 한번 살펴보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;점층적 생성자 패턴 (Telescoping Constructor Pattern)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;매개변수를 점층적으로 받을 수 있게 생성자를 구성하는 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필수 매개변수만 받는 생성자&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필수 매개변수&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;선택 매개변수 1개 받는 생성자&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;선택 매개변수 2개 받는 생성자&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;...&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1640306691138&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NutritionFacts {
    private final int servingSize;      // 1회 제공량       필수
    private final int servings;         // 총 n회 제공량     필수
    private final int calories;         // 1회 제공량당      선택
    private final int fat;              // 1회 제공량(g)    선택
    private final int sodium;           // 1회 제공량(mg)   선택
    private final int carbohydrate;     // 1회 제공량(g)    선택

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories) {
        this(servingSize, servings, calories, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, 
                          int fat) {
        this(servingSize, servings, calories, fat, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, 
                          int fat, int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, 
                          int fat, int sodium, int carbohydrate) {
        this.servingSize    = servingSize;
        this.servings       = servings;
        this.calories       = calories;
        this.fat            = fat;
        this.sodium         = sodium;
        this.carbohydrate   = carbohydrate;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호출은 다음과 같이 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640307236249&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;점층적 생성자 패턴은 쓰는것 자체에는 아무런 문제가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 매개변수의 갯수가 많아지면 클라이언트 코드를 작성하거나, 읽기가 어려워진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;순서가 조금만 바뀌어도 런타임 에러가 발생할 수 있으며, 버그 생성 가능성도 내제되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;자바 빈즈 패턴 (JavaBeans Pattern)&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자바 빈즈 패턴은 매개변수가 없는 생성자를 만든 후, 세터(setter) 메서드들을 호출하여 원하는 매개변수의 값을 설정하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640307211621&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NutritionFacts2 {
    private int servingSize   = -1;      // 필수
    private int servings      = -1;      // 필수
    private int calories      = 0;   
    private int fat           = 0;
    private int sodium        = 0;
    private int carbohydrate  = 0;

    public NutritionFacts2() { }
    
    public void setServingSize(int val)         { servingSize = val; }
    public void setServings(int val)            { servings = val; }
    public void setCalories(int val)            { calories = val; }
    public void setFat(int val)                 { fat = val; }
    public void setSodium(int val)              { sodium = val; }
    public void carbohydrate(int val)           { carbohydrate = val; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호출은 다음과 같이 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640307271551&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setCarbohydrate(27);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 패턴은 심각한 단점을 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체를 하나 만드려면 메서드를 여러 번 호출해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고 호출을 통해 객체가 완전히 생성되기 전까지는 일관성이 무너진 상태로 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이는 버그나 런타임 문제를 디버깅 하는데에 어려움으로 작용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;빌더 패턴 (Builder Pattern)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더 패턴은 처음에 살펴봤던 &lt;u&gt;점층적 생성자 패턴&lt;/u&gt;의 안전성과 &lt;u&gt;자바 빈즈 패턴&lt;/u&gt;의 가독성을 융합한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 명명된 선택적 매개변수(named optional parameters)라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음 세가지 규칙을 지켜 만들어 진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필요한 객체를 직접 만들기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필수 매개변수만으로 생성자 호출&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세터 메서드를 호출하여 선택 매개변수들을 설정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1640307570699&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NutritionFacts3 {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // 필수 매개변수
        private final int servingSize;
        private final int servings;

        // 선택 매개변수 - 기본값으로 초기화
        private int calories        = 0;
        private int fat             = 0;
        private int sodium          = 0;
        private int carbohydrate    = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int val) {
            calories = val;     return this;
        }
        public Builder fat(int val) {
            fat = val;     return this;
        }
        public Builder sodium(int val) {
            sodium = val;     return this;
        }
        public Builder carbohydrate(int val) {
            carbohydrate = val;     return this;
        }

        public NutritionFacts3 build() {
            return new NutritionFacts3(this);
        }
    }
    
    private NutritionFacts3(Builder builder) {
        servingSize     = builder.servingSize;
        servings        = builder.servings;
        calories        = builder.calories;
        fat             = builder.fat;
        sodium          = builder.sodium;
        carbohydrate    = builder.carbohydrate;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;NutritionFacts3 클래스는 불변이며, 모든 매개변수의 기본값들은 한 곳에 모아둔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고 빌더 내부 클래스를 만들어 매개변수들을 통제하도록 한다. 필수 매개변수들은 빌더 생성자의 인자로 받는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호출은 다음과 같이 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640307809921&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NutritionFacts3 cocaCola = new NutritionFacts3.Builder(240, 8)
                               .calories(100).sodium(35).carbohydrate(27).build();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더의 세터 메서드들은 빌더 자신을 반환하기 때문에 연쇄적으로 호출 할 수 있다. 이를 메서드 체이닝 혹은 플루언트 API라고 부른다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더 패턴은 계층적으로 설계된 클래스와 함께 쓰기 더 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 경우 각 계층이 클래스에 관련 빌더를 멤버로 정의해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;피자의 다양한 종류를 표현하는 계층구조의 루트 추상 클래스는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- Pizza.java&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640308459894&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Objects;
import java.util.EnumSet;
import java.util.Set;

public abstract class Pizza {
    public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE };
    final Set&amp;lt;Topping&amp;gt; toppings;
    
    // Pizza.Builder 클래스는 재귀적 타입  한정을  이용하는  제네릭 타입이다.
    abstract static class Builder&amp;lt;T extends Builder&amp;lt;T&amp;gt;&amp;gt; {
        EnumSet&amp;lt;Topping&amp;gt; toppings = EnumSet.noneOf(Topping.class);
        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }

        abstract Pizza build();

        // 하위 클래스는 이 메서드를 재정의하여
        // this 를 반환하도록 해야 한다.
        // 이를 통해 형변환하지 않고도 Method Chaning을 지원할 수 있다.
        // 이러한 우회 방법을 시뮬레이트한 셀프 타입(simulated self-type) 관용구라 한다.
        protected abstract T self();
    }

    Pizza(Builder&amp;lt;?&amp;gt; builder) {
        toppings = builder.toppings.clone();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- NyPizza.java&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640308742779&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Objects;

public class NyPizza extends Pizza {
    public enum Size { SMALL, MEDIUM, LARGE }
    private final Size size;

    public static class Builder extends Pizza.Builder&amp;lt;Builder&amp;gt; {
        private final Size size;

        // size를 필수로 받음
        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }

        // 해당 구체의 하위 클래스를 반환한다.
        // NyPizza 반환
        @Override public NyPizza build() {
            return new NyPizza(this);
        }

        @Override protected Builder self() { return this; }
    }

    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- Calzone.java&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640308813693&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Calzone extends Pizza {
    private final boolean sauceInside;
    
    public static class Builder extends Pizza.Builder&amp;lt;Builder&amp;gt; {
        private boolean sauceInside = false; // 기본값

        // 소스를 넣을지 말지를 선택적으로 받음
        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }

        // 해당 구체의 하위 클래스를 반환한다.
        // Calzone 반환
        @Override public Calzone build() {
            return new Calzone(this);
        }

        @Override protected Builder self() { return this; }
    }

    private Calzone(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음과 같이 호출한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640308874286&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NyPizza pizza = new NyPizza.Builder(SMALL)
          .addTopping(SAUSAGE).addTopping(ONION).build();
          
Calzone calzone = new Calzone.Builder()
          .addTopping(HAM).sauceInside().build();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더 패턴은 상당히 유연하다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더 객체 하나로 여러 객체를 순회하면서 만들 수 있고, 빌더에 넘기는 매개변수에 따라 다른 객체를 만들수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 필드는 알아서 채우도록 할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더 패턴을 쓰려면 빌더 클래스부터 만들어줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더 클래스의 생성 비용은 크지 않지만 성능이 민감한 쪽에서는 문제가 될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 코드가 장황하기 때문에 매개변수 갯수가 일정(4개정도) 이상은 되어야 의미가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;API는 시간이 지날수록 매개변수가 많아지는 경향이 있기 때문에 빌더패턴으로 시작하는 편이 나을 때가 많다.&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;생성자나 정적 펙터리 메서드가 처리해야 할 매개변수가 많은 경우 빌더 패턴을 선택하는 게 더 낫다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특히 매개변수 중 대다수가 필수가 아니거나, 같은 타입이면 더더욱 그렇다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빌더는 점층적 생성자 패턴보다 코드를 읽고 쓰기가 훨씬 간결하며, 자바 빈즈 패턴보다 더 안전하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java/Effective Java</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/543</guid>
      <comments>https://lipcoder.tistory.com/543#entry543comment</comments>
      <pubDate>Tue, 21 Dec 2021 07:56:27 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] Item01. 생성자 대신 정적 팩터리 메서드를 고려하라</title>
      <link>https://lipcoder.tistory.com/542</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인스턴스를 얻을 수 있는 전통적인 수단 ==&amp;gt; 생성자(Constructor)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만, 클래스는 생성자와 별도로 정적 팩터리 메서드를 제공한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 래퍼 클래스 Boolean에서 발췌한 간단한 예&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1639726018300&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// static(정적)
// valueOf(메서드)
public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정적 팩터리 메서드 장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;1. 이름을 가질 수 있다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;/u&gt;생성자 자체 만으로는 반환될 객체의 특성을 제대로 설명하지 못한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 정적 팩터리 메서드는 메서드명을 잘 짓는다면 객체의 특성을 쉽게 묘사할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본 생성자&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; =&amp;gt; BigInteger(int, int, Random)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정적 팩터리 메서드 =&amp;gt; BigInteger.probablePrime(int, int, Random)&amp;nbsp; &amp;nbsp; &amp;lt;--&amp;nbsp; 어떤 의도인지 메서드 명을 통해 알 수 있다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;생성자가 여러개 있는 경우 각각 어떤 역할을 하는지 알기 힘들다. (문서를 보지 않는한...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 정적 팩터리 메서드를 사용하면 각 의미를 메서드명으로 녹여낼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;2. 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위에서 살펴본 Boolean.valueOf(boolean) 메서드는 호출을 위해 객체를 아예 생성하지 않는다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;JVM 실행 시점부터 객체정보가 이미 메서드 영역에 존재하고 있기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇기 때문에 같은 객체가 자주 요청되는 상황에서 성능을 상당히 끌어올려준다. (생성 비용이 클수록 더더욱..)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;/u&gt;생성자와 다르게 반환할 객체의 클래스를 자유롭게 선택할 수 있다. 이는 엄청난 유연성을 가짐을 보여준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적인 예로 컬렉션 프레임웤 java.util.Collections가 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반환타입의 하위 타입이기만 한다면 어떤 클래스의 객체를 반환하든 상관없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표 적인 예로 EnumSet이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;원소가 64개 이하 =&amp;gt; 원소들을 long 변수 하나로 관리한다. (RegularEnumSet 반환)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;원소가 64개 이상 =&amp;gt; long 배열로 관리한다. (JumboEnumSet 반환)&lt;/span&gt;&lt;/blockquote&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;5.정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;/u&gt;이런 유연함은 서비스 제공자 프레임웤을 만드는 근간이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;네가지 대표적인 컴포넌트로 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서비스 인터페이스 : 구현체의 동작을 정의한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제공자 등록 API : 제공자가 구현체를 등록한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서비스 접근 API : 클라이언트가 서비스의 인스턴스를 얻을 때 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서비스 제공자 인터페이스 : 인터페이스의 인스턴스를 생성하는 팩터리 객체를 설명한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적인 예로 JDBC(Java Database Connectivity)가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Connection&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;=&amp;gt; 서비스 인터페이스&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DriverManager.registerDriver&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;=&amp;gt; 제공자 등록 API&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DriverManager.getConnection&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;=&amp;gt; 서비스 접근 API&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Driver&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; =&amp;gt; 서비스 제공자 인터페이스&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그 외에 브리지 패턴과, 의존 객체 주입(DI)도 해당 특징을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정적 팩터리 메서드 단점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;1. 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;상속을 하려면 public이나 protected 생성자가 필요하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;2. 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;생성자처럼 API 설명에 명확하게 드러나지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇기 때문에 사용자는 정적 팩터리 메서드 방식 클래스를 인스턴스화할 방법을 알아내야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정적 팩터리 메서드에서 흔히 사용하는 명명 방식&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- from : 매개변수를 하나 받아 해당 타입의 인스턴스를 반환하는 형변환 메서드&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) Date d = Date.from(instant);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- of : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 매서드&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) Set&amp;lt;Rank&amp;gt; faceCard = EnumSet.of(JACK, QUEEN, KING);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- valueOf : from과 of의 자세한 버전&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; - instance, getInstance : 매개변수로 명시한 인스턴스를 반환, But 같은 인스턴스임을 보장하지 않음 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) StackWalker luke = StackWalker.getInstance(options); &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- create, newInstance : instance, getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) Object newArray = Array.newInstance(classObject, arrayLen); &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- getType : getInstance와 같으나, 다른 클래스에 팩터리 메서드를 정의할 때 사용 Type은 반환할 객체의 타입이다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) FileStore fs = Files.getFileStore(path); &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- newType : newInstance와 같으나, 클래스에 팩터리 메서드를 정의할 때 사용 Type은 반환할 객체의 타입이다. &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) BufferedReader br = Files.newBufferedReader(path); &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- type : getType, newType의 간결한 버전 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) List&amp;lt;Complaint&amp;gt; litany = Collections.list(legacyLitany); &lt;/span&gt;&lt;/blockquote&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;생성자와 정적 팩터리 메서드는 각자의 쓰임새가 있으므로 장단점을 잘 이해하고 적절히 사용하는것이 올바르다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다&amp;nbsp;하더라도&amp;nbsp;정적&amp;nbsp;팩터리&amp;nbsp;메서드를&amp;nbsp;사용하는&amp;nbsp;게&amp;nbsp;유리한&amp;nbsp;경우가&amp;nbsp;더&amp;nbsp;많으므로&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;무작정&amp;nbsp;생성자를&amp;nbsp;제공하던&amp;nbsp;습관이&amp;nbsp;있다면&amp;nbsp;고치도록&amp;nbsp;한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java/Effective Java</category>
      <category>M</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/542</guid>
      <comments>https://lipcoder.tistory.com/542#entry542comment</comments>
      <pubDate>Fri, 17 Dec 2021 17:11:32 +0900</pubDate>
    </item>
    <item>
      <title>포워드 프록시(Forward Proxy), 리버스 프록시(Reverse Proxy) 정의와 차이점</title>
      <link>https://lipcoder.tistory.com/541</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Proxy&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프록시 서버는 클라이언트를 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있도록 해주는 컴퓨터 시스템이나 응용 프로그램을 가리킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버와 클라이언트 사이에서 대리로 통신을 수행하는 것을 가리켜 프록시라고 하며, 이 프록시 기능을 하는 서버를 프록시 서버라고 부른다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;일부 프록시 서버는 서버로부터 요청받은 내용들을 캐시에 저장해둔다. 이를 캐슁이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프록시는 크게 포워드 프록시(Forward&amp;nbsp;Proxy)와 리버스 프록시(Reverse&amp;nbsp;Proxy)로 나뉜다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Forward Proxy&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;포워드 프록시는 클라이언트와 인터넷 사이에 위치하며, 클라이언트의 요청을 대신 받아 이를 서버로 요청하고 받은 결과를 다시 클라이언트에 전달해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프록시 서버는 캐시를 사용하여 자주 사용된 컨텐츠는 요청을 보내지 않고 캐시에서 가져오기 때문에 성능 향상이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIKNJa/btrn55LRkt4/gJTrfA9AkMbX2RKyRIsmoK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIKNJa/btrn55LRkt4/gJTrfA9AkMbX2RKyRIsmoK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIKNJa/btrn55LRkt4/gJTrfA9AkMbX2RKyRIsmoK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIKNJa%2Fbtrn55LRkt4%2FgJTrfA9AkMbX2RKyRIsmoK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;209&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;283&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Reverse Proxy&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리버스 프록시는 서버와 인터넷 사이에 위치하며, 클라이언트가 인터넷을 통해 요청을 하면 내부 서버에서 요청을 받아 결과를 다시 클라이언트에 전달한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 통해 클라이언트는 내부 서버를 알 필요 없이 리버스 프록시에 요청만 하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;내부 서버에 직접적으로 접근하면 보안상 문제가 생길 수 있기 때문에, 중간이 리버스 프록시를 두고 클라이언트와 내부 서버 사이의 통신을 담당하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리버스 프록시를 사용하면 내부 서버를 로드 밸런싱 처리하거나 확장 등을 할 때 더 유리하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdLSAH/btrn4sgggEj/9Bkx0vAROe3k4WVA4qd4yK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdLSAH/btrn4sgggEj/9Bkx0vAROe3k4WVA4qd4yK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdLSAH/btrn4sgggEj/9Bkx0vAROe3k4WVA4qd4yK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdLSAH%2Fbtrn4sgggEj%2F9Bkx0vAROe3k4WVA4qd4yK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;590&quot; height=&quot;209&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;287&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;차이점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;End Point&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;End Point란 서버적인 관점에서 해당 요청을 처리하는 최종목적지, 즉 디바이스를 가리킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;포워드 프록시는 클라이언트가 요청하는 End Point가 실제 서버 도메인이고 프록시는 둘 사이의 통신을 담당해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리버스 프록시는 클라이언트가 요청하는 End Point가 프록시 서버의 도메인이고 실제 서버 정보는 알 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;감춰지는 대상&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;/u&gt;포워드 프록시는 클라이언트가 감춰진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요청 받는 서버는 포워드 프록시를 통해 요청을 받기 때문에 해당 클라이언트의 정보를 알 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리버스 프록시는 반대로 서버가 감춰진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요청을 리버스 프록시가 대신 받아 처리하기 때문에 클라이언트는 요청받은 서버의 정보를 알 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://bcp0109.tistory.com/194&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bcp0109.tistory.com/194&lt;/a&gt;&lt;/p&gt;</description>
      <category>Network</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/541</guid>
      <comments>https://lipcoder.tistory.com/541#entry541comment</comments>
      <pubDate>Fri, 17 Dec 2021 09:56:23 +0900</pubDate>
    </item>
    <item>
      <title>[Clean Code] 4. 주석</title>
      <link>https://lipcoder.tistory.com/540</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;주석은 양날의 검과 같다. 잘 달면 정말 도움되지만, 그렇지 않으면 오히려 잘못된 정보를 제공하기 때문에 코드 이해를 더 어렵게 만든다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;만약에 깔끔하고 직관적인 코드로 그 의도를 표현할 능력이 있다면, 주석은 거의 필요가 없다. 우리는 결국 이런 의도를 표현하지 못하는 실패를 만회하기 위해 그 의도를 설명하려고 주석을 사용한다. 오히려 의도를 잘못 설명할 수도 있는데 말이다. 이런 점에서 어떻게 보면 주석은 '필요악'이라고 할 수 있겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇기 때문에 주석이 필요한 상황에서는 어떻게 의도를 잘 표현하여 주석을 사용하지 않을지 고민을 해봐야한다. 주석을 달때마다 의도를 표현하지 못하는 본인을 한탄하고 이런 실수를 만회하기 위해 노력하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주석은 거짓말쟁이이다. 주석은 너무 자주 거짓말을 한다. 주석은 오래될수록 본래 코드와도 멀어질 뿐더러 완전 다른 의도를 표현할 수도 있다. 코드를 유지보수 한다는 건 들어봤어도, 주석을 유지보수 한다는 말을 들어 본적이 있는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러 상황에 맞게 계속해서 변화하는 것이 코드이다. 불행히도 주석은 이런 코드를 항상 따라가지 못한다. 점점 코드에서 분리되어 왕따가 되어 버린다.&lt;/p&gt;
&lt;pre id=&quot;code_1639124007188&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MockRequest request;
private final String HTTP_DATE_REGEXP = 
	&quot;[XMTWF][a-z]{2}\\,\\s[0-9]{2}\\s[JFMASOND][a-z]{2}\\s&quot;+
    &quot;[0-9]{4}\\s[0-9]{2}\\:[0-9]{2}\\:[0-9]{2}\\sGMT&quot;;
private Response response;
// 생략... 
private FitNesseContect context;
// Example: &quot;Tue, 02 Apr 2003 22:18:49 GMT&quot;  ==&amp;gt;  뜬금없다???&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;분명 다른 코드들이 추가되면서 HTTP_DATE_REGEXP 상수와 Example 주석이 분리된게 틀림없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주석을 엄격히 관리하여, 정확도가 언제나 높아야 한다고 생각할 수도 있다. 맞는 말이다. 하지만 차라리 좋은 코드로 그 의도를 표현하여 주석을 없애는게 더 효율적이지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;부정확한 주석은 주석이 없는것보다 더 안좋다. 부정확한 주석은 사용자로 하여금 잘못된 방향으로 이끈다. 분명 잘못된 해석을 통해 잘못된 방향으로 구현하는 결과를 초래할 것이 뻔하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코드만이 정확한 정보를 전달하는 유일한 출처이다. 그렇기 때문에 우리는 주석이 필요할지라도 가능한 줄이도록 계속해서 노력하는 자세가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주석은 나쁜 코드를 보완하지 못한다&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코드에 주석을 추가하는 이유는 코드 품질이 나쁘기 때문이다. 모듈을 만들고 보니 짜임새가 맞지 않고 이해가 어렵다. 알아먹기 힘든 모듈이라는 사실을 깨닫지만 개발자는 그저 &quot;주석을 달아야겠군!&quot; 이런 생각 뿐이다. 코드를 고쳐야 겠다는 생각은 이미 머릿속에서 사라졌을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주석이 없어도 표현력이 풍부하고 깔끔한 코드가 주석이 있는 복잡한 코드보다 훨씬 좋다. 그러므로 복잡한 코드가 있다면 잔말말고 고치는데에 시간을 보내자. 그것이 오래 걸리더라도 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드로 의도를 표현하라!&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코드만으로 의도를 설명하기 어려운 경우도 없지는 않다. 다음 코드를 보자. 어느쪽이 나은가?&lt;/p&gt;
&lt;pre id=&quot;code_1639125090595&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 직원에게 복지 혜택을 받을 자격이 있는지 검사한다.
if((employee.flags &amp;amp; FOURLY_FLAG) &amp;amp;&amp;amp;
   (employee.age &amp;gt; 65))
   
   
// 다음 코드는 어떠한가?
if(employee.isEligibleForFullBenefits())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;좀만 생각하면 코드로 대다수의 의도를 표현할 수 있다. 주석으로 달려고 했던 설명을 함수로 만들어 표현해도 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;좋은 주석&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어떤 주석을 필요하거나 유익하다. 이제부터 글자 값을 한다고 생각하는 주석 몇가지를 소개한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다시 한번 짚고 엄어갈 것이 있는데, '정말로 좋은 주석은, 주석을 달지 않는 것'이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;u&gt;법적인 주석&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;때때로 회사에서는 자사 표준에 맞춰 법적인 이유로 특정 주석 넣으라고 명시한다. 예를 들어 첫머리에 주석으로 들어가는 저작권 정보와 소유권 정보는 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음은 FitNess에서 모든 소스 파일 첫머리에 추가한 표준 주석 헤더이다.&lt;/p&gt;
&lt;pre id=&quot;code_1639125869405&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
// GNU General Public License 버전 2 이상을 따르는 조건으로 배포&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;소스 파일 첫머리에 들어가는 주석이 반드시 법적인 정보일 필요는 없다. 모든 정보를 열거하는 대신에, 가능하다면, 표준 라이선스나 외부 문서를 참조해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;u&gt;정보를 제공하는 주석&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음처럼 기본적인 정보를 주석으로 제공하면 편리하다. 다음 코드는 메서드의 반환 반환값을 설명한다.&lt;/p&gt;
&lt;pre id=&quot;code_1639126213084&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 테스트 중인 Responder 인스턴스를 반환한다.
protected abstract Responder responderInstance();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이런 경우, 가능하다면 함수 이름에 정보가 녹아들어가게 구성할 수도 있을 것이다. 함수 이름을 responderBeingTested로 바꾸면 주석이 필요 없어진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위에서 살펴봤던 HTTP_DATE_REGEXP 정규식을 설명하는 주석도 이에 포함된다. 하지만 이 경우도 날짜를 변환하는 클래스를 만들어 코드를 옮겨주면 주석이 필요 없어진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;의미를 명료하게 밝히는 주석&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;/u&gt;모호한 인수나 반환값은 그 의미를 좋게 표현하면 이해가 쉬워진다. 인수나 반환값이 표준 라이브러리거나 변경 불가능한 코드에 속한다면 그 의미를 정확하게 밝히는 주석이 유용하다.&lt;/p&gt;
&lt;pre id=&quot;code_1639139220671&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void testCompareTo() throws Exception
{
    assertTrue(a.compareTo(a) == 0);      // a == a
    assertTrue(a.compareTo(b) != 0);      // a != b
    assertTrue(ab.compareTo(ab) == 0);    // ab == ab
    assertTrue(a.compareTo(b) == -1);     // a &amp;lt; b
    assertTrue(aa.compareTo(ab) == -1);   // aa &amp;lt; ab
    assertTrue(ba.compareTo(bb) == -1);   // ba &amp;lt; bb
    assertTrue(b.compareTo(a) == 1);      // b &amp;gt; a
    assertTrue(ab.compareTo(aa) == 1);    // ab &amp;gt; aa
    assertTrue(bb.compareTo(ba) == 1);    // bb &amp;gt; ba
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;잘못된 주석을 달아놓을 위험은 굉장히 높다. 또한 올바른지 검증도 쉽지 않다. 그러므로 위와 같은 주석을 달 때에는 더 나은 방법이 없는지 먼저 고민하고 정확히 달려고 하는 노력이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;결과를 경고하는 주석&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;때로 다른 프로그래머에게 결과를 경고할 목적으로 주석을 사용한다. 예를 들어, 다음 특정 테스트 케이스를 꺼야하는 이유를 설명하는 주석이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639141268078&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 여유 시간이 충분하지 않다면 실행하지 마십시오.
public void _testWithReallyBigFile() {
    writeLinesToFile(10000000);
    
    response.setBody(testFile);
    response.readyToSend(this);
    String responseString = output.toString();
    assertSubString(&quot;Content-Length: 1000000000&quot;, responseString);
    assertTrue(byteSent &amp;gt; 1000000000);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;요즘은 JUnit4으로 @Ignore 속성을 이용해 테스트 케이스를 꺼버릴수 있다. 그리고 이 속성 문자열에 구체적인 설명을 넣어줄 수 있다. @Ignore(&quot;실행이 너무 오래 걸린다!&quot;). JUnit4가 나오기 전에는 메서드 앞에 '_' 를 붙이는 방법이 일반적인 관례였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음 주석은 아주 적절한 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1639141987408&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static SimpleDateFormat makeStandardHttpDateFormat() 
{
    // SimpleDateFormat은 스레드에 안전하지 못하다.
    // 따라서 각 인스턴스를 독립적으로 생성해야 한다.
    SimpleDateFormat df = new SimpleDateFormat(&quot;EEE, dd MMM  yyyy HH:mm:ss z&quot;);
    df.setTimeZone(TimeZone.getTimeZone(&quot;GMT&quot;));
    return df;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기서는 주석이 아주 합리적이다. 성능을 높히기 위해 해당 함수를 사용하려던 프로그래머가 있다면 주석 때문에 큰 실수를 면하게 될것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;TODO 주석&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;/u&gt;앞으로 해야 할 일을 TODO 주석으로 남겨두면 편하다. 다음 코드를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1639142229554&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// TODO-MdM 현재 필요하지 않음
// 체크아웃 모델을 도입하면 함수가 필요 없음
protected VersionInfo makeVersion() throws Exception
{
    return null;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;TODO 주석은 해당 코드가 필요한 경우이지만 당장 구현이 어려운 경우 기술한다. 또한 필요없는 기능 삭제 알림, 문제를 봐달라는 요청, 더 좋은 이름을 떠올리라는 충고, 발생할 이벤트에 맞춰 코드 수정 요구 등에 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만 어떤 용도로 사용하든 시스템에 나쁜 코드를 남겨 놓은 핑계가 되어서는 안된다. &amp;nbsp;요즘 대다수 IDE는 TODO 주석 전부를 찾아 보여주는 기능을 제공하므로 주석을 잊어버릴 걱정은 할 필요가 없다. 그래도 TODO는 주기적으로 사용이 끝났다면 없애야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;중요성을 강조하는 주석&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;별거 아니라고 느껴질만한 것도 중요성을 강조하기 위해 주석을 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1639345650669&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String listItemContent = match.group(3).trim();
// 여기서 trim은 정말 중요하다. trim 함수는 문자열에서 시작 공백을 제거한다.
// 문자열에 시작 공백이 있으면 다른 문자열로 인식되기 때문이다.
new ListItemWidget(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end());&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;&lt;b&gt;나쁜 주석&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;대다수의 주석이 여기에 속한다. 이 주석들은 허술한 코드를 지탱하거나, 혹은 변명하거나, 합리화 하는 프로그래머의 변명에서 크게 벗어나지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;주절거리는 주석&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어떤 이유 없이 마지못해 주석을 다는 경우 시간낭비를 할 뿐이다. 주석을 달기로 결정했다면 충분한 고려를 통해 완벽한 주석을 달 수 있게 노력해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음 코드를 보도록 하자.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639346142553&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void loadProperites() 
{
    try
    {
        String propertiesPath = propertiesLocation + &quot;/&quot; + PROPERTIES_FILE;
        FileInputStream propertiesStream = new FileInputStream(propertiesPath);
        loadedProperties.load(propertiesStream);
    }
    catch(IOException e)
    {
        // 속성 파일이 없다면 기본값을 모두 메모리로 읽어 들였다는 의미이다.
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;catch 블록 내에 주석은 무슨 의미일까? 확실히 어떤 의미를 담고 있겠지만, 그 의미가 다른 사람들에게 까지는 전달되지 않는다. 주석을 통해 유추하자면 IOException은 속성 파일이 없다는 뜻이고, 그러면 모든 기본값을 메모리로 읽어 들인 상태란다. 하지만 모든 기본값을 어디서 읽어들일 것이고, 어떻게 구현할 것인지에 대한 구체적인 설명이 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;답을 찾기 위해서는 다른 코드를 찾아볼 수 밖에 없다. 이해가 되지 않아 다른 코드를 살펴봐야 하는 주석은 부족한 주석이다. 이런 주석은 그저 공간만 차지할 뿐이고, 아무런 도움이 되지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;같은 이야기를 중복하는 주석&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;/u&gt;다음 코드를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1639346602541&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// this.closed가 true일 때 반환되는 유틸리티 메서드이다.
// 타임아웃에 도달하면 예외를 던진다.
public synchronized void waitForClose(final long timeoutMillis)
throws Exception
{
    if(!closed)
    {
        wait(timeoutMillis);
        if(!closed)
            throw new Exception(&quot;MockResponseSender could not be closed&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위와 같은 주석을 다는 이유는 무엇일까? 주석이 코드보다 더 많은 정보를 제공하지 못하고 있다. 오히려 코드보다 읽기가 수월하지 않다. 또한 코드보다 부정확하여 함수를 대충 이해하고 넘어가게 만든다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이렇게 코드보다 못한 주석은 안다는게 훨씬 더 깔끔하다. 만약 서로 같다고 하더라도 주석을 달지 말아야 한다. 그저 중복되는 내용을 주석으로 적었을 뿐이기 때문이다. 주석은 코드의 이해가 어려운 경우 그것의 의도를 부연설명하는 수단이라는 것을 절대 잊어서는 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;의무적으로 다는 주석&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;모든 함수에 Javadocs를 달거나 모든 변수에 주석을 달아야 한다는 규칙은 어리석기 그지없다. 이런 주석들은 코드를 복잡하게 만들며, 잘못된 정보를 전달하고, 혼동을 초래한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/540</guid>
      <comments>https://lipcoder.tistory.com/540#entry540comment</comments>
      <pubDate>Fri, 10 Dec 2021 17:57:55 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 마스터 1급 합격 후기</title>
      <link>https://lipcoder.tistory.com/539</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGZMW8/btrneuMj1Dg/r67mpwAYToX2fPmYv1nsY1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGZMW8/btrneuMj1Dg/r67mpwAYToX2fPmYv1nsY1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGZMW8/btrneuMj1Dg/r67mpwAYToX2fPmYv1nsY1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGZMW8%2FbtrneuMj1Dg%2Fr67mpwAYToX2fPmYv1nsY1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;736&quot; height=&quot;173&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;계기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;회사 개발업무를 하면서 리눅스 터미널을 만질 일이 정말 많았다. 학부 시절 리눅스는 고사하고 윈도우 파워셸도 다뤄보지 못한 나로서는 개발에 어려움이 많았다. (여담이지만 운영체제 과목도 소홀히 했다...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;때문에 리눅스 공부에 대한 필요성을 크게 느꼈다. 그러면서 자연스럽게 리눅스 자격증을 알아보기 시작했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사실 자격증이 실무에 직접적으로 큰 도움이 된다고 생각하지는 않는다. 기술 트랜드에도 둔감한면이 없지않아 있고, 합격 후 공부한 내용을 리마인드 하지 않으면 백지처럼 날아가 버리기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 자격증 취득이라는 목표아래 공부에 대한 동기부여를 해준다는 점에서는 확실한 이점이 있다고 생각한다. 그리고 실무에서도 간접적으로나마 도움이 된다고 생각한다. &lt;span&gt;회사 우대사항에 자격증 취득란이 왜 있겠는가? &lt;/span&gt;만약 자격증이 아무런 도움이 되지 않았다면, 아무도 자격증을 안땄을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;시작&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래서 나는 리눅스 마스터 1급을 목표로 공부를 시작했다. 1급을 선택한 이유는 좀 더 깊이있는 공부를 하고 싶었던 것도 있었지만, 시험을 실제 터미널을 이용해 응시가 가능하다는 점에서 매력을 느꼈기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나는 이기적 기본서를 보고 공부하였다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1638511275336&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;book&quot; data-og-title=&quot;2021 이기적 리눅스마스터 1급 기본서 - YES24&quot; data-og-description=&quot;떠오르는&amp;nbsp;신흥&amp;nbsp;강자!&amp;nbsp;리눅스마스터&amp;nbsp;1급&amp;nbsp;2021년&amp;nbsp;도서가&amp;nbsp;드디어&amp;nbsp;영진닷컴에서&amp;nbsp;출간되었다.&amp;nbsp;시행처에서&amp;nbsp;발표한&amp;nbsp;출제기준에&amp;nbsp;맞는&amp;nbsp;핵심이론&amp;nbsp;내용과&amp;nbsp;이론을&amp;nbsp;공부한&amp;nbsp;뒤&amp;nbsp;바로&amp;nbsp;문제를&amp;nbsp;풀어&quot; data-og-host=&quot;m.yes24.com&quot; data-og-source-url=&quot;http://m.yes24.com/Goods/Detail/99042965&quot; data-og-url=&quot;http://m.yes24.com/Goods/Detail/99042965&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bpCbls/hyMzsaT3cY/QfKSb4lwoyqduxczhjuxLk/img.jpg?width=900&amp;amp;height=1200&amp;amp;face=0_0_900_1200,https://scrap.kakaocdn.net/dn/birNW4/hyMzl3XePM/hP06xTnulGASiARv5wlICk/img.jpg?width=900&amp;amp;height=1200&amp;amp;face=0_0_900_1200&quot;&gt;&lt;a href=&quot;http://m.yes24.com/Goods/Detail/99042965&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://m.yes24.com/Goods/Detail/99042965&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bpCbls/hyMzsaT3cY/QfKSb4lwoyqduxczhjuxLk/img.jpg?width=900&amp;amp;height=1200&amp;amp;face=0_0_900_1200,https://scrap.kakaocdn.net/dn/birNW4/hyMzl3XePM/hP06xTnulGASiARv5wlICk/img.jpg?width=900&amp;amp;height=1200&amp;amp;face=0_0_900_1200');&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;2021 이기적 리눅스마스터 1급 기본서 - YES24&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;떠오르는&amp;nbsp;신흥&amp;nbsp;강자!&amp;nbsp;리눅스마스터&amp;nbsp;1급&amp;nbsp;2021년&amp;nbsp;도서가&amp;nbsp;드디어&amp;nbsp;영진닷컴에서&amp;nbsp;출간되었다.&amp;nbsp;시행처에서&amp;nbsp;발표한&amp;nbsp;출제기준에&amp;nbsp;맞는&amp;nbsp;핵심이론&amp;nbsp;내용과&amp;nbsp;이론을&amp;nbsp;공부한&amp;nbsp;뒤&amp;nbsp;바로&amp;nbsp;문제를&amp;nbsp;풀어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;m.yes24.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 책에 대한 평은 솔직히 말하면 별로였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대략 세가지 정도 뽑아 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;첫번째는 &lt;u&gt;이론 내용 자체가 요약되어 있어서 생각보다 이해가 잘 안됐다.&amp;nbsp;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;한 책에 모든 내용을 담으려다 보니 개념을 표를 이용하여 나열하는 경우가 대부분이였고, 명령어 또한 옵션별 리스트와 그에 대한 예제만 있을 뿐 어떤걸 주로 사용한다거나 같은 내용이 없어서 많이 아쉬웠다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;두번째는 &lt;u&gt;뭔가 부족한 강의 제공이다.&lt;/u&gt; 부족한 이론 설명이나 이해가 안되는 부분은 강의를 이용해 채우려고 마음먹고 있었다. 하지만 강의를 듣고 많이 실망했다. 책의 저자가 강의를 하는데, 강의 경험이 별로 없는건지, 말이 중간마다 계속 끊기는 경우가 많았다. 강의 내용의 대부분은 그저 책에 있는 내용을 읽는 수준이 전부였다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세번째는 &lt;u&gt;잦은&amp;nbsp;내용 오타이다.&lt;/u&gt;&amp;nbsp; 내용 오타는 생각보다 치명적이라고 생각한다. 이론적인 내용이야 문맥의 흐름으로 어느정도 유추가 가능하지만, 명령어 예제의 오타는 그게 불가능하기 때문이다. 만약 명령어 오타를 보고 공부했다가 소중한 한문제가 틀린다면? 이로 인해 불합격 한다면 얼마나 속상하겠는가? 이 문제는 조속히 개선해야 된다고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그런데도 불구하고 이 책을 사야하는 이유는 무엇이냐..? 바로 대체제가 없기 때문이다. 다른 책들을 살펴보면 대부분 2급 책을 취급하지, 1급 책은 찾아보기 힘들다. 그나마 인지도가 있는게 이기적 시리즈였던것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;1차 시험 (필기)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리눅스를 다뤄 봤으니, 별로 안어렵겠구나 생각하고 공부를 했다. 이는 크나큰 착각이였다. 학부 레벨(?)의 운영체제, 네트워크 이론과 생소한 명령어들이 나를 힘들게 했다. 앞 부분은 회사 업무를 통해 다뤄봤던 내용이 있어서 보는데에는 큰 무리가 없었지만, 뒷 부분은 생소한 것 투성이라 무척이나 힘들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필기를 보기까지 한 2번 정도 완독한거 같다. 명령어 외우는게 많이 힘들었지만, 이론적인 부분은 어느정도 파악이되었다. 문제은행 방식으로 공부했는데, 이게 생각보다 큰 도움이 됐다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필기 시험은 기존 기출보다 쉽게 나온 편이였던거 같다. 그럼에도 불구하고 실수를 많이해서 그런지 거의 턱걸이로 합격하였다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;2차 시험 (실기)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리눅스 마스터 1급과 2급의 큰 차이는 2차 시험에 있다고 생각한다. 2급은 객관식 형태로 종이시험을 보지만, 1급은 서술형 형태로 직접 컴퓨터 앞에 앉아 리눅스를 이용하면서 시험을 치룬다는 차이점이 있다. 그래서 1급과 2급의 난이도 차이가 상당히 크며, 합격률도 1급이 낮은 편이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실기는 나오는 내용이 제한되어 있는 편이고, 그 부분을 집중적으로 공부하면 시간을 절약할 수 있다. 보통 이론책 후반부 내용에서 많이 출제된다. 리눅스를 직접 깔아서 명령어를 하나하나 입력해보면서 공부했다. 이 방법이 지루하지도 않을 뿐더러, 명령어에 익숙해지는데에 많은 도움이 됐다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;어느정도 이론지식과 명령어에 익숙해졌을 무렵, 실기 기출 문제를 풀어보는데, 솔직히 너무 어려웠다. 대부분 문제를 틀렸고, 합격선에 근접하지도 못했다. 공부 방식이 잘못되었다는 것을 뒤늦게 깨달았고, 시험을 포기할까 진지하게 생각도 해봤다. 그래도 여기까지 왔는데, 포기하지 않고 계속 달려가기로 마음을 먹었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실기 시험의 핵심은 세가지이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;첫번째는 &lt;u&gt;주요 도움되는 명령어에 익숙해지는 것&lt;/u&gt;이다. 도움되는 명령어는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;man&lt;/b&gt;: 해당 명령어의 정의와 사용법 등을 조회할 수 있는 명령어&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;--help&lt;/b&gt;: 해당 명령어의 사용법을 간략하게 보여주는 옵션&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;find&lt;/b&gt;: 원하는 파일이나 명령어를 찾을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;vi, vim&lt;/b&gt;: 파일을 수정할 수 있는 명령어&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;man 명령어와 --help 옵션을 써보면 알겠지만, 죄다 영어로 되어있기 때문에, 영어를 특출나게 잘하는게 아니라면 시험에 자주 나오는 명령어는 자주 쓰이는 옵션이나 사용법을 공부하가는 것이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;find는 명령어의 일부만 기억날때, 혹은 설정 파일을 찾을때 꽤 도움이 된다. 최상위 루트에서 찾으면 원하지 않는 검색결과가 많이 나올 수 있기 때문에, 명령어는 /bin/ 혹은 /sbin/ 경로에서 찾으면 되고, 설정 파일은 /etc/ 경로에서 찾으면 된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;vi, vim은 사용법이 처음에는 많이 어려울 수 있기 때문에 자주 사용하면서 익숙해지는게 도움이 된다. 사용법이 직관적이지 않기 때문에 자주 쓰는 단축키를 어느정도 숙지하고 있어야 편하다. 익숙해지면 nano보다 더 쓰기 편한거 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;두번째는 &lt;u&gt;단답식 보다는 작업식 문제를 정복하는 것&lt;/u&gt;이다. 실기에는 단답식과 작업식 문제로 나눠지는데, 보통 단답식은 10문제, 작업식은 5~7문제 정도 나온다. 단답식은 명령어와 옵션을 적는 문제가, 작업식은 환경 설정 문제가 주를 이룬다. 단답식은 한문제에 최대 4점이지만, 작업식은 한문제에 최대 12점이다. 이렇게 점수 차이가 많이 나기 때문에 작업식의 점수비중이 더 높다. 단답식 40점, 작업식 60점으로 작업식만 다 맞아도 합격권이다. 이러한 이유로 작업식은 절대 포기하면 안되며, 오히려 익숙해지고 친해져야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세번째는 &lt;u&gt;기출문제를 많이 풀어보는 것&lt;/u&gt;이다. 교재에 보통 18년도 부터 20년도까지 기출문제가 포함되어 있을텐데, 이 문제들은 모두 풀어보는것이 좋다. 처음에 많이 틀려도 실망하지 말자. 그냥 풀어보고, 틀리면 오답노트를 쓰는걸 반복하자. 이걸 계속 하다보면 어떤 부분에서 많이 출제되는지 알 수 있고, 주로 쓰이는 명령어들은 확실히 머리속에 각인시킬 수 있다. 운이 좋으면 문제가 그대로 출시되는 경우도 있다. 나는 기출문제의 덕을 많이 봤기 때문에 적극 추천하는 방법이다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실기시험은 서울의 한 대학교에서 치뤄졌다. 가면 버추얼박스 형식으로 CentOS 7 이 깔려있다. 계정과 비밀번호는 시험 시작 직전에 알려주기 때문에 참고하자. 시험시간은 100분으로 그렇게 빡빡하지도 넉넉하지도 않은 시간이였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;20년도 마지막 기출에 모르는게 많이 나와서 걱정했는데, 다행히 대부분 아는것들 위주로 출제되어서 막힘없이 풀었던것 같다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;후기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리눅스 마스터를 공부하면서 리눅스의 강력한 기능들을 알아보고, 이를 좀 더 효율적이고 다채롭게 다룰 수 있는 기회가 되었다고 생각한다. 응시료가 조금 무겁고, 어렵지만 적어도 웹 개발자의 길을 걷는다면 2급보다는 1급을 따는걸 추천한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>잡담</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/539</guid>
      <comments>https://lipcoder.tistory.com/539#entry539comment</comments>
      <pubDate>Fri, 3 Dec 2021 15:14:23 +0900</pubDate>
    </item>
    <item>
      <title>[리눅스 마스터 1급] 제 2002화 2차 실기 정리</title>
      <link>https://lipcoder.tistory.com/538</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# rpm&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 의존성 목록을 확인할 경우 -R 혹은 --requires 옵션을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 패키지 파일이 설치될 파일이나 디렉터리를 미리 확인할 경우 기본 질의 옵션인 -q와 목록 확인을 위한 -l , 패키지를 대상으로 하는 -p 옵션을 함께 사용하여 -qlp가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* rpm의 기본 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-v : 자세한 정보를 출력한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--quiet : 에러 메시지 외에는 다른 정보를 출력하지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--version : rpm의 버전을 출력한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* rpm의 설치 및 업데이트 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-i : 동일한 패키지가 설치되어 있지 않은 경우 패키지를 새로 설치한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-h : 설치 혹은 업그레이드 진행 상황을 # 문자를 이용해 표시한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-U : 패키지를 업그레이드한다. 기존에 설치된 패키지가 없을 경우 새로 설치한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-F : 이전 버전이 설치되어 있는 경우에만 업그레이드한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--force : 기존에 패키지가 설치되어 있더라도 강제로 설치한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--nodeps : 패키지 설치, 업데이트 및 삭제 시 의존성을 점검하지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--test : 실제 설치하지 않고 잠재적 충돌이 있는지 체크한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* rpm의 제거 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-e : 패키지를 삭제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--nodeps : 패키지 삭제 시 의존성 검사를 하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--test : 실제 삭제하지 않고 모의로 삭제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--allmatches : 패키지의 모든 버전을 제거&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* rpm의 질의 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-q : 질의를 위해 기본적으로 사용해야 하는 옵션으로 패키지 이름, 버전, 릴리즈 등 간단한 정보가 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-i : 패키지 정보, 버전, 설명 등 패키지에 대한 자세한 정보를 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-l : 패키지의 목록을 출력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-f : 지정한 파일을 설치한 패키지 출력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-a : 설치된 모든 패키지에 대해 질의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-c : 패키지의 설정 파일이나 스크립트 파일을 출력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-s : 패키지의 각 파일 상태를 normal, not installed, replaced로 표시&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* rpm의 검증 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-V : 검증 시 사용하는 기본 옵션&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;--test : 실제 삭제하지 않고 모의로 삭제&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# 커널 컴파일 관련 make 명령어&lt;/b&gt;&lt;/u&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;make mrproper : 커널 소스의 설정값을 초기화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;make xconfig : X 윈도우 환경의 Qt 기반 설정 도구를 사용하여 커널 컴파일 옵션을 설정한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;make bzImage : 압축된 커널 이미지를 만든다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;make modules : 커널 환경설정에서 모듈로 설정한 기능들을 컴파일한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;make modules_install : 컴파일된 커널 모듈을 /lib/modules 아래 설치한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;make install : 컴파일한 모듈을 설치한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# proc 디렉토리 관련 정보&lt;/b&gt;&lt;/u&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/cmdline : 부팅 시 커널로드할 때 인자로 넘어온 옵션 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/cpuinfo : CPU 제조사, 모델, 속도, 코어 개수 등 CPU 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/devices : 현재 시스템에 로드된 디바이스 드라이버 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/fb : 프레임 버퍼 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/filesystems : 커널이 지원하는 파일 시스템 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/interrupts : 시스템에서 사용 중인 인터럽트 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/iomem : 메모리맵 I/O 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/ioports : 포트 I/O 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/kallsyms : 커널 심볼 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/loadavg : 1분, 5분, 15분만 시스템의 평균 부하량&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/meminfo : 전체 메모리 크기, 캐시, 활성화, 비활성화, 스왑 등 메모리 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/misc : 기타 장치의 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/mounts : 마운트된 장치의 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/partitions : 파티션 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/stat : 시스템 상태 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/swaps : 스왑 파일 및 파티션의 크기와 사용량 및 우선순위&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/uptime : 시스템 동작 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;/proc/version : 리눅스 커널 정보&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# rsyslog의 action 섹션을 터미널로 보내기 위해서는 '/dev/tty[가상터미널번호]' 로 작성한다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# ssh 명령어&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* ssh를 이용한 원격 접속 시 'ssh [사용자계정]@[원격IP]' 형식을 사용한다. 이때 접속 후 수행할 명령문도 함께 입력할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 주요 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-l : 원격 시스템 로그인에 사용할 계정을 지정한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-p : 원격 호스트 연결에 사용할 포트 번호를 지정한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-v : 자세한 정보를 표시한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# htpasswd, htaccess&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* htpasswd : 'htpasswd [옵션] [계정파일] [사용자명]'을 실행 옵션으로 하여 사용자 계정 파일을 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 주요 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-c : 사용자 계정 파일을 생성&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최초 1번은 -c 옵션으로 계정 파일을 만들어야 한다. 이후 생략할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-D : 지정한 사용자를 사용자 계정 파일에서 제거&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-s : SHA 암호화 방식으로 사용자 계정 파일을 암호화&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 특정 페이지에 사용자 인증을 설정하기 위해 대상 디렉터리의 AllowOverride 설정 항목에 AuthConfig를 지정한다. 또한 대상 디렉터리에 '.htaccess' 파일을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# 삼바 클라이언트&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* smbclient : 'smb [옵션] [호스트명]'의 명령 형식을 따르며, 삼바의 공유 디렉터리 정보를 확인하고, 서버에 접속한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 주요 옵션&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-L : 삼바 서버의 공유 디렉터리 정보를 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-M : 메시지를 전송&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-U [사용자 이름] : 사용자 이름을 지정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-p [TCP 포트] : 서버의 TCP 포트 번호를 지정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 호스트의 공유 폴더 이름은 '//172.30.1.12/[공유폴더]/' ('//' 대신 '\\'를 사용가능) 와 같이 지정할 수 있다. 단 '\' 를 이용할 경우 실제 입력시 '\\\\' 와 같이 '\'를 2개씩 써줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# virtusertable 설정 내용 virtusertable.db에 적용하는 명령어&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;makemap hash /etc/mail/virtusertable &amp;lt; /etc/mail/virtusertable&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# DNS 설정&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* acl(access control list) 구문은 여러 호스트들을 하나의 이름으로 지정하여 options 구문의 allow-query, allow-transfer 등에 사용할 수 있도록 한다. 따라서 options 구문 이전에 설정해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ex) ihd 란 이름을 별칭으로 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;acl &quot;ihd&quot; { 192.168.2.24; 192.168.4/24; };&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* options 구문의 주요 설정 항목&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;directory : zone 파일의 저장 디렉터리를 설정, 반드시 필요&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;dump-file : 정보 갱신 시 저장 파일로 사용할 dump-file의 파일명을 지정&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;statistics-file : 통계 정보를 저장할 파일명을 지정&lt;/span&gt;&lt;/li&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;memstatistics-file : 메모리 통계 정보를 저장할 파일명을 지정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# TCP Wrapper 설정&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* TCP Wrapper 는 /etc/hosts.allow 파일과 /etc/hosts.deny 설정 파일을 이용하여 접근 제어를 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 설정 파일은 .allow -&amp;gt; .deny&amp;nbsp; 순으로 적용된다. 규칙이 중복되면 .deny 규칙은 무시된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 모든 서비스를 지정하기 위해 'ALL:'를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 텔넷 서비스를 지정하기 위해 'in.telnetd'를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* ssh 서비스를 지정하기 위해 'sshd'를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* vsftp 서비스를 지정하기 위해 'vsftpd'를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;# iptables에서 --to의 값은 목적지 주소 뿐만 아니라 포트도 설정해줘야 한다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;iptables -t nat -A PREROUTING -p tcp -d 222.235.10.7 --dport 80 -j DNAT --to 192.168.10.7:80&lt;/span&gt;&lt;/p&gt;</description>
      <category>자격증공부/리눅스마스터</category>
      <author>입코딩</author>
      <guid isPermaLink="true">https://lipcoder.tistory.com/538</guid>
      <comments>https://lipcoder.tistory.com/538#entry538comment</comments>
      <pubDate>Sat, 13 Nov 2021 10:39:52 +0900</pubDate>
    </item>
  </channel>
</rss>