<?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: kanthakran</title>
    <description>The latest articles on Forem by kanthakran (@gun27311).</description>
    <link>https://forem.com/gun27311</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%2F512109%2Fd3a9bf37-cda7-433c-abc8-a1e40c17feae.jpeg</url>
      <title>Forem: kanthakran</title>
      <link>https://forem.com/gun27311</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gun27311"/>
    <language>en</language>
    <item>
      <title>GITHUB ACTION (Quick guide)</title>
      <dc:creator>kanthakran</dc:creator>
      <pubDate>Fri, 11 Nov 2022 09:01:25 +0000</pubDate>
      <link>https://forem.com/gun27311/github-workflow-quick-guide-1dgg</link>
      <guid>https://forem.com/gun27311/github-workflow-quick-guide-1dgg</guid>
      <description>&lt;p&gt;** &lt;br&gt;
This article is written as a reminder of myself, if you can put this to good use, you are welcome to comment to add content.&lt;/p&gt;
&lt;h1&gt;
  
  
  What is GITHUB ACTION
&lt;/h1&gt;

&lt;p&gt;it is &lt;a href="https://en.wikipedia.org/wiki/CI/CD" rel="noopener noreferrer"&gt;CICD&lt;/a&gt; of Github .&lt;br&gt;
like a normal CICD in the world but it can integrate some action on git for example push , release tag , create branch , delete branch etc ...&lt;/p&gt;
&lt;h1&gt;
  
  
  How it work ?
&lt;/h1&gt;

&lt;p&gt;If you imagine deploying typically requires writing a script and using a machine to run . yes that it !&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hint machine for run script it naming runner&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Github jest provide share server for run your script (CICD)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners" rel="noopener noreferrer"&gt;But you can register runner for run it&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  The components of GitHub Actions
&lt;/h1&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%2F6r4flyb3tg66g08isag2.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%2F6r4flyb3tg66g08isag2.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
in work flow it have 5 component&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions/using-workflows" rel="noopener noreferrer"&gt;Workflows&lt;/a&gt; : Workflows are defined in the &lt;code&gt;.github/workflows&lt;/code&gt; directory in a repository&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows" rel="noopener noreferrer"&gt;Events&lt;/a&gt; : 
An event is a specific activity in a repository that triggers a workflow run&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions/using-jobs" rel="noopener noreferrer"&gt;Jobs&lt;/a&gt; : A job is a set of steps in a workflow that execute on the same runner. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions/creating-actions" rel="noopener noreferrer"&gt;Actions&lt;/a&gt; : An action is a custom application for the GitHub Actions platform that performs a complex but frequently repeated task&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners" rel="noopener noreferrer"&gt;Runner&lt;/a&gt; : A runner is a server that runs your workflows when they're triggered.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Example work flow
&lt;/h1&gt;

&lt;p&gt;This workflow use for deploy cloudfront aws . it trigger when published release tag start with &lt;code&gt;releases-prod/*&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Why i use when published release tag &lt;br&gt;
because when deploy project it should mark version of deployment example &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;releases-prod/v1.0.1&lt;/code&gt; : when deploy production it check if in below work flow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;releases-staging/v1.0.1&lt;/code&gt; : when deploy staging it check if in below work flow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;releases-develop/v1.0.1&lt;/code&gt; : when deploy develop it check if in below work flow&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Repo/.github/workflows/main.yml
&lt;/h1&gt;

&lt;p&gt;When you create this file in the repo, it will be triggered by itself when you do something that matches the event you set.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;hint: uses for call SDK on Github action example &lt;a href="https://github.com/google-github-actions/setup-gcloud" rel="noopener noreferrer"&gt;gcloud&lt;/a&gt;,&lt;a href="https://github.com/aws-actions/configure-aws-credentials" rel="noopener noreferrer"&gt;aws&lt;/a&gt; ,&lt;a href="https://github.com/messense/huaweicloud-github-runner" rel="noopener noreferrer"&gt;huawei&lt;/a&gt; etc..&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Node.js CICD
on:
  release:
    types: [published]

jobs:
  deploy-prod: # jobs name deploy-prod
    runs-on: ubuntu-latest # script run on ubuntu
    if: startsWith( github.ref, 'refs/tags/releases-prod/')
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '14'
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
          aws-region: ap-southeast-2

      - name: yarn install
        run: yarn

      - name: test
        run: yarn test

      - name: build production
        run: yarn build:production

      - name: aws sync s3
        run: aws s3 sync ./build s3://my-hello-aws --acl public-read

      - name: deploy aws cloudfront
        run: aws cloudfront create-invalidation --distribution-id MY_DISTRIBUTE_ID --paths '/*'

      - name: print
        run: echo "deploy PROD"

#------------ deploy staging ------------
  deploy-staging: 
    runs-on: ubuntu-latest
    if: startsWith( github.ref, 'refs/tags/releases-staging/')
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '14'
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
          aws-region: ap-southeast-2

      - name: yarn install
        run: yarn

      - name: build staging
        run: yarn build:staging

      - name: aws sync s3
        run: aws s3 sync ./build s3://my-hello-aws --acl public-read

      - name: deploy aws cloudfront
        run: aws cloudfront create-invalidation --distribution-id MY_DISTRIBUTE_ID --paths '/*'

      - name: print
        run: echo "deploy STAGING test"

#------------ deploy develop ------------

  deploy-develop: 
    # needs: build-develop
    runs-on: ubuntu-latest
    if: startsWith( github.ref, 'refs/tags/releases-develop/')
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '14'
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_DEVELOP }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_DEVELOP }}
          aws-region: ap-southeast-2

      - name: yarn install
        run: yarn

      - name: build development
        run: yarn build:development

      - name: aws sync s3
        run: aws s3 sync ./build s3://my-hello-aws --acl public-read

      - name: deploy aws cloudfront
        run: aws cloudfront create-invalidation --distribution-id MY_DISTRIBUTE_ID --paths '/*'

      - name: print
        run: echo "deploy develop test"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Secret manager
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;${{ secrets.AWS_ACCESS_KEY_ID_PROD }}&lt;/code&gt; this value store in  secret manager Github can config in below image .when you use it in CICD command it will replace by ****** for hidden.&lt;/p&gt;
&lt;/blockquote&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%2Fyt0y804e6xnpccx8morg.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%2Fyt0y804e6xnpccx8morg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example log
&lt;/h2&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%2Fr51vwc2wufk7s4wq33gv.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%2Fr51vwc2wufk7s4wq33gv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Easy roll back
&lt;/h2&gt;

&lt;p&gt;When you bomb yourself in the new version.&lt;br&gt;
you can click action and rerun action for roll back follow image&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%2Fuploads%2Farticles%2Fouj49weywhqnz7zvsdfw.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%2Fouj49weywhqnz7zvsdfw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;click rerun all jobs for rollback to old version&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%2Fuploads%2Farticles%2Fny1jijasl7fzttbhzpn9.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%2Fny1jijasl7fzttbhzpn9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Try it on your self
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/examples/using-concurrency-expressions-and-a-test-matrix" rel="noopener noreferrer"&gt;Structure explain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-workflows/creating-starter-workflows-for-your-organization" rel="noopener noreferrer"&gt;starter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration" rel="noopener noreferrer"&gt;build test&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Reference
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/" rel="noopener noreferrer"&gt;Github action official&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/actions" rel="noopener noreferrer"&gt;Github action repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>git</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Deploy contract with Hardhat th.</title>
      <dc:creator>kanthakran</dc:creator>
      <pubDate>Tue, 08 Mar 2022 10:15:30 +0000</pubDate>
      <link>https://forem.com/gun27311/deploy-contract-with-hardhat-th-4hck</link>
      <guid>https://forem.com/gun27311/deploy-contract-with-hardhat-th-4hck</guid>
      <description>&lt;p&gt;บทความนี้เหมาะสำหรับคนที่มีความรู้เรื่องการ deploy smart contract อยู่แล้ว&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;แต่ปัญหาที่เจอ Hardhat ไม่ support บาง chain เช่น klaytn ใช้ truffle เหมือนเดิมดีกว่า&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Hardhat vs Truffle
&lt;/h1&gt;

&lt;p&gt;ส่วนตัวผมนั้นเคยใช้ Truffle เป็นประจำอยู่แล้ว จากประสบการณ์ การเขียน smart contract มันมี step เดิมๆ ที่ต้องใช้ tool 2 ตัวนี้&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;test &lt;/li&gt;
&lt;li&gt;run test chain (อาจจะใช้ ganache หรือ testnet ก็ได้)&lt;/li&gt;
&lt;li&gt;complie&lt;/li&gt;
&lt;li&gt;deploy&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Setup Hardhat
&lt;/h1&gt;

&lt;p&gt;ใช้ npm ธรรมดาเลย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev hardhat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Debug
&lt;/h1&gt;

&lt;p&gt;ข้อดีของ hardhat เวลา debug เราสามารถใช้ console.log ได้เลยซึ่จะมีในตัวอย่างตอนที่เราสร้างขึ้นมาตาม command ข้างล่าง&lt;/p&gt;

&lt;h1&gt;
  
  
  Command
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Create project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตรงนี้แล้วแต่จะเลือกเลยจะใช้ อะไรผมชอบ typescript &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uRdEfSdF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pba3xgq68xltl5l8ytgc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uRdEfSdF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pba3xgq68xltl5l8ytgc.png" alt="Image description" width="880" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat compile 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run test chain
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Config Hardhat
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hardhat.org/config/"&gt;https://hardhat.org/config/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy contract
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat run scripts/sample-script.js
or
npx hardhat run scripts/sample-script.js --network localhost 
# สำหรับเลือก network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลังจาก deploy มัน auto verify code ให้เลยถ้าจะปิดหาวิธีเองนะ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4ORCVrNa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jvodrjclwgo4oxqc7e8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ORCVrNa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jvodrjclwgo4oxqc7e8.png" alt="Image description" width="321" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;รวมๆ เป็น tool ที่ครบเครื่องมากๆ ในการ dev ไม่ว่าจะเป็นตัว plugin verify code, ตัว run chain test , test lib ต่างๆ  รวมถึงตัว debug สุดล้ำ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ข้อเสียอย่างเดียวเลยคือ ไม่ได้ support ทุก chain แต่จะ dev ในนี้ไป deploy ใน truffle ก็ไม่เสียหาย hardhat ก็เทสไปใช้เท่าที่ใช้ได้ 555 &lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Starport CLI</title>
      <dc:creator>kanthakran</dc:creator>
      <pubDate>Fri, 21 Jan 2022 08:34:44 +0000</pubDate>
      <link>https://forem.com/gun27311/starport-cli-50n6</link>
      <guid>https://forem.com/gun27311/starport-cli-50n6</guid>
      <description>&lt;p&gt;เป็น CLI ที่ build อยู่บน cosmos SDK&lt;/p&gt;

&lt;h1&gt;
  
  
  มันคืออะไร
&lt;/h1&gt;

&lt;p&gt;มันเป็นเครื่องมือที่ใช้ในการสร้าง บำรุงรักษา blockchain โดยเฉพาะโดยใช้ Cosmos SDK และ Tendermint ตัวมันเองถูกเขียนด้วยภาษา go&lt;/p&gt;

&lt;h1&gt;
  
  
  Install Starport
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://get.starport.network/starport! | bash
sudo mv starport /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  เริ่มต้นสร้าง chain เบื้องต้น (ทำตามตัวอย่างที่เค้าให้มา)
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;starport scaffold chain github.com/cosmonaut/hello
sudo mv starport /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คำสั่งนี้สร้าง Cosmos SDK blockchain ที่เรียกว่า Hello ใน dir hello ประกอบด้วย blockchain ที่พร้อมใช้งานเบื้องต้นให้เรา&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;staking (opens new window)(for delegated proof of stake)&lt;/li&gt;
&lt;li&gt;bank (opens new window)(for fungible token transfers between accounts)&lt;/li&gt;
&lt;li&gt;gov (opens new window)(for on-chain governance)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  ภายใน hello ประกอบด้วย
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File/directory&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;app/&lt;/td&gt;
&lt;td&gt;Files that wire together the blockchain. The most important file is app.go that contains type definition of the blockchain and functions to create and initialize it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cmd/&lt;/td&gt;
&lt;td&gt;The main package responsible for the CLI of compiled binary.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;docs/&lt;/td&gt;
&lt;td&gt;Directory for project's documentation. By default, an OpenAPI spec is generated.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;proto/&lt;/td&gt;
&lt;td&gt;Protocol buffer files describing the data structure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;testutil/&lt;/td&gt;
&lt;td&gt;Helper functions for testing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vue/&lt;/td&gt;
&lt;td&gt;.A Vue 3 web app template.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x/&lt;/td&gt;
&lt;td&gt;Cosmos SDK modules and custom modules.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;config.yml&lt;/td&gt;
&lt;td&gt;A configuration file for customizing a chain in development.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ในตอนนี้เราก็สามารถทำให้บล็อกเชนของคุณทำงานบนโหนดเดียวได้แล้ว (แค่ node.เดียวนะ)&lt;/p&gt;

&lt;h1&gt;
  
  
  Start a Blockchain
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;starport chain serve 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เสร็จแล้วแค่นี้ละ&lt;br&gt;
🌍 Tendermint node: &lt;a href="http://0.0.0.0:26657"&gt;http://0.0.0.0:26657&lt;/a&gt;&lt;br&gt;
🌍 Blockchain API: &lt;a href="http://0.0.0.0:1317"&gt;http://0.0.0.0:1317&lt;/a&gt;&lt;br&gt;
🌍 Token faucet: &lt;a href="http://0.0.0.0:4500"&gt;http://0.0.0.0:4500&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;0.0.0.0 ไปหา ip เครื่องมาใส่ลองเข้าไปดู เล่นได้เล่นดี&lt;/p&gt;

</description>
      <category>blockchain</category>
    </item>
    <item>
      <title>Cloud function ลองเล่น</title>
      <dc:creator>kanthakran</dc:creator>
      <pubDate>Thu, 07 Jan 2021 18:35:32 +0000</pubDate>
      <link>https://forem.com/gun27311/cloud-function-note-559k</link>
      <guid>https://forem.com/gun27311/cloud-function-note-559k</guid>
      <description>&lt;h1&gt;
  
  
  มันคืออะไร
&lt;/h1&gt;

&lt;p&gt;มันคือ FaaS = Function as a service พูดง่ายๆ เหมือนเขียน function ไว้บน gcloud เพื่อทำอะไรตามใจเรารักสามารถทำงานคู่กับหลายๆ อย่างบน gcloud ได้ตัวมันเองนั้นทำงานแบบ async และ serverless สามารถ scale ได้แบบอัตโนมัต&lt;br&gt;
ซึ่งสามารถเขียนได้หลายภาษา &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nodejs &lt;/li&gt;
&lt;li&gt;python&lt;/li&gt;
&lt;li&gt;go &lt;/li&gt;
&lt;li&gt;java&lt;/li&gt;
&lt;li&gt;.NET&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  การเก็บเงินของ Cloud Function
&lt;/h1&gt;

&lt;p&gt;จะเก็บเงินตามที่เราเรียกใช้มันเท่านั้นโดยคิดตามเวลาในการประมวลผลโดยถ้าเราไม่ใช้ก็จะไม่เสียเงินจะดีกว่าการที่เราไปตั้ง host เพราะต้องเสียเงินตลอด&lt;br&gt;
ดูราคาได้เลยยย&lt;br&gt;
&lt;a href="https://cloud.google.com/functions/pricing"&gt;https://cloud.google.com/functions/pricing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  เริ่มทดลองกันเลย
&lt;/h1&gt;

&lt;p&gt;ในตัวอย่างนี้เราจะมาเล่นโดยใช้ nodejs&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VbOm9Nvp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d4vjf6w61950ohbj12pa.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VbOm9Nvp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d4vjf6w61950ohbj12pa.PNG" alt="Alt Text" width="641" height="355"&gt;&lt;/a&gt;&lt;br&gt;
เมื่อเข้ามาแล้วกด create function ได้เลย&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IJSjN068--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/osgdc5xs6lsxd4794p4k.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IJSjN068--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/osgdc5xs6lsxd4794p4k.PNG" alt="Alt Text" width="598" height="182"&gt;&lt;/a&gt;&lt;br&gt;
อันนี้อะไรก็ได้เลย&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vgtDiGqp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rjsd3em250653bh3flkr.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vgtDiGqp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rjsd3em250653bh3flkr.PNG" alt="Alt Text" width="513" height="374"&gt;&lt;/a&gt;&lt;br&gt;
ตรงส่วนนี้ผมรู้สึงว่าน่าสนใจตัว trigger ค่อนข้างหลากหลายมากๆ แต่ขอเล่น http แล้วกันง่ายดี 55&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HrTFFPeT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fuvwhz9pksfv3gu6lmvb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HrTFFPeT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fuvwhz9pksfv3gu6lmvb.PNG" alt="Alt Text" width="461" height="219"&gt;&lt;/a&gt;&lt;br&gt;
ขอเลือกแบบไม่ต้อง authen เพราะแค่ลองเล่นกด save โลด&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p5jWOf80--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iyq828qfw3zywlyqfh3b.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p5jWOf80--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iyq828qfw3zywlyqfh3b.PNG" alt="Alt Text" width="880" height="457"&gt;&lt;/a&gt;&lt;br&gt;
พอถึงหน้านี้แล้วรู้สึกได้ถึงความคุ้นเคย ใช่แล้วมัน express ชัดๆ&lt;br&gt;
ดูค่อนข้างง่ายกับการใช้งานมากๆเลย&lt;br&gt;
ส่วน package.json ใครจะลงอะไรก็ไป set dependency โลด&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6STUdCMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/abmr8td7nmcncpsuecfb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6STUdCMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/abmr8td7nmcncpsuecfb.PNG" alt="Alt Text" width="585" height="222"&gt;&lt;/a&gt;&lt;br&gt;
ในตัวอย่างลองเพิ่ม upper case เข้าไป&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l1YTxMHt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q09p0enb7wu9d7u2tu15.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l1YTxMHt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q09p0enb7wu9d7u2tu15.PNG" alt="Alt Text" width="812" height="239"&gt;&lt;/a&gt;&lt;br&gt;
แล้วเรียกใช้ใน index แล้วกด &lt;strong&gt;Deploy ได้เลย&lt;/strong&gt;&lt;br&gt;
ใช้เวลานานนิดหน่อยนะ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lE6d_dO8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3weehtsxgwujkkcu1rg4.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lE6d_dO8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3weehtsxgwujkkcu1rg4.PNG" alt="Alt Text" width="801" height="422"&gt;&lt;/a&gt;&lt;br&gt;
เราได้หน้าประมาณนี้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S4xaOb36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/exie7sd6tvu3cr2nlyok.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S4xaOb36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/exie7sd6tvu3cr2nlyok.PNG" alt="Alt Text" width="475" height="268"&gt;&lt;/a&gt;&lt;br&gt;
สามารถลองยิงได้ผ่าน url ในหน้า trigger หรือเราจะหน้า test ก็ได้นะ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2tcXMUBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wvtinxmshop0dtzurwxl.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2tcXMUBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wvtinxmshop0dtzurwxl.PNG" alt="Alt Text" width="255" height="172"&gt;&lt;/a&gt;&lt;br&gt;
ผลคือ HELLO เพราะ upper case&lt;/p&gt;

&lt;h2&gt;
  
  
  และมันยังมีอะไรอีกมากมายไปลองเองนะ
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;log &lt;/li&gt;
&lt;li&gt;Runtime environment variables,Build environment variables &lt;/li&gt;
&lt;li&gt;permission &lt;/li&gt;
&lt;li&gt;ฯลฯ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploy แบบ gcloud Command-Line Tool ก็ทำได้นะง่ายด้วย
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/functions/docs/quickstart"&gt;https://cloud.google.com/functions/docs/quickstart&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  สิ่งที่ cloud function ทำได้นั้นดูค่อนข้างหลากหลายมากเลยครับ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ตัวอย่าง Function Notify
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xl1knOFy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/izw403oai63qvi93ui67.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xl1knOFy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/izw403oai63qvi93ui67.png" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;br&gt;
function notify อาจจะเป็น sms , mail ก็ดูไม่แย่นะ ลองดูตัวอย่างการประยุกต์จากลิ๊งข้างล่างเลย&lt;br&gt;
&lt;a href="https://firebase.google.com/docs/functions/use-cases"&gt;https://firebase.google.com/docs/functions/use-cases&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ความเห็นส่วนตัว
&lt;/h2&gt;

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

</description>
      <category>cloud</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Test Driven Development (TDD) th.</title>
      <dc:creator>kanthakran</dc:creator>
      <pubDate>Thu, 17 Dec 2020 06:57:52 +0000</pubDate>
      <link>https://forem.com/gun27311/test-driven-development-tdd-4b16</link>
      <guid>https://forem.com/gun27311/test-driven-development-tdd-4b16</guid>
      <description>&lt;h1&gt;
  
  
  TDD คือ
&lt;/h1&gt;

&lt;p&gt;การสร้าง software ใน scope สั้นๆ โดยเราจะเขียน automate test เอาไว้ให้มัน fail ก่อนเพื่อจะกำหนดการทำงานของโปรแกรมในระดับ function แล้วเขียน code เพื่อให้ผ่าน test (เขียนให้ผ่านก่อน) แล้วเรามา refactor ให้มันดีขึ้นอีกที&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/http%3A%2F%2Fnewyorkschooltalk.org%2Fwp-content%2Fuploads%2F2020%2F02%2F1_ieVWcSsJmeBbZFo6a_dL5g.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/http%3A%2F%2Fnewyorkschooltalk.org%2Fwp-content%2Fuploads%2F2020%2F02%2F1_ieVWcSsJmeBbZFo6a_dL5g.png" alt="tdd"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;a href="http://newyorkschooltalk.org/wp-content/uploads/2020/02/1_ieVWcSsJmeBbZFo6a_dL5g.png" rel="noopener noreferrer"&gt;http://newyorkschooltalk.org/wp-content/uploads/2020/02/1_ieVWcSsJmeBbZFo6a_dL5g.png&lt;/a&gt;
&lt;/h6&gt;

&lt;h1&gt;
  
  
  Step
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;เขียน test (เพื่อให้เห็น scope ของโปรแกรมของเรา)&lt;/li&gt;
&lt;li&gt;run ให้ fail&lt;/li&gt;
&lt;li&gt;เขียน code เขียนให้ผ่านก่อน&lt;/li&gt;
&lt;li&gt;เทสที่เคย fail จะ pass จากการเขียน code&lt;/li&gt;
&lt;li&gt;Refactor แก้ไข ให้ดีขึ้น &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ข้อดี
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;มั่นใจของเก่าไม่พัง &lt;/li&gt;
&lt;li&gt;debug ง่าย &lt;/li&gt;
&lt;li&gt;requirement ไม่หาย &lt;/li&gt;
&lt;li&gt;เราจะสามารถมั่นใจได้ว่าโปรแกรมทำงานได้ตรงตามที่เราเขียนจริงๆ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ข้อเสีย
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;นานเพราะต้องศึกษา &lt;/li&gt;
&lt;li&gt;เสียเวลาเขียนเทสวุ่นเว้อ &lt;/li&gt;
&lt;li&gt;ใช้ประสบการณ์สูง&lt;/li&gt;
&lt;li&gt;ประเมิณเวลายาก เพราะต้องรวมเวลาเขียน test&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;มันน้อยใช่ไหมละที่เขียนมา ใช่น้อยมากเลยแต่จริงๆ มองภาพรวมอาจจะง่ายแต่การแตก task สิ่งที่โปรแกรมเราต้องทำให้ละเอียดพอที่จะเขียน test แต่แรกนั้นต้องใช้เวลาในการฝึก การคิด test case ที่ครอบคลุมมากพอก็ไม่ใช่เรื่องง่าย การเขียน code ที่จะทำให้เราสามารถ mock data เพื่อ test ก็ต้องอาศัยแนวคิด จนกระทั่ง step สุดท้าย refactor อาจจะต้องอาศัยความรู้เรื่อง clean code หรือประสบการณ์ ที่มากพอถึงจะสามารถทำออกมาได้ดีได้&lt;/p&gt;

&lt;p&gt;&lt;em&gt;อาจจะต้องใช้ ความทุ่มเท ใส่ใจ และ passion เพื่อจะเป็นมืออาชีพ&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>programming</category>
    </item>
    <item>
      <title>DI for test</title>
      <dc:creator>kanthakran</dc:creator>
      <pubDate>Sun, 06 Dec 2020 10:59:58 +0000</pubDate>
      <link>https://forem.com/gun27311/structure-for-mock-automate-test-1a42</link>
      <guid>https://forem.com/gun27311/structure-for-mock-automate-test-1a42</guid>
      <description>&lt;p&gt;บทความนี้เป็นบันทึกที่จดไว้เพื่อแชร์สิ่งที่รู้ลงไปถ้าผิดอะไรช่วยกันคอมเม้นไว้ได้นะครับ&lt;/p&gt;

&lt;p&gt;วันนี้ผมมาในหัวข้อเรื่อง dependency injection แต่ก่อนหน้านี้หัวข้อมันคือ Structure สำหรับการ mock เพื่อ test ที่ชื่อหัวข้อแบบนี้เพราะคิดไม่ออก&lt;/p&gt;

&lt;p&gt;สิ่งที่เราจะได้รับจากบทความนี้คือ Loose Coupling และ Dependency Injection มีความสำคัญกับการ mock เพื่อ test ยังไง ผมเป็นคนหนึ่งที่เคยพยามที่จะเขียน test ต่างๆ แต่ติดปัญหา&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;function นี้เป็น private เราจะ test ยังไงควรเปลี่ยน pubilc สำหรับ test ไหม&lt;/li&gt;
&lt;li&gt;แล้วทำไมเราต้องทำ dependency injection ในเมื่อเราสามารถประกาศตัวแปลใช้ได้ตรงๆ ได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;โดย ผมจะไม่สนใจว่าการ test นี้จะเป็นการเทสแบบไหน unit หรือ integration เอาแค่ concept&lt;/p&gt;

&lt;h1&gt;
  
  
  สารบัญ
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;เกรินนำ&lt;/li&gt;
&lt;li&gt;Tight Coupling&lt;/li&gt;
&lt;li&gt;Loose Coupling &amp;amp; Dependency injection&lt;/li&gt;
&lt;li&gt;การ mock เพื่อ automate test&lt;/li&gt;
&lt;li&gt;สรุป&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Loose coupling และ Dependency injection คืออะไร &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Loose coupling คือถ้าเราไปแปลใน google มันจะแปลว่า "ข้อต่อหลวม" มันคือการเขียนโปรแกรมให้ dependency ของ class หลุดออกจากกันเพื่อ mock data เช่น&lt;/p&gt;

&lt;h2&gt;
  
  
  โจทย์
&lt;/h2&gt;

&lt;p&gt;ถ้าผมอยากจะเขียน api get User by status&lt;br&gt;
http method : GET &lt;br&gt;
path : /user/status&lt;br&gt;
ผมต้องการ การ get user by status จาก database&lt;br&gt;
สิ่งที่ผมวางไว้คือ userRepository คือตัวจัดการเอาของออกจาก database&lt;br&gt;
ส่วน userService คือตัวที่จะนำมาคำนวนต่างๆ (ตัวอย่างขอไม่มีการคำนวน)&lt;/p&gt;

&lt;h2&gt;
  
  
  project structure
&lt;/h2&gt;

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

&lt;h1&gt;
  
  
  Tight Coupling &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;เป็นการสร้าง dependency ที่ผูกกันติดจนยากที่จะ mock userRepository getUserByStatus เพราะเกิดการ new ใน class&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DMxjJCPK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nannikycarbe0kp164b5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DMxjJCPK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nannikycarbe0kp164b5.png" alt="Alt Text" width="505" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;เผื่อมองภาพไม่ออก การที่ userRepository ถูก new ใน class userService มันทำให้เราเข้าไปแก้ไขอะไรในนั้นได้ยาก&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8nXrBerR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i2b1yn678irs7tm6e0rd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8nXrBerR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i2b1yn678irs7tm6e0rd.png" alt="Alt Text" width="468" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Loose Coupling &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;จากตัวอย่างด้านบนถ้าเราเอา userRepository มาใส่ใน constructor เป็น parameter มันจะเกิดการ Loose coupling เพราะ userRepository ไม่ได้ขึ้นอยู่กับ class UserService การส่งสิ่งที่เราจะใช้ผ่าน constructor ถือเป็นการทำ Dependency injection ผ่าน constructor&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GsMBcgw7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/es6kemuc3z78k4e4uob3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GsMBcgw7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/es6kemuc3z78k4e4uob3.png" alt="ใน typescript เอา private ไปใส่ใน constructor มันจะกลายเป็น &amp;lt;br&amp;gt;
property ของ class" width="544" height="238"&gt;&lt;/a&gt;&lt;br&gt;
ใน typescript เอา private ไปใส่ใน constructor มันจะกลายเป็น property ของ class เลย&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O4z2hxIw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kldritz7qgtv04kki1c0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O4z2hxIw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kldritz7qgtv04kki1c0.png" alt="Alt Text" width="760" height="287"&gt;&lt;/a&gt;&lt;br&gt;
สิ่งที่เกิดขึ้นคือ เราสามารถที่จะแก้ไข class userRepository ก่อนจะส่งเข้าไปได้&lt;/p&gt;

&lt;h1&gt;
  
  
  การ mock เพื่อ test &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;(mock คือการสร้างของจำลองไว้ test)&lt;br&gt;
จากด้านบนเราจะเห็นแล้วว่าการที่เราจะ mock ของนั้นจะต้องมีโครงสร้างของโปรแกรมที่ดีพอที่จะทำให้เรา mock ได้ Loose Coupling &lt;/p&gt;

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

&lt;p&gt;ตัวอย่างนี้จะใช้ jest นะครับ&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dI8jJDOO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/brsf8ceyll7mcp8uc5xk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dI8jJDOO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/brsf8ceyll7mcp8uc5xk.png" alt="Alt Text" width="654" height="237"&gt;&lt;/a&gt;&lt;br&gt;
ผม mock getCountUserByStatus ให้ return 20 มาเลย&lt;br&gt;
ถ้าใน service มีการคำนวนอะไรเราก็จะสามารถ expect ค่านั้นได้เลย&lt;/p&gt;

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

&lt;p&gt;การ mock เพื่อ test นั้นจำเป็นต้องวางโครงสร้างของโปรแกรมให้ดีเพื่อที่การ mock เพื่อ test จะได้ทำได้ง่าย ไม่ว่าจะเป็นการแยก class ให้ดี หรือการทำ dependency injection ก็ตามถ้าเรา loose coupping ก็ไม่จำเป็นต้องเปลี่ยน function หรือ property เป็น public เพื่อเทส (เพราะมันไม่ควรทำ)&lt;/p&gt;

&lt;p&gt;ผิดถูกยังไง comment ได้นะครับ&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Clean code (TH.)</title>
      <dc:creator>kanthakran</dc:creator>
      <pubDate>Thu, 12 Nov 2020 11:04:15 +0000</pubDate>
      <link>https://forem.com/gun27311/clean-code-th-3eg6</link>
      <guid>https://forem.com/gun27311/clean-code-th-3eg6</guid>
      <description>&lt;p&gt;บทความนี้เป็นการสรุปเนื้อหาเท่าที่ผู้อ่านเข้าใจจากหนังสือ &lt;br&gt;
CleanCode ของ Robert C martin หรือลุง Bob&lt;/p&gt;
&lt;h1&gt;
  
  
  Table Of Contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
Introduction

&lt;ol&gt;
&lt;li&gt;Clean code คืออะไร&lt;/li&gt;
&lt;li&gt;Bad code&lt;/li&gt;
&lt;li&gt;หนี้สินทาง software คืออะไร&lt;/li&gt;
&lt;li&gt;แนวคิดเรื่อง Clean code (สำคัญ)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
หลักการการทำ Clean code 

&lt;ol&gt;
&lt;li&gt;Meaningful Name &lt;/li&gt;
&lt;li&gt;Function&lt;/li&gt;
&lt;li&gt;Comments&lt;/li&gt;
&lt;li&gt;Formatting&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;บทความนี้เป็นการสรุปหนังสือ &lt;strong&gt;Clean Code&lt;/strong&gt; Robert C. Martin &lt;br&gt;
ตามความเข้าใจหากผิดพลาดช่วย Comment กัได้นะเออ&lt;/p&gt;
&lt;h2&gt;
  
  
  Clean code คืออะไร &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Clean code คือ code สะอาดครับ คำว่าสะสาดอาจจะหมายถึง อ่านง่าย แก้ไขง่าย ต่อยอดง่าย แต่เราจะทำยังไงให้มันได้อย่างที่เราบอกกันละ ก่อนอื่นเราต้องรู้จัก Bad code กันก่อน&lt;/p&gt;
&lt;h2&gt;
  
  
  Bad code &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;เราอาจจะเคยต้องอ่านโค๊ทต่อจากคนอื่น หรือ เราไม่ได้ทำ Project นั้นนานๆ แล้วกลับมาอ่านสิ่งที่เราจะเจอ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ตัวแปลตัวนี้คืออะไรวะ dowData อ่านชื่อแล้วงง&lt;/li&gt;
&lt;li&gt;function นี้มันทำอะไรวะ genAcTcUserSta&lt;/li&gt;
&lt;li&gt;อ่าน code แล้วต้องลงไปดูใน function เพราะชื่อไม่สื้อ&lt;/li&gt;
&lt;li&gt;เรา check if เพื่ออะไรวะ for ตรงนี้ไม่เห็นจำเป็นต้องมีนิ&lt;/li&gt;
&lt;li&gt;บางตัวแปลไม่ได้ใช้ประกาศทำไม&lt;/li&gt;
&lt;li&gt;ฯลฯ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;สิ่งเหล่านี้ที่เราเจอมาล้วนเป็นหนี้สินทาง software ทั้งสิ้น&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  หนี้สินทาง software คืออะไร &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;มันคือสิ่งที่ทำให้เราช้าลง เพราะหนี้สินล้วนมีดอกเบี้ย สิ่งที่จะเกิดผลกระทบ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เวลาในการศึกษา code นั้นๆ จะมากขึ้น เช่น มีคนใหม่เข้าทีมอ่านทีหัวแตก (learning curve สูง)&lt;/li&gt;
&lt;li&gt;การแก้ไขโปรแกรมทำได้ยาก ไม่ว่าจะเพิ่ม feature หรือ fix bug&lt;/li&gt;
&lt;li&gt;เขียน test ยาก (ถึงกับไม่รู้จะเขียนยังไง)&lt;/li&gt;
&lt;li&gt;อ่านยากมากๆ อ่าน code แล้วอยากลาออก&lt;/li&gt;
&lt;li&gt;ฯลฯ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;วันหนึ่งจะมีคนพูดว่า "ถ้าอ่านยากขนาดนี้ เขียนใหม่ยังง่ายกว่า"&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  แนวคิดเรื่อง Clean code &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;ถ้าเราถามว่า code ทำงานได้ กับ code สวย อะไรสำคัญกว่ากัน&lt;br&gt;
หลายคนคงตอบไม่ยากว่า งานเสร็จ code ทำงานได้สำคัญกว่าอยู่แล้ว&lt;br&gt;
ความเร็วในการออกของสำคัญมากยิ่งเราอยู่ในโลกของ agile และ scrum&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ผมก็จะบอกว่าถูกครับ&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;เรามองว่า Clean code เป็นสิ่งเล็กๆ แต่คุณลองคิดถึงเวลาคุณมีบ้าน ที่ประตูปิดไม่สนิท เวลาปิดมีเสียง เอี๊ยดดดๆ เหมือนในหนังผี กระเบื้องห้องน้ำเรียงมั่ว ก๊อกน้ำน้ำรั่ว&lt;br&gt;
บางปลั๊กไม่มีไฟ ถามว่าเป็นบ้านไหม เป็น อยู่ได้ไหม ก็อยู่ได้ แต่ทุกสิ่งที่กล่าวมาล้วนปัดเป่าเสน่ของบ้านทั้งสิ้น&lt;/p&gt;

&lt;p&gt;&lt;em&gt;จงให้ความสำคัญกับสิ่งเล็กๆ ในสิ่งเล็กๆ ล้วนสำคัญ&lt;/em&gt;&lt;br&gt;
&lt;em&gt;คนธรรมดากับมืออาชีพ ต่างกันที่ความใส่ใจในรายระเอียด&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;แต่เรามักถูกบีบด้วยเวลา และคนเดินมาเร่งมากมาย &lt;strong&gt;เวลาเกิดปัญหาเราก็จะบอกว่า&lt;/strong&gt;&lt;/p&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;p&gt;จริงๆ แล้วไม่ใช่แค่ Programmer ที่จะต้องเข้าใจในคำว่า หนี้สินทาง software ขอเรียก software debt คำนี้มันเกิดตอนที่ ลุง Robert C. Martin อธิบายให้หัวหน้าฟังเพราะบริษัทที่ทำงานนั้นเกี่ยวกับด้านการเงินเลยเกิดคำนี้มาเพื่อให้หัวหน้าเข้าใจ มันแปลว่าหัวหน้า , PM ใครก็แล้วแต่ที่สั่งเรา ต้องเข้าใจ&lt;br&gt;
ในเรื่อง software debt ด้วยเพื่อใช้ในการประเมิณเวลาในการทำด้วย&lt;/p&gt;


&lt;h1&gt;
  
  
  หลักการในการ Clean Code &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Meaningful Names
&lt;/h2&gt;

&lt;p&gt;การตั้งชื่อ&lt;/p&gt;
&lt;h3&gt;
  
  
  Use Intention-Revealing Names
&lt;/h3&gt;

&lt;p&gt;ชื่อทุกสิ่งที่เราตั้งล้วนต้องมีความหมาย บ่งบอกถึงเจตนาของสิ่งนั้นๆ อย่างชัดเจน เช่น class function val หากชื่อพวกนั้นต้องการ comment แสดงว่าชื่อนั้นยังไม่บอกเจตนาอย่างชัดเจน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Day of week
var dow 

or

var dayOfWeek
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use Pronounceable Names
&lt;/h3&gt;

&lt;p&gt;ชื่อต้องอ่านออกเสียงได้ หลีกเลี่ยงการใช้ &lt;/p&gt;

&lt;h4&gt;
  
  
  number series : a1 a2 a3
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Noise words are another meaningless distinction
&lt;/h4&gt;

&lt;p&gt;ลองนึกภาพว่าคุณมี product class. หากคุณมีชื่ออื่นที่เรียกว่า ProductInfo หรือ ProductData คุณได้สร้างชื่อให้แตกต่างกันโดยไม่ทำให้มีความหมายแตกต่างกัน ข้อมูลและข้อมูลเป็นสัญญาณรบกวนที่ไม่ชัดเจน&lt;br&gt;
คำเช่น a, an และ this&lt;br&gt;
&lt;em&gt;อย่ากลัวที่จะตั้งชื่อยาวหากชื่อนั้นสร้างความแตกต่างอย่างมีความหมายได้&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Noise words are redundant
&lt;/h4&gt;

&lt;p&gt;ไม่ควรใส่ type ของตัวแปลไปหลังชื่อ เช่น nameString, dateLong เพื่อเลี่ยงการปิดเบือนข้อมูลเหมือน accountList ด้านบน และ&lt;/p&gt;

&lt;p&gt;เพราะว่า IDE สมัยนี้หากเราเอาเมาส์ไปชี้ก็จะแสดง type ให้อยู่แล้วถ้าไม่ใช้ตัวแปร dynamic type&lt;/p&gt;
&lt;h3&gt;
  
  
  Avoid Disinformation
&lt;/h3&gt;

&lt;p&gt;หลีกเลี่ยงการทำเกิดความเข้าใจผิด หรือทำให้ความหมายเปลี่ยนแปลง ต่างจากความหมายที่เราตั้งใจไว้ เช่น hp,aix, sco ทั้งหมดนี้ล้วนเป็นชื่อของ platfrom linux &lt;/p&gt;

&lt;p&gt;การตั้งชื่อโดยใส่คำว่า list accountList การตั้งชื่อแบบนี้เสี่ยงต่อการเข้าใจผิดได้ง่ายว่ามันคือ รายการบัญชีหรือกลุ่มของบัญชีหรือเปล่า เราอาจจะใช้ accounts สำหรับ array account หรือ accountGroup สำหรับกลุ่มของ account&lt;/p&gt;
&lt;h3&gt;
  
  
  Make Meaningful Distinctions
&lt;/h3&gt;

&lt;p&gt;ทำให้มีความหมายอย่างแตกต่างบางครั้งการตั้งชื่อให้แตกต่างกันมันก็ยาก ตัวแปรบางตัวที่ชื่อเหมือนกันจะโดนฟ้องโดยคอมไพเรอให้เปลี่ยนชื่อ&lt;/p&gt;
&lt;h3&gt;
  
  
  Use Searchable Names
&lt;/h3&gt;

&lt;p&gt;ใช้ชื่อที่ search ได้ หลีกเลี่ยงการใช้ ตัวอักษรตัวเดียว และ ควรใช้ Constants แทน ตัวเลข มันไม่ง่ายเลยที่เราจะหาตัว i ที่เราตั้งการใน โปรเจค &lt;/p&gt;

&lt;p&gt;หรือเราจะหาตัวเลข 1 ในโปรเจค ควรตั้ง constant แทน เช่น MAX_DRIVER_IN_CAR&lt;/p&gt;
&lt;h3&gt;
  
  
  Avoid Encodings
&lt;/h3&gt;

&lt;p&gt;เลี่ยงการใช้ตัวย่อ เพราะว่ายากต่อการเข้าใจและออกเสียงไม่ได้ คิดถึงหนังสือพิมพ์ นย พตรอ นพ อะไรวะงงเยอะไปหมด&lt;/p&gt;
&lt;h4&gt;
  
  
  Member perfixes
&lt;/h4&gt;

&lt;p&gt;เลี่ยงการใช้คำนำหน้าเช่น m_student ถ้า function เราเล็กพอสิ่งนี้จะไม่เกิดแน่นอน&lt;/p&gt;
&lt;h3&gt;
  
  
  Class Names
&lt;/h3&gt;

&lt;p&gt;ควรเป็นคำนามเท่านั้น ห้ามใช้กริยา&lt;/p&gt;
&lt;h3&gt;
  
  
  Method Names
&lt;/h3&gt;

&lt;p&gt;ควรเป็นกริยาเท่านั้น ห้ามเป็นคำนาม&lt;/p&gt;
&lt;h3&gt;
  
  
  Don't Be Cute
&lt;/h3&gt;

&lt;p&gt;อย่าอวดฉลาดตั้งชื่อตัวแปลเท่ๆ เช่น Eureka ,phoenix, Aileen (แปลว่าแสงสว่าง)&lt;/p&gt;
&lt;h3&gt;
  
  
  Pick one word per concept
&lt;/h3&gt;

&lt;p&gt;เป็นการนิยามชื่อ protocalManager และ ProtocolController ดูเหมือนกันเลยแต่จะเอาอันไหนละ&lt;/p&gt;
&lt;h3&gt;
  
  
  Use Solution Domain Name
&lt;/h3&gt;

&lt;p&gt;ใช้การต่อชื่อไปอย่างสอดคล้องกัน createPluralDependentMessageParts&lt;br&gt;
หากทำไม่ได้การเพิ่ม name space ไว้ข้างหน้าจะเป็นทางออกสุดท้าย&lt;/p&gt;


&lt;h2&gt;
  
  
  Function &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Small ต้องเล็ก
&lt;/h3&gt;

&lt;p&gt;1 บรรทัดไม่เกิน 150 อักษร&lt;br&gt;
1 function ไม่ควรเกิน 100 บรรทัด&lt;br&gt;
แต่จะให้ดี ไม่เกิน 20 บรรทัด&lt;/p&gt;
&lt;h3&gt;
  
  
  Blocks and Indenting
&lt;/h3&gt;

&lt;p&gt;if else if else while statement ไม่ควรเกิน 1 บรรทัด หากเกินควรแยก function&lt;/p&gt;
&lt;h3&gt;
  
  
  Do One Thing
&lt;/h3&gt;

&lt;p&gt;1 function ควรทำแยกสิ่งเดียว&lt;/p&gt;
&lt;h3&gt;
  
  
  Function Arguments
&lt;/h3&gt;

&lt;p&gt;ควรน้อยที่สุดเท่าที่เปิดไปได้ และไม่ควรเกิน 3 ถ้าเกินเราอาจจะสร้าง class มารองรับ&lt;/p&gt;
&lt;h3&gt;
  
  
  Verbs and Keywords
&lt;/h3&gt;

&lt;p&gt;เลือกชื่อที่ดีเป็นกริยาสำหรับ function&lt;/p&gt;
&lt;h3&gt;
  
  
  Have No Side Effects
&lt;/h3&gt;

&lt;p&gt;function เราต้องไม่มี side effects เพราะหากมีเราจะรู้เลยว่า function เราไม่ได้ทำสิ่งเดียว Do One Thing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class UserValidator {
 private Cryptographer cryptographer;
 public boolean checkPassword(String userName, String password) {
       User user = UserGateway.findByName(userName);
 if (user != User.NULL) {
       String codedPhrase = user.getPhraseEncodedByPassword();
       String phrase = cryptographer.decrypt(codedPhrase, password);
       if ("Valid Password".equals(phrase)) {
        Session.initialize();
       return true;
     }
   }
 return false;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;code จาก clean code :Rovert C matin หน้าที่ 44&lt;/p&gt;

&lt;h2&gt;
  
  
  Extract Try/Catch Blocks
&lt;/h2&gt;

&lt;p&gt;การ try catch ลงใน function เลยอาจจะทำให้ดูน่าเกลียด&lt;br&gt;
หากเราไม่แยกการทำงานของ function ให้ทำงานเพียงอย่างเดียว&lt;br&gt;
(ในการ try catch ควรมีแค่ function เดียวการทำงานเดียวที่เราดัก)&lt;/p&gt;

&lt;p&gt;don't &lt;br&gt;
ในตัวอย่างนี้เราจะเห็นได้ว่าเรา try catch ในหลาย function อาจจะทำให้เราสับสนได้ว่า error นี้มาจากกระบวนการไหนของ flow กันแน่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function delete(page){
 try{
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
 }catch(error){
   throw Exception("can't delete page "+page.id+" error :"+error)
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function delete(page){
 try{
  deletePageAndAllReferences(page);
 }catch(error){
  throw Exception("can't delete page "+page.id+" error :"+error)
 }
}
function deletePageAndAllReferences(){
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราควร&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t Repeat Yourself
&lt;/h3&gt;

&lt;p&gt;อย่าทำซ้ำ เช่นซ้ำซ้อนการทำงานต่างๆ duplication&lt;/p&gt;




&lt;h2&gt;
  
  
  Comments &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;code ที่ดีต้องไม่มี comment เราชอบคิดว่ามันซับซ้อนเลยต้องมี comment จริงๆ มันไม่ถูกซะทีเดียวเราควรทำให้ code ดีมากกว่าคิดว่ามันซับซ้อนอ่านยากเลยต้อง comment &lt;br&gt;
comment ที่ควรเขียนมีแค่ Copyright กับ authorship statement&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Formatting &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The coding style and readability เราควรจะจัด code style ให้ตรงกัน ซึ่งสามารถกำหนดใน IDE ได้&lt;br&gt;
เช่น 150 ตัวอักษรสำหรับ 1 บรรทัด ฯลฯ&lt;/p&gt;

&lt;p&gt;ทั้งหมดทั้งมวลนี้อาจจะไม่สอดคล้องกับสิ่งที่คุณรู้เชื่อ หรือเข้าใจ คุณอาจจะไม่เห็นด้วยกับบทความนี้ทั้งหมดก็ได้เพราะหลายคนประสบห์การต่างกันอาจจะมี trick ที่เทคนิคพิเศษที่ต่างกันไป&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%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--846b1Bv3--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fko7x2fa9ztpp9m150vgb.jpg" 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%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--846b1Bv3--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fko7x2fa9ztpp9m150vgb.jpg" alt="Alt text of image"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cleancode</category>
    </item>
  </channel>
</rss>
