<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rungsikorn Rungsikavanich</title>
    <description>The latest articles on Forem by Rungsikorn Rungsikavanich (@zapkub).</description>
    <link>https://forem.com/zapkub</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F340542%2F804007fb-d76f-41ee-817c-bce1f59474b3.jpg</url>
      <title>Forem: Rungsikorn Rungsikavanich</title>
      <link>https://forem.com/zapkub</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zapkub"/>
    <language>en</language>
    <item>
      <title>ใช้ node module 2 version ใน project เดียวกัน</title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Fri, 17 Jun 2022 17:43:42 +0000</pubDate>
      <link>https://forem.com/zapkub/aich-node-module-2-version-ain-project-ediiywkan-1gi9</link>
      <guid>https://forem.com/zapkub/aich-node-module-2-version-ain-project-ediiywkan-1gi9</guid>
      <description>&lt;p&gt;วันนี้เล่านิดหน่อย เรื่องทำยังไงถึงจะใช้ node module อันเดียวกัน แต่ 2 version ได้ ภายใน project เดียว&lt;/p&gt;

&lt;p&gt;ไปเจอว่าถ้าใช้ &lt;code&gt;lerna&lt;/code&gt; จะทำให้ node module ของแต่ละ sub packages ใช้ version แยกกันได้ ตามภาพเลยเด้อ (จะเห็นว่า ซ้ายใช้ &lt;code&gt;spl-token@0.1.8&lt;/code&gt; แต่อีกด้านใช้ &lt;code&gt;spl-token@0.2.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lmF-rRp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aa9lr7l44z7oqo04jcj4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lmF-rRp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aa9lr7l44z7oqo04jcj4.png" alt="2 packages" width="880" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;พอใช้งานรันจริงก็จะเห็นว่า มันเรียกใช้ node module ของใครของมัน ถึงแม้ว่าจะ link deps เข้าหากันก็ตาม&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ptmWGCkJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ifiry5sj4pnn8w3v1yx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ptmWGCkJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ifiry5sj4pnn8w3v1yx.png" alt="2 deps version calling" width="880" height="1174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;วิธีใช้ก็แค่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lerna add @solana/spl-token@0.1.8 --scope=module-a
lerna add @solana/spl-token@0.2.0 --scope=module-b
lerna link
lerna add module-a --scope=module-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reference
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lerna/lerna"&gt;https://github.com/lerna/lerna&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;😎 😎 😎 😎&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>lerna</category>
    </item>
    <item>
      <title>STOP USING window as any</title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Mon, 09 May 2022 10:06:42 +0000</pubDate>
      <link>https://forem.com/zapkub/stop-using-window-as-any-41i1</link>
      <guid>https://forem.com/zapkub/stop-using-window-as-any-41i1</guid>
      <description>&lt;h3&gt;
  
  
  TLDR;
&lt;/h3&gt;

&lt;p&gt;for someone who have a limit of time&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// instead of this&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;MY_GREETING_MESSAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi Earth!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// do this&lt;/span&gt;
&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Window&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
         &lt;span class="nl"&gt;MY_GREETING_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MY_GREETING_MESSAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi Earth!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;You guys typescripter might came across the situation that you need to put something into a global scope variable like &lt;code&gt;window&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;javascript&lt;/code&gt; you may easily put something into it without any complicated step like.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// running in browser&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MY_GREETING_MESSAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi Earth!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;but as Typescript which will do some type checking if any object attribute you are working on is really existed in the view of the static type language. you will be forbidden to do this directly.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MY_GREETING_MESSAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi Earth!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// ^^&lt;/span&gt;
&lt;span class="c1"&gt;// Property 'MY_GREETING_MESSAGE' does not exist on type 'Window &amp;amp; typeof globalThis'.ts(2339)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;The answer is pretty straight, because the interface &lt;code&gt;Window&lt;/code&gt; which declare for this global &lt;code&gt;window&lt;/code&gt; variable does not have &lt;code&gt;MY_GREETING_MESSAGE&lt;/code&gt; property&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fac82op96fs304x891atp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fac82op96fs304x891atp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Here come the &lt;code&gt;window as any&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;for most of new Typescript developer may unable to solve this issue and put this dirty workaround like explicitly cast &lt;code&gt;window&lt;/code&gt; to &lt;code&gt;any&lt;/code&gt; which means we will access &lt;code&gt;window&lt;/code&gt; without any type safety and no type checking in the runtime!&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;MY_GREETING_MESSAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi Earth!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Bring back the type
&lt;/h3&gt;

&lt;p&gt;As &lt;code&gt;window&lt;/code&gt; has been declared by the standard Ambient type from Typescript library. The better approach is to extend this type like this&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Window&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
         &lt;span class="nl"&gt;MY_GREETING_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MY_GREETING_MESSAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi Earth!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and this will let Typescript recognize the property you want to put into the ambient &lt;code&gt;window&lt;/code&gt; object&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3ihxfj94q4ktf4508r9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3ihxfj94q4ktf4508r9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;noted that you need to make sure the value has been assigned before use, or you may make it as an optional property&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>global</category>
      <category>window</category>
    </item>
    <item>
      <title>How to proper use ambient enum from Definition file</title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Mon, 25 Apr 2022 06:39:14 +0000</pubDate>
      <link>https://forem.com/zapkub/how-to-proper-use-ambient-enum-from-definition-file-5ddg</link>
      <guid>https://forem.com/zapkub/how-to-proper-use-ambient-enum-from-definition-file-5ddg</guid>
      <description>&lt;p&gt;If you guy need to declare your &lt;code&gt;enum&lt;/code&gt; in definition file you may encounter a weird behavior and lead to something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// module A&lt;/span&gt;
&lt;span class="c1"&gt;/// types.d.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;MyEnumA&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;/// module B&lt;/span&gt;
&lt;span class="c1"&gt;/// main.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyEnumA&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyEnumA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// TypeError: cannot read property 'A' of undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;In the nutshell, Definition file cannot be reference as value and that is why they call it 'Ambient'&lt;/p&gt;




&lt;h2&gt;
  
  
  How to properly solve it?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;const enum&lt;/code&gt; solution (Not recommended)
&lt;/h3&gt;

&lt;p&gt;If your project have a very simple setup. You may able to use the typescript feature call &lt;code&gt;const enum&lt;/code&gt; which &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;const&lt;/code&gt; as a prefix of &lt;code&gt;enum&lt;/code&gt; will turn this &lt;code&gt;enum&lt;/code&gt; into an inline constant in compiler time.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// module A&lt;/span&gt;
&lt;span class="c1"&gt;/// types.d.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;MyEnumA&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;/// module B&lt;/span&gt;
&lt;span class="c1"&gt;/// main.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyEnumA&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyEnumA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="c1"&gt;/// module B compiled&lt;/span&gt;
&lt;span class="c1"&gt;/// main.js&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;&amp;lt;&amp;lt; here is the hardcoded value from enum&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But why this approach is not recommended?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;this approach does not support &lt;code&gt;isolatedModule&lt;/code&gt; option&lt;/li&gt;
&lt;li&gt;as &lt;code&gt;MyEnumA.A&lt;/code&gt; is transpile into a hardcoded value. if &lt;code&gt;module B&lt;/code&gt; enum value is change, you need to recompile &lt;code&gt;module A&lt;/code&gt; again to update the hardcoded value&lt;/li&gt;
&lt;li&gt;Typescript team does not recommend it &lt;a href="https://www.typescriptlang.org/docs/handbook/enums.html#const-enum-pitfalls" rel="noopener noreferrer"&gt;https://www.typescriptlang.org/docs/handbook/enums.html#const-enum-pitfalls&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Declare ambient value in global scope (Recommended)
&lt;/h3&gt;

&lt;p&gt;The proper solution is to assign this enum value ambient. As ambient is just an abstraction, in the implementation file you need to assign this value as you declare in ambient too.&lt;/p&gt;

&lt;p&gt;So we will declare &lt;code&gt;enum&lt;/code&gt; in definition file as an ambient and assign value into global scope variable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// module A&lt;/span&gt;
&lt;span class="c1"&gt;/// types.d.ts&lt;/span&gt;
&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;MyEnumAValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// ambient enum&lt;/span&gt;
     &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;MyEnumA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;MyEnumAValue&lt;/span&gt; &lt;span class="c1"&gt;// ambient value&lt;/span&gt;

&lt;span class="c1"&gt;/// module B&lt;/span&gt;
&lt;span class="c1"&gt;/// types.ts as ambient value file&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;MyEnumAValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MyEnumA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MyEnumAValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;/// this will be checking with ambient if enum value is consistent with ambient enum&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MyEnumA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MyEnumAValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="c1"&gt;/// main.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyEnumA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is how the type checking work&lt;/p&gt;

&lt;h4&gt;
  
  
  Consistent
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt80kip5s417yoty536a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt80kip5s417yoty536a.png" alt="Image description" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Inconsistent
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqbcp6klm492xi0ztkr5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqbcp6klm492xi0ztkr5.png" alt="Image description" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you want to use a type definition file and you want to declare enum in it.&lt;/p&gt;

&lt;p&gt;in the implementation file you need to assign the value as you declare in the ambient too.&lt;/p&gt;

&lt;p&gt;The best way to do it is assign the enum value to global scope variable.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>enum</category>
    </item>
    <item>
      <title>Terra Network SmartContract Migration</title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Sun, 31 Oct 2021 14:50:45 +0000</pubDate>
      <link>https://forem.com/zapkub/terra-network-smartcontract-migration-4i56</link>
      <guid>https://forem.com/zapkub/terra-network-smartcontract-migration-4i56</guid>
      <description>&lt;p&gt;Terra network มีอัพเดทครั้งใหญ่ เพื่อเพิ่มประสิทธิภาพของ Network แต่ในบทความนี้ ผมจะไม่พูดเรื่อง Network แต่จะไป focus เรื่อง Smart Contract แทน โดยถ้าอยากรู้ว่ามีอะไรเปลี่ยนไปบ้าง ลองดูได้ลิ้งนี้แทน&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/terra-money/columbus-5-launches-welcome-to-the-future-of-terra-8a9ebfa570c5"&gt;https://medium.com/terra-money/columbus-5-launches-welcome-to-the-future-of-terra-8a9ebfa570c5&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;หนึ่งในการอัพเดทคือการ Bump cosmwasm ไปเป็น version 0.16 ( ซึ่ง breaking change กระจาย ) เรามาดูกันว่า เราต้องเปลี่ยนอะไรบ้างจาก contract version เดิม ( 0.10 ) &lt;/p&gt;

&lt;p&gt;นอกจากนี้ feature ที่เพิ่มมาก็เยอะมาก เพราะมัน upgrade กันข้ามมา 6 version ถ้าต้องการไล่อ่าน ตามไปที่ &lt;a href="https://github.com/CosmWasm/cosmwasm/blob/main/CHANGELOG.md"&gt;https://github.com/CosmWasm/cosmwasm/blob/main/CHANGELOG.md&lt;/a&gt; ได้เลย&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OtJyUto8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ex4435aqwh78d0niwzka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OtJyUto8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ex4435aqwh78d0niwzka.png" alt="image" width="880" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ของ Avareum protocol พังไป 240 errors 😱&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  มีอะไรเปลี่ยนไปบ้าง?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API มีความกระชับขึ้น Type ต่างๆ Generic ต่างๆใช้ง่ายขึ้น&lt;/li&gt;
&lt;li&gt;Support การทำ Migration ผ่าน Contract ได้แล้ว&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;โดยบทความนี้จะยกเอาแค่ Major change หลักๆ ที่ทีม Avareum ต้อง Migrate ซึ่งทางทีมก็ยังใช้ Feature ของมันไม่หมด (เยอะเกิน)&lt;/p&gt;



&lt;h2&gt;
  
  
  Support On-chain Contract Migration
&lt;/h2&gt;

&lt;p&gt;อันนี้คือที่รอคอยมานาน ซึ่งพึ่งมาเพิ่มใน coswasm 0.14 ทำให้ Contract สามารถ Migrate กันเองได้แบบ On-chain &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OCBEOGM5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lwugxnyhc8up2xadehxo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OCBEOGM5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lwugxnyhc8up2xadehxo.png" alt="Image description" width="880" height="50"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;โดยที่ก่อนหน้านี้ จะจำกัดเรื่องการ migrate contract สามารถทำได้โดยผ่าน Off Chain API อย่างเดียว ทำให้ต้องเป็นหน้าที่ของ Owner ของ Contract เท่านั้นที่สามารถ Migrate ได้และหากมีหลาย Contract ก็ต้องทำทีละอันจาก Off chain&lt;/p&gt;

&lt;p&gt;จาก Feature นี้ทำให้เราสามารถ Deploy contract set ที่มี Logic ในการ ทำ Migration ออกมาและสั่ง Migrate ที่เดียวจาก Off chain จาก Entrypoint ที่เดียว&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[cfg_attr(not(feature&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"library"&lt;/span&gt;&lt;span class="nd"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;entry_point)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;migrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DepsMut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MigrateMsg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ContractError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;query_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.add_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nn"&gt;CosmosMsg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Wasm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;WasmMsg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Migrate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="py"&gt;.executor_mirror_address&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;new_code_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="py"&gt;.sub_contract.executor_mirror_code_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;to_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="py"&gt;.sub_contract.executor_mirror_migrate_msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nn"&gt;CosmosMsg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Wasm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;WasmMsg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Migrate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="py"&gt;.executor_anchor_address&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;new_code_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="py"&gt;.sub_contract.executor_anchor_code_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;to_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="py"&gt;.sub_contract.executor_anchor_migrate_msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nn"&gt;CosmosMsg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Wasm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;WasmMsg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Migrate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="py"&gt;.executor_terraswap_address&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;new_code_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="py"&gt;.sub_contract.executor_terraswap_code_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;to_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="py"&gt;.sub_contract.executor_terraswap_migrate_msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  วิธี binding Entrypoint เปลี่ยนใหม่
&lt;/h3&gt;

&lt;p&gt;จากปกติก่อนหน้านี้ การกำหนด entrypoint ทั้งหมดจะอยู่ที่ &lt;code&gt;lib.rs&lt;/code&gt; ให้ลบตรงนั้นทิ้งออกให้หมดแล้วไปใช้ macro กับ function ชื่อ &lt;code&gt;entry_point&lt;/code&gt; แทน&lt;br&gt;
พร้อมกับ เปลี่ยนชื่อ &lt;code&gt;init&lt;/code&gt; เป็น &lt;code&gt;instantiate&lt;/code&gt; และ &lt;code&gt;handle&lt;/code&gt; เป็น &lt;code&gt;execute&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CosmWasm/cosmwasm/blob/main/CHANGELOG.md#changed-6"&gt;https://github.com/CosmWasm/cosmwasm/blob/main/CHANGELOG.md#changed-6&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
&lt;span class="nd"&gt;#[cfg_attr(not(feature&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"library"&lt;/span&gt;&lt;span class="nd"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;entry_point)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DepsMut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InitMsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ContractError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;


&lt;span class="nd"&gt;#[cfg_attr(not(feature&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"library"&lt;/span&gt;&lt;span class="nd"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;entry_point)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DepsMut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ExecuteMsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ContractError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Extern API เปลี่ยนเป็น Deps และ DepsMut
&lt;/h3&gt;

&lt;p&gt;จากการใช้งาน &lt;code&gt;Extern&lt;/code&gt; กับ Generic type ทาง cosmwasm ได้เปลี่ยนมาเป็น type alias ทำให้ ปกติที่ใช้ &lt;code&gt;Extern&lt;/code&gt; ให้เปลี่ยนเป็น &lt;code&gt;Deps&lt;/code&gt; และ &lt;code&gt;mut Extern&lt;/code&gt; เปลี่ยนเป็น &lt;code&gt;DepsMut&lt;/code&gt; &lt;br&gt;
&lt;a href="https://github.com/CosmWasm/cosmwasm/blob/main/MIGRATING.md#011---012"&gt;Reference&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  ตัวอย่าง
&lt;/h4&gt;

&lt;p&gt;จาก&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Querier&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Extern&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InitMsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StdResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;InitResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เปลี่ยนเป็น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DepsMut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InitMsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StdResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;InitResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากอันนี้ การ access funds ที่ส่งมาจะเปลี่ยนจาก access ที่ env ไปผ่านตัว info แทน&lt;/p&gt;



&lt;h3&gt;
  
  
  เพิ่ม Arguments ให้กับ Contract entry point ( init, handle, migrate )
&lt;/h3&gt;

&lt;p&gt;Type &lt;code&gt;Env&lt;/code&gt; ถูกนำเอา sender ออกและย้ายไปไว้ใน Type ชื่อ &lt;code&gt;MessageInfo&lt;/code&gt; เข้าใจว่าเพื่อให้เป็นระเบียบมากขึ้นเฉยๆ&lt;/p&gt;
&lt;h4&gt;
  
  
  ตัวอย่าง
&lt;/h4&gt;

&lt;p&gt;จาก&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DepsMut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HandleMsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StdResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HandleResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;.....&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;senderAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="py"&gt;.message.sender&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เปลี่ยนเป็น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DepsMut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HandleMsg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StdResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HandleResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;.....&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;senderAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="py"&gt;.sender&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  Migrate Response, HandleResponse, InitResponse กลายเป็น Response เฉยๆ และเป็น non_exhaustive
&lt;/h3&gt;

&lt;p&gt;มีการรวม Response ต่างๆเป็นอันเดียว และใช้ Higher order function ในการ assign parameter ต่างๆให้กับ Response ( ไม่อนุญาตให้สร้าง Response แบบ struct expression แล้ว&lt;/p&gt;

&lt;p&gt;ซึ่งผมชอบนะอันนี้ ดูกระชับขึ้นเยอะเลย ( ถึงจะต้องแก้ Contract เก่าเยอะหน่อย )&lt;/p&gt;

&lt;p&gt;จาก&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;cosmwasm_std&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt; &lt;span class="n"&gt;HandleResponse&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="o"&gt;.....&lt;/span&gt;

 &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HandleResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เปลี่ยนเป็น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;cosmwasm_std&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="o"&gt;.....&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.add_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.add_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h4&gt;
  
  
  Log API เปลี่ยนชื่อเป็น Attribute
&lt;/h4&gt;

&lt;p&gt;version 0.16 เอา log ออกหมดเลย เปลี่ยนไปเรียกว่า Attribute แทน รวมถึงการ return log จาก response ก็จะเปลี่ยนไปใช้ &lt;code&gt;add_attributes&lt;/code&gt; หรือ &lt;code&gt;add_attribute&lt;/code&gt; จาก Response แทน ( เพราะว่า &lt;code&gt;HandleResponse&lt;/code&gt; ถูก Deprecated ไปแล้วจากด้านบน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogAttribute&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Attribute&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;

&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;HandleResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.add_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  HumanAddr ถูก Deprecated
&lt;/h3&gt;

&lt;p&gt;ใน API version ใหม่จะมี &lt;code&gt;Addr&lt;/code&gt; มาแทน &lt;code&gt;HumanAddr&lt;/code&gt; โดยที่ API ส่วนใหญ่ ที่ใช้ &lt;code&gt;HumanAddr&lt;/code&gt; จะเปลี่ยนไปใช้ &lt;code&gt;String&lt;/code&gt; แทนแล้ว&lt;/p&gt;

&lt;p&gt;เช่น &lt;code&gt;WasmMsg:Execute&lt;/code&gt; จากปรกติ รับ &lt;code&gt;contarct_addr&lt;/code&gt; เป็น &lt;code&gt;HumanAddr&lt;/code&gt; ตอนนี้จะรับเป็น &lt;code&gt;String&lt;/code&gt; แทน ซึ่งหากเราตัดสินใจใช้ &lt;code&gt;Addr&lt;/code&gt; ก็จะมี &lt;code&gt;to_string&lt;/code&gt; ให้ใช้เปลี่ยนจาก &lt;code&gt;Addr&lt;/code&gt; เป็น &lt;code&gt;String&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HumanAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nn"&gt;WasmMsg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;contract_addr&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลักๆเราต้อง Migrate ตัว contract ประมานนี้ ส่วนใหญ่ยังไม่มีอะไรที่ Breaking Change ถึงกับขนาดต้องออกแบบ Contract ใหม่&lt;/p&gt;

&lt;p&gt;ส่วนอื่นๆ นอกจากนี้ลึกๆ ตามไปไล่อ่านที่นี่ได้เลยจ้า&lt;br&gt;
&lt;a href="https://github.com/CosmWasm/cosmwasm/blob/main/MIGRATING.md"&gt;https://github.com/CosmWasm/cosmwasm/blob/main/MIGRATING.md&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terremoney</category>
      <category>coswasm</category>
    </item>
    <item>
      <title>Project Layout ของ Golang EP.1</title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Sat, 12 Dec 2020 12:18:28 +0000</pubDate>
      <link>https://forem.com/zapkub/project-layout-golang-ep-1-1gh3</link>
      <guid>https://forem.com/zapkub/project-layout-golang-ep-1-1gh3</guid>
      <description>&lt;p&gt;วันนี้จะมาเล่าเรื่อง Project Layout ครับ เรียกได้ว่าเป็นหนึ่งในสิ่งสำคัญที่จะทำให้เราพัฒนา application ด้วยภาษา Golang ได้ตรงตามที่ผู้พัฒนาต้องการให้เราทำ ( หรือ Idiomatic ที่แปลว่า ลักษณะจำเพาะ ) เพื่อให้โปรเจคเรา ใกล้เคียงความเป็น Gopher project มากที่สุดกันครับ&lt;/p&gt;

&lt;h1&gt;
  
  
  ✨ TL;DR อีกแล้ว
&lt;/h1&gt;

&lt;p&gt;Golang ไม่มี layout standard เป็นตัวเป็นตนจาก Go Core Dev team ที่มีอยู่ตอนนี้ก็คือ ตั้งแต่ Go &lt;code&gt;1.4&lt;/code&gt; เป็นต้นไป folder &lt;code&gt;internal&lt;/code&gt; จะไม่สามารถถูกเรียกใช้จากนอก package หลักได้ &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://golang.org/doc/go1.4#internalpackages" rel="noopener noreferrer"&gt;release note เรื่อง internal folder&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;นอกนั้นก็ตามแล้วแต่ผู้ดูแลโปรเจคจะเป็นคนกำหนด convention ของ layout ตัวเอง&lt;/p&gt;

&lt;p&gt;ส่วนทางด้าน community และ open source ก็มีตัวอย่างที่ใช้กันบ่อยๆ ฮิตๆก็ดูได้จาก Repository นี้ (และ open source ของ Golang อื่นๆ)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/golang-standards/project-layout" rel="noopener noreferrer"&gt;https://github.com/golang-standards/project-layout&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;หลักๆคือ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cmd&lt;/code&gt; ใช้สำหรับเก็บ package ที่เป็น entry point ของ application (ส่วนใหญ่ก็คือ package main) โดยจะไม่นำ code มาเขียนตรงนี้เยอะ โดย package ใน &lt;code&gt;cmd&lt;/code&gt; จะไปเรียกใช้ code ที่อยู่ในส่วนของ &lt;code&gt;interal&lt;/code&gt; และ &lt;code&gt;pkg&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;internal&lt;/code&gt; เก็บ package ที่เป็น implementation หลักของ application (หรือ library) ซึ่งไม่ต้องการให้มีการ import จากนอก package&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;pkg&lt;/code&gt; ใช้เก็บ package ที่เหมือนกัน &lt;code&gt;internal&lt;/code&gt; แต่สามารถ import ไปใช้งานได้นอก application (หรือ library) เหมาะสำหรับใช้ reuse package ไปที่ project อื่นๆ&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;และนอกจากนี้ เรายังสามารถศึกษาได้จาก Open Source Project อื่นๆที่พัฒนาด้วย Golang (ดูต่อที่ Reference)&lt;/p&gt;

&lt;p&gt;แต่ยังไงก็ตาม การทำงานที่มีประสิทธิภาพที่สุด ก็คือการทำงานบน convention ที่เราสามารถสร้าง productivity ได้มากที่สุด เพราะฉะนั้น ก็ไม่จำเป็นจะต้องทำตามสิ่งเหล่านี้ทั้งหมดครับ เราอาจจะใช้ layout ของ NodeJS หรือ Java ก็ไม่เป็นอะไร ถ้าเราสามารถ deliver งานได้ตามที่ business ต้องการ&lt;/p&gt;




&lt;p&gt;เริ่มเนื้อหาแบบยาว...&lt;/p&gt;

&lt;h1&gt;
  
  
  Project Layout คืออะไร?
&lt;/h1&gt;

&lt;p&gt;ในการพัฒนาแอพพลิเคชั่นแต่ละภาษา ก็จะมี Project Layout แตกต่างกันออกไปครับ เพื่อการ organize code ที่ดี แต่ละภาษาก็มี convention แตกต่างกันออกไปตาม design pattern ของภาษา&lt;/p&gt;

&lt;p&gt;เช่นเมื่อ New Project ใน ​&lt;code&gt;Java&lt;/code&gt;, &lt;code&gt;C#&lt;/code&gt;, &lt;code&gt;Swift&lt;/code&gt; หรือ &lt;code&gt;NodeJS&lt;/code&gt; รวมไปถึงระดับ Framework เช่น Laravel หรือ Angular เราก็จะได้ project layout แตกต่างกันออกไป แต่ก็เพื่อให้สามารถจัดการ Code ง่ายที่สุด ตามที่ผู้พัฒนาภาษาคิดมาซึ่งส่วนใหญ่ หนีไม่พ้น ทุกแบบก็จะประกอบไปด้วย&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependencies and Information&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Build&lt;/li&gt;
&lt;li&gt;Distributed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เช่น &lt;code&gt;Swift&lt;/code&gt; เราก็จะมี &lt;code&gt;Podfile&lt;/code&gt;, &lt;code&gt;xcodeproj&lt;/code&gt; หรือ &lt;code&gt;NodeJS&lt;/code&gt; เราจะมี &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;src&lt;/code&gt; folder&lt;/p&gt;

&lt;h1&gt;
  
  
  Dependencies and Project Information
&lt;/h1&gt;

&lt;p&gt;สำหรับ Golang แล้ว ก่อนที่จะมี &lt;code&gt;go mod&lt;/code&gt; เราบันทึก dependencies ไว้ภายในตัว code เอง (ใน import) แต่หลังจากนั้นก็มี tools เพื่อควบคุม version เช่น &lt;code&gt;glider&lt;/code&gt; หรือ &lt;code&gt;godeps&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;ปัจจุบัน Golang มี dependency management เองแล้วชื่อ &lt;code&gt;go mod&lt;/code&gt; ซึ่งประกอบด้วย &lt;code&gt;go.mod&lt;/code&gt; และ &lt;code&gt;go.sum&lt;/code&gt; ภายในบ่งบอกถึง dependencies ต่างๆที่เราจะใช้งาน&lt;/p&gt;

&lt;p&gt;ส่วน Project Information ต้องบอกก่อนว่า Golang เราทำ document ด้วยการ comment เป็นหลัก (เรื่องการทำ &lt;code&gt;godoc&lt;/code&gt; จะเอาไว้เขียนบทความหน้า) เพราะฉะนั้น Information ของ package ต่างๆก็เลยถูกเขียนไว้ใน comment ทั้งหมด&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;

&lt;p&gt;ส่วนที่เราเก็บ code ที่เราเขียนไว้จะประกอบด้วย 4 packages หลักๆ (จริงๆมีมากกว่านั้น แต่ผู้เขียนเลือกอันที่ใช้ และเจอบ่อยมาเพื่อความเรียบง่าย ลองดูใน Go Standard Layout เพิ่มเติมครับ)&lt;/p&gt;

&lt;h2&gt;
  
  
  1. cmd Folder
&lt;/h2&gt;

&lt;p&gt;Folder หลักที่ใช้เก็บ Entry point package ต่างๆของ application โดยส่วนมากจะเป็น Package main โดย package ภายใต้ folder นี้ไม่จำเป็นจะต้องมี implementation ที่ซับซ้อนมากมาย ทำแค่เพียงเป็น entry point เรียก implementation อื่นๆจาก package ใน folder &lt;code&gt;internal&lt;/code&gt;, &lt;code&gt;web&lt;/code&gt; และ &lt;code&gt;pkg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ตัวอย่างจาก &lt;a href="https://github.com/ethereum/go-ethereum/tree/master/cmd/abidump" rel="noopener noreferrer"&gt;Ethereum Golang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feyqahw469qmi1y3kvvrz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feyqahw469qmi1y3kvvrz.png" alt="Etereum cmd"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ตัวอย่างจาก &lt;a href="https://github.com/golang/pkgsite/blob/master/cmd/frontend/main.go" rel="noopener noreferrer"&gt;Go Pkgsite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Figwp3u8tsklg09ztavvn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Figwp3u8tsklg09ztavvn.png" alt="gopkgsite"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  2. internal Folder
&lt;/h2&gt;

&lt;p&gt;Folder นี้น่าจะเป็น folder ที่มี source code เก็บอยู่มากที่สุด (ถ้าเป็น application) เพราะประกอบด้วย implementation หลักของ Project ที่ไม่สามารถ import ผ่าน package อื่นๆนอกจาก Project นี้ได้ (หรือภายใต้ &lt;code&gt;go module&lt;/code&gt; เดียวกัน)&lt;/p&gt;

&lt;p&gt;ตัวอย่างจาก &lt;a href="https://github.com/golang/pkgsite/tree/master/internal" rel="noopener noreferrer"&gt;Go Pkgsite&lt;/a&gt; ซึ่ง package แน่นมาก&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyamj6oh07jvwquo8hfi3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyamj6oh07jvwquo8hfi3.png" alt="gopkg internal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ถึงใน standard project layout จะบอกว่าเป็น folder ที่อยู่ด้านนอกสุด (workspace root) แต่ก็ไม่จำเป็น เพราะ Golang จะ recognize folder internal ให้ตลอด เพราะฉะนั้นไม่จำเป็นที่จะต้องอยู่ที่ workspace root ก็ได้&lt;/p&gt;

&lt;p&gt;เช่นตัวอย่างจาก &lt;a href="https://github.com/golang/go/tree/master/src/internal" rel="noopener noreferrer"&gt;Golang source code&lt;/a&gt; เองก็มีการวาง folder internal ไว้ภายใน &lt;code&gt;src&lt;/code&gt; folder ( ซึ่ง &lt;code&gt;src&lt;/code&gt; folder ไม่ได้มีใน Standard Project Layout )&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fthxfa70r5zo29ol3md1g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fthxfa70r5zo29ol3md1g.png" alt="gosource internal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. pkg Folder ( หรืออยู่ที่ root ไปเลย )
&lt;/h2&gt;

&lt;p&gt;คล้ายๆกันกับ &lt;code&gt;internal&lt;/code&gt; (อ่าว พูดเหมือนใน TL;DR เลย) แต่ในนี้จะประกอบด้วย code ที่สามารถนำไป reuse ใช้งานภายนอก package หลักได้&lt;/p&gt;

&lt;p&gt;หรือบาง repository ก็ไม่ใช้เลย โดยนำเอา package ต่างๆมาไว้ที่ workspace root (ที่เดียวกับ &lt;code&gt;go.mod&lt;/code&gt; ไปเลย) โดยมีการเถียงกันที่ issue นี้ 555555&lt;br&gt;
&lt;a href="https://github.com/golang-standards/project-layout/issues/10" rel="noopener noreferrer"&gt;https://github.com/golang-standards/project-layout/issues/10&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ถ้าดูตัวอย่าง ส่วนใหญ่จะเป็น Library หรือ Opensource tools ต่างๆ เช่น&lt;br&gt;
ตัวอย่างจาก &lt;a href="https://github.com/moby/moby/tree/master/pkg" rel="noopener noreferrer"&gt;Moby (container engine ของ docker)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv4gctv9t6zdig1b5dt7k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv4gctv9t6zdig1b5dt7k.png" alt="moby pkg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ตัวอย่างจาก &lt;a href="https://github.com/kubernetes/kubernetes/tree/master/pkg" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj837d2hy81ud3unbbzmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj837d2hy81ud3unbbzmv.png" alt="kube pkg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ตัวอย่างจาก &lt;a href="https://github.com/gorilla/mux" rel="noopener noreferrer"&gt;Gorilla Mux&lt;/a&gt; ที่ไม่ใส่ folder อะไรเลย เอาไว้มันโต้งๆนี่แหล่ะ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxlw3ck6f5tyo5546lh7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxlw3ck6f5tyo5546lh7x.png" alt="mux pkg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. web Folder
&lt;/h2&gt;

&lt;p&gt;Folder นี้จะประกอบด้วย source code ของ frontend ซะส่วนใหญ่ (ถ้าเป็น web base application) โดยเราจะเอา html template, static asset ต่างๆมาเก็บไว้ในนี้ หรือถ้าเป็น Javascript framework อย่าง Angular ก็นำมาเก็บไว้ในนี้ได้ (ในกรณี Monorepository)&lt;/p&gt;

&lt;p&gt;ตัวอย่างจาก &lt;a href="https://github.com/traefik/traefik" rel="noopener noreferrer"&gt;traefik (http engine ที่เขียนด้วย golang (คล้ายๆ nginx)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fabwhkspajn9qrk821j6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fabwhkspajn9qrk821j6u.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;go pkgsite นั้นเอาไว้ใน &lt;code&gt;content&lt;/code&gt; folder แทน &lt;a href="https://github.com/golang/pkgsite/tree/135895829587fb7ebda46246157eefcf9c1b1f1d/content/static/html/pages" rel="noopener noreferrer"&gt;&lt;code&gt;go pkgsit repository&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;จบแล้วสำหรับ part แรก เดี๋ยวส่วนอื่นๆที่เหลือ จะเขียนต่อใน part ต่อไปครับ&lt;/p&gt;

&lt;p&gt;Happy Christmas and coding!&lt;br&gt;
🎄 🤖&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://golang.org/doc/code.html" rel="noopener noreferrer"&gt;https://golang.org/doc/code.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/go" rel="noopener noreferrer"&gt;https://github.com/golang/go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/golang-standards/project-layout" rel="noopener noreferrer"&gt;https://github.com/golang-standards/project-layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gorilla/mux" rel="noopener noreferrer"&gt;https://github.com/gorilla/mux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/kubernetes" rel="noopener noreferrer"&gt;https://github.com/kubernetes/kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/pkgsite/commit/4ad1f04766f983b16d42c752c6e12f011f155207" rel="noopener noreferrer"&gt;https://github.com/golang/pkgsite/commit/4ad1f04766f983b16d42c752c6e12f011f155207&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/moby/moby" rel="noopener noreferrer"&gt;https://github.com/moby/moby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/traefik/traefik" rel="noopener noreferrer"&gt;https://github.com/traefik/traefik&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>layout</category>
      <category>structure</category>
    </item>
    <item>
      <title>10110 การทำ Flag ด้วย Bitset  ใน Golang</title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Sat, 05 Dec 2020 12:45:58 +0000</pubDate>
      <link>https://forem.com/zapkub/10110-flag-bitset-golang-3n5e</link>
      <guid>https://forem.com/zapkub/10110-flag-bitset-golang-3n5e</guid>
      <description>&lt;p&gt;โปรแกรมเมอร์รุ่นใหม่ๆ ที่ไม่คุ้นกับภาษา Go (หรือภาษาเก่าๆอื่นๆ) อาจจะสงสัยว่า ไอ้ parameter ที่มัน &lt;code&gt;OR&lt;/code&gt; ได้นี่มันคืออะหยังหนอ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pathtofile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_APPEND&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_RDWR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0755&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                      &lt;span class="o"&gt;^^^&lt;/span&gt; &lt;span class="n"&gt;ไอ&lt;/span&gt;&lt;span class="err"&gt;้&lt;/span&gt;&lt;span class="n"&gt;นี&lt;/span&gt;&lt;span class="err"&gt;่&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Llongfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LUTC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                         &lt;span class="o"&gt;^^^&lt;/span&gt; &lt;span class="n"&gt;ไอ&lt;/span&gt;&lt;span class="err"&gt;้&lt;/span&gt;&lt;span class="n"&gt;พวกนี&lt;/span&gt;&lt;span class="err"&gt;้&lt;/span&gt;&lt;span class="n"&gt;ด&lt;/span&gt;&lt;span class="err"&gt;้&lt;/span&gt;&lt;span class="n"&gt;วย&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;มันคือ Flags นั่นเองครับ underhood มันคือ int ธรรมดาแต่ถูกจัดการด้วย bitwise operator ซึ่งจะเป็นหัวข้อของ blog นี้&lt;/p&gt;

&lt;h1&gt;
  
  
  🌟 TL;DR สรุปก่อนไปเลย
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://play.golang.org/p/lH5P1ncioFG" rel="noopener noreferrer"&gt;ตัวอย่างสุดท้าย ใน Playground&lt;/a&gt;&lt;br&gt;
Bitset Flag จะทำให้เราสามารถ pass enum parameter ได้มากกว่า 1 parameter โดยไม่ต้องแก้ไข signature ของ function เพิ่ม ทำให้สามารถส่ง enum เข้าไปใน function ได้โดยไม่ต้องใช้ slice&lt;/p&gt;

&lt;p&gt;การทำ Flag ใน Golang เหมือนกับการทำ Flag ในภาษาอื่นๆ แต่ด้วยความสามารถของ &lt;code&gt;iota&lt;/code&gt; ทำให้การทำ Flag ง่ายขึ้นนิดนึง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;flagWithA&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;iota&lt;/span&gt;
    &lt;span class="n"&gt;flagWithB&lt;/span&gt;
    &lt;span class="n"&gt;flagWithC&lt;/span&gt;
    &lt;span class="n"&gt;flagWithD&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flagWithA&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flagWithB&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flagWithC&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flagWithD&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ExampleBitsetFlag&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flagWithA&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;flagWithD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// output: true false false true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h1&gt;
  
  
  Flag คืออะไร
&lt;/h1&gt;

&lt;p&gt;การพัฒนา application ด้วย Golang คงจะเคยเจอการใช้ Flag กันผ่านๆมาแล้ว โดยเฉพาะการ &lt;code&gt;OpenFile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"somedir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_APPEND&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_CREATE&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_RDWR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0655&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;^^^^&lt;/span&gt; &lt;span class="n"&gt;ตรงนี&lt;/span&gt;&lt;span class="err"&gt;้&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน parameter ที่ 2 จะเห็นว่าเราสามารถ pass parameter ไปได้มากกว่า 1 ตัวทั้งๆที่ parameter ตรงนี้กำหนดไว้แค่ int อย่างเดียวใน signature&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// OpenFile is the generalized open call; most users will use Open&lt;/span&gt;
&lt;span class="c"&gt;// or Create instead. It opens the named file with specified flag&lt;/span&gt;
&lt;span class="c"&gt;// (O_RDONLY etc.). If the file does not exist, and the O_CREATE flag&lt;/span&gt;
&lt;span class="c"&gt;// is passed, it is created with mode perm (before umask). If successful,&lt;/span&gt;
&lt;span class="c"&gt;// methods on the returned File can be used for I/O.&lt;/span&gt;
&lt;span class="c"&gt;// If there is an error, it will be of type *PathError.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;OpenFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;perm&lt;/span&gt; &lt;span class="n"&gt;FileMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลายคนที่ย้ายมาจากภาษาอื่นๆ อาจจะไม่คุ้นตากับการใช้ Flag แบบนี้สักเท่าไหร่ (เนื่องจากภาษาอื่นก็มี pattern อื่นๆในการ pass value แบบนี้แทนแล้ว)&lt;/p&gt;

&lt;p&gt;แต่เนื่องจาก Golang พัฒนามากับความเรียบง่าย เราเลยยังเห็นการใช้ Bitset และ bitwise operator เพื่อทำ flag parameter อยู่&lt;/p&gt;

&lt;h2&gt;
  
  
  Bitwise Operator คืออะไร?
&lt;/h2&gt;

&lt;p&gt;ในภาษาต่างๆ เราอาจจะเคยเห็นการทำ Bitwise Operator กันมาบ้าง ถ้าเป็น Developer ใหม่ๆอาจจะไม่คุ้นชินตาเท่าไหร่ (ถ้าไม่ใช่ภาษาอย่าง C หรือ C++ หรือตอนเรียนมหาลัย)&lt;/p&gt;

&lt;p&gt;ในบทความนี้มี 3 bitwise operators ที่เราจะใช้งานกันคือ &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; left shift&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&lt;/code&gt; AND&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;|&lt;/code&gt; OR&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Left shift operator
&lt;/h3&gt;

&lt;p&gt;เครื่องหมาย &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; หมายถึงการขยับ bit value ไปด้านซ้าย (และกลับด้านกัน &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; right shift คือขยับไปขวา)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ExampleBitwise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// output: 512&lt;/span&gt;
    &lt;span class="c"&gt;// 128&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ในตัวอย่างจะเห็นว่ามีการ &lt;code&gt;assign left shift int(2)&lt;/code&gt; ให้กับตัวแปร &lt;code&gt;n&lt;/code&gt; สิ่งที่ได้จาก expression นี้คือเราทำการขยับ bit ปัจจุบันไปด้านซ้าย จำนวน 8 ตัวให้กับ int(2)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decimal Number&lt;/th&gt;
&lt;th&gt;Binary Number&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;10 ( มี 0 จำนวน 1 ตัว )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;512&lt;/td&gt;
&lt;td&gt;1000000000 (มี 0 จำนวน 9 ตัว )&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  AND และ OR operator
&lt;/h3&gt;

&lt;p&gt;สำหรับการทำ &lt;code&gt;AND&lt;/code&gt; operator เราจะได้ผลลัพธ์ออกมาเป็น bitset ที่ตรงกัน สำหรับ 2 values (intersect)&lt;/p&gt;

&lt;p&gt;และ &lt;code&gt;OR&lt;/code&gt; operator เราจะได้ผลลัพธ์ของ bit position ที่มีค่า (union)&lt;/p&gt;

&lt;p&gt;ตัวอย่างเช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ExampleBitsetAnd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;   &lt;span class="c"&gt;// this is 0100&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt; &lt;span class="c"&gt;// this is 1100&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%b %b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// output: 100 1100&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  สร้าง Enum ด้วยค่าของ bit set
&lt;/h2&gt;

&lt;p&gt;จาก Operator ที่ได้เกริ่นมา จะทำให้เราสามารถเอาหลักการ bitset มาใช้แทน value ของ flags ได้ด้วยการให้แต่ละ Bit บ่งบอกถึงการเปิดและปิดของ flag ต่างๆ&lt;/p&gt;

&lt;p&gt;ยกตัวอย่างเช่น &lt;br&gt;
Function &lt;code&gt;echoHello&lt;/code&gt; สามารถ echo &lt;code&gt;Hello&lt;/code&gt; ในภาษาต่างๆได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       0000  // 4 bits
       ^ first bit represents echo in English
        ^ second bit represents echo in Thai
         ^ third bit represents echo in Japanese
          ^ last bit represents echo in French
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราก็จะได้ enum ออกมาเป็นแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;EchoEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c"&gt;// 0001&lt;/span&gt;
    &lt;span class="n"&gt;EchoTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c"&gt;// 0010&lt;/span&gt;
    &lt;span class="n"&gt;EchoJP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="c"&gt;// 0100&lt;/span&gt;
    &lt;span class="n"&gt;EchoFR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="c"&gt;// 1000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ExampleEchoHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ส่ง 1011 เข้าไป&lt;/span&gt;
    &lt;span class="n"&gt;echoHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoEN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EchoTH&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;EchoFR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// output: Hello&lt;/span&gt;
    &lt;span class="c"&gt;// สวัสดี&lt;/span&gt;
    &lt;span class="c"&gt;// Bonjour&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;echoHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c"&gt;// flags input คือ 1011&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;EchoEN&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// ผลลัพธ์ของการ 1011 AND 0001 คือ 0001&lt;/span&gt;
      &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;EchoTH&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// ผลลัพธ์ของการ 1011 AND 0010 คือ 0010&lt;/span&gt;
      &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"สวัสดี"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="c"&gt;// .... do the rest of logic&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากตัวอย่างชุดโปรแกรมด้านบน จะทำให้เราเห็นว่า เราสามารถใช้ bitset เพื่อแทน ค่าของ boolean หลายๆตัวได้ โดยไม่ต้องใช้ slice&lt;/p&gt;

&lt;h2&gt;
  
  
  ใช้ &lt;code&gt;iota&lt;/code&gt; และ เปลี่ยนจาก int เป็น type ใหม่เพื่อให้ bitset ใช้งานง่ายขึ้น
&lt;/h2&gt;

&lt;p&gt;จาก code ด้านบนจะเป็นการเขียนโปรแกรมตรงๆ ไม่ได้ใช้คุณสมบัติอะไรพิเศษจาก Golang ตอนนี้เราจะมาใช้คุณสมบัติของ Golang ให้ bitset flag เราใช้งานง่ายขึ้น&lt;/p&gt;

&lt;p&gt;เริ่มจาก ประกาศ enum และ left shift โดยใช้ &lt;code&gt;iota&lt;/code&gt; (คีย์เวิร์ดสำหรับทำ successive integer หรือเลขที่เพิ่มขึ้นเรื่อยๆ &lt;a href="https://www.mathsisfun.com/definitions/successive.html" rel="noopener noreferrer"&gt;อธิบาย successive integer&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;EchoEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;iota&lt;/span&gt; &lt;span class="c"&gt;// 1 &amp;lt;&amp;lt; 0 = 0001&lt;/span&gt;
    &lt;span class="n"&gt;EchoTH&lt;/span&gt;             &lt;span class="c"&gt;// 1 &amp;lt;&amp;lt; 1 = 0010&lt;/span&gt;
    &lt;span class="n"&gt;EchoJP&lt;/span&gt;             &lt;span class="c"&gt;// 1 &amp;lt;&amp;lt; 2 = 0100&lt;/span&gt;
    &lt;span class="n"&gt;EchoFR&lt;/span&gt;             &lt;span class="c"&gt;// 1 &amp;lt;&amp;lt; 3 = 1000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้น เพื่อทำให้ง่ายต่อการเช็ค bit เราจะทำ type ใหม่สำหรับ Echo Flag และเขียน function เพื่อตรวจว่า bitset นั้นมี enum ที่เราอยากรู้มั้ย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;EchoFlag&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;EchoFlag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;EchoFlag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
     &lt;span class="c"&gt;// ตัวอย่างถ้า e มีค่า = 12 ( 1100 )&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; 
     &lt;span class="c"&gt;// ถ้า f คือ 0001 จะ return false เพราะ 1100 &amp;amp; 0001 = 0000&lt;/span&gt;
     &lt;span class="c"&gt;// ถ้า f คือ 0100 จะ return true  เพราะ 1100 &amp;amp; 0100 = 0100&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นเรามาแก้ให้ &lt;code&gt;echoHello&lt;/code&gt; เรารับ &lt;code&gt;EchoFlag&lt;/code&gt; และใช้ &lt;code&gt;has()&lt;/code&gt; เพื่อเช็ค flag ของ input&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;echoHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="n"&gt;EchoFlag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"สวัสดี"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoJP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"こんにちは"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoFR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bonjour"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เสร็จหมดแล้ว! 🎊 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.golang.org/p/lH5P1ncioFG" rel="noopener noreferrer"&gt;ตัวอย่าง ใน Playground&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  แล้วมันเอาไว้ใช้ทำอะไร?
&lt;/h2&gt;

&lt;p&gt;อย่างที่ยกตัวอย่างไปตั้งแต่แรก Native package ของ Golang อย่าง &lt;code&gt;os&lt;/code&gt; จะใช้ Flag ในการทำ operation ต่างๆ โดยเฉพาะ arguments ที่จะส่งไปหาระบบปฏิบัติการ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F771tyvpn033jhvp2tfhn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F771tyvpn033jhvp2tfhn.png" alt="os flag"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;หรือ package &lt;code&gt;log&lt;/code&gt; ที่ใช้ flag ในการ set output option ของการ log&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa7r64r76zz1ykniz49sv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa7r64r76zz1ykniz49sv.png" alt="log flag"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;นอกจากนี้ผมก็ไม่รู้เหมือนกันว่าเอาไว้ทำอะไรอีก 🤨&lt;/p&gt;

&lt;p&gt;จบสวัสดี 🙆‍♂️&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>ใช้งาน Interface แบบพิลึกของ Golang  </title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Sat, 21 Nov 2020 07:38:25 +0000</pubDate>
      <link>https://forem.com/zapkub/interface-golang-1582</link>
      <guid>https://forem.com/zapkub/interface-golang-1582</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;บทความนี้ อ้างอิงแนวคิดจาก &lt;a href="https://golang.org/doc/effective_go.html"&gt;Effective Go&lt;/a&gt; และ &lt;a href="https://github.com/golang/go/wiki/CodeReviewComments#interfaces"&gt;Go CodeReviews&lt;/a&gt; เป็นหลัก &lt;/p&gt;

&lt;p&gt;บทความนี้ต้องการความเข้าใจเกี่ยวกับสาเหตุ หรือเหตุผลของการใช้ Interface ในการเขียนโปรแกรม เบื้องต้นก่อน&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  ⚡️ ชิงสรุปก่อนเลย TL:DR
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Golang มี interface ที่ทำงานได้ยืดหยุ่นกว่า interface ภาษา OOP ทั่วไป โดยไม่ต้องมีการประกาศ implements และ &lt;strong&gt;Golang จะไม่นิยมประกาศ interface ไว้ที่ Library ต้นทาง แต่จะประกาศ Interface ไว้ที่ implementation ที่ใช้งานแทน&lt;/strong&gt; โดยวิธีนี้ ทำให้การเขียน code สะอาดขึ้น และ Unit test ได้ง่ายขึ้น&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  👶 เรื่อง Interface คร่าวๆ
&lt;/h1&gt;

&lt;p&gt;พูดถึงเรื่อง Interface กันหน่อยดีกว่า อย่างที่เรารู้กันว่า Interface กับภาษา Strong type เป็นของคู่กันมาตั้งแต่ไหนแต่ไร เพื่อให้ Programmer สามารถกำหนด Abstraction ของส่วนประกอบต่างๆภายในโปรเจคได้&lt;/p&gt;

&lt;p&gt;ภาษา OOP อย่างที่เราคุ้นเคยกัน เช่น Java หรือ C# เนี้ย Interface แทบจะเป็นหัวใจหลักของการออกแบบระบบที่ซับซ้อน แทบจะขาดกันไม่ได้เลยทีเดียว เพราะหลายๆ Design Pattern ต้องการใช้ความสามารถของ Interface เพื่อทำให้บรรลุเป้าหมายได้&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface ใน OOP 🐣
&lt;/h2&gt;

&lt;p&gt;ก่อนที่จะเข้าเรื่อง Interface ของ Golang เรามาดูหน้าตาของ Interface ทั่วไปที่ใช้กันใน OOP language ก่อนซิ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySQLUserRepository&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
         &lt;span class="c1"&gt;// doing convert User entity to SQL statement and&lt;/span&gt;
         &lt;span class="c1"&gt;// execute SQL statement&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BufferUserRepository&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
         &lt;span class="c1"&gt;// doing in-memory buffering user stuff....&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากตัวอย่าง snippet ด้านบน จะทำให้เราสามารถเลือกใช้ &lt;code&gt;UserRepository&lt;/code&gt;  อันใดอันนึงได้ โดยไม่ต้องยึดติดกับ implementation ของ class ใด class หนึ่ง โดยมีประโยชน์ในการทำ Unit test หรือการ Mocking test ใน package อื่นๆที่มี &lt;code&gt;UserRepository&lt;/code&gt; เป็น dependency&lt;/p&gt;

&lt;p&gt;ตัวอย่าง เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// 🙅‍♂️ อย่าหาทำ การเพิ่ม Dependency แบบ Concrete ( ไม่ใช่ทุกกรณี )&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginUseCase&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;LoginUseCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySQLUserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// do initialize stuff&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 🙆‍♂️ ควรทำแบบนี้ มี dependency เป็น interface หรือ abstract class&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginUseCase&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;LoginUseCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// do initialize stuff&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🐭 เข้าเรื่อง Interface ของ Golang
&lt;/h2&gt;

&lt;p&gt;ใน Golang นั้นมันดันไม่ใช้ 100% OOP ซะทีเดียว อย่างเช่นภายใน Golang เราไม่มี Class และไม่มีการ ประกาศ Extends หรือ Implements&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ผู้เขียนปวดกะบาลมาก สมัยเริ่มศึกษา Golang ใหม่ๆ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ถึงแม้ว่า OOP concept จะไม่ได้ถูกยกมาเต็มๆภายใน Golang แต่หลายๆ Idea ของ OOP ก็เป็นประโยชน์มากๆในการพัฒนา Software ด้วยภาษา Golang&lt;/p&gt;

&lt;h4&gt;
  
  
  เรามาเริ่มกันที่สิ่งที่ OOP มีแต่ Golang 🚫 ไม่มีกันก่อนซิ
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;ไม่มี abstract class&lt;/li&gt;
&lt;li&gt;ไม่มี class ( มี struct แทนซึ่งเกือบๆจะเหมือน class แหล่ะแต่ไม่มี constructor )&lt;/li&gt;
&lt;li&gt;ไม่มี Extends&lt;/li&gt;
&lt;li&gt;ไม่มี Implements&lt;/li&gt;
&lt;li&gt;interface ไม่มี Attribute ( Member Variable ) มีแต่ Method&lt;/li&gt;
&lt;li&gt;ไม่มี Generic Type ( ปัจจุบัน version 1.14 ยังไม่มี จะมีใน 1.18 )&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ✅ แล้วสิ่งที่เหมือนกันหล่ะ
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;มี interface ( ก็แน่ซิวะ )&lt;/li&gt;
&lt;li&gt;มีการทำ Encapsulation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;อย่างที่รู้กันว่า Golang เป็นภาษาที่โง่เง่าแทบจะใกล้เคียง C++ โดยที่ Feature ต่างๆที่คุ้นเคยใน Modern programming langauge นั้นมันแทบจะไม่เอามาเลย เพราะฉะนั้นการใช้ interface ใน Golang มันก็เลยแสนจะเรียบง่ายแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MySQLUserRepository&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;MySQLUserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c"&gt;// doing convert User entity to SQL statement and&lt;/span&gt;
    &lt;span class="c"&gt;// execute SQL statement&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จบแล้ว!? จาก snippet ถ้าผู้อ่านมาจากพื้นฐานการใช้ interface ภาษาอื่นก็อาจจะ มึนๆว่า &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;แล้วมันไป implements กันตอนไหนวะ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ความพิเศษของ Interface ใน Golang ถูกเขียนไว้ในบทความ Effective Go ว่า&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a way to specify the behavior of an object: if something can do this, then it can be used here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ห้ะ อะไรทำตามนี้ได้ ก็เอามาใส่ตรงนี้ได้ 🤨&lt;/p&gt;

&lt;h1&gt;
  
  
  if something can do this, then it can be used here.
&lt;/h1&gt;

&lt;p&gt;แน่นวลว่า ในภาษา Strong Type OOP อย่าง Java ไม่อนุญาติให้เรา assign class ที่ไม่ได้ implements interface ที่ถูกต้องเข้าไปใน Variable ของ interface นั้น&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ถึงแม้ว่ามันทำงานได้ตรงตาม Behavior ที่ประกาศไว้ใน interface เป้ะๆ ก็ตาม&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;อย่างเช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.company&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySQLUserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userrepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySQLUserRepository&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// ^^^^ java: incompatible types: com.company.MySQLUserRepository cannot be converted to com.company.UserRepository&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;วิธีการแก้อันนี้ก็คือ ตัว &lt;code&gt;MySQLUserRepository&lt;/code&gt; จะต้อง Explicit ประกาศการ implements ของ &lt;code&gt;UserRepository&lt;/code&gt; ด้วยถึงสามารถ Compile ผ่าน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySQLUserRepository&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แต่สำหรับ Golang ไม่เป็นแบบนั้น เนื่องจากอย่างที่บอกไว้ใน Effective Go ว่าอะไรทำงานได้ตรงตาม interface ก็เอามาใส่ได้เลยสิวะ&lt;/p&gt;

&lt;p&gt;ผลลัพธ์ก็คือ &lt;strong&gt;ไม่จำเป็นจะต้องมี syntax implements ใดๆใน type declaration หาก type นั้นสามารถทำงานได้ตรงกับที่ interface กล่าวไว้ ถือว่าใช้ได้&lt;/strong&gt; สามผ่าน!!!!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MySQLUserRepository&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;MySQLUserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userrepo&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt;
    &lt;span class="n"&gt;userrepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;MySQLUserRepository&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; 
    &lt;span class="c"&gt;// ^^^^^^^ บรรทัดนี้ใช้งานได้เลย ผ่าน เพราะ MySQLUserRepository สามารถ Save(user User) error ได้&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อมีความยืดหยุ่นขนาดนี้ ทำให้ interface ใน Golang มันสามารถตีลังกาใช้งานได้หลายแบบ ตามความเหมาะสมของ design pattern หรือ ปัญหาต่างๆที่เราพยายามจะควบคุมอยู่&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;เนื้อหาต่อไปจะเป็นวิธีการใช้งานส่วนหนึ่งที่ผู้เขียนใช้งานอยู่&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1. ประกาศ interface บริเวณที่ต้องการมี Dependency
&lt;/h3&gt;

&lt;p&gt;ตามที่ Go CodeReviewComments ได้กล่าวไว้ในหัวข้อ &lt;a href="https://github.com/golang/go/wiki/CodeReviewComments#interfaces"&gt;Interfaces&lt;/a&gt; ว่า &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values. The implementing package should return concrete (usually pointer or struct) types: that way, new methods can be added to implementations without requiring extensive refactoring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  แปล
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;p&gt;Go interface ปกติแล้วจะต้องอยู่ใน package ที่ใช้งาน interface นั้น, ไม่ใช่ package ที่ implements สิ่งนั้นๆ. package ที่ implement ควรจะต้อง return concrete types ซึ่งวิธีนี้ จะสามารถทำให้เพิ่ม method ใหม่ๆได้ง่ายโดยไม่ต้องใช้เวลาในการ refactoring มาก.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;หัวข้อนี้น่าจะเป็น &lt;strong&gt;หัวใจของการใช้ interface ของ Golang&lt;/strong&gt; เลยทีเดียว ในปกติแล้ว ภาษา OOP จะมี interface ควบคู่กับ implementation ตลอดเพื่อให้รู้ว่า package นั้นจะมีอะไรให้ใช้งานบ้าง แต่ใน Golang จะพยายามทำกลับด้านกัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="c"&gt;// login.go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserFinder&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// นี่คือส่ิงที่เราต้องการ มีแค่ Find ก็พอแล้ว&lt;/span&gt;
    &lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;LoginUseCase&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;Userfinder&lt;/span&gt; &lt;span class="n"&gt;UserFinder&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;LoginUseCase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userfinder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="c"&gt;// user.go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c"&gt;// UserRepository เป็น implementation เต็มๆ&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="c"&gt;// main.go&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userrepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
   &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;loginuc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoginUseCase&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="n"&gt;UserFinder&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userrepo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// สามารถใช้ได้เพราะ มี Find()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จาก Snippet จะพบว่า สิ่งที่ &lt;code&gt;LoginUseCase&lt;/code&gt; ต้องการนั้นไม่ใช่ &lt;code&gt;UserRepository&lt;/code&gt; แต่เป็นอะไรก็ได้ที่มี&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Find(context.Context, id string) (*entity.User, error)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตามที่กล่าวไว้ใน &lt;code&gt;UserFinder&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;และเนื่องจาก &lt;code&gt;UserRepository&lt;/code&gt; นั้นมี method นี้อยู่ จีึงสามารถ assign ให้กับ &lt;code&gt;LoginUseCase&lt;/code&gt; ได้&lt;/p&gt;

&lt;p&gt;ดังนั้นสิ่งที่เกิดขึ้นคือ &lt;code&gt;LoginUseCase&lt;/code&gt; นั้นไม่จำเป็นต้องรับรู้ว่ามี &lt;code&gt;UserRepository&lt;/code&gt; หรือเปล่า โดย &lt;code&gt;LoginUseCase&lt;/code&gt; แค่ประกาศสิ่งที่ต้องใช้งานไว้ที่ตัวเอง และรอ package อื่นๆเป็นคนโยนเข้ามาให้&lt;/p&gt;

&lt;h3&gt;
  
  
  2. ประกาศ Getter interface เพื่อทำ Union Type
&lt;/h3&gt;

&lt;p&gt;จาก การใช้งานข้อ 1. ทำให้เราสามารถรวม 2 Type (หรือมากกว่า) เป็น Type เดียวกันได้ ในกรณีต้องการรับ parameter ให้ได้มากกว่า 1 type ยกตัวอย่างเช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Whiskers&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Fangs&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SpellName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="err"&gt;???&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;SpellName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Happies"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Whiskers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;SpellName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Howard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Fangs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ปัญหานี้ เกิดจาก Golang นั้นไม่มี Attribute ที่เป็น Value ใน interface  และไม่สามารถทำ Union Type แบบภาษาอื่นๆได้ ทำให้ต้องมีการทำ Get เพื่อทำให้ 2 types สามารถ compat กันได้ (หรือสามารถทำ type assertion ได้ ซึ่งจะเล่าในบทความอื่น)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Whiskers&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Fangs&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SpellName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
     &lt;span class="c"&gt;//           ^^^^^ ตรงนี้ bonus การทำ inline interface&lt;/span&gt;
     &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;SpellName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Happies"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Whiskers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;SpellName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Howard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Fangs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. ประกาศ interface ควบคู่กับ struct ที่ package ไปเลย
&lt;/h3&gt;

&lt;p&gt;ข้อนี้อาจจะขัดใจ Gopher ทั้งหลายอยู่บ้าง เพราะนี่คือการใช้งาน interface แบบ ภาษา OOP ทั่วไปคือการประกาศ interface ไว้ที่ package ต้นทาง เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="c"&gt;// user.go&lt;/span&gt;

&lt;span class="c"&gt;// **ต้องคิดดีๆก่อนเอา interface นี้ไปใช้&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SQLUserRepository&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c"&gt;// UserRepository เป็น implementation เต็มๆ&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SQLUserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SQLUserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เนื่องจากการประกาศ interface จะทำให้รู้ overview คร่าวๆของ สิ่งที่ package นี้ provide ออกมา ทำให้การ maintain struct ใหญ่ๆจะง่ายขึ้น ผู้เขียน บางคร้ังมีการประกาศ interface ไว้เพื่อควบคุม signature ของ concrete ที่ package นี้รับผิดชอบอยู่&lt;/p&gt;

&lt;p&gt;แต่ในตัวอย่างนั้น &lt;code&gt;UserRepository&lt;/code&gt; จะแทบไม่ได้ถูกใช้งานโดย package อื่นเนื่องจาก ขนาดของ interface นี้จะเริ่มใหญ่ขึ้นตาม concrete ที่ implement ซึ่งจะขัดกับหลักการ interface segregation และทำให้ maintain ยาก&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;อยู่ข้างบนสุดแล้ว หัวข้อ TR:DR&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ขอให้มีความสุขกับการเขียนโค้ด!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>interface</category>
      <category>pattern</category>
    </item>
    <item>
      <title>เล่าเรื่องการจัดการทีม เพื่อทำงานแบบ Remote ใน 2 เดือนที่ผ่านมา</title>
      <dc:creator>Rungsikorn Rungsikavanich</dc:creator>
      <pubDate>Sat, 13 Jun 2020 06:28:21 +0000</pubDate>
      <link>https://forem.com/zapkub/remote-2-3oen</link>
      <guid>https://forem.com/zapkub/remote-2-3oen</guid>
      <description>&lt;h4&gt;
  
  
  TL;DR
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;ใช้ Communication tools ที่เหมาะสมกับการทำงาน (แนะนำให้ใช้ Workplace messaging แทน Social Messaging)&lt;/p&gt;

&lt;p&gt;ควรมี Task Management ที่ทุกคนสามารถใช้งานได้ทั่วถึง &lt;/p&gt;

&lt;p&gt;และ ทำ Peer Review ทั้งเชิง Technical และ Business ก่อน Deliver&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;เนื่องจากสถานะการแพร่ระบาดของเชื้อไวรัส COVID-19 ภายใต้บริษัทที่ผมทำงานอยู่จึงออกมาตราการให้ทุกคนทำงานจากที่บ้านถ้าหากเป็นไปได้&lt;/p&gt;

&lt;p&gt;ตัดภาพมาที่ทีมที่ผมดูแลอยู่มี Developer จำนวน 6 คนและ Application ที่อยู่ในช่วง Development 1 โปรเจค ประกอบด้วย ชาวต่างชาติ 4 คนและคนไทย 2 คนและ&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ทุกคนไม่เคยมีประสบการณ์ Remotely Working มาก่อน&lt;/strong&gt; 😱&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ความท้าทายของการทำงานแบบ Remotely Working คือการควบคุมขั้นตอนการทำงาน และการสื่อสาร&lt;/p&gt;

&lt;p&gt;เนื่องจากโดยส่วนตัวแล้ว ผมเองไม่คิดว่าการทำงานแบบ Remotely หรือ Work From Home จะมีประสิทธิภาพดีกว่าการทำงานแบบ Face To Face ได้ในแง่ของการสื่อสาร&lt;/p&gt;

&lt;p&gt;แต่ด้วยสถานะการบังคับ เราเลยต้องมีการวางแผนและออกแบบวิธีการทำงาน เพื่อให้ได้ประสิทธิภาพการทำงานเท่าเดิม (หรือดีกว่า) ให้ได้&lt;/p&gt;

&lt;h3&gt;
  
  
  ผมแบ่งหัวข้อในการออกแบบวิธีการทำงานของทีมเป็น
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;การสื่อสาร - Communication&lt;/li&gt;
&lt;li&gt;การติดตามความคืบหน้า - Tracking&lt;/li&gt;
&lt;li&gt;การตรวจสอบคุณภาพงาน และส่งงาน - Peer Review and Deliver&lt;/li&gt;
&lt;/ol&gt;



&lt;h2&gt;
  
  
  🌏 1. การสื่อสาร - Communication
&lt;/h2&gt;

&lt;p&gt;เราคงจะเถียงไม่ได้ว่า การเดินไปจิกงาน หรืออธิบายรายละเอียดของงานนั้น ทำได้ง่ายกว่าในกรณี Face To Face แต่เมื่อเราต้อง Remotely Working สิ่งสำคัญอันดับแรกก็คือ&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Communication Tools&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Party ที่สำคัญหลักๆในการพัฒนาซอฟแวร์ไม่ได้มีเพียงแค่ Developer อย่างเดียว &lt;/p&gt;

&lt;p&gt;เพราะยังรวมถึง Business Analysis team, Business Unit team, Management team, Test team ซึ่งทั้งหมดควรมี Protocol  ในการสื่อสารเหมือนกัน&lt;/p&gt;

&lt;p&gt;ภายใต้กลุ่มบริษัทของผม เราใช้ Microsoft 365 เป็นหลักในการทำงาน ดังนั้น Policy ของบริษัทจึงแนะนำให้ใช้ &lt;strong&gt;Microsoft Teams&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(สามารถเป็น อะไรก็ได้เช่น Slack, Hipchat, Facebook Workplace)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LvSVKCKj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1200/0%2AmkYblca8SyBPNygs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LvSVKCKj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1200/0%2AmkYblca8SyBPNygs.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ก่อนหน้านี้ ทุกคนสามารถใช้ Line ในการสื่อสารได้เพราะว่า การสื่อสารเป็นแค่การ สื่อความเล็กๆน้อยๆไม่ซับซ้อน &lt;/p&gt;

&lt;p&gt;แต่หลังจากที่ต้องทำงานแบบ 100% Remotely เราพบว่า Line ไม่สามารถตอบสนองความซับซ้อนของการสนทนาในหลายแง่เช่น&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;การแยกบทสนทนาเป็นรายหัวข้อ ( การทำ Thread และ Post )&lt;/li&gt;
&lt;li&gt;การจัดการ Channel, Chatroom เครื่องมืออย่าง Slack และ MSTeam ทำได้ดีกว่า Social Messaging ทั่วไป&lt;/li&gt;
&lt;li&gt;การ Integrate เข้ากับ Cloud หรือ Storage ภายใต้ Microsft Office นั้น MS Team สามารถทำได้ดีกว่า Line มาก ในการแชร์เอกสารร่วมกัน&lt;/li&gt;
&lt;li&gt;การประชุมสาย MS Team สามารถทำได้ดีกว่า Line และสามารถ Record การสนทนาได้ และสามารถนัดประชุมล่วงหน้าได้ (ใช้ร่วมกันกับ Outlook Calendar)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Protocol ของการสื่อสาร
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;ภายใต้หัวข้อนี้จะพูดถึงการใช้งาน Microsoft Team เป็นหลัก&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  การใช้ Channel
&lt;/h4&gt;

&lt;p&gt;ภายใต้ feature ของ Microsoft Team เราสามารถจัดการหัวข้อการสนทนาได้อย่างละเอียดกว่า Social Messaging ทั่วไปโดยภายใต้ทีมของผม เราใช้ Channel ในการสนทนาเชิงวิเคราะห์ต่างๆเช่น วิเคราะห์ Requirement, รายงานปัญหาที่เกิดจาก Release ต่างๆ &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B5RWPuNI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6sftj7l43zn5jyw4l63d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B5RWPuNI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6sftj7l43zn5jyw4l63d.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ภายใต้ Channel มีการทำ Annoncement และการ Posts&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OasFmStl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/22nih2pgnhz9a2k4tljf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OasFmStl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/22nih2pgnhz9a2k4tljf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  การใช้ Chat และ Group Chat
&lt;/h4&gt;

&lt;p&gt;เนื่องจาก MS Team นั้นมี Feature การสนทนาค่อนข้างแตกต่างจาก Line และ Social Messaging ทั่วไป ชนิดของบทสนทนานั้นแบ่งออกเป็น &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Channel&lt;/li&gt;
&lt;li&gt;Post, Annoucement&lt;/li&gt;
&lt;li&gt;Meeting Chat&lt;/li&gt;
&lt;li&gt;Chat and Group Chat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ทั้งสามอย่างมีวิธีการใช้แตกต่างกันตามแต่ละทีมจะนำไปประยุกต์ใช้และเราใช้ Chat และ Group Chat กับการสนทนาประจำวัน&lt;/p&gt;

&lt;h4&gt;
  
  
  มีการรายงานสถานะประจำวันของแต่ละคน Daily Meeting
&lt;/h4&gt;

&lt;p&gt;ทางทีมยังคงใช้รูปแบบการทำงานที่ชื่อว่า Agile อยู่ เรายังมีการทำ Remotely Daily Meeting ทุกวันในช่วงเวลาที่ทุกคนสะดวก ( 11:00am ) เพื่อให้ทุกคนสามารถรายงานความคืบหน้าและสถานะการของตัวเอง (เฉลี่ย ไม่ควรเกิน 20 นาทีต่อครั้ง)&lt;/p&gt;

&lt;h5&gt;
  
  
  หัวข้อของ Daily Meeting ประกอบด้วย
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;เมื่อวานนี้ทำอะไร&lt;/li&gt;
&lt;li&gt;วันนี้ทำอะไร&lt;/li&gt;
&lt;li&gt;ต้องการให้ใครช่วย&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ทำเอกสารให้มันใช้งานได้จริงๆ
&lt;/h4&gt;

&lt;p&gt;หลังจาก Work From Home เราเน้นเรื่องเอกสารมากขึ้น ในการทำงานแต่ละ Issues &lt;/p&gt;

&lt;p&gt;ยกตัวอย่างเช่น การทำ Merge Request จะต้องมี Template ของการทำ MR ชัดเจนเพื่อให้การทำ Peer Review ทำได้สะดวก&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O3uii4KF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/x6tvuvip9lad5tcxug7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O3uii4KF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/x6tvuvip9lad5tcxug7b.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  อื่นๆ
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;เราใช้ Gitlab และการทำ Merge Request เพื่อทำ Peer review&lt;/li&gt;
&lt;li&gt;เราออกแบบ Git branching strategy ร่วมกันเพื่อให้การทำงานทุกคนไปในทิศทางเดียวกัน&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  ปัญหาที่เจอในการสื่อสาร
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;สมาชิกทีมบางส่วนยังคุ้นเคยกับการใช้งาน Line มากกว่า เนื่องจาก Microsft Team ไม่ใช่ Social Messaging จึงมีขั้นตอนการใช้งานยุ่งยากมากกว่า Line ที่ออกแบบมาเพื่อการใช้งานอย่างเรียบง่าย การ Adopt ใช้ Microsoft Team ต้องมีการเรียนรู้เพิ่มเติมจาก เอกสารต่างๆหรือ Training Session เพื่อให้ใช้งานได้อย่างมีประสิทธิภาพ ทำให้บางส่วนของ Team ยังมีการใช้ Line ในการสื่อสารอยู่&lt;/li&gt;
&lt;li&gt;ปัญหา Internet Connection และ คุณภาพของ Microphone เนื่องจากทุกคนไม่คิดว่าการทำงานแบบ Remotely จะยืดยาวจึงไม่ได้มีการเตรียมพร้อมหา Internet Connection ที่พร้อมสำหรับการใช้งาน รวมถึงอุปกรณ์การสื่อสารต่างๆเช่น คุณภาพของ Microphone &lt;/li&gt;
&lt;li&gt;กำแพงด้านภาษา เนื่องจากภายในทีมมีชาวต่างชาติ การสื่อสารบางอย่างค่อนข้างติดขัดบ้าง เพราะว่าภายในทีมบางส่วนไม่คุ้นเคยกับการใช้ภาษาอังกฤษในการทำงาน&lt;/li&gt;
&lt;li&gt;ความขี้เกียจเขียนเอกสารของ Developer&lt;/li&gt;
&lt;/ol&gt;



&lt;h2&gt;
  
  
  🧑🏼‍💻 2. การติดตามความคืบหน้า - Tracking
&lt;/h2&gt;

&lt;p&gt;อย่างที่กล่าวไปเบื้องต้นแล้วว่าเราใช้ Agile ในการทำงาน การสื่อสาร Tools ที่ทางบริษัทมีให้ใช้คือ Atlassian JIRA&lt;/p&gt;

&lt;p&gt;เนื่องจาก Position ผมเองเป็น Technical Lead และ Scrum Master ไปในตัว เราจึงเป็นคนที่ควบคุมกระบวนการ การทำงานของทีมไปด้วย&lt;/p&gt;

&lt;p&gt;โชคดีของเราคือ Test team มีการใช้งาน JIRA ร่วมกัน ทำให้การทำ Bug tracking นั้นสะดวกมากยิ่งขึ้น (ปกติทาง Test team ใช้ HPQC แต่ช่วยมาทำใน JIRA ให้ด้วย)&lt;/p&gt;

&lt;p&gt;ทำให้เราสามารถ tracking งานต่างๆ และเห็นภาพรวมของโปรเจคได้ชัดเจน&lt;/p&gt;

&lt;p&gt;เนื่องจากการใช้ JIRA และทำ Issue Tracking เรามีการปฏิบัติอยู่แล้วตั้งแต่ก่อน Work From Home จึงไม่มีอะไรกระทบมากนัก&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lOpNGEUy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kxwgnmpj5cfzrygx6dwk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lOpNGEUy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kxwgnmpj5cfzrygx6dwk.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Draft Release note ให้ชัดเจน
&lt;/h4&gt;

&lt;p&gt;Release Note เป็นส่วนหนึ่งที่มีประโยชน์มากในการวางแผนการพัฒนาซอฟแวร์ &lt;/p&gt;

&lt;p&gt;การทำ Release Note ที่ดี จะทำให้เราสามารถกำหนดและสื่อสารสิ่งที่จะ Deliver มาได้ชัดเจน ให้กับลูกค้าหรือ ทีมอื่นๆที่จะต้องเข้ามามีส่วนร่วมในการพัฒนาซอฟแวร์&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NPexaErt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zi6xxh9m087jdoqyr3xn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NPexaErt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zi6xxh9m087jdoqyr3xn.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q0UdHuNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/70s9wwmqw7wbws5ub1v7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q0UdHuNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/70s9wwmqw7wbws5ub1v7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  ปัญหาที่เจอ
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;ในฐานะคนดูแล Sprint และ Technical ไปพร้อมกัน ทำให้บางครั้ง ข้อมูลต่างๆภายใน JIRA ไม่ได้ถูกอัพเดทตามต่อวัน&lt;/li&gt;
&lt;li&gt;Notification ใน JIRA เมื่อเกิด Activity ต่างๆ (เวอร์ชั่นเก่า) ยังไม่ดีเท่าที่พอใจ บางครั้งทำให้การ Response Issue ต่างๆใน JIRA ค่อนข้างช้า&lt;/li&gt;
&lt;li&gt;Integration ระหว่าง Gitlab กับ JIRA ทำได้ยาก เนื่องจากข้ามผลิตภัณฑ์กัน จึงไม่ Seemless เท่าที่ควร (ถ้าเป็น BitBucket จะสามารถ Integrate JIRA task เข้ากับ Merge Request ได้ง่ายกว่า)&lt;/li&gt;
&lt;/ol&gt;



&lt;h1&gt;
  
  
  🤖 📦 การตรวจสอบคุณภาพงาน และส่งงาน - Peer Review and Deliver
&lt;/h1&gt;

&lt;p&gt;เนื่องจากซอฟแวร์ที่ดูแล มีขั้นตอนการทำงานในเชิงธุรกิจ ( Business logic and Functionality ) ที่ค่อนข้างซับซ้อนและครอบคลุมหลายผลิตภัณฑ์ในด้านการเงิน &lt;/p&gt;

&lt;p&gt;ทำให้การส่งงาน ( Merge code ) จำเป็นต้องมีการ Review จากหลายส่วน เพื่อให้รองรับการดูแลรักษาในอนาคต (Maintainability)&lt;/p&gt;

&lt;p&gt;จึงต้องมีการทำ Policy ต่างๆขึ้นมาเพื่อรองรับการทำงาน เช่น&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;การส่งงานใน Merge Request ต้องครอบคลุมถึงการเขียน Test ที่สำคัญใน Merge Request Change นั้นๆ&lt;/li&gt;
&lt;li&gt;Convention ของการเขียนโค้ด (Code Style and Convention Guideline)&lt;/li&gt;
&lt;li&gt;Template ของการเปิด Merge Request&lt;/li&gt;
&lt;li&gt;Branching Strategy และการ Merge Request เข้า release branch ให้ถูกต้อง&lt;/li&gt;
&lt;li&gt;ทำ ​Technical Peer Review&lt;/li&gt;
&lt;li&gt;CI/CD เพื่อรัน Unit-test, Integration-test และ E2E-test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เรายังมีการจัด Business Functionality Review Session เพื่อให้ Business Team ได้เข้ามามีส่วนร่วมในการ Review ชิ้นงานแต่ละ Feature ก่อน Merge เข้า Stable Branch&lt;/p&gt;



&lt;h1&gt;
  
  
  สรุป
&lt;/h1&gt;

&lt;p&gt;เขียนมาถึงตรงนี้ก็หมดแรงแล้ว ถึงอย่างไรบทความข้างต้นเป็นการออกแบบการทำงานเพื่อรองรับกับทีมที่ผมเป็นคนดูแลอยู่&lt;/p&gt;

&lt;p&gt;สุดท้ายแล้วการทำงานจะเป็นแบบไหนขึ้นอยู่กับลักษณะเฉพาะของงาน และทีมที่เราทำงานอยู่ด้วย&lt;/p&gt;

&lt;p&gt;การทำให้ทีมทำงานได้อย่างมีประสิทธิภาพ ต้องอาศัยการทำความเข้าใจคนภายในทีม รูปแบบการทำงาน นิสัย ทัศนคติ เพื่อนำมาออกแบบวิธีการทำงานให้เกิดประสิทธิภาพสูงสุด&lt;/p&gt;

</description>
      <category>workremotely</category>
      <category>softwareprocess</category>
    </item>
  </channel>
</rss>
