<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>저 높은 곳으로</title>
    <link>https://izagood.tistory.com/</link>
    <description>자굿 개발노트</description>
    <language>ko</language>
    <pubDate>Wed, 27 May 2026 07:49:03 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>자굿</managingEditor>
    <image>
      <title>저 높은 곳으로</title>
      <url>https://tistory1.daumcdn.net/tistory/5127314/attach/ac6b64bec19e402fbd31ff4cb0900071</url>
      <link>https://izagood.tistory.com</link>
    </image>
    <item>
      <title>CKAD - Use Ingress rules to expose applications</title>
      <link>https://izagood.tistory.com/189</link>
      <description>&lt;h1&gt;Ingress&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress는 클러스터 외부에서 클러스터 내부 Service로 HTTP와 HTTPS 경로를 열어준다.&lt;/li&gt;
&lt;li&gt;Ingress resource에 규칙을 정하여 트래픽을 컨트롤할 수 있다(Load Balance).&lt;/li&gt;
&lt;li&gt;Ingress는 외부에서 서비스로 접속이 가능한 URL, 로드 밸런스 트래픽, SSL/TLS 종료, 이름 기반의 가상 호스팅 기능을 구성할 수 있다.&lt;/li&gt;
&lt;li&gt;Ingress Controller는 일반적으로 로드 밸런서(ex. Nginx)를 사용해서 Ingress를 수행할 책임이 있으며, 트래픽을 처리하는데 도움이 되도록 에지 라우터 또는 추가 프런트 엔드를 구성할 수도 있다.&lt;/li&gt;
&lt;li&gt;Ingress는 임의의 포트 또는 프로토콜을 노출시키지 않는다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP와 HTTPS 이외의 서비스를 인터넷에 노출하려면 보통 Service.Type=NodePort 또는 Service.Type=LoadBalancer 유형의 서비스를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ingress 작동 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 요청이 들어오면 Ingress 컨트롤러가 Ingress 규칙에 따라 해당 트래픽을 적절한 서비스로 라우팅하고 서비스는 트래픽을 받아서 클러스터 내의 Pod로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전제조건&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress Controller가 실행되고 있어야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어 Ingress-Nginx Controller가 배포 상태여야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ingress resource&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클러스터 내에서 트래픽을 어떻게 라우팅할지 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress object는 유효한 DNS 서브도메인 이름이여야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DNS 서브도메인 이름 규칙
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;253자를 넘지 말아야 한다.&lt;/li&gt;
&lt;li&gt;소문자와 영숫자 - 또는 . 만 포함한다.&lt;/li&gt;
&lt;li&gt;영숫자로 시작한다.&lt;/li&gt;
&lt;li&gt;영숫자로 끝난다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ingress object는 위 예시에서 &lt;code&gt;minimal-ingress&lt;/code&gt;를 가르킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ingress Controller&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress resource에 정의된 규칙을 실제로 구현하는 소프트웨어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 ingress controller들이 있지만 &lt;a href=&quot;https://kubernetes.github.io/ingress-nginx/deploy/&quot;&gt;ingress-nginx&lt;/a&gt; ingress controller가 가장 많이 사용됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ingress rules&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress 규칙은 외부에서 클러스터 내의 서비스로 트래픽을 어떻게 라우팅할지 정의한다.&lt;/li&gt;
&lt;li&gt;이 규칙들은 Ingress 리소스 내의 &lt;code&gt;spec&lt;/code&gt; 섹션에 지정되며, 주로 HTTP와 HTTPS 트래픽을 대상으로 한다.&lt;/li&gt;
&lt;li&gt;Ingress 규칙을 사용하면 단일 IP 주소를 여러 서비스에 매핑하고, URL 경로, 호스트 이름, 또는 둘 모두를 기반으로 트래픽을 라우팅할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ingress 규칙 구성 요소&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Host&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트가 지정한 HTTP 헤더의 호스트 부분.&lt;/li&gt;
&lt;li&gt;특정 호스트에 대한 요청을 특정 서비스로 라우팅하는 데 사용됨&lt;/li&gt;
&lt;li&gt;호스트를 지정하지 않으면 Ingress 컨트롤러는 모든 호스트에 대한 트래픽을 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Path&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL의 Path(ex. /service1)를 사용하여 트래픽을 특정 서비스로 라우팅할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Backend&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;경로와 호스트 규칙이 일치하는 요청을 처리할 서비스.&lt;/li&gt;
&lt;li&gt;백엔드는 서비스 이름과 서비스 내의 포트를 지정.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ingress 규칙 예시&lt;/h3&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /service1
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80
      - path: /service2
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 80&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;경로 유형&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Exact&lt;/b&gt;: 경로가 정확히 일치해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Prefix&lt;/b&gt;: 지정된 경로로 시작하는 모든 요청이 일치함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ImplementationSpecific&lt;/b&gt;: Ingress 컨트롤러에 따라 경로 매칭 방식이 결정.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가 설정과 어노테이션&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ingress 리소스에 어노테이션을 추가함으로써, Ingress 컨트롤러의 특정 동작을 세부적으로 제어할 수 있다.&lt;/li&gt;
&lt;li&gt;예를 들어, URL 재작성, SSL/TLS 종료, CORS 정책 설정 등이 가능함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Troubleshoot&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;kubectl describe ingress &amp;lt;ingress-name&amp;gt;&lt;/code&gt; 명령어를 사용하여 ingress 설정을 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Reference&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/ingress/&quot;&gt;https://kubernetes.io/docs/concepts/services-networking/ingress/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/&quot;&gt;https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.github.io/ingress-nginx/deploy/&quot;&gt;https://kubernetes.github.io/ingress-nginx/deploy/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/&quot;&gt;https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Tools for IT/- Kubernetes</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/189</guid>
      <comments>https://izagood.tistory.com/189#entry189comment</comments>
      <pubDate>Wed, 10 Apr 2024 23:51:05 +0900</pubDate>
    </item>
    <item>
      <title>CKAD - Provide and troubleshoot access to applications via services</title>
      <link>https://izagood.tistory.com/188</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;서비스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Service는 동일한 기능을 제공하는 Pod 그룹에 대한 안정적인 접근 방식을 제공한다.&lt;/li&gt;
&lt;li&gt;Service는 클라이언트가 Pod 그룹을 네트워크에서 사용할 수 있도록 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서비스 타입&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ClusterIP&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Service에 내부 IP를 할당하여 클러스터 내부에서만 접근할 수 있게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NodePort&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;1216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIQ7Mq/btsGu2wD2zc/CbkzEKc8oNHqKsKy8dq1C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIQ7Mq/btsGu2wD2zc/CbkzEKc8oNHqKsKy8dq1C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIQ7Mq/btsGu2wD2zc/CbkzEKc8oNHqKsKy8dq1C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIQ7Mq%2FbtsGu2wD2zc%2FCbkzEKc8oNHqKsKy8dq1C0%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;1508&quot; height=&quot;1216&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;1216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ClusterIP에 기반하며, 각 Node의 지정된 Port를 통해 외부에서 Service에 접근할 수 있게 한다.&lt;/li&gt;
&lt;li&gt;Ports
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;port&lt;/li&gt;
&lt;li&gt;targetPort&lt;/li&gt;
&lt;li&gt;nodePort&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NodePort 서비스 생성 YAML&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30007&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;LoadBalancer:&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LoadBalancer를 사용해 외부 IP를 Service에 할당한다.&lt;/li&gt;
&lt;li&gt;LoadBalancer 서비스 생성 YAML&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30007&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ExternalName&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스를 특정 ExternalName을 DNS(example.com)에 매핑하여 Service에 접근할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;ExternalName 서비스 생성 YAML&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: example.com&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Troubleshoot 케이스&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 서비스가 동작하지 않을 때&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Selector와 Pod 레이블의 매핑 확인&lt;/li&gt;
&lt;li&gt;Service의 port와 targetPort 확인&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;kubectl get service&lt;/span&gt;&amp;nbsp;를 실행하여 서비스 실행여부 확인&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;kubectl describe service &amp;lt;service-name&amp;gt;&lt;/span&gt;을 실행하여 Servcie 내부 정보 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- NodePort나 LoadBalancer 접근 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;방화벽이나 보안 그룹 설정 확인&lt;/li&gt;
&lt;li&gt;지정한 port로 트래픽이 허용되는지 확인&lt;/li&gt;
&lt;li&gt;LoadBalancer 구성 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&quot;mttContainer&quot; class=&quot;notranslate&quot; style=&quot;transform: translate(766px, 2831px);&quot; aria-expanded=&quot;false&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Tools for IT/- Kubernetes</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/188</guid>
      <comments>https://izagood.tistory.com/188#entry188comment</comments>
      <pubDate>Tue, 19 Mar 2024 22:03:13 +0900</pubDate>
    </item>
    <item>
      <title>CKAD - Application Deployment</title>
      <link>https://izagood.tistory.com/187</link>
      <description>&lt;h1&gt;Understand Deployments and how to perform rolling updates&lt;/h1&gt;
&lt;h1&gt;Use Kubernetes primitives to implement common deployment strategies (e.g. blue/green or canary)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Deployment&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Create&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl create -f &amp;lt;deployment_yml_file&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Get&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;kubectl get deployments&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Describe&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl describe deployment &amp;lt;deployment_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Update&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Apply file&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl apply -f &amp;lt;deployment_yaml_file&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&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;Set image&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl set image deployment/&amp;lt;deployment_name&amp;gt; &amp;lt;container_name&amp;gt;=&amp;lt;image_detail&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Status&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Status&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl rollout status deployment/&amp;lt;deployment_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;History&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl rollout history deployment/&amp;lt;deployment_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;code style=&quot;letter-spacing: 0px;&quot;&gt;kubectl history&lt;/code&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;에서 &lt;/span&gt;&lt;code style=&quot;letter-spacing: 0px;&quot;&gt;CHANGE-CAUSE&lt;/code&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;는 &amp;lt;none&amp;gt;으로 되어 있고 &lt;/span&gt;&lt;code style=&quot;letter-spacing: 0px;&quot;&gt;CHANGE-CAUSE&lt;/code&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;에 기록하길 원한다면 아래와 같이 deployment를 생성할 때&lt;/span&gt;&lt;code style=&quot;letter-spacing: 0px;&quot;&gt;--record&lt;/code&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;를 설정해줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl create -f &amp;lt;deployment_yml_file&amp;gt; --record&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Delete&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl delete deployment &amp;lt;deployment_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Rollback&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 상태의 배포의 오류가 발생했을때 이전 배포 상태로 돌리는 기능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl rollout undo deployment/&amp;lt;deployment_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배포 전략&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Recreate&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 pod를 한 번에 down 시키고 새로운 것을 한 번에 up 하는 단순한 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Rolling Update&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 pod로 하나씩 교체(기본 배포 전략)&lt;/li&gt;
&lt;li&gt;RollingUpdateStrategy: 25% max unavailable, 25% max surge
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;maxSurge: 업데이트 중 desired Pod 개수 중 생성될 수 있는 Pod 비율
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;e.g. desired Pod: 4개, maxSurge: 25% -&amp;gt; 새로 생성될 수 있는 Pod: 1개&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;maxUnavailable: 업데이트 중 unavailable Pod로 만들 수 있는 Pod 비율
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;e.g. desired Pod: 4개, maxUnavailable: 25% -&amp;gt; 정지시킬 수 있는 Pod: 1개&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Blue Green&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Blue와 Green 모두 배포한 상태에서 배포된 Green의 테스트가 완료되면 트래픽을 한 번에 100% 전환하는 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;Blue: 기존 버전&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;Green: 신규 버전&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;Deployment 배포 전략으로 선택할 수는 없고 Deployment와 Service로 구현해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Blue Green 구현&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;구현 순서
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;Deployment - blue 배포 &amp;lt;- Service가 blue Deployment의 selector 설정&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;Deployment - green 배포&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;green 테스트 및 완료&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;Service 라벨 선택기 green으로 Update&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;myapp-blue.yml (Deployment yaml file)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710776366827&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-blue
  labels:
    app: myapp
    type: front-end
spec:
  template:
    metadata:
      name: myapp-pod
      labels:
        version: v1
    spec:
      containers:
      - name: app-container
        image: myapp-image:1.0
replicas: 5
selector:
  matchLabels:
    version: v1&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;my-service.yml (Service yaml file)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710776494019&quot; class=&quot;routeros&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    version: v1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;기존의 배포(blue) 상태는 위와 같음.&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;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;아래과 같이 변경한 green 배포&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;myapp-green.yml (Deployment yaml file)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710777432206&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-green
  labels:
    app: myapp
    type: front-end
spec:
  template:
    metadata:
      name: myapp-pod
      labels:
        version: v2
    spec:
      containers:
      - name: app-container
        image: myapp-image:2.0
replicas: 5
selector:
  matchLabels:
    version: v2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Green 테스트 완료 후 service selector update&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&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;my-service.yml (Service yaml file)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710777547330&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    version: v2&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Canary&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Canary 배포 방식
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기존 배포 Pod들 배포된 상태&lt;/li&gt;
&lt;li&gt;몇 개의 Test 용 새로운 버전의 Pod 배포&lt;/li&gt;
&lt;li&gt;적은 양의 트래픽만 새로운 버전으로 경로를 지정&lt;/li&gt;
&lt;li&gt;새로운 버전으로 들어온 트래픽이 정상적으로 동작하는 것이 테스트 완료&lt;/li&gt;
&lt;li&gt;기존 배포들을 새로운 버전으로 Update&lt;/li&gt;
&lt;li&gt;Test 용 새로운 버전의 Pod 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;Blue/Green 배포 전략과 마찬가지로 Deployment 배포 전략으로 선택할 수는 없고 Deployment와 Service로 구현해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Canary 구현&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현 순서
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기존 primary 배포가 존재하는 상태 &amp;lt;- Service가 front-end를 selector로 선택&lt;/li&gt;
&lt;li&gt;canary를 최소 replica(1)로 설정하여 배포
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이때 canary의 image와 version은 Update&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Service는 label을 선택하여 트래픽을 분산하기 때문에 primary(5)와 canary(1)로 트래픽이 분산됨&lt;/li&gt;
&lt;li&gt;canary가 정상적으로 동작하는 것이 테스트 완료&lt;/li&gt;
&lt;li&gt;primary의 image와 version을 Update&lt;/li&gt;
&lt;li&gt;canary 배포 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;myapp-primary.yml (Deployment yaml file)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710778872278&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-primary
  labels:
    app: myapp
    type: front-end
spec:
  template:
    metadata:
      name: myapp-pod
      labels:
        version: v1
        app: front-end
    spec:
      containers:
      - name: app-container
        image: myapp-image:1.0
replicas: 5
selector:
  matchLabels:
    version: front-end&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;my-service.yml (Service yaml file)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710778995295&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    version: front-end&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;mttContainer&quot; class=&quot;notranslate&quot; style=&quot;transform: translate(566px, 1401px);&quot; aria-expanded=&quot;false&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 배포된 상태에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;canary 배포&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;myapp-canary.yml (Deployment yaml file)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710779050121&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-canary
  labels:
    app: myapp
    type: front-end
spec:
  template:
    metadata:
      name: myapp-pod
      labels:
        version: v2
        app: front-end
    spec:
      containers:
      - name: app-container
        image: myapp-image:2.0
replicas: 1
selector:
  matchLabels:
    version: front-end&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Tools for IT/- Kubernetes</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/187</guid>
      <comments>https://izagood.tistory.com/187#entry187comment</comments>
      <pubDate>Mon, 11 Mar 2024 17:59:13 +0900</pubDate>
    </item>
    <item>
      <title>오브젝트 - 계약에 의한 설계</title>
      <link>https://izagood.tistory.com/186</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;6장에서 설명한 메시지와 인터페이스 원칙에 따라 의도를 드러내도록 인터페이스를 다듬고 명령과 쿼리를 분리했다고 하더라도 명령으로 인해 발생하는 부수 효과를 명확하게 표현하는 데는 한계가 있다&lt;/li&gt;
&lt;li&gt;여기서 말하고 싶은 것은 인터페이스만으로는 객체의 행동에 관한 다양한 관점을 전달하기 어렵다는 것이다&lt;/li&gt;
&lt;li&gt;우리에게 필요한 것은 명령에 부수 효과를 쉽고 명확하게 표현 할 수 있는 커뮤니케이션 수단이다. 이럴 때 필요한 것이 계약에 의한 설계이다&lt;/li&gt;
&lt;li&gt;계약에 의한 설계를 사용하면 협력에 필요한 다양한 제약과 부수 효과를 명시적으로 정의하고 문서와 할 수 있다&lt;/li&gt;
&lt;li&gt;클라이언트 개발자는 오퍼레이션의 구현을 살펴 보지 않더라도 객체 사용 법을 쉽게 이해할 수 있다&lt;/li&gt;
&lt;li&gt;계약은 실행 가능하기 때문에 구현 의 동기화돼 있는지 여부를 런타임에 검증할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;01 협력과 계약&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;부수효과를 명시적으로&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향 핵심은 협력 안에서 객체들이 수행하는 행동이다&lt;/li&gt;
&lt;li&gt;인터페이스는 개체가 수신 할 수 있는 메시지는 정의할 수 있지만 객체 사이에 의사소통 방식은 명확하게 정리할 수 없다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;계약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계약에 세부적인 내용은 상황에 따라 다르겠지만 일반적으로 다음과 같은 특성을 가진다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 계약 당사자는 계약으로부터 이익을 기대하고 이익을 위해 의무를 이행한다&lt;/li&gt;
&lt;li&gt;각 계약 당사자의 이과 의무는 계약서에 문서화된다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;여기서 눈여겨볼 부분은 한쪽에 음모가 반대쪽에 권리가 된다는 것이다&lt;br /&gt;&lt;a href=&quot;https://wiki.python.org/moin/PythonDecoratorLibrary#Pre-.2FPost-Conditions&quot;&gt;https://wiki.python.org/moin/PythonDecoratorLibrary#Pre-.2FPost-Conditions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;02 계약에 의한 설계(Design By Contract, DBC)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버트란드 마이어는 Eiffel 언어를 만들면서 사람들 사이의 계약의 차단 한 계약에 의한 설계 기법을 고안했다.&lt;/li&gt;
&lt;li&gt;계약에 의한 설계 개념은 &quot;인터페이스에 대해 프로그램 밍 하라&quot;는 원칙을 확장하는 것이다&lt;/li&gt;
&lt;li&gt;계약에 의한 설계를 이용하면 오퍼레이션의 시그니처를 구성하는 다양한 요소들을 이용해 협력에 참여하는 객체들이 지켜야 하는 제약 조건을 명시할 수 있다&lt;/li&gt;
&lt;li&gt;계약에 의한 설계를 구성하는 3가지 요소는 사전 조건, 사후 조건, 불변식이라고 부른다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사전 조건(precondition): 메서드가 호출되기 위해 만족돼야 하는 조건. 사전 조건이 만족되지 않을 경우 메서드가 실행돼서는 안 된다. 사전 조건을 만족시키는 것은 클라이언트의 의무다.&lt;/li&gt;
&lt;li&gt;사후 조건(postcondition): 메소드가 실행된 후에 클라이언트에게 보장해야 하는 조건. 사전 조건을 만족시켰는데도 사후 조건을 만족시키지 못한 경우에는 클라이언트에게 예외를 던져야 한다. 사후 조건을 만족시키는 것은 서버의 의무이다.&lt;/li&gt;
&lt;li&gt;불변식(invariant): 항상 참이라고 보장되는 서버의 조건. 메서드가 실행되는 도중에 에는 불변 식을 만족시키지 못할 수 있지만 메서드를 실행하기 전이나 종료된 후에는 불변 식은 항상 참이어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사전조건&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사전 조건이란 메소드가 정상적으로 실행되기 위해 만족해야 하는 조건이다.&lt;/li&gt;
&lt;li&gt;사전 조건은 메서드의 전달 된 인자의 정합성을 체크하기 위해 사용된다.&lt;/li&gt;
&lt;li&gt;클라이언트가 사전 조건을 만족시키지 못할 경우 최대한 빨리 실패해서 클라이언트에게 버그가 있다는 사실을 알린다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사후조건&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사후 조건은 메서드 실행 결과가 올바른지 검사하고 실행 후의 객체가 유효한 상태로 남아 있는지를 검증한다.&lt;/li&gt;
&lt;li&gt;일반적으로 사후조건은 다음과 같은 3가지 용도로 사용된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인스턴스 변수의 상태가 올바른지를 서술&lt;/li&gt;
&lt;li&gt;메서드의 전달 된 파라미터 값이 올바르게 변경했는지를 서술&lt;/li&gt;
&lt;li&gt;변환 값이 올바른지를 서술&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다음과 같은 2가지 이유로 사전조건보다 사후 조건을 정리하는 것이 어려울 수 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 메서드 안에서 return 문이 여러 번 나올 경우&lt;/li&gt;
&lt;li&gt;실행 전과 실행의 값을 비교해야 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;불변식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사전조건과 사후조건은 각 메서드마다 달라지는데 반에 불변식은 인스턴스 생명 주기 전반에 걸쳐 지켜야 하는 규칙을 명세한다&lt;/li&gt;
&lt;li&gt;일반적으로 불변식은 객체의 내부 상태와 관련이 있다&lt;/li&gt;
&lt;li&gt;불변식은 다음과 같은 2가지 특성을 가진다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불변식은 클래스의 모든 인스턴스가 생성된 후에 만족돼야 한다 이것은 클래스의 정의된 모든 생성자는 불변식을 준수해야 한다는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;불변식은 클라이언트의 의해 호출 가능한 모든 메서드의 준수돼야 한다 메서드가 실행되는 중에는 객체의 상태가 불안정한 상태로 빠질 수 있기 때문에 불변 식을 만족 할 필요는 없지만 메서드 실행 전과 메서드 종료 후에는 항상 불변 식을 만족하는 상태가 유지돼야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;불변식은 클래스의 모든 메서드의 사전조건과 사후 조건에 추가되는 공통의 조건으로 생각할 수 있다&lt;/li&gt;
&lt;li&gt;불변식은 메서드가 실행 되기 전에 사전조건과 함께 실행되며 메서드가 실행되는 사후조건과 함께 실행된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 불변식을 수작업으로 작성한다면 모든 메서드의 동일한 불변식을 추가해야 할 것이다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;불변식은 생성자 실행 후, 메서드 실행 전, 메소드 실행 후에 호출돼야 한다는 점을 기억하라. &lt;br /&gt;만약 직접 불변식을 코딩하고 관리 해야 한다면 모든 생성자의 마지막 위치와 메서드 시작 지점, 메서드 종료 지점에 불변식을 호출하도록 일일이 코드를 작성해야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;03 계약에 의한 설계와 서브타이핑&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계약에 의한 설계는 클라이언트가 만족시켜야 하는 사전조건과 클라이언트의 관점에서 서버가 만족시켜야 하는 사후조건을 기술한다&lt;/li&gt;
&lt;li&gt;계약의 의한 설계와 리스코프 치환 원칙이 만나는 지점이 바로 이것이다&lt;/li&gt;
&lt;li&gt;리스코프 치환 원칙은 슈퍼타입의 인스턴스와 협력하는 클라이언트의 관점에서 서브타입의 인스턴스가 슈퍼타입을 대체하더라도 협력에 지장이 없어야 한다는 것을 의미한다. 따라서 다음과 같이 정리할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브타입이 리스코프 치환 원칙을 만족시키기 위해서는 클라이언트와 슈퍼타입 간에 체결된 계약을 준수해야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리스코프 치환 원칙의 규칙을 2가지 종류로 세분화할 수 있다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 규칙은 협력에 참여하는 객체에 대한 기대를 표현하는 &lt;b&gt;계약 규칙&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;두 번째 규칙은 교체 가능한 타입과 관련된 &lt;b&gt;가변성 규칙&lt;/b&gt;이다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계약 규칙(contract rules)&lt;/b&gt;은 슈퍼타입과 서브타입 사이의 사전조건, 사후조건, 불변식에 대해 서술할 수 있는 제약에 관한 규칙이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브타입에 더 강력한 사전조건을 정의할 수 없다&lt;/li&gt;
&lt;li&gt;서브타입에 더 완화된 사후조건을 정의할 수 없다&lt;/li&gt;
&lt;li&gt;슈퍼타입의 불변식은 서브타입에서도 반드시 유지돼야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가변성 규칙(variance rules)&lt;/b&gt;은 파라미터와 리턴 타입의 변형과 관련된 규칙이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브타입의 메서드 파라미터는 반공변성을 가져야 한다&lt;/li&gt;
&lt;li&gt;서브타입의 리턴 타입은 공변성을 가져야 한다&lt;/li&gt;
&lt;li&gt;서브타입은 슈퍼타입이 발생시키는 예외와 다른 타입의 예외를 발생시켜서는 안 된다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;대부분 객체지향 언어에서 공변성과 반공연성이 중요해지는 곳은 상속이 제네릭 프로그래밍과 만나는 지점이다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/186</guid>
      <comments>https://izagood.tistory.com/186#entry186comment</comments>
      <pubDate>Wed, 24 Jan 2024 21:08:26 +0900</pubDate>
    </item>
    <item>
      <title>오브젝트 - Chapter 15 디자인 패턴과 프레임워크</title>
      <link>https://izagood.tistory.com/185</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디자인 패턴: 소프트웨어 설계에서 반복적으로 발생하는 문제에 대해 반복적으로 적용할 수 있는 설계의 묶음이다.&lt;/li&gt;
&lt;li&gt;프레임워크: 설계와 코드를 함께 재사용하기 위한 것
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레임워크는 애플리케이션의 아키텍처를 구현 코드의 형태로 제공한다.&lt;/li&gt;
&lt;li&gt;프레임워크가 제공하는 아키텍처가 요구사항에 적합하다면 견고한 구현 코드를 쉽고 빠르게 재사용할 수 있다.&lt;/li&gt;
&lt;li&gt;프레임워크는 각 애플리케이션 요구에 따라 적절하게 커스터마이징 할 수 있는 확장 포인트를 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디자인 패턴과 프레임워크 모두 일관성 있는 협력과 관련이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디자인 패턴은 특정한 변경을 일관성 있게 다룰 수 있는 &lt;b&gt;협력 템플릿&lt;/b&gt;을 제공한다.&lt;/li&gt;
&lt;li&gt;프레임워크는 특정한 변경을 일관성 있게 다룰 수 있는 확장 가능한 &lt;b&gt;코드 템플릿&lt;/b&gt;을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;01 디자인 패턴과 설계 재사용&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;소프트웨어 패턴&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패턴이란 무엇인가?를 논의할 때면 반복적으로 언급되는 몇 가지 핵심적인 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패턴은 반복적으로 발생하는 &lt;b&gt;문제와 해법의 쌍&lt;/b&gt;으로 정의된다.&lt;/li&gt;
&lt;li&gt;패턴을 사용함으로써 이미 알려진 문제와 이에 대한 해법을 문서로 정리할 수 있으며, 이 지식을 다른 사람과 의사소통할 수 있다.&lt;/li&gt;
&lt;li&gt;패턴은 추상적인 원칙과 실제 코드 작성 사이의 간극을 메워주며 실질적인 코드 작성을 돕는다.&lt;/li&gt;
&lt;li&gt;패턴의 요점은 패턴이 실무에서 탄생했다는 점이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;패턴은 한 컨텍스트에서 유용한 동시에 다른 컨텍스트에서도 유용한 '아이디어'이다.&lt;/li&gt;
&lt;li&gt;패턴이 지닌 가장 큰 가치는 경험을 통해 축적된 실무 지식을 효과적으로 요약하고 전달할 수 있다는 점이다&lt;/li&gt;
&lt;li&gt;패턴의 '이름'은 커뮤니티가 공유할 수 있는 중요한 어휘집을 제공한다. 패턴에 이름은 높은 수준의 대화를 가능하게 하는 원천이다&lt;/li&gt;
&lt;li&gt;크리스토퍼 알렉산더는 &quot;연관된 패턴들의 집합들이 모여 하나의 패턴 언어(Pattern Language)를 구성한다. &quot;고 정의하고 있다.&lt;/li&gt;
&lt;li&gt;패턴 언어는 연관된 패턴 카테고리뿐만 아니라 패턴의 생성 규칙과 함께 패턴 언어에 속한 다른 패턴 과의 관계 및 협력 규칙을 포함한다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패턴 분류&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패턴의 분류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아키텍처 패턴(Architecture Pattern)&lt;/li&gt;
&lt;li&gt;분석 패턴(Analysis Pattern)&lt;/li&gt;
&lt;li&gt;디자인 패턴(Design Pattern)&lt;/li&gt;
&lt;li&gt;이디엄(Idiom)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디자인 패턴은 특정 정황 내에서 일반적인 설계 문제를 해결하며, 협력하는 컴포넌트들 사이에서 반복적으로 발생하는 구조를 서술한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디자인 패턴&lt;/b&gt;은 중간 규모의 패턴으로 특정한 설계 문제를 해결하는 것을 목적으로 하며 프로그래밍 언어나 프로그래밍 패러다임의 독립적이다&lt;/li&gt;
&lt;li&gt;디자인 패턴의 상웨에는 소프트웨어의 전체적인 구조를 결정하기 위해 사용할 수 있는 &lt;b&gt;아키텍처 패턴&lt;/b&gt;이 있다. (프로그래밍 언어나 프로그래밍 패러다임의 독립적이다)&lt;/li&gt;
&lt;li&gt;디자인 패턴의 하위에는&lt;b&gt; 이디엄&lt;/b&gt;이 위치한다. 이디엄은 특정 프로그램밍 언어에만 국한된 하위 레벨 패턴이다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분석패턴&lt;/b&gt;은 도메인 내에서 업무 모델링 시에 발견되는 공통적인 구조를 표현하는 개념들의 집합이다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패턴과 책임-주도 설계&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향 설계에서 가장 중요한 일은 올바른 책임을 올바른 객체에게 할당하고 객체 간의 유연한 협력 관계를 구축하는 일이다.&lt;/li&gt;
&lt;li&gt;책임과 협력의 윤곽은 캡슐화, 크기, 의존성, 유연성, 성능, 확장 가능성, 재사용성 등의 다양한 요소들의 트레이드오프를 통해 결정된다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패턴은&lt;/b&gt; 공통으로 사용할 수 있는 &lt;b&gt;역할, 책임, 협력의 템플릿&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;특정한 상황에 적용 가능한 패턴을 잘 알고 있다면 책임 주도 설계의 절차를 하나하나 따르지 않고도 시스템 안에 구현할 개체들의 역할과 책임, 협력, 관계를 빠르고 손쉽게 구성할 수 있다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패턴의 구성 요소는&lt;/b&gt; 클래스가 아니라 '&lt;b&gt;역할&lt;/b&gt;'이다.&lt;/li&gt;
&lt;li&gt;어떤 구현 코드가 어떤 디자인 패턴을 따른다고 이야기할 때는 역할 책임 협력에 관점에서 유사성을 공유한다는 것이지 특정한 구현 방식을 강제한다는 것이 아니라는 점을 이해하는 것 역시 중요하다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캡슐화와 디자인 패턴&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 디자인 패턴의 목적은 &lt;b&gt;특정한 변경을 캡슐화함&lt;/b&gt;으로써 유연하고 일관성 있는 협력을 설계할 수 있는 경험을 공유하는 것이다.&lt;/li&gt;
&lt;li&gt;디자인 패턴에서 중요한 것은 디자인 패턴의 구현 방법이나 구조가 아니다.&lt;/li&gt;
&lt;li&gt;어떤 디자인 패턴이 어떤 변경을 캡슐화 하는지를 이해하는 것이 중요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패턴은 출발점이다&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패턴은 출발점이지 목적지가 아니다.&lt;/li&gt;
&lt;li&gt;패턴이 설계의 목표가 돼서는 안 된다.&lt;/li&gt;
&lt;li&gt;디자인 패턴이 현재의 요구사항이나 적용 기술, 프레임워크에 적합하지 않다면 패턴을 그대로 따르지 말고 목적에 맞게 패턴을 수정하라.&lt;/li&gt;
&lt;li&gt;패턴을 사용하면서 부딪히게 되는 대부분의 문제는 패턴을 맹목적으로 사용할 때 발생한다.&lt;/li&gt;
&lt;li&gt;해결하려는 문제가 아니라 패턴이 제시하는 구조를 맹목적으로 따르는 것은 불필요하게 복잡하고 난해하며 유지 보수 하기 어려운 시스템을 낳는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패턴은 복잡성의 가치가 단순성을 넘어설 때만 정당화돼야 한다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;패턴을 적용할 때는 항상 설계를 좀 더 단순하고 명확하게 만들 수 있는 방법이 없는지 고민해야 한다.&lt;br /&gt;또한 코드를 공유하는 모든 사람들이 적용된 패턴을 알고 있어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;02 프레임워크와 코드 재사용&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드 재사용 대 설계 재사용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디자인 패턴은 프로그래밍 언어에 독립적으로 재사용 가능한 설계 아이디어를 제공하는 것을 목적으로 한다.&lt;br /&gt;따라서 언어에 종속적인 구현 코드를 정의하지 않기 때문에 디자인 패턴을 적용하기 위해서는 설계 아이디어를 프로그래밍 언어의 특성에 맞춰 가공해야 하고 매번 구현 코드를 재작성해야 한다는 단점이 있다.&lt;/li&gt;
&lt;li&gt;재사용 관점에서 설계 재사용보다 더 좋은 방법은 코드 재사용이다.&lt;/li&gt;
&lt;li&gt;가장 이상적인 형태의 재사용 방법은 설계 재사용과 코드 재사용을 적절한 수준으로 조합하는 것이다.&lt;/li&gt;
&lt;li&gt;&quot;설계를 재사용하면서도 유사한 코드를 반복적으로 구현하는 문제를 피할 수 있는 방법은 없을까?&quot; 이 질문에 대한 객체지향 커뮤니티의 대답이 바로 &lt;b&gt;프레임워크&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프레임워크&lt;/b&gt;란&lt;br /&gt;'추상 클래스나 인터페이스를 정의하고 인스턴스 사이의 상호작용을 통해 시스템 전체 혹은 일부를 구현해 놓은 재사용 가능한 설계' &lt;br /&gt;또는 '애플리케이션 개발자가 현재의 요구사항에 맞게 커스터마이징 할 수 있는 애플리케이션의 골격(skeleton)'을 의미한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 정의가 프레임워크의 구조적인 측면에 초점을 맞추고 있다면&lt;/li&gt;
&lt;li&gt;두 번째 정의는 코드와 설계의 재사용이라는 프레임워크의 사용 목적에 초점을 맞춘다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프레임워크는 코드를 재사용함으로써 설계 아이디어를 재사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상위 정책과 하위 정책으로 패키지 분리 하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프레임워크의 핵심은 추상 클래스나 인터페이스와 같은 추상화라고 할 수 있다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;추상클래스와 인터페이스가 일관성 있는 협력을 만드는 핵심 재료라는 것을 기억하라&lt;/li&gt;
&lt;li&gt;협력을 일관성 있고 유연하게 만들기 위해서는 &lt;b&gt;추상화를 이용해 변경을 캡슐화&lt;/b&gt;해야 한다&lt;br /&gt;그리고 협력을 구현하는 코드 안에 의존성은 가급적이면 추상 클래스나 인터페이스와 같은 추상화를 향하도록 작성해야 한다&lt;/li&gt;
&lt;li&gt;객체지향 이전에 구조적인 설계와 같은 전통적인 소프트웨어 개발방법의 경우 상위 레벨 모듈이 하위 레벨 모듈에, 그리고 상위 정책이 구체적인 세부사항에 의존하도록 소프트웨어를 구성한다&lt;br /&gt;하지만 상위 정책은 상대적으로 변경에 안정적이지만 세부 사항은 자주 변경 된다.&lt;/li&gt;
&lt;li&gt;만약 변하지 않는 상위 정책이 자주 변하는 세부사항의 의존 한다면 변경에 대한 파급효과로 인해 상위 정책이 불안정해질 것이다.&lt;/li&gt;
&lt;li&gt;그리고 상위 정책이 세부사항에 비해 재사용될 가능성이 높다&lt;/li&gt;
&lt;li&gt;요점은 상위 정책이 세부사항 보다 더 다양한 상황에서 재사용될 수 있어야 한다는 것이다.&lt;/li&gt;
&lt;li&gt;이 문제를 해결할 수 있는 가장 좋은 방법은 의존성 역전 원칙에 맞게 상위 정책과 세부사항 모두 추상화 의존하게 만드는 것이다&lt;/li&gt;
&lt;li&gt;의존성 역전 원칙의 관점에서 세부 사항은 '변경'을 의미한다&lt;/li&gt;
&lt;li&gt;이를 위한 첫걸음은 변하는 부분과 변하지 않는 부분을 별도의 패키지로 분리하는 것이다&lt;/li&gt;
&lt;li&gt;의존성 역전 원칙에 따라 추상화에만 의존하도록 의존성의 방향을 조정하고 추상화를 경계로 패키지를 분리했기 때문에 세부사항을 구현한 패키지는 항상 상위의 정책을&amp;nbsp; 구현한 패키지 의존 해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제어 역전 원리(Inversion Of Control, IoC)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상위 정책을 재사용한다는 것은 결국 도메인의 존재하는 핵심개념들 사이에 협력 관계를 재사용한다는 것을 의미한다&lt;/li&gt;
&lt;li&gt;객체지향 설계의 재사용성은 개별 클래스가 아니라 객체들 사이에 공통적인 협력 흐름으로부터 나온다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의존성 역전 원리는 전통적인 설계방법과 객체지향을 구분하는 가장 핵심적인 원리이다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;의존성 역전 원칙에 따라 구축되지 않은 시스템은 협력 흐름을 재사용할 수 없으며 변경에 유연하게 대처할 수도 없다.&lt;/li&gt;
&lt;li&gt;로버트 마틴은 &quot;훌륭한 객체지향 설계는 의존성이 역전된 설계&quot;라는 점을 강조한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의존성 역전 원리는 프레임워크의 가장 기본적인 설계 메커니즘이다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;의존성 역전은 의존성의 방향뿐만 아니라 &lt;b&gt;제어 흐름에 주체 역시 역전&lt;/b&gt;시킨다. 따라서 프레임워크를 사용할 경우 개별 애플리케이션에서 프레임워크로 제어흐름의 주체가 이동한다. 이를 &lt;b&gt;제어 역전 원리&lt;/b&gt;라고 한다&lt;/li&gt;
&lt;li&gt;프레임워크에서는 일반적인 해결책만 제공하고 애플리케이션에 따라 달라질 수 있는 특정한 동작은 비워 둔다 그리고 이렇게 완성되지 않은 채로 남겨진 동작을 훅(hook)이라고 부른다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/185</guid>
      <comments>https://izagood.tistory.com/185#entry185comment</comments>
      <pubDate>Wed, 24 Jan 2024 21:07:03 +0900</pubDate>
    </item>
    <item>
      <title>오브젝트 - Chapter 10 상속과 코드 재사용</title>
      <link>https://izagood.tistory.com/183</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향 프로그래밍의 장점 중 하나는 코드를 재사용하기 용이하다는 것이다.&lt;/li&gt;
&lt;li&gt;전통적인 패러다임에서 코드의 재사용은 코드를 복사 후 수정하는 것이다.&lt;/li&gt;
&lt;li&gt;객체지향에서 코드는 일반적으로 클래스 안에 작성되기 때문에&lt;br /&gt;객체지향에서 클래스를 재사용하기 위한 전통적인 방법은 새로운 클래스를 추가하는 것이다.&lt;/li&gt;
&lt;li&gt;이번 장에서는 클래스를 재사용하기 위해 새로운 클래스를 추가하는 가장 대표적인 기법인 &lt;b&gt;상속&lt;/b&gt;에 대해서 살펴본다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상속&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;재사용 관점에서 상속이란 클래스 안에 정의된 인스턴스 변수와 메서드를 자동으로 새로운 클래스에 추가하는 구현 기법이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;합성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 클래스의 인스턴스 안에 기존 클래스의 인스턴스를 포함시키는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 재사용하려는 강력한 동기 이면에는 중복된 코드를 제거하려는 욕망이 숨어 있다.&lt;br /&gt;중복 코드가 초래하는 문제점을 먼저 보고 가자.&lt;/p&gt;
&lt;h1&gt;01 상속과 중복 코드&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DRY 원칙&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;중복 코드는 변경을 방해한다&lt;/b&gt;. 이것은 중복 코드를 제거해야 하는 가장 큰 이유이다.&lt;/li&gt;
&lt;li&gt;프로그램의 본질은 비즈니스와 관련된 지식을 코드로 변환하는 것이다.&lt;/li&gt;
&lt;li&gt;지식은 항상 변하고 지식을 표현하는 코드도 항상 변경해야 한다.&lt;/li&gt;
&lt;li&gt;중복 코드가 가지는 가장 큰 문제는 코드를 수정하는데 필요한 노력을 몇 배로 증가시키는 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중복의 판단 기준은 변경&lt;/b&gt;이다. 요구사항이 변경되었을 때 두 코드를 함께 수정해야 한다면 이 코드는 중복이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;D&lt;/b&gt;on't &lt;b&gt;R&lt;/b&gt;epeat &lt;b&gt;Y&lt;/b&gt;ourself 원칙을 지키자&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;중복과 변경&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시 코드에서 중복된 코드를 작성하고 변경 시 중복된 코드를 모두 수정해야 됨을 보여주고 있다.&lt;/li&gt;
&lt;li&gt;중복된 코드에 변경된 내용을 모두 반영하지 못 하면 변경이 모두 반영되지 못하는 결과를 초래할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;타입 코드 사용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 클래스를 하나로 합치고 각각 타입 코드를 부여하고 각 타입 코드에 따라 분기시켜 두 클래스를 합칠 수 있다.&lt;/li&gt;
&lt;li&gt;객체지향 프로그래밍 언어는 타입 코드를 사용하지 않고도 중복 코드를 관리할 수 있는 효과적인 방법을 제공한다.&lt;br /&gt;&lt;b&gt;상속&lt;/b&gt;이 바로 그것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상속을 이용해서 중복 코드 제거하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상속의 기본 아이디어는 이미 존재하는 클래스와 유사한 클래스가 필요하다면 코드를 복사하지 말고 상속을 이용해 코드를 재사용하라는 것이다.&lt;/li&gt;
&lt;li&gt;예시 코드를 통해서 보여주고 있는 것은&lt;br /&gt;상속을 이용해 코드를 재사용하기 위해서는 부모 클래스의 개발자가 세웠던 가정이나 추론 과정을 정확하게 이해해야 한다.&lt;/li&gt;
&lt;li&gt;이것은 자식 클래스의 작성자가 부모 클래스의 구현 방법에 대해 정확한 지식을 가져야 한다는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;따라서 상속은 결합도를 높인다.&lt;/li&gt;
&lt;li&gt;상속이 초래하는 부모 클래스와 자식 클래스 사이의 강한 결합으로 인해 코드의 수정을 어렵게 만든다.&lt;/li&gt;
&lt;li&gt;중복 코드를 제거하기 위해 상속을 사용하였는데 새로운 로직을 추가하기 위해서는 부모, 자식 클래스 모두를 수정해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속을 위한 경고 1&lt;br /&gt;자식 클래스의 메서드 안에서 super 참조를 이용해 부모 클래스의 메서드를 직접 호출할 경우 두 클래스는 강하게 결합된다.&lt;br /&gt;super 호출을 제거할 수 있는 방법을 찾아 결합도를 제거하라.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상속 관계로 연결된 자식 클래스가 부모 클래스의 변경에 취약해지는 현상을 &lt;b&gt;취약한 기반 클래스 문제&lt;/b&gt;라고 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;02 취약한 기반 클래스 문제(Fragile Base Class Problem, Brittle Base Class Problem)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 클래스의 작은 변경에도 자식 클래스는 컴파일 오류와 실행 에러라는 고통에 시달린다.&lt;/li&gt;
&lt;li&gt;이 문제는 상속을 사용한다면 피할 수 없는 객체지향 프로그래밍의 근본적인 취약성이다.&lt;/li&gt;
&lt;li&gt;상속 관계를 추가할수록 전체 시스템의 결합도가 높아진다는 사실을 알고 있어야 한다.&lt;/li&gt;
&lt;li&gt;취약한 기반 클래스 문제는 캡슐화를 약화시키고 결합도를 높인다.&lt;/li&gt;
&lt;li&gt;캡슐화는 변경에 의한 파급효과를 제어할 수 있기 때문에 가치가 있다.&lt;/li&gt;
&lt;li&gt;객체지향의 기반은 캡슐화를 통한 변경의 통제이다.&lt;/li&gt;
&lt;li&gt;상속은 코드의 재사용을 위해 캡슐화의 장점을 희석시키고 구현에 대한 결합도를 높임으로써 객체지향이 가진 강력함을 반감시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;불필요한 인터페이스 상속 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;java.util.Properties&lt;/code&gt;와 &lt;code&gt;java.util.Stack&lt;/code&gt; 예시를 통해 부모 클래스에 public 인터페이스를 불필요하게 상속받아 발생하는 문제점을 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속을 위한 경고 2&lt;br /&gt;상속받은 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨트릴 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메서드 오버라이딩의 오작용 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시 코드를 통해 부모 클래스의 메서드를 오버라이딩 했을때 부모 클래스의 구현에 결합되어 발생할 수 있는 문제를 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속을 위한 경고 3&lt;br /&gt;자식 클래스가 부모 클래스의 메서드를 오버라이딩할 경우 부모 클래스가 자신의 메서드를 사용하는 방법에 자식 클래스가 결합될 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;부모 클래스와 자식 클래스의 동시 수정 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식 클래스는 부모 클래스의 메서드를 오버라이딩하거나 불필요한 인터페이스를 상속받지 않았음에도 부모 클래스를 수정할 때 자식 클래스를 함께 수정해야 할 수도 있다&lt;/li&gt;
&lt;li&gt;결합도란 다른 대상에 대해 알고 있는 지식의 양이다.&lt;/li&gt;
&lt;li&gt;상속은 기본적으로 부모 클래스의 구현을 재사용한다는 기본 전제를 따르기 때문에 자식 클래스가 부모 클래스의 내부에 대해 속속들이 알도록 강요한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속을 위한 경고 4&lt;br /&gt;클래스를 상속하면 결합도로 인해 자식 클래스와 부모 클래스의 구현을 영원히 변경하지 않거나, 자식 클래스와 부모 클래스를 동시에 변경하거나 둘 중 하나를 선택할 수밖에 없다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;03 Phone 다시 살펴보기&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추상화에 의존하자&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필자의 코드 중복을 제거하기 위해 상속을 도입할 때 따르는 두 가지 원칙
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;두 메서드가 유사하게 보인다면 차이점을 메서드로 추출하라. 메서드 추출을 통해 두 메서드를 동일한 형태로 보이도록 만들 수 있다.&lt;/li&gt;
&lt;li&gt;부모 클래스의 코드를 하위로 내리지 말고 자식 클래스의 코드를 상위로 올려라. 부모 클래스의 구체적인 메서드를 자식 클래스로 내리는 것보다 자식 클래스의 추상적인 메서드를 부모 클래스로 올리는 것이 재사용성과 응집도 측면에서 더 뛰어난 결과를 얻을 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;차이를 메서드로 추출하라.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 먼저 할 일은 중복 코드 안에서 차이점을 별도 메서드로 추출하는 것이다.&lt;br /&gt;이것은 흔히 말하는 &quot;변하는 것으로부터 변하지 않는 것을 분리하라&quot; 또는 &quot;변하는 부분을 찾고 이를 캡슐화하라&quot;라는 조언을 메서드 수준에서 적용한 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;중복 코드를 부모 클래스로 올려라.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 클래스를 추가하자.&lt;/li&gt;
&lt;li&gt;목표는 모든 클래스들이 추상화에 의존하도록 만드는 것이기 때문에 이 클래스는 추상 클래스로 구현하는 것이 적합할 것이다.&lt;/li&gt;
&lt;li&gt;클래스들의 공통(완전히 동일한) 부분을 부모 클래스로 이동시키자.&lt;br /&gt;메서드 -&amp;gt; 변수 순으로 옮기는 것이 편리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추상화가 핵심이다.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공통 코드를 이동시킨 후에 각 클래스는 서로 다른 변경의 이유를 가진다는 것에 주목하라.&lt;br /&gt;단일 책임 원칙을 준수하게 되었다.&lt;/li&gt;
&lt;li&gt;새로운 클래스가 필요하다면 부모 클래스를 상속받는 새로운 클래스를 만들고 메서드만 오버라이딩하면 된다.&lt;br /&gt;다른 클래스들을 수정할 필요가 없다.&lt;br /&gt;현재 설계는 확장에는 열려 있고 수정에는 닫혀 있기 때문에&lt;br /&gt;개방-폐쇄 원칙을 준수하게 되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;의도를 드러내는 이름 선택하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인스턴스 변수가 추가되는 경우에는 자식, 부모 클래스 모두 영향을 유발한다.&lt;/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;size16&quot;&gt;위 내용들을 도입하여 최대한 상속으로 인한 결합을 피하려고 했으나 완전히 피할 수 있는 방법은 없다.&lt;br /&gt;상속은 어떤 방식으로든 부모 클래스와 자식 클래스를 결합시킨다.&lt;br /&gt;메서드 구현에 대한 결합은 추상 메서드를 추가함으로써 어느 정도 완화할 수 있지만 인스턴스 변수에 대한 잠재적인 결합을 제거할 수 있는 방법은 없다.&lt;br /&gt;우리가 원하는 것은 행동을 변경하기 위해 인스턴스 변수를 추가하더라도 상속 계층 전체에 걸쳐 부작용이 퍼지지 않게 막는 것이다.&lt;/p&gt;
&lt;h1&gt;04 차이에 의한 프로그래밍&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 코드와 다른 부분만을 추가함으로써 애플리케이션의 기능을 확장하는 방법을 &lt;b&gt;차이에 의한 프로그래밍(programming by difference)&lt;/b&gt;라고 부른다.&lt;/li&gt;
&lt;li&gt;차이에 의한 프로그래밍의 목표는 중복 코드를 제거하고 코드를 재사용하는 것이다.&lt;/li&gt;
&lt;li&gt;사실 중복 코드 제거와 코드 재사용은 동일한 행동을 가르키는 서로 다른 단어이다.&lt;/li&gt;
&lt;li&gt;중복을 제거하기 위해서는 코드를 재사용 가능한 단위로 분해하고 재구성해야 한다.&lt;/li&gt;
&lt;li&gt;코드를 재사용하기 위해서는 중복 코드를 제거해서 하나의 모듈로 모아야 한다.&lt;/li&gt;
&lt;li&gt;프로그래밍의 세계에서 중복 코드는 악의 근원이다.&lt;/li&gt;
&lt;li&gt;객체지향 세계에서 중복 코드를 제거하고 코드를 재사용할 수 있는 가장 유명한 방법은 상속이다.&lt;/li&gt;
&lt;li&gt;상속은 코드 재사용과 관련된 대부분의 경우에 우아한 해결 방법이 아니다. 더 좋은 방법은 &lt;b&gt;합성&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/183</guid>
      <comments>https://izagood.tistory.com/183#entry183comment</comments>
      <pubDate>Fri, 24 Nov 2023 22:35:30 +0900</pubDate>
    </item>
    <item>
      <title>오브젝트 - Chapter 05 책임 할당하기</title>
      <link>https://izagood.tistory.com/182</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;책임에 초점을 맞춰서 설계할 때 가장 큰 어려움은 어떤 객체에 어떤 책임을 할당할지를 결정하기 쉽지 않다는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01 책임 주도 설계를 향해&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터보다 행동을 먼저 결정하라&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;책임 중심 설계에서는 &quot;이 객체가 수행해야 하는 책임은 무엇인가&quot;를 결정한 후에 &quot;이 책임을 수행하는 데 필요한 데이터(상태)는 무엇인가&quot;를 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;협력이라는 문맥 안에서 책임을 결정하라&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;협력에 적합한 책임이란 메시지 수신자가 아니라 메시지 전송자에게 적합한 책임을 의미한다.&lt;/li&gt;
&lt;li&gt;협력에 적합한 책임을 할당하기 위해서는 메시지를 결정한 후에 객체를 선택해야 한다.&lt;/li&gt;
&lt;li&gt;메시지를 수신하기로 결정된 객체는 메시지를 처리할 &lt;b&gt;책임&lt;/b&gt;을 할당 받게 된다.&lt;/li&gt;
&lt;li&gt;협력이라는 문맥 안에서 메시지에 집중하는 책임 중심 설계는 캡슐화의 원리를 지키기가 훨씬 쉬워진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;책임 주도 설계&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다.&lt;/li&gt;
&lt;li&gt;시스템 책임을 더 작은 책임으로 분할한다.&lt;/li&gt;
&lt;li&gt;분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다.&lt;/li&gt;
&lt;li&gt;객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.&lt;/li&gt;
&lt;li&gt;해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책임 주도 설계의 핵심은 책임을 결정한 후에 책임을 수행할 객체를 결정하는 것이다. 그리고 협력에 참여하는 객체들의 책임이 어느 정도 정리될 때까지는 객체의 내부 상태에 대해 관심을 가지지 않는 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02 책임 할당을 위한 GRASP 패턴&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GRASP은 &quot;General Responsibility Assignment Software Pattern(일반적인 책임 할당을 위한 소프트웨어 패턴)&quot;의 약자로 객체에게 책임을 할당할 때 지침으로 삼을 수 있는 원칙들의 집합을 패턴 형식으로 정리한 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도메인 개념에서 출발하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설계를 시작하기 전에 도메인에 대한 개략적인 모습을 그려 보는 것이 유용한다.&lt;/li&gt;
&lt;li&gt;도메인 안에는 무수히 많은 개념들이 존재하며 이 도메인 개념들을 책임 할당의 대상으로 사용하면 코드에 도메인의 모습을 투영하기가 좀 더 수월해진다.&lt;/li&gt;
&lt;li&gt;올바른 도메인 모델이란 존재하지 않는다. -&amp;gt; 도메인을 구현하는데 도움이 되는 실용적이면서 유용한 모델이라면 모두 맞다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정보 전문가에게 책임을 할당하라&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체에게 책임을 할당하는 첫 번째 원칙은 책임을 수행할 정보를 알고 있는 객체에게 책임을 할당하는 것이다. GRASP에서는 이를 INFORMATION EXPERT(정보 전문가) 패턴이라고 부른다.&lt;/li&gt;
&lt;li&gt;여기서 이야기하는 정보는 데이터와 다르다는 사실에 주의하라. 책임을 수행하는 객체가 정보를 '알고' 있다고 해서 그 정보를 '저장'하고 있을 필요는 없다.&lt;/li&gt;
&lt;li&gt;책임을 수행하는데 필요한 작업을 구상해 보고 스스로 처리할 수 없는 작업이 무엇인지를 파악하고 &lt;br /&gt;만약 스스로 처리할 수 없는 작업이 있다면 외부에 도움을 요청해야 한다.&lt;br /&gt;이 요청이 외부로 전송해야 하는 새로운 메시지가 되고, 최종적으로 이 메시지가 새로운 객체의 책임으로 할당된다.&lt;br /&gt;이 같은 연쇄적인 메시지 전송과 수신을 통해 협력 공동체가 구성되는 것이다.&lt;/li&gt;
&lt;li&gt;INFORMATION EXPERT 패턴을 따르는 것만으로도 자율성이 높은 객체들로 구성된 협력 공동체를 구축할 가능성이 높아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;높은 응집도와 낮은 결합도&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설계는 트레이드오프 활동이라는 것을 기억하라.&lt;br /&gt;동일한 기능을 구현할 수 있는 무수히 많은 설계가 존재한다.&lt;/li&gt;
&lt;li&gt;높은 응집도와 낮은 결합도는 객체에 책임을 할당할 때 항상 고려해야 하는 기본 원리다.&lt;/li&gt;
&lt;li&gt;GRASP에서는 이를 LOW COUPLING(낮은 결합도) 패턴과 HIGH COHESION(높은 응집도) 패턴이라고 부른다.&lt;/li&gt;
&lt;li&gt;책임을 할당하고 코드를 작성하는 매순간마다 LOW COUPLING과 HIGH COHESION의 관점에서 전체적인 설계 품질을 검토하면 단순하면서도 재사용 가능하고 유연한 설계를 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;창조자에게 객체 생성 책임을 할당하라&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GRASP의 CREATOR(창조자) 패턴은 객체를 생성할 책임을 어떤 객체에게 할당할지에 대한 지침을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CREATOR 패톤&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 A를 생성해야 할 때 어떤 객체에게 객체 생성 책임을 할당해야 할까? 아래 조건을 최대한 많이 만족하는 B에게 객체 생성 책임을 할당하라
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;B가 A 객체를 포함하거나 참조한다.&lt;/li&gt;
&lt;li&gt;B가 A 객체를 기록한다.&lt;/li&gt;
&lt;li&gt;B가 A 객체를 긴밀하게 사용한다.&lt;/li&gt;
&lt;li&gt;B가 A 객체를 초기화하는데 필요한 데이터를 가지고 있다(이 경우 B는 A에 대한 정보 전문가다)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CREATOR 패턴의 의도는 어떤 방식으로든 생성되는 객체와 연결되거나 관련될 필요가 있는 객체에 해당 객체를 생성할 책임을 맡기는 것이다. 생성될 객체에 대해 잘 알고 있어야 하거나 그 객체를 사용해야 하는 객체는 어떤 방식으로든 생성될 객체와 연결될 것이다.&lt;br /&gt;다시 말해 두 객체는 서로 결합된다.&lt;/li&gt;
&lt;li&gt;이미 결합돼 있는 객체에게 생성 책임을 할당하는 것은 설계의 전체적인 결합도에 영향을 미치지 않는다.&lt;/li&gt;
&lt;li&gt;결과적으로 CREATOR 패턴은 이미 존재하는 객체 사이의 관계를 이용하기 때문에 설계가 낮은 결합도를 유지할 수 있게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03 구현을 통한 검증&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지(함수)는 송신자의 의도를 표현한다.&lt;/li&gt;
&lt;li&gt;코드 내용은 책 146-151 같이 보기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DiscountCondition 개선하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 큰 문제점은 변경에 취약한 클래스를 포함하고 있다는 것이다.&lt;/li&gt;
&lt;li&gt;변경에 취약한 클래스란 코드를 수정해야 하는 이유를 하나 이상 가지는 클래스다.&lt;/li&gt;
&lt;li&gt;DiscountCondition이 변경될 수 있는 서로 다른 3 가지 이유
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 할인 조건 추가&lt;/li&gt;
&lt;li&gt;순번 조건을 판단하는 로직 변경&lt;/li&gt;
&lt;li&gt;기간 조건을 판단하는 로직 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DiscountCondition은 하나 이상의 변경 이유를 가지기 때문에 응집도가 낮다.&lt;/li&gt;
&lt;li&gt;따라서 낮은 응집도가 초래하는 문제를 해결하기 위해서는&amp;nbsp;&lt;b&gt;변경의 이유에 따라 클래스를 분리해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;일반적으로 설계를 개선하는 작업은 변경의 이유가 하나 이상인 클래스를 찾는 것으로부터 시작하는 것이 좋다.&lt;/li&gt;
&lt;li&gt;변경의 이유가 하나 이상인 클래스에는 위험 징후를 또렷하게 드러내는 몇 가지 패턴이 존재한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파악 방법 1: 인스턴스 변수가 초기화되는 시점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응집도가 높은 클래스는 인스턴스를 생성할 때 모든 속성을 함께 초기화한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함께 초기화되는 속성을 기준으로 코드를 분리해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파악 방법 2: 메서드들이 인스턴스 변수를 사용하는 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응집도를 높이기 위해서는 &lt;b&gt;속성 그룹과 해당 그룹에 접근하는 메서드 그룹을 기준으로 코드를 분리해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클래스 응집도 판단하기&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스가 다음과 같은 징후를 보인다면 클래스의 응집도는 낮은 것이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스가 하나 이상의 이유로 변경돼야 한다면 응집도가 낮은 것이다. -&amp;gt; 변경의 이유를 기준으로 클래스를 분리하라.&lt;/li&gt;
&lt;li&gt;클래스의 인스턴스를 초기화하는 시점에 경우에 따라 서로 다른 속성들을 초기화하고 있다면 응집도가 낮은 것이다.&lt;br /&gt;-&amp;gt; 초기화되는 속성의 그룹을 기준으로 클래스를 분리하라.&lt;/li&gt;
&lt;li&gt;메서드 그룹이 속성 그룹을 사용하는지 여부로 나뉜다면 응집도가 낮은 것이다. -&amp;gt; 이들 그룹을 기준으로 클래스를 분리하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;타입 분리하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DiscountCondition의 가장 큰 문제는 순번 조건과 기간 조건이라는 두 개의 독립적인 타입이 하나의 클래스 안에 공존하고 있다는 점이다.&lt;/li&gt;
&lt;li&gt;클래스를 분리하면 앞에서 언급했던 문제점들이 모두 해결된다.&lt;/li&gt;
&lt;li&gt;그런데 클래스를 분리하고 나면 Movie의 인스턴스는 SequenceCondition과 PeriodCondition이라는 두 개의 서로 다른 클래스의 인스턴스 모두와 협력할 수 있어야 한다.&lt;br /&gt;클래스를 분리한 후에 설계의 관점에서 전체적인 결합도가 높아진 것이다.&lt;br /&gt;(DiscountCondition -&amp;gt; SequenceCondition과 PeriodCondition)&lt;/li&gt;
&lt;li&gt;그리고 새로운 할인 조건을 추가하기가 더 어려워졌다. 수정 후에는 할인 조건을 추가하려면 Movie도 함께 수정해야 한다.&lt;br /&gt;DiscountCondition의 입장에서 보면 응집도가 높아졌지만 변경과 캡슐화라는 관점에서 보면 전체적으로 설계의 품질이 나빠지고 만 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다형성을 통해 분리하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사실 Moive의 입장에서 보면 SequenceCondition과 PeriodCondition은 아무 차이도 없다.&lt;/li&gt;
&lt;li&gt;Moive 입장에서는 동일한 책임을 수행한다는 것은 동일한 &lt;b&gt;역할&lt;/b&gt;을 수행한다는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;역할을 사용하면 객체의 구체적인 타입을 추상화(Interface or Abstract)할 수 있다.&lt;/li&gt;
&lt;li&gt;GRASP에서는 이를 POLYMORPHISM(다형성) 패턴이라고 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변경으로부터 보호하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DiscountCondition의 두 서브클래스는 서로 다른 이유로 변경된다는 사실을 알 수 있다.&lt;br /&gt;서로 다른 변경이 두 개의 서로 다른 클래스 안으로 캡슐화된다.&lt;/li&gt;
&lt;li&gt;변경을 캡슐화하도록 책임을 할당하는 것을 GRASP에서는 PROTECTED VARIATIONS(변경 보호) 패턴이라고 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변경과 유연성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설계를 주도하는 것은 변경이다.&lt;/li&gt;
&lt;li&gt;개발자로서 변경에 대비할 수 있는 두 가지 방법이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드를 이해하고 수정하기 쉽도록 최대한 단순하게 설계하는 것이다.&lt;/li&gt;
&lt;li&gt;코드를 수정하지 않고도 변경을 수용할 수 있도록 코드를 더 유연하게 만드는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;합성&lt;/b&gt;을 통해서 코드를 유연하게 만들 수 있다. (164p 그림 5.8)&lt;/li&gt;
&lt;li&gt;도메인 모델은 코드의 변화에 발맞춰 함께 변화해야 한다.&lt;br /&gt;도메인 모델을 코드와 분리된 막연한 무엇으로 생각하지 않기 바란다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04 책임 주도 설계의 대안&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메서드 응집도&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;긴 메서드는 응집도가 낮기 때문에 이해하기도 어렵고 재사용하기도 어려우며 변경하기도 어렵다.&lt;br /&gt;이런 메서드를 &lt;b&gt;몬스터 메서드&lt;/b&gt;라고 부른다.&lt;/li&gt;
&lt;li&gt;메서드를 작게 분해해서 각 메서드의 응집도를 높여라.&lt;/li&gt;
&lt;li&gt;메서드의 응집도를 높이는 이유도 변경과 관련이 깊다.&lt;br /&gt;응집도 높은 메서드는 변경되는 이유가 단 하나여야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체를 자율적으로 만들자&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 메서드를 어떤 클래스로 이동시켜야 할까?&lt;/li&gt;
&lt;li&gt;자신이 소유하고 있는 데이터를 자기 스스로 처리하도록 만든 것이 자율적인 객체를 만드는 지름길이다.&lt;br /&gt;따라서 메서드가 사용하는 데이터를 저장하고 있는 클래스로 메서드를 이동시키면 된다.&lt;/li&gt;
&lt;li&gt;데이터 중심으로 코드를 작성하고 &lt;b&gt;리팩터링 하더라도&lt;/b&gt; 캡슐화, 결합도, 응집도를 이해하고 객체지향 원칙을 적용하기 위해 노력한다면 책임 주도 설계와 유사한 결과를 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/182</guid>
      <comments>https://izagood.tistory.com/182#entry182comment</comments>
      <pubDate>Sun, 22 Oct 2023 16:13:35 +0900</pubDate>
    </item>
    <item>
      <title>실용주의 프로그래머 - 9장 실용주의 프로젝트</title>
      <link>https://izagood.tistory.com/181</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트의 성패를 좌우하는 핵심&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Topic 49 실용주의 팀&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;L 그룹에서 스토펠은 여섯 명의 일류 프로그래머를 감독한다. 이는 말하자면 고양이 떼를 모는 일에 비할 만한 도전적인 관리 업무다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래머는 고양이 같은 면이 있다.&lt;br /&gt;호기심이 많고 제멋대로이며, 고집이 세고, 독립적인 데다, 가끔은 인터넷에서 숭배를 받기도 한다.&lt;/li&gt;
&lt;li&gt;이제까지 우리는 개인이 더 나은 프로그래머가 되게끔 도와주는 실용주의 기법들을 살펴보았다.&lt;br /&gt;이런 방법이 팀에도 적용될까? 제멋대로이고 독립적인 사람들이 모인 팀에서도?&lt;br /&gt;답은 명쾌한 &quot;그렇다!&quot;이다.&lt;/li&gt;
&lt;li&gt;실용주의 팀은 작다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구성원이 대략 10~12명 이하여야 하고,&lt;/li&gt;
&lt;li&gt;구성원이 추가되거나 빠지는 일은 드물어야 한다.&lt;/li&gt;
&lt;li&gt;모두가 서로 잘 알고, 신뢰하며, 의존해야 한다.&lt;/li&gt;
&lt;/ul&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;size16&quot;&gt;Tip 84 작고 안정적인 팀을 유지하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;깨진 창문을 없애라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팀 전체가 깨진 창문을 용납하지 않아야 한다.&lt;/li&gt;
&lt;li&gt;품질은 팀원 모두가 제각기 기여할 때만 보장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;삶은 개구리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팀은 개인보다 더 삶은 개구리가 되기 쉽다.&lt;/li&gt;
&lt;li&gt;모든 사람이 적극적으로 환경 변화를 감시하도록 권장하라.&lt;/li&gt;
&lt;li&gt;새 요구사항에 대한 수치를 관리하라.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;번다운 차트보다는 번업 차트가 더 낫다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러분의 지식 포트폴리오를 계획하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구형 시스템 유지 보수
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신규 시스템에서 일하는 것을 좋아하겠지만, 구형 시스템에도 해야 할 유지 보수 업무가 있다. 수행하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스 회고와 개선
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지속적인 개선이 일어나려면 무엇이 잘되고 무엇이 잘되지 않았는지 확인한 다음에 계획을 세우고, 고쳐라.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;새로운 기술 탐험
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기술을 &quot;다들 쓰니까&quot;라는 이유로, 또는 콘퍼런스에서 본 것이나 인터넷에서 읽은 글을 바탕으로 도입하지 말라.&lt;/li&gt;
&lt;li&gt;후보 기술로 프로토타이을 만들어 보고 신중하게 조사하라. 시도해 보고 결과를 분석하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;학습 및 기술 갈고 닦기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기술을 팀 전체로 퍼트려라&lt;/li&gt;
&lt;/ul&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;size16&quot;&gt;Tip 85 실현하려면 계획하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;팀의 존재를 소통하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팀이라는 것 역시 더 큰 조직의 일부라는 사실을 잊어버리기 쉽다.&lt;/li&gt;
&lt;li&gt;팀도 나머지 세상과 명확하게 의사소통해야 하는 존재다.&lt;/li&gt;
&lt;li&gt;외부 사람들에게 무뚝뚝하고 과묵해 보이는 프로젝트팀이야말로 최악이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;반복하지 말라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좋은 의사소통이 이런 문제를 피하는 핵심이다.&lt;/li&gt;
&lt;li&gt;&quot;좋은&quot;이란 즉각적이고 매끄러운 것을 말한다.&lt;/li&gt;
&lt;li&gt;만약 질문을 하거나 상황을 공유하기 위해 일주일 남은 팀 회의시간까지 기다려야 한다면 엄청 껄끄러운 커뮤니케이션이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;e.g. 일일 스크럼 스탠드업을 금요일에만 하는 팀&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;팀 예광탄&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예광탄을 사용하여 처음에는 작고 제한적일지라도 시스템의 끝에서 끝까지 전체에 걸쳐 있는 단일 기능을 개발할 것을 추천한다.&lt;/li&gt;
&lt;li&gt;작업에 필요한 기술을 팀 안에 모두 갖추어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tip 86 모든 기능을 갖춘 팀을 조직하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드를 끝에서 끝까지 점진적이고 반복적으로 쌓아 올릴 수 있는 팀을 만들어라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자동화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일관성과 정확성을 모두 보장하는 확실한 방법은 팀이 하는 모든 일을 자동화하는 것이다.&lt;/li&gt;
&lt;li&gt;코드 스타일&lt;/li&gt;
&lt;li&gt;CI/ CD&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;멈춰야 할 때를 알라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팀은 개인들로 이루어진다는 사실을 명심하라.&lt;/li&gt;
&lt;li&gt;각 팀원이 자신의 방식대로 빛나게 하라.&lt;/li&gt;
&lt;li&gt;프로젝트가 가치를 만들어 내기에 딱 좋을 만큼의 구조를 제공하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Topic 50 코코넛만으로는 부족하다&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(책 예시) 코코넛 껍질로 만든 모조 공항은 진짜를 대체할 수 없다.&lt;/li&gt;
&lt;li&gt;(책 예시) 스크럼을 이름만 가져다 쓰는 있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;맥락의 중요성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정한 개발 방법이나 프레임워크, 테스트 기법을 굳이 사용하는 이유가 무엇인가?&lt;/li&gt;
&lt;li&gt;성공한 회사의 정책과 프로세스를 다들 앞다투어 도입하고 있다. 각자의 방식으로 소프트웨어를 개발하고 관리한다.&lt;br /&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;size16&quot;&gt;Tip 87 유행하는 것이 아니라 실제로 잘 맞는 것을 사용하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;잘 맞는 것&quot;을 어떻게 알 수 있을까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한번 해 보라.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시험해 보고 잘 맞는 것 같은 좋은 부분만 유지하고 나머지는 버리면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;만병통치약은 아무 병도 못 고친다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소프트웨어 개발 방법론의 목표는 사람들이 함께 일하는 것을 돕는 것이다.&lt;/li&gt;
&lt;li&gt;소프트웨어를 개발할 때 늘 따를 수 있는 단 하나의 계획이란 것은 없다.&lt;/li&gt;
&lt;li&gt;특정 방법론에서 가장 좋은 부분만 가져다가 적절히 조정하여 사용해야 한다.&lt;/li&gt;
&lt;li&gt;만병통치약은 없고, 현재의 방법론들도 아직 완성되려면 멀었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;진짜 목표&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;진짜 목표는 당연히 &quot;스크럼을 한다&quot;나 &quot;애자일을 한다&quot;, &quot;린을 한다&quot; 같은 종류가 아니다.&lt;/li&gt;
&lt;li&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;size16&quot;&gt;Tip 88 사용자에게 필요할 때 제공하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버전 관리 시스템의 기능(feature) 브랜치가 아니라 주(main) 브랜치 혹은 트렁크(trunk)에서 개발해야 한다.&lt;/li&gt;
&lt;li&gt;사용자에게 선택적으로 시범적 기능을 공개할 때는 '기능 스위치'같은 기법을 활용하라.&lt;/li&gt;
&lt;li&gt;하지만 우리말을 곧이곧대로 받아들이지는 말라.&lt;/li&gt;
&lt;li&gt;직접 이런 접근 방법들을 조사하고 시도해 보라.&lt;/li&gt;
&lt;li&gt;하지만 지나치지 않도록 주의하라.&lt;/li&gt;
&lt;li&gt;하나에 고착되면 머지않아 다른 길을 보기 어렵게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Topic 51 실용주의 시작 도구&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;생각 없이 행할 수 있는 중요한 작업의 수가 늘어남에 따라 문명은 발전한다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일상적인 작업은 모두 자동화해야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드, 릴리스, 테스트, 프로젝트 서류 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;size16&quot;&gt;&lt;b&gt;버전 관리로 운용하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트를 빌드하는데 필요한 모든 것을 버전 관리하에 두어야 한다.&lt;/li&gt;
&lt;li&gt;빌드 머신이나 빌드 클러스터를 필요할 때마다 클라우드의 스폿 인스턴스를 이용하여 만들어 쓸 수 있다.&lt;/li&gt;
&lt;li&gt;배포 설정도 역시 버전 관리 시스템 안에 있으므로 실제 서비스에 릴리스하는 것도 자동으로 처리된다.&lt;/li&gt;
&lt;li&gt;프로젝트 차원에서는 버전 관리 시스템이 빌드와 릴리스 프로세스를 운용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tip 89 버전 관리 시스템으로 빌드, 테스트, 릴리스를 운용하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버전 관리 시스템의 커밋이나 푸시로 빌드와 테스트, 배포가 시작된다.&lt;/li&gt;
&lt;li&gt;빌드는 클라우드의 컨테이너 위에서 돌아간다.&lt;/li&gt;
&lt;li&gt;테스트를 위해 스테이징 서버에 배포할지 실제 서비스에 릴리스할지는 버전 관리 시스템의 태그를 사용하여 지정한다.&lt;/li&gt;
&lt;li&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;size16&quot;&gt;&lt;b&gt;가차 없고 지속적인 테스트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;많은 개발자들이 무의식적으로 코드가 어디에서 깨지는지 파악하고서는 약한 지점을 피해 다니면서 살살 테스트하려 한다.&lt;/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;size16&quot;&gt;Tip 90 일찍 테스트하고, 자주 테스트하라, 자동으로 테스트하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;훌륭한 프로젝트에는 제품 코드보다 테스트 코드가 더 많을 수도 있다.&lt;/li&gt;
&lt;li&gt;길게 보면 테스트를 하는 쪽이 훨씬 더 싸게 먹히며, 결함이 거의 없는 제품을 만드는 꿈이 정말 이루어지기도 한다.&lt;/li&gt;
&lt;li&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;size16&quot;&gt;Tip 91 모든 테스트가 끝날 때까지는 코딩이 끝난 게 아니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동 빌드가 모든 가용한 테스트를 수행한다.&lt;/li&gt;
&lt;li&gt;&quot;진짜 상황 테스트&quot;를 목표로 하는 것이 중요하다.&lt;br /&gt;즉 테스트 환경은 실제 환경과 최대한 비슷해야 한다.&lt;br /&gt;두 환경의 차이에서 버그가 번식한다.&lt;/li&gt;
&lt;li&gt;빌드 과정에는 소프트웨어 테스트의 몇 가지 주요 유형이 들어가야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단위 테스트, 통합 테스트, 유효성 평가 및 검증, 성능 테스트가 그것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단위 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 모듈을 테스트하는 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;통합 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트를 구성하는 주요 서브시스템이 다른 부분과 제대로 작동하는지 테스트&lt;/li&gt;
&lt;li&gt;단위 테스트의 확장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;유효성 평가 및 검증
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자들이 필요로 하는 것인가?&lt;/li&gt;
&lt;li&gt;시스템의 기능적 요구 사항을 충족하는가?&lt;/li&gt;
&lt;li&gt;버그가 없는 시스템일지언정 잘못된 문제를 푼다면 별 쓸모가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;성능 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;= 스트레스 테스트&lt;/li&gt;
&lt;li&gt;소프트웨어가 실세계 조건에서 선능 요구 사항들을 준수하는지 테스트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;테스트를 테스트하기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의도적으로 버그를 생기도록 하여 테스트&lt;/li&gt;
&lt;li&gt;e.g. 카오스 몽키&lt;/li&gt;
&lt;/ul&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;size16&quot;&gt;Tip 92 버그를 심어 놓고 테스트를 테스트하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;철저한 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;100 % 커버리지를 기대하지는 말라.&lt;/li&gt;
&lt;li&gt;프로그램의 모든 가능한 상태를 확인해야 할 것이다.&lt;/li&gt;
&lt;/ul&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;size16&quot;&gt;Tip 93 코드 커버리지만 올리지 말고 상태 조합을 테스트하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;속성 기반 테스트&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그물 조이기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tip 94 버그는 한 번만 잡아라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한번 인간 테스트가 버그를 찾았다면 해당 버그를 확인할 수 있게 자동화 테스트를 수정해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 자동화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수작업이 필요해서는 안 된다.&lt;/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;size16&quot;&gt;Tip 95 수작업 절차를 사용하지 말라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 것이 자동화의 의존한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버전 관리, 가차 없는 테스트, 전체 자동화&lt;/b&gt;라는 세 기둥이 있다면 프로젝트에 필수적인 견고한 기반이 생긴 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Topic 52 사용자를 기쁘게 하라&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;당신이 사람들을 황홀하게 만들 때, 당신의 목표는 그들로부터 돈을 벌거나, 당신이 원하는 일을 시키는 것이 아닙니다.&lt;br /&gt;사람들을 커다란 기쁨으로 충만하게 하는 것입니다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자로서 우리의 목표는 사용자를 기쁘게 하는 것이다.&lt;/li&gt;
&lt;li&gt;사용자가 기대하는 것은 소프트웨어와 관련이 없다.&lt;/li&gt;
&lt;li&gt;소프트웨어는 목적을 달성하기 위한 수단일 뿐이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용자 관점에서 생각하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 팀 구성원이 사용자가 기대하는 바를 완전히 이해해야 한다.&lt;/li&gt;
&lt;li&gt;결정을 내릴 때면 어떤 선택이 사용자의 기대에 더 가깝게 가는 길인지 생각하라.&lt;/li&gt;
&lt;li&gt;이런 기대를 염두에 두고 사용자 요구 사항을 비판적으로 분석하라.&lt;br /&gt;요구 사항을 바꾸면 프로젝트가 목표에 가까워진다는 것을 보여줄 수 있는가? 주저하지 말고 바꾸자고 제안하라.&lt;/li&gt;
&lt;li&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;size16&quot;&gt;Tip 96 사용자를 기쁘게 하라. 그저 코드만 내놓지 말라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직함이 명목상으로는 &quot;소프트웨어 개발자&quot;나 &quot;소프트웨어 엔지니어&quot; 비슷한 이름일지 몰라도 진정한 우리의 직함은 &quot;문제 해결사&quot;다.&lt;/li&gt;
&lt;li&gt;우리는 문제를 해결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Topic 53 오만과 편견&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;너는 지금까지 우리를 충분히 즐겁게 해 주었단다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실용주의 프로그래머는 책임을 회피하지 않는다.&lt;/li&gt;
&lt;li&gt;그 대신 도전을 수용하고 자신의 전문성이 널리 알려지는 것을 기뻐한다.&lt;/li&gt;
&lt;li&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;size16&quot;&gt;Tip 97 자신의 작품에 서명하라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;익명성은 특히 큰 프로젝트에서 적당주의나 실수, 태만, 나쁜 코드의 온상이 될 수 있다.&lt;/li&gt;
&lt;li&gt;우리는 소유권에 대한 긍지(pride)를 보고 싶다.&lt;/li&gt;
&lt;li&gt;&quot;내가 이걸 만들었고, 내 작품의 품질을 보증합니다.&quot;&lt;/li&gt;
&lt;li&gt;우리의 서명이 품질의 보증 수표로 인식되게 해야 한다.&lt;/li&gt;
&lt;li&gt;사람들이 코드에 붙은 우리의 이름을 보고 그것이 튼튼하고 잘 작성되었으며 제대로 테스트되었을 뿐 아니라 훌륭히 문서화되었을 것이라고 기대하도록 만들자.&lt;/li&gt;
&lt;li&gt;전문가가 만든 진정으로 전문가다운 결과물.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/181</guid>
      <comments>https://izagood.tistory.com/181#entry181comment</comments>
      <pubDate>Mon, 28 Aug 2023 18:45:58 +0900</pubDate>
    </item>
    <item>
      <title>실용주의 프로그래머 - 7장 코딩하는 동안</title>
      <link>https://izagood.tistory.com/180</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일단 코딩에 들어가면 대부분 기계적인 작업, 즉 설계 내용을 컴퓨터가 실행할 수 있는 문장으로 바꾸는 일만 하면 된다고들 많이 생각한다.&lt;br /&gt;우리가 보기에는 이런 태도가 소프트웨어 프로젝트가 실패하는 가장 큰 원인이다.&lt;br /&gt;이런 태도 때문에 많은 시스템이 결국 너저분해지고, 비효율적이 되고, 구조가 망가지고, 유지 보수가 힘들어지고, 한마디로 완전 잘못되고 만다.&lt;/li&gt;
&lt;li&gt;코딩은 기계적인 작업이 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Topic 37 파충류의 뇌에 귀 기울이기&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;오직 인간만이 무언가를 직접 보고, 정확한 예측에 필요한 모든 정보를 획득하고, 심지어 순간적으로는 정확한 예측을 한 후에도, 그런데 그것이 아니라고 말할 수 있다.&lt;br /&gt;- 개빈 드 베커&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;본능이란 우리 뇌의 무의식 속에 채워져 있는 패턴에 대한 단순한 반응이다.&lt;/li&gt;
&lt;li&gt;프로그래머로서 경험이 늘어 갈수록 우리의 뇌에는 암묵적인 지식이 켜켜이 쌓인다.&lt;/li&gt;
&lt;li&gt;모든 본능에는 공통점이 있다. 바로 말로 표현할 수 없다는 것, 생각이 아니라 느낌이라는 점이다.&lt;/li&gt;
&lt;li&gt;본능이 반응한다고 머리 위에 반짝이는 전구가 나타나지는 않는다. 오히려 그저 불안하고 초조해지기만 한다.&lt;/li&gt;
&lt;li&gt;이럴 때의 해결책은 일단 본능이 반응하고 있음을 인지하는 것이다.&lt;/li&gt;
&lt;li&gt;그리고 왜 그런 느낌이 드는지 알아내야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;백지의 공포&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;누구나 텅 빈 화면을 두려워한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자신과 싸우기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가끔은 코드가 우리의 뇌에서 에디터로 거침없이 술술 옮겨지고, 생각을 비트로 바꾸는 일이 전혀 힘들지 않은 날이 있다.&lt;/li&gt;
&lt;li&gt;반면에 코딩이 진창에서 오르막길을 걷는 것처럼 느껴지는 날도 있다.&lt;/li&gt;
&lt;li&gt;하지만 전문가라면 계속 나가야 하지 않을까?&lt;/li&gt;
&lt;li&gt;아니다. 정반대이다. 우리의 코드가 무언가를 말하려는 것이다.&lt;/li&gt;
&lt;li&gt;어쩌면 구조나 설계가 틀렸을 수도 있고, 엉뚱한 문제를 붙들고 있을 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;파충류와 이야기하는 법&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Tip 61 여러분 내면의 파충류에게 귀 기울여라.&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일단, 하고 있는 일을 멈춰라.&lt;/li&gt;
&lt;li&gt;뇌가 정리를 할 수 있도록 약간의 시간과 공간을 확보하라.&lt;/li&gt;
&lt;li&gt;코드에 대해 생각하지 말고 키보드에서 떨어져서 잠깐 머리를 비운 채로 할 수 있는 일을 하라.&lt;/li&gt;
&lt;li&gt;산책을 하고 점심을 먹고 다른 사람과 수다를 떨어라.&lt;/li&gt;
&lt;li&gt;언젠가 다시 갱각이 의식의 영역으로 올라와서 '아하!' 하는 순간이 찾아올 것이다.&lt;/li&gt;
&lt;li&gt;이 방법이 잘 안 된다면 다른 사람에게 설명해 보라.&lt;/li&gt;
&lt;li&gt;여전히 막혀있다면 프로토타이핑을 하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;놀이 시간이다!&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로토타이핑을 하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;'여러분'의 코드뿐이 아니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 사람의 코드를 보면서 새로운 것을 배울 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코드뿐이 아니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직감에 귀 기울이는 방법은 계속 갈고닦아야 할 중요한 기술이다.&lt;br /&gt;그런데 이 기술은 더 많은 일에 적용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/180</guid>
      <comments>https://izagood.tistory.com/180#entry180comment</comments>
      <pubDate>Sat, 22 Jul 2023 16:04:23 +0900</pubDate>
    </item>
    <item>
      <title>실용주의 프로그래머 - 6장 동시성</title>
      <link>https://izagood.tistory.com/179</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동시성(concurrency) : 둘 이상의 코드 조각이 실행될 때 동시에 실행 중인 것처럼 행동하는 것&lt;/li&gt;
&lt;li&gt;병렬성(parallelism) : 실제로 동시에 실행되는 것&lt;/li&gt;
&lt;li&gt;동시성을 얻으려면 실행 중에 코드의 다른 부분으로 실행을 전환할 수 있는 환경에서 코드를 구동해야 한다. 보통은 파이버(fiber)나 스레드, 프로세스 등을 사용하여 동시성을 구현한다.&lt;/li&gt;
&lt;li&gt;병렬성을 얻으려면 두 가지 일을 동시에 할 수 있는 하드웨어가 필요하다.&lt;/li&gt;
&lt;li&gt;애플리케이션이 실제 세상을 다루기 원한다면 동시성은 필수다. 세상은 비동기적이기 때문이다.&lt;/li&gt;
&lt;li&gt;가장 큰 문제는 '공유 상태(shared state)'다. 둘 이상의 코드 뭉치가 하나의 변경 가능한 데이터를 참조하고 있다면 공유 상태가 존재하는 것이다. 그리고 &amp;lt;Topic 34. 공유 상태는 틀린 상태&amp;gt;다.&lt;/li&gt;
&lt;li&gt;동시성을 갖춘 애플리케이션을 구축하는 더 나은 방법들이 있다. '액터(actor) 모델'이 그중 하나다.&lt;/li&gt;
&lt;li&gt;액터 모델에서는 프로세스들이 독립적으로 수행되며 서로 데이터를 공유하지 않는다. 대신 채널을 통해 잘 정의된 단순한 의미론을 사용하여 의사소통한다.&lt;/li&gt;
&lt;li&gt;동시에 혹은 병렬로 작동하는 코드가 신기하던 시절도 있었지만 이제는 필수이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Topic 33 시간적 결합 깨트리기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;'시간적 결합(temporal coupling)'이란 도대체 무엇인가?&lt;/li&gt;
&lt;li&gt;소프트웨어의 설계 요소로서 시간의 역할 중 중요한 두 가지 요소가 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동시성: 동시에 일어나는 일들&lt;/li&gt;
&lt;li&gt;순서: 시간의 흐름 속에서 일들의 상대적인 위치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;아키텍처를 설계하거나 프로그램을 짜기 시작할 때는 보통 직선적 사고를 하기 마련이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사람들의 사고방식이 대개 그렇다. '이것을 하고, 그런 다음에 저것을 하고'&lt;/li&gt;
&lt;li&gt;하지만 이런 식으로 생각하다 보면 시간적 결합을 만들게 된다.&lt;/li&gt;
&lt;li&gt;메서드 A는 언제나 반드시 메서드 B보다 먼저 호출해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이러한 접근 방법은 그다지 유연하지 않고 현실과도 동떨어져 있다.&lt;/li&gt;
&lt;li&gt;우리는 동시성을 확보해야 한다.&lt;/li&gt;
&lt;li&gt;시간이나 순서에 의존하는 시간적 결합을 끊는 방법을 생각해 내야 한다. 그렇게 함으로써 유연성도 얻을 수 있고, 작업 흐름 분석과 아키텍처, 설계, 배포와 같은 개발의 여러 측면에서 시간과 관련된 의존성도 함께 줄일 수 있다.&lt;/li&gt;
&lt;li&gt;결과적으로 분석하기 더 쉽고 응답속도도 더 빠르며 더 안정적인 시스템을 만들 수 있을 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;동시성 찾기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;'활동 다이어그램(activity diagram)' 같은 표기법을 사용해서 작업 흐름을 기록하는 것이 한 방법이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;Tip 56 작업 흐름 분석으로 동시성을 개선하라.&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;활동 다이어그램을 사용하면 동시에 수행할 수 있는데도 아직 동시에 하고 있지 않은 활동들을 찾아내서 병렬성을 극대화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Topic 34 공유 상태는 틀린 상태&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레스토랑 예시 (책)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;비-원자적 갱신&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;갱신하는 동작이 원자적(atomic)이지 않기 때문이다.&lt;/li&gt;
&lt;li&gt;실제 값이 그사이에 바뀔 수 있다.&lt;/li&gt;
&lt;li&gt;어떻게 원자적으로 바꿀 수 있을까?&lt;/li&gt;
&lt;li&gt;세마포어 및 다른 상호 배제 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세마포어(semaphore)는 단순히 한 번에 한 사람만이 가질 수 있는 무언가다.&lt;/li&gt;
&lt;li&gt;세마포어를 만들어서 다른 리소스의 사용을 제어하는 데 쓸 수 있다.&lt;/li&gt;
&lt;li&gt;전통적으로는 세마포어를 획득하는 작업을 P로, 반환하는 작업을 V로 불렀지만, 요즈음은 lock/unlock, claim/release 등으로 부른다.&lt;/li&gt;
&lt;li&gt;이 접근 방식에는 몇 가지 문제가 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 큰 문제는 모든 프로세스가 세마포어를 사용해야만 제대로 동작한다는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리소스를 트랜잭션으로 관리하라
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재의 설계가 미흡한 것은 사용하는 사람에게 책임을 전가하기 때문이다.&lt;/li&gt;
&lt;li&gt;제어를 중앙으로 집중시키자.&lt;/li&gt;
&lt;li&gt;그러려면 API를 바꿔서 하나의 호출로 리소스를 확인함과 동시에 가져가도록 만들어야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스 관리 코드를 리소스 클래스 안으로 옮긴다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;이 메서드 자체도 여러 개의 스레드에서 동시에 호출될 수 있으므로 여전히 세마포어로 보호해야 한다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오류 발생 시에도 세마포어를 unlock 해주어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러 리소스와 트랜잭션&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 리소스 자체를 하나의 리소스로 보는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;트랜잭션이 없는 갱신&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공유 메모리는 동시성 문제의 원인으로 많이 지목받는다. 하지만 사실 수정 가능한 리소스를 공유하는 애플리케이션 코드 어디에서나 동시성 문제가 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;코드의 인스턴스 둘 이상이 파일, 데이터베이스, 외부 서비스 등 어떤 리소스에 동시에 접근할 수 있다면 잠재적인 문제를 안고 있는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;Tip 58 불규칙한 실패는 동시성 문제인 경우가 많다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그 밖의 독점적인 접근&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 언어에는 공유 리소스에 독점적으로 접근하는 것을 도와주는 라이브러리가 있다.&lt;/li&gt;
&lt;li&gt;상호 배제(mutual exclusion)를 의미하는 뮤텍스(mutex)라고 부르기도 하고, 모니터(monitor)나 세마포어라고 부르기도 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Topic 35 액터와 프로세스&lt;/h3&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;작가가 없다면 이야기는 쓰이지 않을 것이다.&lt;br /&gt;배우(actor)가 없다면 이야기는 생명을 얻지 못할 것이다.&lt;br /&gt;- 앤지-마리 델산테&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액터(actor)와 프로세스를 사용하면 흥미로운 방식으로 동시성을 구현할 수 있다.&lt;/li&gt;
&lt;li&gt;공유 메모리 접근을 동기화하느라 고생할 필요도 없다.&lt;/li&gt;
&lt;li&gt;'액터'는 자신만의 비공개 지역 상태(state)를 가진 독립적인 가상 처리 장치(virtual processor)다.&lt;/li&gt;
&lt;li&gt;'프로세스'는 본래 더 일반적인 가상 처리기로, 보통 운영 체제가 동시성을 지원하기 위하여 구현한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이번 Topic에서는 프로세스를 마치 액터처럼 동작하도록 관례를 만들어 제한적으로만 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;액터는 언제나 동시성을 띤다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액터의 정의에서 찾아볼 수 없는 것이 몇 가지 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액터를 관리하는 것이 없다.&lt;/li&gt;
&lt;li&gt;시스템이 저장하는 상태는 오직 메시지 그리고 각 액터의 지역 상태뿐이다. 메시지는 수신자가 읽는 것 외에는 확인할 방법이 없고, 지역 상태는 액터 바깥에서는 접근이 불가능하다.&lt;/li&gt;
&lt;li&gt;모든 메시지는 일방향이다. 답장이란 개념이 없다.&lt;/li&gt;
&lt;li&gt;각 메시지를 끝날 때까지 처리하고 중간에 다른 일을 하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결과적으로 액터들은 아무것도 공유하지 않으면서 비동기적으로 동시에 실행된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;Tip 59 공유 상태 없는 동시성을 위하여 액터를 사용하라.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;간단한 액터&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액터 예시 (책)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;드러나지 않는 동시성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액터 모델에서는 동시성을 다루는 코드를 쓸 필요가 없다.&lt;/li&gt;
&lt;li&gt;공유된 상태가 없기 때문이다.&lt;/li&gt;
&lt;li&gt;액터는 수신하는 메시지에 따라서 알아서 실행된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;얼랭이 장을 마련하다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;얼랭(Erlang) 언어와 런타임은 액터 구현의 좋은 사례다.&lt;/li&gt;
&lt;li&gt;얼랭은 액터를 '프로세스'라고 부르는데 일반적인 운영 체제의 프로세스와는 다르다.&lt;br /&gt;오히려 우리가 여기서 이야기하는 액터에 더 가깝다.&lt;/li&gt;
&lt;li&gt;얼랭 그리고 얼랭의 후손인 엘리서만 액터가 있는 것은 아니다.&lt;br /&gt;다른 대부분의 언어에도 액터 구현이 있다.&lt;/li&gt;
&lt;li&gt;python 액터 라이브러리 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://pykka.readthedocs.io/en/stable/&quot;&gt;Pykka&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;동시에 실행되는 작업을 구현할 때 액터를 사용하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Topic 36 칠판&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;형사들이 살인 사건을 조사해서 사건을 해결하기 위해 '칠판(blackboard)'을 어떻게 사용하는지 한번 생각해 보라.&lt;/li&gt;
&lt;li&gt;칠판 접근 방법의 몇 가지 주요 특징은 다음과 같다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;형사들은 다른 형사의 존재를 알 필요가 없다.&lt;/li&gt;
&lt;li&gt;형사들은 여러 유형이고 사건을 해결하고 싶은 마음만 공통점이다.&lt;/li&gt;
&lt;li&gt;수사 과정에서 여러 형사들이 다양한 시간에 접근한다.&lt;/li&gt;
&lt;li&gt;칠판에는 제한 없이 어떤 것이든 올릴 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일종의 '자유방임주의'적 동시성이다.&lt;/li&gt;
&lt;li&gt;각 형사는 독립된 프로세스, 에이전트, 액터 등과 같다.&lt;/li&gt;
&lt;li&gt;컴퓨터 기반의 칠판 시스템은 원래 음성 인식, 지식 기반 추론 시스템 등 해결해야 할 문제의 규모가 크고 복잡한 인공 지능 애플리케이션에서 사용되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;칠판 사용 사례&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주택 담보 대출이나 신용 대출 신청을 받아서 처리하는 프로그램을 작성한다고 가정해 보자.&lt;/li&gt;
&lt;li&gt;정부, 금융위원회, 지방 자치 단체 각각 복잡한 규칙을 가지고 있다.&lt;/li&gt;
&lt;li&gt;추가적으로 많은 문제들이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답은 정해진 순서가 없이 도착한다.&lt;/li&gt;
&lt;li&gt;데이터가 비동기적으로 도착한다.&lt;/li&gt;
&lt;li&gt;어떤 데이터는 다른 데이터에 의존적이다.&lt;/li&gt;
&lt;li&gt;새로운 데이터는 새로운 정책을 적용해야 할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;작업 흐름 시스템을 이용해서 모든 조합과 환경을 통제할 수도 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡하고 프로그래머의 노력이 많이 들어간다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;칠판 시스템을 법적 요구 사항을 캡슐화하는 규칙 엔진과 함께 사용하면 이러한 어려움을 우아하게 해결할 수 있다.&lt;br /&gt;데이터의 도착 순서는 이제 상관없다.&lt;/li&gt;
&lt;li&gt;어떤 사실이 칠판에 올라가면 적절한 규칙이 발동되도록 하면 된다.&lt;/li&gt;
&lt;li&gt;결과에 대한 피드백도 마찬가지이다.&lt;br /&gt;어떤 규칙에서 나온 것이든 그 결과를 다시 칠판에 올려서 다른 규칙들이 발동 되록하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;Tip 60 칠판으로 작업 흐름을 조율하라.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;메시지 시스템과 칠판의 유사성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2019년 기준으로, 메시징 시스템(messaging system)으로 통신하는 작고 분리된 서비스들(MSA)로 애플리케이션을 구성하는 경우가 많다.&lt;/li&gt;
&lt;li&gt;카프카(Kafka)나 NATS 같은 메시징 시스템은 단순히 데이터를 A에서 B로 보내는 것보다 훨씬 많은 일을 한다.&lt;/li&gt;
&lt;li&gt;메시징 시스템을 칠판 또는 여러 액터를 실행하는 플랫폼으로 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만 그렇게 간단하지 않다...&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아키텍처에서 액터와 칠판, 마이크로서비스를 활용하면 애플리케이션에서 생길 수 있는 모든 종류의 동시성 문제를 예방할 수 있을 것이다.&lt;br /&gt;하지만 거기에는 비용이 따른다.&lt;/li&gt;
&lt;li&gt;이런 접근 방식을 사용하면 많은 동작이 간접적으로 일어나므로 분석이 더 힘들다.&lt;/li&gt;
&lt;li&gt;메시지 형식 및 API를 모아두는 중앙 저장소를 운영하면 도움이 될 것이다.&lt;/li&gt;
&lt;li&gt;고유한 추적 아이디(trace id)를 만들어서 사용하자
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;trace id를 해당 작업에 관여하는 모든 액터로 전파하면 로그 파일을 뒤져서 어떤 일이 일어났는지 재구성해 볼 수 있을 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이런 종류의 시스템은 맞춰야 하는 구성 요소 수가 더 많기 때문에 배포하고 관리하기 더 까다롭다.&lt;br /&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;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study</category>
      <author>자굿</author>
      <guid isPermaLink="true">https://izagood.tistory.com/179</guid>
      <comments>https://izagood.tistory.com/179#entry179comment</comments>
      <pubDate>Sat, 22 Jul 2023 16:01:47 +0900</pubDate>
    </item>
  </channel>
</rss>