<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>알고풀자</title>
    <link>https://algopoolja.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 14 Jun 2026 07:05:13 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>AlgoPoolJa</managingEditor>
    <image>
      <title>알고풀자</title>
      <url>https://tistory1.daumcdn.net/tistory/3825108/attach/e7daf06cb51b4d959ac3411307127c3a</url>
      <link>https://algopoolja.tistory.com</link>
    </image>
    <item>
      <title>__init__.py 톺아보기</title>
      <link>https://algopoolja.tistory.com/137</link>
      <description>&lt;h2 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;들어가기 전에&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파이썬으로 작업할 때 종종 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 를 볼 때가 있습니다. &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;어떤 역할을 하는 것 인지 유추하기 위해 파일을 클릭해봐도 빈 파일이거나 알 수 없는 &lt;/span&gt;&lt;span&gt;__all__ = ['이상한', '문자열']&lt;/span&gt;&lt;span&gt; 등이 있거나&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;from .module import SomeClass&lt;/span&gt;&lt;span&gt; 와 같이 알 수 없는 import 를 하는 코드만 나와있습니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;어떤 역할을 하는 것인지 알 수 없어 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 의 역할을 톺아보는 시간을 이번 포스팅에서 갖겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 를 왜 사용할까?&lt;/span&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;디렉토리를 패키지로 인식 시키기 위해&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;많은 글들을 보면 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 를 사용하므로써 파이썬에게 디렉토리가 패키지임을 알려주는 파일이라고 합니다. 하지만 이런 설명은 패키지와 디렉토리와 같은 개념을 알아야 이해할 수 있습니다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;디렉토리는 파일 시스템의 폴더입니다. 예를들어 다음과 같은 구조가 있다고 가정해보겠습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;haskell&quot; style=&quot;background-color: #f8f8f8; text-align: left;&quot;&gt;&lt;code&gt;my_project/
 &amp;nbsp; &amp;nbsp;main.py
 &amp;nbsp; &amp;nbsp;utils.py
 &amp;nbsp; &amp;nbsp;data/
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;data.csv&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;여기서 &lt;/span&gt;&lt;span&gt;my_project&lt;/span&gt;&lt;span&gt; 와 &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; 폴더는 디렉토리 입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span&gt;패키지&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;my_project&lt;/span&gt;&lt;span&gt; 에 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 가 추가되었습니다. 이제 &lt;/span&gt;&lt;span&gt;my_project&lt;/span&gt;&lt;span&gt; 는 패키지가 됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 가 붙으나 마나 그게 무슨 상관인데?&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;파이썬 3.3 이전 버전에서는 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 를 가 붙지 않은 디렉토리의 모듈을 사용하려고 하면 에러가 발생하였습니다. 예를들어 다음과 같은 코드가 있다고 가정해보겠습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;background-color: #f8f8f8; text-align: left;&quot;&gt;&lt;span&gt;my_package/&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; module_a.py&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; module_b.py&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;3.3 이전 버전에서는 다음 코드를 실행하면 에러가 발생합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;background-color: #f8f8f8; text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;my_package&lt;/span&gt; &lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;module_a&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ModuleNotFoundError&lt;/span&gt;: &lt;span style=&quot;color: #000000;&quot;&gt;No&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;named&lt;/span&gt; &lt;span style=&quot;color: #aa1111;&quot;&gt;'my_package'&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;background-color: #f8f8f8; text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;my_project&lt;/span&gt;&lt;span style=&quot;color: #981a1a;&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;__init__&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;main&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;utils&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color: #981a1a;&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;data&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;csv&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;디렉토리&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #333333; text-align: left;&quot;&gt;&lt;code&gt;하지만 3.3 이상 버전부터는 `__init__.py` 가 없어도 파이썬이 패키지로 인식하기 때문에 문제가 없습니다. 단, 하위 호환성을 위해 이런 컨벤션을 지 키기도 합니다.(그런데 3.3 이전 버전을 어떤 이유로 쓰실까요 ㅎㅎ. 크리티컬한 문제가 아니면 빠르게 업데이트 하시는게 좋을지도.....?)
​
따라서 1번의 이유는 3.3 이하 버전에만 해당 하는 설명입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;패키지 수준 변수 및 함수 정의&lt;/span&gt;&lt;span&gt;예시로 다음의 코드를 들 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;background-color: #f8f8f8; text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #aa5500;&quot;&gt;# 폴더 구조&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;circle&lt;/span&gt;&lt;span style=&quot;color: #981a1a;&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;__init__&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;area&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;main&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #aa5500;&quot;&gt;# __init__.py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #3300aa;&quot;&gt;print&lt;/span&gt;(&lt;span style=&quot;color: #aa1111;&quot;&gt;&quot;CIRCLE IS INITIALIZED!&quot;&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;RADIUS&lt;/span&gt; &lt;span style=&quot;color: #981a1a;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #116644;&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;PI&lt;/span&gt; &lt;span style=&quot;color: #981a1a;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #116644;&quot;&gt;3.14&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #aa5500;&quot;&gt;# area.py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;circle&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;print_area&lt;/span&gt;():&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp;&lt;span style=&quot;color: #3300aa;&quot;&gt;print&lt;/span&gt;(&lt;span style=&quot;color: #000000;&quot;&gt;RADIUS&lt;/span&gt;&lt;span style=&quot;color: #981a1a;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;RADIUS&lt;/span&gt;&lt;span style=&quot;color: #981a1a;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;PI&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #aa5500;&quot;&gt;# main.py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;circle&lt;/span&gt; &lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;print_area&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;print_area&lt;/span&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #aa5500;&quot;&gt;# output&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #aa1111;&quot;&gt;&quot;CIRCLE IS INITIALIZED!&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #116644;&quot;&gt;28.26&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 파일 내에서 패키지 수준의 변수나 함수를 정의할 수 있으며, 패키지를 임포트 하거나 패키지 하위의 서브 패키지 및 모듈을 임포트할 때 초기화 됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;하위 모듈의 임포트 제어&lt;/span&gt;&lt;span&gt;패키지 구조와 코드가 다음처럼 되어 있다고 해보겠습니다.&lt;/span&gt;&lt;span&gt;만약 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 에 아무것도 추가해주지 않았다면 다음처럼 사용해야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;background-color: #f8f8f8; text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;my_package&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;module_a&lt;/span&gt; &lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;function_a&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;my_package&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;module_b&lt;/span&gt; &lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;function_b&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;background-color: #f8f8f8; text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;my_package&lt;/span&gt;&lt;span style=&quot;color: #981a1a;&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;__init__&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;module_a&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;module_b&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;main&lt;/span&gt;.&lt;span style=&quot;color: #000000;&quot;&gt;py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #aa5500;&quot;&gt;# __init__.py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;from&lt;/span&gt; .&lt;span style=&quot;color: #000000;&quot;&gt;module_a&lt;/span&gt; &lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;function_a&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;from&lt;/span&gt; .&lt;span style=&quot;color: #000000;&quot;&gt;module_b&lt;/span&gt; &lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;function_b&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;__all__&lt;/span&gt; &lt;span style=&quot;color: #981a1a;&quot;&gt;=&lt;/span&gt; [&lt;span style=&quot;color: #aa1111;&quot;&gt;'function_a'&lt;/span&gt;, &lt;span style=&quot;color: #aa1111;&quot;&gt;'function_b'&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #aa5500;&quot;&gt;# main.py&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #770088;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;my_package&lt;/span&gt; &lt;span style=&quot;color: #770088;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #000000;&quot;&gt;function_a&lt;/span&gt;, &lt;span style=&quot;color: #000000;&quot;&gt;function_b&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 파일을 사용하면 패키지 내의 특정 모듈만 외부로 노출시킬 수 있습니다. 이를 통해 패키지의 내부 구조를 숨기고 API 를 깔끔하게 유지할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 를 왜 사용하는지 알아보았습니다. 추가적으로 &lt;/span&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;span&gt; 에 자주 사용되는 &lt;/span&gt;&lt;span&gt;__all__&lt;/span&gt;&lt;span&gt; 을 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;__all__&lt;/span&gt;&lt;span&gt; 변수는 패키지 내의 모듈에서 &lt;/span&gt;&lt;span&gt;from &amp;lt;module&amp;gt; import *&lt;/span&gt;&lt;span&gt; 형태의 임포트를 수행할 때 어떤 심볼(변수, 함수, 클래스 등)이 임포트될지 지정하는 데 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;__all__&lt;/span&gt;&lt;span&gt; 변수는 문자열의 리스트로, 해당 모듈에서 임포트하고자 하는 심볼의 이름을 나열합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어, 아래와 같은 패키지 형태와 모듈이 있다고 가정해봅시다:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #333333; text-align: left;&quot;&gt;&lt;code&gt;my_package
├── __init__.py
└── my_module.py
main.py
​
# my_module.py
def function_a():
 &amp;nbsp; &amp;nbsp;print(&quot;function A&quot;)
​
def function_b():
 &amp;nbsp; &amp;nbsp;print(&quot;function B&quot;)
​
def function_c():
 &amp;nbsp; &amp;nbsp;print(&quot;function C&quot;)
 &amp;nbsp; &amp;nbsp;
# __init__.py
from .my_module import (function_a, function_b, function_c)
​
__all__ = [&quot;function_a&quot;, &quot;function_b&quot;]
​
# main.py
from my_package import *
​
function_a() &amp;nbsp;# 출력: Function A
function_b() &amp;nbsp;# 출력: Function B
function_c() &amp;nbsp;# NameError: name 'function_c' is not defined&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;__all__&lt;/span&gt;&lt;span&gt; 변수를 사용하면 모듈의 사용자가 임포트할 수 있는 심볼을 제한하거나 명확하게 지정할 수 있으므로, API를 깔끔하게 유지하고 내부 구현을 숨기는 데 유용합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>언어/파이썬</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/137</guid>
      <comments>https://algopoolja.tistory.com/137#entry137comment</comments>
      <pubDate>Sat, 12 Aug 2023 20:56:45 +0900</pubDate>
    </item>
    <item>
      <title>일간 Git(1)</title>
      <link>https://algopoolja.tistory.com/136</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;일간 Git(1)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;git clone 시 디렉터리 이름을 다른것으로 하고 싶을 때&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;**git clone  &amp;lt;원하는-이름&amp;gt;
ex. git clone &amp;lt;https://github.com/fightnyy/Algorithm&amp;gt; my-algorithm**
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;git diff 시 이미 staged 된 것을 보고 싶을 때&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;**git status --staged
git status --cached
# 둘이 같은 옵션**
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;git rm&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;**git rm = rm + git add
# 만약 로컬에 있는 파일은 그대로 두고 원격(github)에 있는 파일만 삭제하고 싶을 때
git rm &amp;lt;file_name&amp;gt; --cached
git commit -a -m &quot;commit message&quot;
git push**
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;git mv&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;**# file 이름 변경하기
git mv &amp;lt;from_file_name&amp;gt; &amp;lt;to_file_name&amp;gt; =
mv &amp;lt;from_file_name&amp;gt; &amp;lt;to_file_name&amp;gt; + git rm &amp;lt;from_file_name&amp;gt; + git add &amp;lt;to_file_name&amp;gt;**

&lt;/code&gt;&lt;/pre&gt;</description>
      <category>git</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/136</guid>
      <comments>https://algopoolja.tistory.com/136#entry136comment</comments>
      <pubDate>Thu, 30 Mar 2023 21:43:25 +0900</pubDate>
    </item>
    <item>
      <title>Mockk(relaxed = true) 는?</title>
      <link>https://algopoolja.tistory.com/135</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 코드를 짜다보면 특정 클래스의 메서드가 특정 방식이 반환되기를 기대할 때 종종 Mock을 이용해 테스트를 짭니다. 언어마다 여러가지 목킹 도구들이 있고, 그중 코틀린은 Mockk 가 주로 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코틀린의 테스트 코드를 보면 모킹을 다룰 때 mockk(relaxed = true) 로 되어있는것을 볼 수 있습니다. relaxed = true 를 파라미터로 줄 때와 그렇지 않을 때의 사용방법이 어떻게 다른지 비교해보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;relaxed = true&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;// Member.kt
@Entity
class Member(
 &amp;nbsp; &amp;nbsp;@Column(name = &quot;name&quot;)
 &amp;nbsp; &amp;nbsp;val name: String,
) {
 &amp;nbsp; &amp;nbsp;@Id
 &amp;nbsp; &amp;nbsp;@GeneratedValue(strategy = GenerationType.IDENTITY)
 &amp;nbsp; &amp;nbsp;private val id: Long? = null

 &amp;nbsp; &amp;nbsp;@Column(name = &quot;deleted_at&quot;)
 &amp;nbsp; &amp;nbsp;private val deletedAt: String? = null
}

// PaymentService.kt
@Service
class PaymentService(private val memberRepository: MemberRepository) {

 &amp;nbsp; &amp;nbsp;fun getBoolean() = true
 &amp;nbsp; &amp;nbsp;fun getInt(): Int {
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 1
 &amp;nbsp;  }

 &amp;nbsp; &amp;nbsp;fun getString() = &quot;Hello&quot;

 &amp;nbsp; &amp;nbsp;fun getLong() = 1L

 &amp;nbsp; &amp;nbsp;fun getFloat() = 1.0f

 &amp;nbsp; &amp;nbsp;fun getMember() = Member(&quot;fightnyy&quot;)

 &amp;nbsp; &amp;nbsp;fun saveMemberFromDB(): Member {
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return memberRepository.save(Member(&quot;fightnyy&quot;))
 &amp;nbsp;  }
}

// MockTest.kt
@SpringBootTest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
class MockTest {

 &amp;nbsp; &amp;nbsp;val paymentService = mockk&amp;lt;PaymentService&amp;gt;(relaxed = true)

 &amp;nbsp; &amp;nbsp;@Test
 &amp;nbsp; &amp;nbsp;@DisplayName(&quot;Mock Test&quot;)
 &amp;nbsp; &amp;nbsp;fun testLong(): Any {
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;every { memberRepository.save(any()) } returns Member(&quot;Nice&quot;)

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of Boolean : &quot; + paymentService.getBoolean()) // false

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of Long! : &quot; + paymentService.getLong()) // 0

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of Int : &quot; + paymentService.getInt()) // 0

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of String : &quot; + paymentService.getString()) // &quot;&quot;

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of String is same as empty? : &quot; + paymentService.getString().isEmpty()) // true

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of Float : &quot; + paymentService.getFloat()) // 0.0

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of Member : &quot; + paymentService.getMember()) // Member(child of #2#4)

 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;result of Member from DB : &quot; + paymentService.saveMemberFromDB()) // Member(child of #2#5)
 &amp;nbsp; &amp;nbsp; &amp;nbsp;// 여기서 반환되는 Member의 값은 name = &quot;&quot;, id = 0, deleted_at = &quot;&quot; 입니다.
 &amp;nbsp;  }
}
&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;relaxed = true 옵션을 주게 되면 primitive 값들은 모두 기본값(0, false, &quot;&quot;)을 반환하게 됩니다. 또한 클래스의 경우에는 chained mocks 리턴됩니다.(Member(child of #2#4) 같은 형식인데 클래스 내부 primitive 값들은 모두 기본값들을 반환합니다.)&lt;/li&gt;
&lt;li&gt;만약 relaxed = true 옵션을 주지 않게 되면 어떤일이 벌어질까요?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;no answer found for: ...... 와 같은 형식의 에러 로그로 반환됩니다. 즉 목킹은 했는데 해당 목킹에 반환 값을 적용해주지 않았다는 의미입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;relaxUnitFun = true&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 옵션은 Unit 으로 반환되는 함수들만 목킹합니다. 위의 paymentService 에 함수를 하나 추가해보겠습니다.&lt;/li&gt;
&lt;li&gt;해당 함수는 relaxUnitFun = true 옵션을 줘도 되고 relaxed = true 옵션을 줘도 테스트가 통과하지만, 어떠한 파라미터도 주지 않은 경우는 다시 no answer found for: ....... 로그가 나옵니다.&lt;/li&gt;
&lt;li&gt;relaxUnitFun 은 반환타입이 Unit 인(즉, 함수가 아무것도 반환되지 않는 경우) 함수만 테스트에 모킹된 것처럼 동작합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1690760484067&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service class PaymentService(
    private val memberRepository: MemberRepository)
){ 
    // ... fun unitFunction(): Unit {        println(&quot;unitFunction&quot;)   } 
 }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>언어/Kotlin</category>
      <category>Kotlin</category>
      <category>mockk</category>
      <category>relaxedUnitFun</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/135</guid>
      <comments>https://algopoolja.tistory.com/135#entry135comment</comments>
      <pubDate>Mon, 13 Mar 2023 23:00:24 +0900</pubDate>
    </item>
    <item>
      <title>비콘체인</title>
      <link>https://algopoolja.tistory.com/134</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;비콘 체인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인은 이더리움 생태계에 지분 증명(Proof-of-Stake)을 도입했습니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;비콘체인은 2022년 9월에 기존 이더리움 작업 증명(Proof-of-Work) 체인과 합병되었습니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;비콘 체인은 현재의 이더리움을 보호하는 합의 로직과 블록 가십 프로토콜을 도입했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인은 2020년 12월 1일에 출시되었으며, 2022년 9월 15일에 더 머지 업그레이드를 통해 이더리움의 합의 메커니즘으로 지분 증명을 공식화했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;비콘 체인이 무엇인가요?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인은 2020년에 출시된 최초의 지분 증명 블록체인의 이름입니다. 이더리움 메인넷에서 지분 증명(Proof-of-Stake) 합의 로직을 활성화하기 전에 지속 가능하고 나이스한 방식인지 확인하기 위해 만들어졌습니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;따라서 기존 작업 증명(Proof-of-Work) 이더리움과 함께 운영되었습니다. 이더리움에서 작업 증명 방식을 종료하고 지분 증명 방식으로 운영하려면 비콘 체인에 원래 이더리움 체인에서 온 트랜잭션을 수락하고 해당 트랜잭션들을 블록으로 묶은 후, 지분 증명(Proof-of-Stake) 기반 합의 메커니즘을 사용하여 블록체인을 구성하도록 해야했습니다. 동시에 기존 이더리움 클라이언트는 채굴, 블록 전파, 합의 로직을 모두 종료하고 이 권한을 비콘 체인에 넘겨주었습니다. 이 이벤트는 The Merge로 알려졌습니다. The Merge 후 더 이상 두 개의 블록체인이 아닌 하나의 지분 증명 이더리움 체인만 존재하게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;비콘 체인이 어떤 역할을 했나요?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인은 이더리움 소유자가 실제 이더리움 트랜잭션의 유효성을 검사하기 전에 이더리움 staker 네트워크를 관리하고 조정하는 계정 원장에 부여된 이름입니다. 비콘체인은 트랜잭션을 처리하거나 스마트 콘트랙트를 처리하지 않았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인은 이더리움의 작업 증명 마이닝을 대신하는 합의 엔진(또는 &quot;합의 레이어&quot;)을 도입했으며, 이를 통해 많은 중요한 개선 사항을 가져왔습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인은 현재 안전하고 환경 친화적이며 확장 가능한 이더리움의 기본 구성 요소였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;비콘 체인이 가져온 효과&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;스테이킹 도입&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인은 이더리움에 지분 증명을 도입했습니다. 이를 통해 이더리움을 안전하게 보호하고 검증자는 이 과정에서 더 많은 이더를 획득할 수 있습니다. 실제로 스테이킹은 검증 프로그램을 활성화하기 위해 이더를 스테이킹해야 합니다. 이더리움 소유자는 체인에서 새로운 블록을 생성하고 검증하는 소프트웨어를 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스테이킹은 채굴과 비슷한 목적을 가지고 있지만, 여러 면에서 다릅니다. 채굴은 강력한 하드웨어와 에너지 소비를 통해 규모의 경제를 실현하고 중앙 집중화를 촉진하는 형태로 막대한 사전 지출을 필요로 했습니다. 또한 채굴에는 자산을 담보로 묶어둘 필요가 없었기 때문에 공격 후 악의적인 행위자를 처벌할 수 있는 프로토콜의 기능이 제한적이었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지분 증명으로의 전환으로 이더리움은 작업 증명에 비해 훨씬 더 안전하고 탈중앙화되었습니다. 네트워크에 참여하는 사람이 많을수록 네트워크는 더욱 탈중앙화되고 공격으로부터 안전해집니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;샤딩을 위한 설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비콘 체인이 오리지널 이더리움 메인넷과 합쳐진 이후, 이더리움 커뮤니티는 네트워크 확장을 모색하기 시작했습니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;지분 증명은 주어진 시간에 승인된 모든 블록 생산자의 레지스트리를 보유할 수 있다는 장점이 있으며, 각 블록 생산자는 이더를 걸고 있습니다. 이 레지스트리는 특정 네트워크 책임을 안정적으로 분할하고 처리할 수 있는 기반을 마련합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 책임은 채굴자가 네트워크에 대한 의무가 없고 아무런 영향 없이 순식간에 채굴을 중단하고 노드 소프트웨어를 영구적으로 끌 수 있는 작업 증명과는 대조적입니다. 또한 알려진 블록 제안자의 레지스트리가 없으며 네트워크 책임을 안전하게 분할할 수 있는 신뢰할 수 있는 방법도 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;샤딩&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;샤딩은 데이터베이스를 수평으로 분할하여 부하를 분산하는 프로세스입니다. 이더리움 맥락에서 샤딩은 &quot;샤드&quot;로 알려진 새로운 체인을 생성하여 네트워크 혼잡을 줄이고 초당 트랜잭션을 증가시킵니다. 또한 네트워크에서 모든 트랜잭션 전체를 처리하지 않아도 되는 각 검증자의 부하를 경감할 수 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Web3</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/134</guid>
      <comments>https://algopoolja.tistory.com/134#entry134comment</comments>
      <pubDate>Tue, 7 Mar 2023 19:43:02 +0900</pubDate>
    </item>
    <item>
      <title>Spring delete 메소드 주의사항</title>
      <link>https://algopoolja.tistory.com/133</link>
      <description>&lt;h1&gt;&lt;span&gt;Delete 쿼리 종류&lt;/span&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;TL;DR&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;속도 측면에서는 &lt;/span&gt;&lt;span&gt;deleteAllInBatch()&lt;/span&gt;&lt;span&gt; 가 가장 빠르다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;test 코드를 제외하고는 &lt;/span&gt;&lt;span&gt;deleteAllInBatch()&lt;/span&gt;&lt;span&gt; 를 사용하지 말자&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;delete(entity)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 메서드는 &lt;/span&gt;&lt;span&gt;CrudRepository&lt;/span&gt;&lt;span&gt; 에 등록되어 있는 메서드 입니다. 엔티티를 파라미터로 받아 해당 엔티티를 삭제합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;deleteAll()&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 메서드는 &lt;/span&gt;&lt;span&gt;CrudRepository&lt;/span&gt;&lt;span&gt; 에 등록되어 있는 메서드로 해당 레포지토리에서 관리 되는 모든 entity 를 삭제합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;deleteAllInBatch()&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 메서드는 &lt;/span&gt;&lt;span&gt;JpaRepository&lt;/span&gt;&lt;span&gt; 에 등록되어 있는 메서드로 모든 entity 를 한번의 함수 실행으로 삭제합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;예시&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;코드의 예시로 설명해보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예시로 다룰 엔티티는 &lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt; 로 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Where(clause = &quot;deleted_at is null&quot;)
@SQLDelete(sql = &quot;update member set deleted_at = now() where id = ?&quot;)
@Entity
class Member(
 &amp;nbsp; &amp;nbsp;@Column(name = &quot;name&quot;)
 &amp;nbsp; &amp;nbsp;val name: String,
) {
 &amp;nbsp; &amp;nbsp;@Id
 &amp;nbsp; &amp;nbsp;@GeneratedValue(strategy = GenerationType.IDENTITY)
 &amp;nbsp; &amp;nbsp;private val id: Long? = null
​
 &amp;nbsp; &amp;nbsp;@Column(name = &quot;deleted_at&quot;)
 &amp;nbsp; &amp;nbsp;private val deletedAt: String? = null
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@SpringBootTest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
class MemberRepositoryTest(
 &amp;nbsp; &amp;nbsp;val memberRepository: MemberRepository,
) {
 &amp;nbsp; &amp;nbsp;@Test
 &amp;nbsp; &amp;nbsp;@DisplayName(&quot;멤버 삭제&quot;)
 &amp;nbsp; &amp;nbsp;fun deleteMember() {
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------MemberSave START---------------------&quot;)
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;val member = memberRepository.save(MemberFactory.of(&quot;test&quot;))
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;val member2 = memberRepository.save(MemberFactory.of(&quot;test&quot;))
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;val member3 = memberRepository.save(MemberFactory.of(&quot;test&quot;))
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------MemberSave END---------------------&quot;)
​
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------Member DELETE START---------------------&quot;)
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;memberRepository.delete(member)
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------Member DELETE END---------------------&quot;)
​
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------Member DELETE ALL START---------------------&quot;)
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;memberRepository.deleteAll()
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------Member DELETE ALL END---------------------&quot;)
​
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------Member DELETE ALL IN BATCH START---------------------&quot;)
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;memberRepository.deleteAllInBatch()
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;println(&quot;---------------------Member DELETE ALL IN BATCH END---------------------&quot;)
 &amp;nbsp;  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;---------------------MemberSave START---------------------
Hibernate: 
 &amp;nbsp;  insert 
 &amp;nbsp;  into
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  (deleted_at, name) 
 &amp;nbsp;  values
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  (?, ?)
Hibernate: 
 &amp;nbsp;  insert 
 &amp;nbsp;  into
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  (deleted_at, name) 
 &amp;nbsp;  values
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  (?, ?)
Hibernate: 
 &amp;nbsp;  insert 
 &amp;nbsp;  into
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  (deleted_at, name) 
 &amp;nbsp;  values
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  (?, ?)
---------------------MemberSave END---------------------
​
​
​
---------------------Member DELETE START---------------------
Hibernate: 
 &amp;nbsp;  select
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.id as id1_0_0_,
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.deleted_at as deleted_2_0_0_,
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.name as name3_0_0_ 
 &amp;nbsp;  from
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member member0_ 
 &amp;nbsp;  where
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.id=? 
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  and (
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.deleted_at is null
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  )
Hibernate: 
 &amp;nbsp;  update
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member 
 &amp;nbsp; &amp;nbsp;set
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  deleted_at = now() 
 &amp;nbsp;  where
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  id = ?
---------------------Member DELETE END---------------------
​
​
​
---------------------Member DELETE ALL START---------------------
Hibernate: 
 &amp;nbsp;  select
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.id as id1_0_,
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.deleted_at as deleted_2_0_,
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.name as name3_0_ 
 &amp;nbsp;  from
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member member0_ 
 &amp;nbsp;  where
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  (
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  member0_.deleted_at is null
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  )
Hibernate: 
 &amp;nbsp;  update
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member 
 &amp;nbsp; &amp;nbsp;set
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  deleted_at = now() 
 &amp;nbsp;  where
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  id = ?
Hibernate: 
 &amp;nbsp;  update
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member 
 &amp;nbsp; &amp;nbsp;set
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  deleted_at = now() 
 &amp;nbsp;  where
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  id = ?
---------------------Member DELETE ALL END---------------------
​
​
​
---------------------Member DELETE ALL IN BATCH START---------------------
Hibernate: 
 &amp;nbsp;  delete 
 &amp;nbsp;  from
 &amp;nbsp; &amp;nbsp; &amp;nbsp;  member
---------------------Member DELETE ALL IN BATCH END---------------------
​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;코드의 결과를 살펴보면 &lt;/span&gt;&lt;span&gt;delete(entity) 와 deleteAll()&lt;/span&gt;&lt;span&gt; 는 soft delete 가 잘 작동하는 것을 확인할 수 있습니다. 또한 &lt;/span&gt;&lt;span&gt;deleteAll()&lt;/span&gt;&lt;span&gt; 은 하나의 레코드마다 하나의 &lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt; 쿼리가 생성되는것을 확인할 수 있습니다. 하지만 &lt;/span&gt;&lt;span&gt;deleteAllInBatch()&lt;/span&gt;&lt;span&gt; 는 모든 레코드는 hard delete 하는것을 확인할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 속도를 위해 &lt;/span&gt;&lt;span&gt;deleteAllInBatch()&lt;/span&gt;&lt;span&gt; 를 사용할 수 있지만 비즈니스 로직에서 쓰는것은 hard delete 할 일이 아닌 이상 매우 경계하면서 사용해야 합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>Kotlin</category>
      <category>Spring</category>
      <category>Test</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/133</guid>
      <comments>https://algopoolja.tistory.com/133#entry133comment</comments>
      <pubDate>Tue, 14 Feb 2023 22:33:37 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin 에서 Spring 으로 테스트할 때 주의사항</title>
      <link>https://algopoolja.tistory.com/132</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;문제 상황&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;kotlin 에서 JUnit 을 사용하여 테스트를 구성했지만 &lt;/span&gt;&lt;span&gt;org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter&lt;/span&gt;&lt;span&gt; 오류가 발생했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span style=&quot;color: #b8bfc6;&quot;&gt;@SpringBootTest&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #c88fd0;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #8d8df0;&quot;&gt;MemberRepositoryTest&lt;/span&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #c88fd0;&quot;&gt;val&lt;/span&gt; &lt;span style=&quot;color: #8d8df0;&quot;&gt;memberRepository&lt;/span&gt;: &lt;span style=&quot;color: #b8bfc6;&quot;&gt;MemberRepository&lt;/span&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #b8bfc6;&quot;&gt;@Test&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #b8bfc6;&quot;&gt;@DisplayName&lt;/span&gt;(&lt;span style=&quot;color: #d26b6b;&quot;&gt;&quot;멤버 삭제&quot;&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #c88fd0;&quot;&gt;fun&lt;/span&gt; &lt;span style=&quot;color: #8d8df0;&quot;&gt;deleteMember&lt;/span&gt;() { &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #c88fd0;&quot;&gt;val&lt;/span&gt; &lt;span style=&quot;color: #8d8df0;&quot;&gt;member&lt;/span&gt; &lt;span style=&quot;color: #b8bfc6;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #b8bfc6;&quot;&gt;memberRepository&lt;/span&gt;.&lt;span style=&quot;color: #b8bfc6;&quot;&gt;save&lt;/span&gt;(&lt;span style=&quot;color: #b8bfc6;&quot;&gt;MemberFactory&lt;/span&gt;.&lt;span style=&quot;color: #b8bfc6;&quot;&gt;of&lt;/span&gt;(&lt;span style=&quot;color: #d26b6b;&quot;&gt;&quot;test&quot;&lt;/span&gt;)) &amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #b8bfc6;&quot;&gt;memberRepository&lt;/span&gt;.&lt;span style=&quot;color: #b8bfc6;&quot;&gt;delete&lt;/span&gt;(&lt;span style=&quot;color: #b8bfc6;&quot;&gt;member&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;해결 방법&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우선 &lt;/span&gt;&lt;span&gt;junit.jupiter&lt;/span&gt;&lt;span&gt; 에서 궁금한 점이 생겼습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Junit 5&lt;/span&gt;&lt;span&gt; 의 경우 크게 3가지 부분으로 이루어져 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Jupiter&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;JUnit platform 을 구현한 구현체로, JUnit 5의 구현체입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Vintage&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;JUnit platform 을 구현한 구현체로, JUnit3, 4 의 구현체 입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JUnit Platform&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;실행할 수 있는 엔진을 포함하고 여러 도구에 일관성있는 API 를 제공합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그다음 &lt;/span&gt;&lt;span&gt;ParameterResolver&lt;/span&gt;&lt;span&gt; 의 역할이 궁금했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생성자 매개변수의 경우 &lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt; 패키지에 있는 코드들은 Spring IoC 컨테이너가 이를 해결합니다. 하지만 &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt; 패키지에서는 생성자 매개변수 관리를 &lt;/span&gt;&lt;span&gt;Jupiter&lt;/span&gt;&lt;span&gt; 가 담당하게 됩니다. 그래서 &lt;/span&gt;&lt;span&gt;@Autowired&lt;/span&gt;&lt;span&gt; 를 명시적으로 선언해주어야 &lt;/span&gt;&lt;span&gt;Jupiter&lt;/span&gt;&lt;span&gt; 가 Spring Contrainer 에게 빈 주입을 요청 할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테스트 프레임워크에서 프레임워크의 주체는 &lt;/span&gt;&lt;span&gt;Jupiter&lt;/span&gt;&lt;span&gt; 이기 때문에 생성자 주입이라 한들 &lt;/span&gt;&lt;span&gt;@Autowired&lt;/span&gt;&lt;span&gt; 애노테이션이 명시되지 않은 객체는 의존성 주입을 받을 수 없게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Jupiter&lt;/span&gt;&lt;span&gt; 는 생성자 매개변수를 처리할 &lt;/span&gt;&lt;span&gt;ParameterResolver&lt;/span&gt;&lt;span&gt; 를 찾지만 이를 다룰 수 있는 &lt;/span&gt;&lt;span&gt;ParameterResolver&lt;/span&gt;&lt;span&gt; 를 찾을 수 없고, 예외를 던지게 됩니다. 따라서 &lt;/span&gt;&lt;span&gt;@Autowired&lt;/span&gt;&lt;span&gt; 를 사용해 &lt;/span&gt;&lt;span&gt;Jupiter&lt;/span&gt;&lt;span&gt;가 Spring Container 에게 빈 주입을 요청하도록 &lt;/span&gt;&lt;span&gt;@Autowired&lt;/span&gt;&lt;span&gt; 애노테이션을 추가하면 해결됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@SpringBootTest
class MemberRepositoryTest @Autowired constructor(
 &amp;nbsp; &amp;nbsp;val memberRepository: MemberRepository,
) {
 &amp;nbsp; &amp;nbsp;@Test
 &amp;nbsp; &amp;nbsp;@DisplayName(&quot;멤버 삭제&quot;)
 &amp;nbsp; &amp;nbsp;fun deleteMember() { &amp;nbsp; &amp;nbsp;
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;val member = memberRepository.save(MemberFactory.of(&quot;test&quot;)) &amp;nbsp; 
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;memberRepository.delete(member)
 &amp;nbsp;  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;향상된 방법&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JUnit5 부터는 생성자를 통한 의존관계 주입이 가능해졌습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Spring 에서 제공하는 &lt;/span&gt;&lt;span&gt;@TestConstructor&lt;/span&gt;&lt;span&gt; 애노테이션을 사용하면 됩니다. 이를 사용하면 테스트 클래스 생성자에 들어있는 필드들에 의존관계를 주입해 줄 수 있습니다. 주입해줄 수 있는 방법은 크게 2가지 방법이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;ALL&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;테스트 생성자의 모든 파라미터는 자동 주입이 됩니다.(생성자의 모든 파라미터에 &lt;/span&gt;&lt;span&gt;@Autowired&lt;/span&gt;&lt;span&gt; 가 붙어있다고 생각하면 편합니다.)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;ANNOTATED&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;@Autowired, @Qualifer, @Value&lt;/span&gt;&lt;span&gt; 로 어노테이션이 붙어져 있는 생성자 필드에 대해 각각이 자동 주입됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@SpringBootTest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
class MemberRepositoryTest (
 &amp;nbsp; &amp;nbsp;val memberRepository: MemberRepository,
) {
 &amp;nbsp; &amp;nbsp;@Test
 &amp;nbsp; &amp;nbsp;@DisplayName(&quot;멤버 삭제&quot;)
 &amp;nbsp; &amp;nbsp;fun deleteMember() { &amp;nbsp; &amp;nbsp;
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;val member = memberRepository.save(MemberFactory.of(&quot;test&quot;)) &amp;nbsp; 
 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;memberRepository.delete(member)
 &amp;nbsp;  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Spring</category>
      <category>Kotlin</category>
      <category>Spring</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/132</guid>
      <comments>https://algopoolja.tistory.com/132#entry132comment</comments>
      <pubDate>Tue, 14 Feb 2023 20:19:13 +0900</pubDate>
    </item>
    <item>
      <title>데이터 중심 애플리케이션 설계</title>
      <link>https://algopoolja.tistory.com/131</link>
      <description>&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;요약&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;분산시스템에서 일어날 수 있는 문제들&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;네트워크로 패킷을 보낼땐 패킷은 손실되거나 임의대로 지연될 수 있다는 것을 항상 기억 해야 합니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;분산 시스템에 올라간 노드는 서로의 시간이 일치하지 않을 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;노드의 응답 시간은 상당기간 동안 반환 되지 않을 수 있습니다. 이 경우, 다른 노드에 의해 죽었다고 판단될 수 해당 노드는 재시작 될 수도 있습니다. 다시 살아났더라도 멈췄다는 사실을 알지 못할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;부분 실패&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 가 생길 수 있다는 사실이 분산 시스템의 뚜렷한 특성입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대부분의 시스템은 노드에 장애가 발생했는지 알 수 있는 정확한 메커니즘이 없어서 대부분의 분산 알고리즘은 원격 노드를 아직 쓸 수 있는 지 결정하기 위해 타임아웃을 사용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;단일 노드에서는 오히려 이런 합의 알고리즘등을 생각하지 않아도 되니 여러가지 이점이 있을 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 단일 노드에서는 장애가 발생했을 때 서비스 자체가 멈추는 문제도 발생하고, 짧은 지연 시간의 문제를 해결할 수 없다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;9장에서는 이런 분산시트엠의 문제에 대처하도록 설계된 알고리즘을 살펴봅니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;추가로 알아보면 좋을 것들&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;노드끼리의 시간은 어떻게 공유 될 수 있을까? &lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;NTP 라는 프로토콜이 있는걸 확인했는데 이 방법에 대해 확인해보면 좋을 듯 하다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>책/데이터 중심 애플리케이션 설계</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/131</guid>
      <comments>https://algopoolja.tistory.com/131#entry131comment</comments>
      <pubDate>Sun, 12 Feb 2023 20:35:34 +0900</pubDate>
    </item>
    <item>
      <title>회복탄력성</title>
      <link>https://algopoolja.tistory.com/130</link>
      <description>&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최근 정말 운이 좋게 정말 좋은 분들을 많이 만났습니다. &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;그 중 한분에게 제가 가지고 있는 미래에 대한 막연한 불안감과 현재 가지고 있는 불안감을 얘기 했을 때 그 분께서 김주환 교수님의 영상을 추천해주셨습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사실 교수님께서 하시는 말씀이 &lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GWFxAk1doqE&amp;amp;t=414s&quot;&gt;&lt;span&gt;영상&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;span&gt;으로는 잘 이해되지 않았습니다. 하지만 얼핏 들은 키워드로 도움이 많이 될 수 있을 거 같다는 생각으로 교수님의 저서중 하나인 회복 탄력성을 구매해 읽게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;살아가면서 개인적으로 이런생각을 많이 했습니다. &quot;수능만 끝나면 내 인생은 행복할거야&quot;, &quot;군대만 제대하면 내 인생은 행복할거야&quot;, &quot;취업만 되면 내 인생은 행복할거야&quot; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사실 이 말도 맞는 말이라고 생각합니다. 실제로 이 일들이 일어났을때 저는 너무 행복했고 많이 웃고 다녔습니다. 하지만 이런 행복감은 긴 시간 동안 행복을 유지해 주진 않았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;책에서 말하고자 하는 긍정적인 생각이 삶 전반에 많은 영향을 주며, 실질적으로 퍼포먼스를 개선하는 수치화된 많은 연구 결과를 보여주면서 의식적으로 긍정적인 마인드를 가져야 한다는 것에 깊은 공감을 할 수 있었습니다. 또한, 어떻게 해야 긍정적인 마인드를 가질 수 있는 알려주는 훈련법도 쓰여져 있습니다.(감사 일기, 운동, 의식적인 훈련) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;방금 막 책을 읽고 나와서 제 의식이 어떻게 변화하는지는 더 훈련을 해봐야 알 수 있을거 같습니다. 하지만 제가 갖고 있던 부끄러운 고정관념들을 깨주는 책이자, 곰돌이 푸가 말했던 &quot;매일 행복하지는 않지만, 행복한 일은 매일 있어&quot; 를 이해하게 된 책입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 책을 알게해준 그 분께 매우 깊은 감사를 드리며, 이 책을 이번년 처음으로 읽게 되어 너무나 좋은 경험이었습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>읽은 책들</category>
      <category>annotation</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/130</guid>
      <comments>https://algopoolja.tistory.com/130#entry130comment</comments>
      <pubDate>Tue, 10 Jan 2023 20:44:29 +0900</pubDate>
    </item>
    <item>
      <title>하루의 3단계</title>
      <link>https://algopoolja.tistory.com/129</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫번째 단계(기상 후 6 - 9 시간) 8 - 9 시간 동안 최대한 주변을 밝게 유지하자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두번째 단계(기상 후 9 -16시간)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;빛을 서서히 어둡게 하는 게 필요&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;노출되는 청색광을 점점 줄여야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막 단계(기상후 16 - 24시간)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;빛을 최소한으로 줄여야합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;그렇지 않으면 일상에 많은 피해를 입게됩니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;하지만 어쩔 수 없이 밤을 새워 일해야 하고 최대한의 집중을 원한다면 최대한 밝게 해주는 것이 좋습니다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각성제 없이 깨어있는 팁은 다음과 같습니다. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-mark=&quot;*&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;1리터 정도의 물을 마신 후에 90분간 화장실에 가지 않는 것입니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;방광이 뇌로 화장실을 가고 싶다는 신호를 보내며 각성하게 되는 것입니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;불을 최대한 킵니다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>잘 사는법</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/129</guid>
      <comments>https://algopoolja.tistory.com/129#entry129comment</comments>
      <pubDate>Thu, 29 Dec 2022 21:52:44 +0900</pubDate>
    </item>
    <item>
      <title>Copy On Write (COW) 란?</title>
      <link>https://algopoolja.tistory.com/128</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Copy On Write는 A라는 변수에 B라는 변수를 할당해주었을 때, 새로 메모리에 할당하는 것이 아니라, B의 메모리를 A가 공유하는 형태로 구성됩니다. 그러다가 A가 값이 수정될 때 새로 메모리에 할당이 되는 식으로 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 코드로 보면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;std::string x(&quot;Hello&quot;);
std::string y = x; // x, y 는 같은 버퍼를 사용합니다.
y += &quot; World&quot;; // y 에 값이 변경 되었으므로 y 는 다른 버퍼를 사용합니다. &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>운영체제</category>
      <category>Copy On Write</category>
      <category>cow</category>
      <author>AlgoPoolJa</author>
      <guid isPermaLink="true">https://algopoolja.tistory.com/128</guid>
      <comments>https://algopoolja.tistory.com/128#entry128comment</comments>
      <pubDate>Sun, 18 Dec 2022 21:12:44 +0900</pubDate>
    </item>
  </channel>
</rss>