<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by I&#39;Boss Potiwarakorn on Medium]]></title>
        <description><![CDATA[Stories by I&#39;Boss Potiwarakorn on Medium]]></description>
        <link>https://medium.com/@iboss?source=rss-7ee6829f80e3------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*z-ma52i6XeP5oygE0lLyQg.jpeg</url>
            <title>Stories by I&amp;#39;Boss Potiwarakorn on Medium</title>
            <link>https://medium.com/@iboss?source=rss-7ee6829f80e3------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 17:27:56 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@iboss/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Estimate งานยังไงให้แม่น?]]></title>
            <link>https://medium.com/redacted-org/estimate-%E0%B8%87%E0%B8%B2%E0%B8%99%E0%B8%A2%E0%B8%B1%E0%B8%87%E0%B9%84%E0%B8%87%E0%B9%83%E0%B8%AB%E0%B9%89%E0%B9%81%E0%B8%A1%E0%B9%88%E0%B8%99-a97264dc0400?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/a97264dc0400</guid>
            <category><![CDATA[estimations]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Wed, 01 Dec 2021 11:10:58 GMT</pubDate>
            <atom:updated>2021-12-01T11:10:58.642Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*sJgtz6Tm4glnEIzgfm9Tlw.png" /></figure><p>โลกนี้ไม่มีอะไรแน่นอน…</p><p>ผมทำ software มา 5–6 ปี ในโลก software development ที่ทุกอย่างเปลี่ยนตลอดเวลา ทำๆ ไปเจออะไรก็ไม่รู้ ยิ่งไม่แน่นอน</p><p>ตลอดเวลาที่ทำงานมา อยู่ใน agile environment ตลอดมามักจะมีความรู้สึกเหล่านี้</p><ul><li>estimate ไปทำไม เดี๋ยวก็ผิดอยู่ดี</li><li>ไหนบอก story points, t-shirt sizing เป็นแค่ relative sizing ไม่เกี่ยวกับ effort แต่สุดท้ายก็เอาไปคิดแลข ไปทำ burn up/down chart วัด velocity วาง timeline อยู่ดี</li></ul><p>เคยทำงานแบบไม่ estimate เลย เดี๋ยวก็จะต้องมี party อื่นที่ต้องพึ่งเรา มาถามเราอยู่ดี จะตอบส่งๆ ไปแบบไม่คิด เดี๋ยวอาจจะทำเราลำบากทีหลังอีก</p><p>ลึกๆ ในใจก็คิดว่า ถ้าอธิบายอนาคตได้บ้าง เท่าที่ความรู้มี ก็คงจะดี จะได้วางแผนได้รัดกุมมากขึ้น</p><p>ไปเจอหนังสือเล่มนึงที่ผมชอบมาก ชื่อว่า “How to measure anything” เลยเอาสิ่งที่เรียนรู้จากหนังสือเล่มนี้ มาลองปรับใช้กับ development estimation</p><ul><li>ไม่มีอะไรแน่นอน เพราะฉะนั้นถ้าจะทำความเข้าใจมัน ต้องยอมรับมันก่อน</li><li>ความรู้และประสบการณ์ของเราคือข้อมูล</li><li>หากความไม่แน่นอนมีมากเกินไป จงแตกปัญหาออกมาเป็นชิ้นที่เล็กลง หรือหาข้อมูลเพิ่ม</li></ul><h4>ยอมรับความไม่แน่นอน</h4><p>เวลาเราให้ตัวเลขไป 1 ตัว t-shirt ไป 1 size เอาไปแปลเป็นเวลาที่ใช้ เอามาบวกกัน เพื่อบอกเวลาที่จะใช้ทั้งหมด ก็เหมือนกับหลอกตัวเอง เพราะจริงๆ แล้วเวลาเราบอกว่า 3 story points มันอาจจะแปลว่า 1 วันก็ได้ 5 วันก็ได้ แต่เราพอจะเดาได้ว่า เร็วที่สุด เร็วแค่ไหน ช้าที่สุด ช้าแค่ไหน แบบไม่ surprise มากๆๆ จริงๆ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/413/0*g6uHU0uyKHwUU1mY.jpg" /></figure><p>สมมติว่า การที่</p><blockquote>“เราไม่ surprise มากๆๆ จริงๆ”</blockquote><p>แปลให้ formal ได้ว่า</p><blockquote>“เรามั่นใจ 90% ที่จะทำงานชิ้นนี้เสร็จเร็วสุดภายใน 1 วัน ช้าสุดภายใน 5 วัน”</blockquote><p>โดย assume ว่า การกระจายตัวของข้อมูลจะเป็น normal distribution</p><p>ทีนี้เราก็มีข้อมูลทั้ง “มันน่าจะเสร็จเมื่อไหร่” และ “มั่นใจแค่ไหน” ที่เอามาใช้ในการคำนวณได้แล้ว</p><p>ก่อนจะไปต่อ คนเรามักจะ underestimate (หรือบางคนก็ overestimate) สิ่งที่อยู่ตรงหน้า เพราะฉะนั้น เวลาจะ estimate ควรจะ calibrate ผู้ให้ข้อมูลด้วย เช่น</p><p>ถ้าให้เลือกพนัน 1 BTC บนเกม 2 เกม</p><blockquote>1. ถ้า estimate ถูก งานเสร็จภายใน 1–5 วัน คุณชนะ</blockquote><blockquote>2. ถ้ามี lottery 100 ใบ 90 ใบในนั้นจะทำให้คุณชนะ ที่เหลือจะทำให้คุณแพ้</blockquote><p>ถ้าชนะ จะได้ 1 BTC แพ้เสีย 1 BTC คุณจะเล่นเกมไหน?</p><p>ลองคิดตามดูนะครับ</p><p>…</p><p>…</p><p>คำตอบคือ ต้องรู้สึกไม่ต่างกัน เล่นเกมไหนก็ได้ ทั้งสองเกมควรมีความน่าจะเป็นที่จะชนะเท่ากัน คือ 90%</p><p>ถ้าเลือกเกม 1 แปลว่า คุณ <strong>overestimate </strong>งาน เพราะคุณเชื่อว่า ช่วงความมั่นใจที่ estimate มันกว้างกว่า 90% ยังไงงานก็มีโอกาสทำเสร็จในช่วงมากกว่า</p><p>ถ้าเลือกเกม 2แปลว่า คุณ <strong>underestimate </strong>งาน เพราะคุณเชื่อว่า ช่วงความมั่นใจที่ estimate มันแคบกว่า 90% เล่น lottery มีโอกาสชนะเยอะกว่า</p><p>แล้วก็ปรับการ estimate กันไป ฝึกให้ทีมชินกับ concept นี้ แล้วเราก็จะได้ข้อมูลในการคาดการณ์อนาคตที่แม่นยำขึ้น</p><h4>ความไม่แน่นอนมีมากเกินไป</h4><p>1–3 วัน กับ 3–20 วัน นั้นต่างกันอย่างเห็นได้ชัด ความไม่แน่ใจของผู้ให้ข้อมูลถูกแสดงออกมาเป็นตัวเลข ซึ่งจะส่งผลต่อความไม่แน่นอนของการพยากรณ์ในที่สุด</p><p>เราทำอะไรได้บ้าง?</p><ol><li>แตกปัญหาให้เล็กลง แล้วลอง estimate ใหม่ ปัญหาที่เล็กลง เราจะเข้าใจมันได้ดีมากขึ้น</li><li>ใช้เวลาไปเก็บข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่ไม่แน่ใจ</li></ol><h4>รวบรวมผล</h4><p>สุดท้าย เราอยากรู้ว่า ด้วยงานทั้งหมด เราจะใช้เวลาเท่าไหร่ แต่เราจะเอา upper bound มาบวกกันให้หมด เอา lower bound มาบวกกันให้หมด ก็ไม่ได้ เพราะจริงๆ แล้วตัวแปรที่เรามี เป็นตัวแปรแบบสุ่ม (random variable) ตัวเลขที่เราได้คือตัวแทนของ normal distribution</p><p>วิธีที่เราใช้รวมรวมผลทั้งหมดคือ monte carlo simulation</p><p>อธิบาย monte carlo simulation ง่ายๆ ก็คือ สมมติมี งานสามชิ้น</p><ol><li>1–4 วัน</li><li>2–7 วัน</li><li>4–5 วัน</li></ol><p>เราจะเอา upper, lower bound มาหา normal distribution parameters</p><pre>mean = (upper + lower) / 2<br>sd = (upper - lower) / 3.29</pre><p>เมื่อได้ mean กับ sd แล้ว เราจะเอาไปใช้สุ่มใน program ต่างๆ ได้ เช่น ใน python</p><pre>np.random.normal(mean, sd, 1000) # 1000 samples</pre><p>สมมติ เราสุ่มหยิบรอบแรก ได้ (1.2, 3.3, 4.1) เวลาที่ใช้จากผลการสุ่มรอบแรกคือ 1.2 + 3.3 + 4.1 = 8.6 วันอย่างนี้เป็นต้น สุ่มไปหลายๆ ผลลัพธ์จะกระจายตัวเป็น normal distribution อีกครั้ง</p><p>ตัวอย่าง tool ที่เราใช้กันเองในทีม เราดึงข้อมูลมาจาก task management แล้วทำการคำนวณตามที่อธิบายไปข้างต้น ได้ผลลัพธ์หน้าตาแบบนี้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sJgtz6Tm4glnEIzgfm9Tlw.png" /></figure><p>มีข้อมูลมากพอสามารถคำนวณ progress และ projection ของความมั่นใจว่างานจะเสร็จในช่วงเวลาไหนได้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RuS_GbRv9LEKJUkZn9qa9A.png" /></figure><p>ซึ่งช่วยให้เราวางแผนได้แม่นยำขึ้น ที่เหลือคือต้องไปจัดการความวุ่นวายภายนอกทีมที่อาจมีผลกระทบต่อแผน เพราะต่อให้แม่นยำจัดการปัจจัยภายนอกไม่ได้ ก็ไม่แม่นอยู่ดี</p><p>พวกเรา █████ ทีมเรารักที่จะ experiment, ทำงานเกี่ยวกับ software development, cryptocurrency, blockchain เพราะงั้นเราต้องการคนที่พื้นฐานแข็งแรงมาจอยกัน เพราะทีมนี้อยากซิ่ง ไม่อยากทวนเรื่องพื้นฐานกันแล้ว</p><p>สนใจร่วมงานกัน หรืออยากคุยด้วยเฉยๆ มาพูดคุยกันใน discord ได้<a href="https://discord.gg/7d4DZu6v">ที่นี่</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a97264dc0400" width="1" height="1" alt=""><hr><p><a href="https://medium.com/redacted-org/estimate-%E0%B8%87%E0%B8%B2%E0%B8%99%E0%B8%A2%E0%B8%B1%E0%B8%87%E0%B9%84%E0%B8%87%E0%B9%83%E0%B8%AB%E0%B9%89%E0%B9%81%E0%B8%A1%E0%B9%88%E0%B8%99-a97264dc0400">Estimate งานยังไงให้แม่น?</a> was originally published in <a href="https://medium.com/redacted-org">█████ [REDACTED] .org</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fixing GMMK pro’s rotary knob after flashing firmware with QMK]]></title>
            <link>https://iboss.medium.com/fixing-gmmk-pros-rotary-knob-after-flashing-firmware-with-qmk-28002e78cf3e?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/28002e78cf3e</guid>
            <category><![CDATA[gmmk]]></category>
            <category><![CDATA[mechanical-keyboards]]></category>
            <category><![CDATA[qmk]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Thu, 04 Nov 2021 03:00:31 GMT</pubDate>
            <atom:updated>2021-11-04T03:00:31.297Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*A0ge_ChWrbUrbxCfkwZtRA.png" /></figure><p>After flashing firmware on GMMK pro for key mapping using binary produced from <a href="https://config.qmk.fm/">QMK Configurator</a>, one might find rotary knob no longer works.</p><p>The reason being, the configurator does not have the functionality to handle rotary encoder. We need to build the firmware ourselves.</p><blockquote><strong><em>disclaimer</em></strong><em>: I am on macbook m1, so I used docker for the job since installing </em><em>qmk cli locally does not work for me. If you want to thread down the path of installing the cli locally, please </em><a href="https://docs.qmk.fm/?q=docker#/newbs_getting_started"><em>check this out</em></a><em>.</em></blockquote><h3>Environment Setup</h3><p>You need <a href="https://git-scm.com/">git</a> and <a href="https://www.docker.com/">docker</a> installed. If you are a software engineer, you probably already familiar with them, if you are not you need terminal console in order to interact with the following content.</p><p>Mac has default <strong>Terminal</strong> app,</p><p>On windows, this could get tricky. Using <a href="https://docs.microsoft.com/en-us/windows/wsl/install">Linux Subsystem</a> might be the best bet IMHO but I haven’t tested it myself.</p><p>For Linux users, I think you know what to do…</p><h3>Getting Started</h3><ol><li>Let’s clone the qmk firmware repository and change directory into it.</li></ol><pre>git clone --recurse-submodules <a href="https://github.com/qmk/qmk_firmware.git">https://github.com/qmk/qmk_firmware.git</a> &amp;&amp; cd qmk_firmware</pre><p>2. Download your already configured keymap json file and move it into qmk_firmware directory mentioned above. By default, the file name would be gmmk_pro_ansi_layout_mine.json</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/918/1*v-FpKxB9ecrQDhxE329mrQ.png" /></figure><p>3. On the same terminal console, current directory as qmk_firmware, create directory to store new keymap, you can name it however you like instead of my_keymap_name</p><pre>mkdir -p keyboards/gmmk/pro/ansi/keymaps/my_keymap_name</pre><p>4. Convert json to C code for further modification</p><pre>docker run --rm -it \<br>-w /qmk_firmware \<br>-v &quot;$(pwd)&quot;:/qmk_firmware qmkfm/qmk_cli \<br>qmk json2c -o keyboards/gmmk/pro/ansi/keymaps/my_keymap_name/keymap.c gmmk_pro_ansi_layout_mine.json</pre><p>5. Open the C file with your text editor of choice, any plaintext editor would work (not Words or Pages but TextEdit or Notepads). I use <a href="https://code.visualstudio.com/">VScode</a> for syntax highlighting but you don’t need to. Then add the following lines at the bottom:</p><pre>bool encoder_update_user(uint8_t index, bool clockwise) {<br>    if (clockwise) {<br>      tap_code(KC_VOLU);<br>    } else {<br>      tap_code(KC_VOLD);<br>    }<br>    return true;<br>}</pre><p>5. Now you can run the following command to build the firmware, which will output the file in qmk_firmware directory. This will take awhile. (it’s the same process as what you click <em>compile</em> in the configurator)</p><pre>util/docker_build.sh gmmk/pro/ansi:my_keymap_name</pre><p>6. The first time you flash the firmware, stock reset combination on your keyboard is &lt;Space&gt; + B but after the first time, it is potentially changed. If you have no idea what did you remap the reset command to, it would by default be fn + \</p><p><strong>TS;WM</strong></p><p>By default, there is the modifier MO(1) down here to go to layer 1</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/522/1*IFYQraqsvjpltSVs2LMoJg.png" /></figure><p>And on layer 1</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/272/1*eWjqXhXGTYEq1f4pBcVo8g.png" /></figure><p>The RESET is here</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/452/1*9WZLsjadzw098fFsO4su1w.png" /></figure><p>7. Go to your QMK Toolbox and open the file gmmk_pro_ansi_my_keymap_name.bin in the qmk_firmware directory. Then unplug your gmmk pro, hold Fn + \, plug the cable back and then flash the firmware.</p><p>It is quite a wild ride since it gets very technical, but for me, I just learned about the existence of QMK and I see that there are a lot I can do with it. I can make rotary on different layer behaves differently, for example. And I might do a tutorial for that in the next post.</p><p>Have fun typing.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=28002e78cf3e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[3 คำถามก่อนเริ่ม retrospective]]></title>
            <link>https://iboss.medium.com/3-%E0%B8%84%E0%B8%B3%E0%B8%96%E0%B8%B2%E0%B8%A1%E0%B8%81%E0%B9%88%E0%B8%AD%E0%B8%99%E0%B9%80%E0%B8%A3%E0%B8%B4%E0%B9%88%E0%B8%A1-retrospective-f6ae6019c154?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/f6ae6019c154</guid>
            <category><![CDATA[retrospectives]]></category>
            <category><![CDATA[agile]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Sat, 30 Jan 2021 03:10:05 GMT</pubDate>
            <atom:updated>2021-01-30T03:10:05.481Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*GZsNXnPK0zeKc92f" /><figcaption>Photo by <a href="https://unsplash.com/@hjrc33?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Héctor J. Rivas</a> on <a href="https://unsplash.com/s/photos/abstract?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>เมื่อเช้าอยู่ในห้องน้ำแล้วอยู่ๆ ก็คิดขึ้นมาว่า มีหลายครั้งที่คนรู้สึกว่า retrospective มันไร้สาระ เสียเวลา บางครั้งผมเองก็รู้สึก ทั้งๆ ที่ก็รู้ว่ามันมีประโยชน์</p><p>หรือจริงๆ แล้วมันเป็นเพราะ dynamic ของคนในห้องรึเปล่านะที่ทำให้เกิดความรู้สึกว่า ปัญหาที่เราคิดว่าสำคัญไม่ได้ถูก address จริงๆ พูดกันแต่เรื่องอะไรก็ไม่รู้ เราเองก็ไม่อยากจะไปแย้งอะไรเขา กลัวชาวบ้านเค้าเสียเวลาเหมือนกัน</p><p>สำหรับผม หน้าที่ของ retrospective นอกจากมามองปัญหาในอดีต และแก้ไขปัญหาแล้ว สิ่งสำคัญของมันซึ่งน่าตลกดีที่มักจะถูกละเลยคือ การให้ทุกคนได้รู้จักคนอื่นๆ ในทีมลึกขึ้น ได้ฟังมากขึ้น และได้รู้ว่าเราแชร์ อะไรร่วมกันอยู่บ้าง</p><h3>Insight</h3><p>เวลาทำ product เค้ายังไปทำ user research เพื่อเก็บ insight มาออกแบบ product เลย ทำไม facilitator จะเก็บ insight มาออกแบบ retro บ้างไม่ได้ เคยเห็นท่าที่ใช้ทำ health checking โดยการถามว่า</p><blockquote>สบายใจจะพูดแค่ไหน ให้คะแนน 1–5</blockquote><p>แต่บางครั้ง เราตอบ 4 ตอบ 5 เราก็ไม่ค่อยจะพูดอยู่ดี หรือมิติมันน้อยเกินไปทำให้คน over-evaluated ความสบายใจของตัวเอง?</p><h3>3 คำถาม</h3><p>เลยนึกถึงคำถามที่เปิดให้ทีมได้มีโอกาส inspect ตัวเอง ก่อนที่จะไป inspect team เพราะถ้าตัวเองยังไม่รู้เลยว่าในใจเรามีอะไรบ้าง มัวแต่ไปโฟกัสเรื่องคนอื่นก็รังแต่จะกังวล ไม่กล้าพูดมากนักเสียเปล่าๆ การเปิดโอกาสให้ได้คิดถึงตัวเอง ทำให้คนกล้าที่จะพูดสิ่งที่ตัวเองคิดมากขึ้น</p><p>นอกจากนั้นยังเอา insight ที่ได้จากตัวเองมาลง pool of meaning ของ team แล้ว facilitator ก็สามารถนำสิ่งเหล่านี้ไปประกอบ discussion ต่อๆ ไปได้อีกต่างหาก</p><blockquote>ถ้าต้องให้นึกถึงแค่เรื่องเดียวที่เราเชื่อว่าเป็นเป้าหมายสำคัญที่สุดสำหรับทีมในตอนนี้ ไม่มีใครตัดสินว่าสิ่งที่เราเชื่อมันถูกหรือผิด คุณนึกถึงเรื่องอะไร</blockquote><p>คำถามนี้จะช่วย set tone ของ retrospective ว่าเราควรจะคุยเรื่องอะไรกันแน่ หลายๆ ครั้งจะเห็น pattern ว่าจริงๆ แล้วหลายคนแคร์เรื่องเดียวกัน แต่ไม่มีโอกาสได้พูดออกมาดังๆ เลยไม่ได้ align กัน</p><blockquote>มีไอเดียบางอย่างที่ยังตั้งไข่อยู่ในหัว คิดว่าต้องเจ๋งแน่ๆ แต่ยังคิดไม่เสร็จ ไม่กล้าพูดออกไป สิ่งนั้นคืออะไร</blockquote><p>คนเรามักจะ doubt ตัวเองว่าสิ่งที่พูดไปคนต้องไม่เข้าใจแน่ๆ logic ของเรายังไม่แข็งแรงพอ ถ้าเราไม่กล้าพูดถึงไอเดียพวกนี้ให้ทีมฟัง ก็พอจะเห็นได้ว่า psycological safety ในทีมยังมีไม่พอรึเปล่า ซึ่งผมเห็นว่าเป็นวิธีเข้าใจถึงความสบายใจของคนในทีมมากกว่าถามว่าสบายใจมากแค่ไหน แถมบางที แค่ตระหนักได้ว่ามีความกังวลนั้นอยู่ ก็อาจจะก้าวข้ามมันด้วยตัวเองได้ด้วยซ้ำ เพราะขั้นแรกของการแก้ปัญหา คือการตระหนักรู้ว่ามีปัญหา และ psycological safety ก็มักจะเป็นปัญหาที่คนไม่ค่อย recognize กันซักเท่าไหร่</p><blockquote>นึกถึงเรื่องที่พลาดหรือเรื่องโง่ๆ ล่าสุดที่ทำลงไป จะเล็กน้อยแค่ไหนก็ได้ เรากล้าเล่ากลางห้องนี้มากแค่ไหน?</blockquote><p>0 คือไม่กล้าเลย<br>1 คือพูดอ้อมๆ<br>2 คือยอมรับว่าพลาดอย่างเต็มอก</p><p>เป็นการเน้นย้ำให้ยอมรับถึงความไม่ perfect ของตัวเองและคนอื่น ตระรู้และก้าวข้ามมันไปด้วยกัน ถ้าต้องการความช่วยเหลือจากทีมก็จะทำให้สบายใจที่จะพูดออกมา</p><p>คำถามเหล่านี้ นอกจากจะทำให้เห็นถึง insight ของทีมแล้ว ยังช่วยเพิ่ม psychological safety ของคนในทีมอีกด้วย หลังอยากได้ insight มาแล้ว facilitator จะได้เห็นว่า จะ facilitate ต่อไปท่าไหนดี จะไป focus ที่ goal ที่ไม่ align, ที่ไอเดียที่อาจจะไปแก้ปัญหาที่ชัดแล้ว, psychological safety ของทีม, discussion ไหนสำคัญ ควรลงลึก discussion ไหนปล่อยไปคุยนอกรอบ</p><p>ลองเอาไปปรับใช้กันดูนะครับ หวังว่าจะทำให้ retrospective มีความหมายและมีประโยชน์มากขึ้น</p><p>เวิร์คไม่เวิร์คยังไงมาบอกด้วย!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f6ae6019c154" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[“Why Student Don’t Like School” #1 –What I Have Learned]]></title>
            <link>https://iboss.medium.com/why-student-dont-like-school-1-what-i-have-learned-85ef853e5237?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/85ef853e5237</guid>
            <category><![CDATA[learning]]></category>
            <category><![CDATA[cognitive-science]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Mon, 14 Dec 2020 02:46:52 GMT</pubDate>
            <atom:updated>2020-12-16T02:30:51.363Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1S5G5fecP0CcCrbfTbThpQ.png" /><figcaption>Photo by <a href="https://unsplash.com/@ixebeeh?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Camille</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>I stumbled across <a href="https://laconicml.com/andrew-ng-books-recommendation/?fbclid=IwAR1jxYdjSO3fD7FpS_zDsaW9GESKX3JROpQDyQuybZxzuUeFrKtjSvKZ_-M">this post,</a> which contains a list of books claimed to be suggested by <a href="https://en.wikipedia.org/wiki/Andrew_Ng">Andrew Ng</a>. And I found this book interesting since I’m looking for ways to improve my teaching as well as improving my personal learning guide.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/265/0*w9ApD4pcMDZLWLy-.jpg" /></figure><p>In this first part, by the time I wrote this, I have finished about half of the book (4 out out of 9 chapters) and here is what I have understood so far.</p><p><strong>Thinking</strong> is hard, we tends to avoid it. How could we overcome this curse?</p><ul><li>Human tends to be curious, which could lead to thinking.</li><li>When curiosity resolves, we feel pleasured.</li><li>But curiosity is fragile, if content is exceeding cognitive limits we will give up.</li><li>If the explanation is too exhaustive, we will not be curious. Which could be labeled as boring.</li></ul><blockquote>Trigger students curiosity, urging them to ponder about problem and let them solves, while respecting their cognitive limits helps them get the pleasure of solving problem.</blockquote><p>Critical thinking requires <strong>background knowledge</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/0*KrtCdKHnJNmfp9g-.jpg" /><figcaption>figure 1: simple memory model</figcaption></figure><ul><li>Factual knowledge improves memory. Since having an idea about a certain subject reduce the burden of working memory and free up computing power for processing new information.</li><li>Knowledge that should be instilled is the unifying idea in the subject that comes up over and over again. Since it will be retrieved to aids new learning effectively.</li><li>Shallow knowledge is better than no knowledge.</li><li>Knowledge must be meaningful. Unconnected fact and drilling leads to boredom rather than joy of discovery.</li></ul><blockquote>Teaching only facts, not skills has been a common complaints for ages, but in reality “factual knowledge precede skills”. So instilling important factual knowledge in a meaningful way improves critical thinking ability.</blockquote><p><strong>Thinking</strong> kept being mentioned since it’s an important steps to store information in long-term memory.</p><ul><li>Memory is the residue of thought.</li><li>We memorize things in the aspect that we think about.</li><li>Make student think about meaning, since it’s easier for later drawing connection thus easier to retrieve them from long-term memory.</li><li>“The answer has never been interesting, but if you know the question, it might.”</li><li>Attention grabbers might distract students’ thought, use it to point to the right direction and only when the students has enough background knowledge to process what’s happening.</li><li>If some thing really has no meaning (eg. multiplication table) then use mnemonics.</li><li>Design lesson to have story structure since it’s natural for student to draw connections.</li><li>That does not mean it has to be story telling, but do whatever activity that eventually contains 4Cs.</li></ul><pre><strong>Causality</strong>: Sense of connection</pre><pre><strong>Character</strong>: Establishing perspective</pre><pre><strong>Conflict</strong>: Main focus that requires to be resolved</pre><pre><strong>Complications</strong>: Minor curiosity igniter that keeps attention</pre><blockquote>Using story structure to guide student to think about meaning of the subject. The context set for learning affect what students will remember since <strong>they remember what they</strong> <strong>think about.</strong></blockquote><p>It’s hard to understand <strong>abstract ideas</strong>.</p><ul><li>Concrete ideas are easier to grab since we already have some idea related to them.</li><li>Abstract ideas comes from generalizing concrete idea, so gives more example around the same abstract idea.</li><li>Ask student to compare the difference between example helps shaping abstract ideas since they will have to think about what are the shared properties as well.</li><li>Metaphor works, since it draws connection with existing knowledge.</li></ul><blockquote>Abstract ideas could be shaped out of examples, let the student pondering about the differences to get over the “surface structure” and get the sense of “deep structure”. Making deep structure being spoken to emphasize their thinking rather than keep invoking thoughts about factual knowledge too much. And make realistic expectation, deep knowledge is hard but shallow knowledge is better than no knowledge at all.</blockquote><p>So, this is what I have learned so far.</p><p>What do you <strong>think</strong> about it?</p><p>See you again in <em>Part 2</em> (coming soon)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=85ef853e5237" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Functional Programming resources I’ve found useful]]></title>
            <link>https://iboss.medium.com/functional-programming-resources-ive-found-useful-ce25b2279eb7?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/ce25b2279eb7</guid>
            <category><![CDATA[lambda-calculus]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[category-theory]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Mon, 29 Jul 2019 13:44:10 GMT</pubDate>
            <atom:updated>2019-07-29T13:44:10.838Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*keGTly_-fWlT89pP" /><figcaption>Photo by <a href="https://unsplash.com/@kornyeir?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Regös Környei</a> on <a href="https://unsplash.com/search/photos/loop?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>I’ve got a chance to walk through my <a href="https://github.com/iboss-ptk/trading-card-game-kata">trading card game kata</a> with a bunch of passionate new grads in a personal boot camp run by <a href="https://medium.com/u/7c33c7e5d660">Salah Chalermthai</a>. The code is written in TypeScript but in a very functional manner. They asked me to point out some good resources about functional programming. So I compiled this list to aid their curiosity.</p><p>I would like to separate into 3 sections, <strong>Practical</strong>,<strong> Theoretical</strong> and <strong>Interesting Functional Languages</strong>. While practicality is important, understanding the underlying concept of things makes you better at reasoning about and utilize tools in your toolbox. Learning different languages that has different philosophy can change the way you think about programming. I will point out some languages with different flavors so you can explore.</p><h3>Practical</h3><p><a href="https://medium.com/funk-tional/hello-functional-programming-eacb0091a53c"><strong>Hello, Functional Programming!</strong></a></p><p>Well, this has written by me. It’s a very brief introduction to the subject, just to get the sense of what it means.</p><p><a href="https://blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/"><strong>SOLID: The Next Step is Functional</strong></a></p><p>This one is about design principle that is widely known in OO community. SOLID has been discussed in the boot camp so I think it would be interesting to look at it from a functional lens.</p><p><a href="https://egghead.io/courses/professor-frisby-introduces-composable-functional-javascript"><strong>Professor Frisby Introduces Composable Functional JavaScript</strong></a></p><p>Functional programming tends to be discussed in a very abstract manner since it has a lot of useful composable abstractions at hand to be used to reason about and model things. This course is more example based, practical use case driven and when you see the pattern they will extract those patterns and form abstractions which can be reused further in many context.</p><p><a href="https://fsharpforfunandprofit.com/site-contents/"><strong>F# for fun and profit</strong></a></p><p>One of my favorite website about functional programming. The author use F# language as a medium to talk about lots of interesting concept in functional programming and how can they be useful in solving real business problem.</p><p><a href="https://blog.ploeh.dk/2017/10/04/from-design-patterns-to-category-theory/"><strong>From Design Pattern to Category Theory</strong></a></p><blockquote><em>How do you design good abstractions? By using abstractions that already exist.</em></blockquote><p>This series of blog posts talk about utilizing a branch of mathematics called Category Theory as design patterns. Category Theory has bunches of small and lawful, well defined abstractions which we can built upon. It’s a study of mathematical structures but turns out to be very useful in programming as well.</p><h3>Theoretical</h3><p><a href="https://www.youtube.com/watch?v=3VQ382QG-y4"><strong>Lambda Calculus — Fundamentals of Lambda Calculus &amp; Functional Programming in JavaScript</strong></a></p><p>Lambda Calculus is a formal system for expressing computation which can simulate any Turing machine. It’s based on function abstraction and application which is the basic of functional paradigm.</p><p><a href="https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/"><strong>Category Theory for Programmer</strong></a></p><p>If you get hooked into Category Theory at some point and wants to understand more about what it actually means, this might be interesting for you. This will take you to have a deeper look into Category Theory and also map those ideas into Haskell (I also learn a bit of Haskell in the mean time).</p><p>There’s also a <a href="https://www.youtube.com/playlist?list=PLbgaMIhjbmEnaH_LTkxLI7FMa2HsnawM_">video version</a> and <a href="https://github.com/hmemcpy/milewski-ctfp-pdf/">pdf version</a>.</p><p><strong><em>Warning:</em></strong> this might be very abstract to some, it takes sometimes to digest. I would not recommend this for those who has just started functional programming but after awhile you will encounter those weird terms from Category Theory, so come here when you are really curious about it.</p><h3>Interesting Functional Languages</h3><p><a href="https://www.haskell.org/"><strong>Haskell</strong></a></p><p>An advanced, purely functional programming language. It’s not a must learning Haskell to understand FP but if you want to really understand FP, you should give it a try.</p><p>Haskell resources:</p><ul><li><a href="http://learnyouahaskell.com/">Learn You Haskell for Great Good!</a></li><li><a href="http://haskellbook.com/">Haskell programming from first principles</a></li><li><a href="http://dev.stephendiehl.com/hask/">What I Wish I Knew When Learning Haskell</a></li></ul><p><a href="https://clojure.org/"><strong>Clojure</strong></a></p><p>While Haskell type system is static. Clojure is dynamic. Clojure takes different approach from Haskell which has a lot of higher level abstraction, Clojure only cares about few set of data structures and lots of functions to manipulate them.</p><p>Clojure resources:</p><ul><li><a href="https://www.braveclojure.com/">Clojure for brave and true</a></li></ul><p><a href="https://elixir-lang.org/"><strong>Elixir</strong></a></p><p>Elixir has a friendly syntax like ruby with a lot of language features that aids functional paradigm. It runs on Erlang vm which is used for building highly concurrent system for telephone switches back in the days. Elixir can spawn a very lightweight process and send messages to each others which is a very nice building block for modelling concurrency.</p><p>I hope this is useful :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ce25b2279eb7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mocking static method in Kotlin]]></title>
            <link>https://medium.com/hackernoon/mocking-static-method-in-kotlin-614df89482ae?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/614df89482ae</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[mocking]]></category>
            <category><![CDATA[testing]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Tue, 10 Jul 2018 15:28:31 GMT</pubDate>
            <atom:updated>2018-07-14T12:29:00.765Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*78lDdKSPwr50lccR64qEiQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/photos/ym3QFTHYUE4?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Susan Yin</a> on <a href="https://unsplash.com/search/photos/mock?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Static method is bad, or at least, when it’s not <strong>pure</strong>.</p><p>Pure, in this context, means that:</p><ul><li>It causes no side-effects, mutates nothing outside of the method scope.</li><li>It is referential transparent, meaning any reference must be passed as an argument or else mutation of your referenced value will results in non-deterministic result.</li></ul><p>Why is that bad?</p><p>Because whoever consumes that impure static method will not be easy to test. If the static method is pure it might be fine since you can predict its behavior and you don’t need to mock them (less mocking is great!), just asserting the return value is enough. But the impure one, it’s a different story.</p><p>If the code is under your control, you can and should avoid impure static method. But if you have to use static method from a library or framework and you can’t avoid them, what can you do?</p><p>For example, we want to send sms notification using <a href="https://www.twilio.com/">Twillo</a>.</p><p>Twillo SDK provides static method Message.creator which is a factory method for constructing MessageCreator. The method that actually makes a request to Twillo to send sms is messageCreator.create(restClient).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4057ca838468ecd9ef90fa47b8abd997/href">https://medium.com/media/4057ca838468ecd9ef90fa47b8abd997/href</a></iframe><p>Even though Message.creator is pure, but messageCreator.create(restClient) which is the method of the result of Message.creator is not. So we need to mock the create method by first stubbing return value of Message.creator. But since Message.creator is static, we don’t have our way in.</p><p>One might say: we can create a wrapper class around that static method, so that we can mock the wrapper instead.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d91b7a72e032a690a5b992d70173f974/href">https://medium.com/media/d91b7a72e032a690a5b992d70173f974/href</a></iframe><p>But testing is all about increasing confidence in your code. Adding another level of indirection just for testing doesn’t increase confidence level in your system under test and adding more complexity to your code base.</p><p>So if adding wrapper helps you improving team’s coding experience consuming the API and it is being use a lot then it might worth investment, not just for the sake of testing.</p><p>Then, is there a leaner way?</p><h4>Higher-order function FTW</h4><p>We want to somehow create a path to replace Message.creator with something else. In Kotlin and a many languages these days treat function as a first-class citizen. The smallest reusable component is no more class but function. So you can pass function around like any other object.</p><p>In a strict functional and mathematical sense, function must be pure. But in Kotlin context, seems like function is allowed to be impure.</p><p>The difference between method and function in Kotlin is, while method is associated to an object, function doesn’t need to. You can see that the fun keyword which refers to function everywhere regardless of being a method declaration or top-level function declaration, which means function is a super-set of method, at least in this context.</p><p>But what is Higher-order function?</p><p>Higher-order function is basically means the function that has function as parameter(s) or returns function.</p><p>Even though function that does not have function as parameter(s) and not returning function is called first-order function, the term higher-order is being used here instead of second-order or third-order because, in theory, we can nest “function that has function as parameter(s) or returns function” infinitely many level. So that it’s higher than second or third order.</p><p>Let’s get back to our main topic. So we want to inject Message.creator into notify and we can achieve that by making notify a higher-order function so that we can pass Message.creator in as an argument.</p><p>In order to do that, first step, we need get the type right.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7d248b743dfebbc0733bcdf992a540b0/href">https://medium.com/media/7d248b743dfebbc0733bcdf992a540b0/href</a></iframe><p>Let’s figure out the type of this particular function. Here is the implementation of the original creator in the SDK:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/671e54eadfd6e19a13a65abad862a260/href">https://medium.com/media/671e54eadfd6e19a13a65abad862a260/href</a></iframe><p>So it has a type</p><pre>(PhoneNumber, String, String) -&gt; MessageCreator</pre><p>which means parameter types on the left side of the arrow “-&gt;” and return type on the right side.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f60e7b35fedd6dd85ed005d866b4ed9e/href">https://medium.com/media/f60e7b35fedd6dd85ed005d866b4ed9e/href</a></iframe><p>Now let’s define our typealias to refer to this function type and name it for readability.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8c3c9265aad8bc41b02020be2f4e8cc5/href">https://medium.com/media/8c3c9265aad8bc41b02020be2f4e8cc5/href</a></iframe><p>But now, we’ve just changed our interface, which is not really nice since normally we don’t need to pass creator to notify except in test.</p><p>In Kotlin, we can avoid that by providing default argument.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d53b0444a4d0bad3a2035e1604cedb08/href">https://medium.com/media/d53b0444a4d0bad3a2035e1604cedb08/href</a></iframe><p>So now, our existing interface stays the same and we have our way in!</p><h4>Let’s mock!</h4><p>I’m using <a href="https://spekframework.org/">Spek</a> and <a href="https://github.com/nhaarman/mockito-kotlin">mockito-kotlin</a> here.</p><p>So we define a creator that returns a mocked MessageCreator that stub create method to return Message we want.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d7e55e8c8f530dca2b0e120f0a6c9a70/href">https://medium.com/media/d7e55e8c8f530dca2b0e120f0a6c9a70/href</a></iframe><p>You might ask, at line 22:</p><ul><li>Why don’t we just use Message constructor? =&gt; It’s private.</li><li>Why don’t we mock getters? =&gt; It’s final.</li></ul><p>So we end up using fromJson instead.</p><p><strong><em>Edit 14 July 2018: </em></strong><a href="https://medium.com/u/417d954d6bf5"><em>David Kirchner</em></a><em> point out that mockito 2 can mock </em><em>final class and method already. See full response </em><a href="https://medium.com/@dpkirchner/mockito-now-supports-mocking-final-classes-natively-although-you-have-to-opt-in-and-be-aware-of-37fa0545d20e"><em>here</em></a></p><p>And I reference to creator function by using ::creator, it will regard as a value. The other way, we can use lambda and assign it to val instead of fun.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3096748ff0021ebf834eac5246800597/href">https://medium.com/media/3096748ff0021ebf834eac5246800597/href</a></iframe><p>By using lambda, we can just ignore the arguments using _ since we are not using it in this context. This is not possible if we define it with fun.</p><p>For more info about how all these functions and lambdas work, <a href="https://kotlinlang.org/docs/reference/lambdas.html">you can find out in Kotlin documentation</a>.</p><p>Now, we might want to verify if the creator is being called with correct arguments. The problem is mockito’s verify only supports method call verification. How can we verify creator that is not associate to any object?</p><p>But turns out, function is actually just a class with invoke method, so instead of creating function on our own, we can mock the function type. That way, mockito can verify the invoke method of that function if it’s being called by correct arguments. Here is how function being defined in it’s standard library.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b329572694827347a8c12e974f31831a/href">https://medium.com/media/b329572694827347a8c12e974f31831a/href</a></iframe><p>Now we know that we can mock our function to verify the call and we can also stub the return value. Let’s do both!</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dce7b659a609476749e823e8b388df5a/href">https://medium.com/media/dce7b659a609476749e823e8b388df5a/href</a></iframe><p>As you can see, we can verify our function call and stubbing the return value of the static method without hacking the language.</p><h4>Summary</h4><p>We are leveraging higher-order function and default argument feature of the language to allow us to inject static method into a function that we want to test so that we can mock/stub it while retaining the old interface. Any language that has both features can also use the same trick as well.</p><p>I hope you’ve got the idea.</p><p>Thanks for reading! Enjoy testing :D</p><p>Follow me on twitter <a href="https://twitter.com/ibossptk">@ibossptk</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=614df89482ae" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/mocking-static-method-in-kotlin-614df89482ae">Mocking static method in Kotlin</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advance Flow type: Table of Contents]]></title>
            <link>https://iboss.medium.com/advance-flow-type-table-of-contents-343e0559d5e1?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/343e0559d5e1</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[type]]></category>
            <category><![CDATA[flowtype]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Tue, 23 Jan 2018 14:36:50 GMT</pubDate>
            <atom:updated>2018-01-24T01:02:31.703Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YnuSfdW_qF6JUekH5sCpMw.png" /></figure><p>The main goal of this series is to discuss about how to make Flow more being more cooperative with you, catch more bugs, helps you being more confident and productive. Some topic might be general enough to be applicable to other type system as well.</p><p>I might also mention a bit about some academic sounding stuffs as well just to wet your appetite and have clearer picture of why things work the way it is and why something being named in a particular way, but I will put them in context as much as possible.</p><p>Here is the list of the topics:</p><ol><li><a href="https://medium.com/@ibosz/advance-flow-type-1-exhaustive-checking-with-empty-type-a02e503cd3a0">Exhaustive checking with empty type</a></li><li>Determining return type by argument(s)</li></ol><p>and more to come…</p><p>Follow me on twitter <a href="https://twitter.com/ibossptk">@ibossptk</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=343e0559d5e1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advance Flow type #1: Exhaustive checking with empty type]]></title>
            <link>https://iboss.medium.com/advance-flow-type-1-exhaustive-checking-with-empty-type-a02e503cd3a0?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/a02e503cd3a0</guid>
            <category><![CDATA[flowtype]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[type]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Tue, 23 Jan 2018 14:35:01 GMT</pubDate>
            <atom:updated>2018-01-23T14:44:15.575Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vbUIZkMPEkSzPjMPa43wJQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/photos/7VliWOXYLro?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Peter Lewicki</a> on <a href="https://unsplash.com/search/photos/empty?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p><a href="https://medium.com/@ibosz/advance-flow-type-table-of-contents-343e0559d5e1">Advance Flow type: Table of Contents</a></p><p>This post is the first post in Advance Flow type series and might be the least advance one but I think it is quite useful.</p><p>From the title, there are two interesting terms: <strong>exhaustive checking</strong> and <strong>empty type.</strong> What are they? Why do I need to care?</p><h4>Exhaustive Checking</h4><p>When we do conditional branching like if else or switch you might end up leaving some branch unhandled. Consider this simple function:</p><pre><strong>const</strong> f = (x: &#39;A&#39; | &#39;B&#39;) =&gt; {<br>  <strong>if</strong> (x === &#39;A&#39;) {<br>    <strong>return</strong> 0<br>  }<br>}</pre><p>Flow will not complain you anything, even though the &#39;B&#39; case is not handled. The return type will be infered to ?number since it implicitly return undefined.</p><p>We can add else block to handle the rest of the case like this</p><pre><strong>const</strong> f = (x: &#39;A&#39; | &#39;B&#39;): number =&gt; {<br>  <strong>if</strong> (x === &#39;A&#39;) {<br>    <strong>return</strong> 0<br>  } <strong>else</strong> {<br>    <strong>return</strong> 1<br>  }<br>}</pre><p>I also specify number as return type of this function to make sure that it will never implicitly return undefined.</p><p>Moving forward, we need to extract type of x out to somewhere else like this.</p><pre>// type.js</pre><pre><strong>type</strong> X = &#39;A&#39; | &#39;B&#39;</pre><p>And the function lives in another file.</p><pre>// function.js</pre><pre><strong>const</strong> f = (x: X): number =&gt; {<br>  <strong>if</strong> (x === &#39;A&#39;) {<br>    <strong>return</strong> 0<br>  } <strong>else</strong> {<br>    <strong>return</strong> 1<br>  }<br>}</pre><p>Now, let’s assume that type X is being used by someone else as well. If one day we have to add &#39;C’ to the type.</p><pre><strong>type</strong> X = &#39;A&#39; | &#39;B&#39; | &#39;C&#39;</pre><p>You have to go back and find every branching on X to make sure that it handle &#39;C&#39; correctly and not just fall into default case which is not expected behavior.</p><p>What if I told you that if we just add two more line of code and you can prevent this problem? What if when we add &#39;C&#39; our beloved type system will just guide us back to where we need to care about rather than tracing back yourself?</p><p>Or to put it in another way, to exhaustively check if we have already handled every cases.</p><h4>Empty Type</h4><p>In order to do that in Flow, you need empty type.</p><p>What is empty type?</p><p>Empty type is the type that has no element at all. So if we assert (x: empty)</p><pre><strong>const</strong> f = (x: X): number =&gt; {<br>  <strong>if</strong> (x === &#39;A&#39;) {<br>    <strong>return</strong> 0<br>  } <strong>else if </strong>(x === &#39;B&#39;) {<br>    <strong>return</strong> 1<br>  } <strong>else </strong>{<br>    (x: empty)<br>    <strong>throw</strong> <strong>new</strong> Error(`${x} is not an element of type &#39;X&#39;`)<br>  }<br>}</pre><p>It will have type error since x is so far refined to &#39;C&#39; which means it still not empty. So all you need to do is to add another case to handle &#39;C&#39; and Flow will be happy.</p><pre><strong>const</strong> f = (x: X): number =&gt; {<br>  <strong>if</strong> (x === &#39;A&#39;) {<br>    <strong>return</strong> 0<br>  } <strong>else</strong> <strong>if</strong> (x === &#39;B&#39;) {<br>    <strong>return</strong> 1<br>  } <strong>else</strong> <strong>if</strong> (x === &#39;C&#39;) {<br>    <strong>return</strong> 2<br>  } <strong>else</strong> {<br>    (x: empty)<br>    <strong>throw</strong> <strong>new</strong> Error(`${x} is not an element of type X`)<br>  }<br>}</pre><p>If you don’t <strong>throw </strong>you will have a problem of implicitly return undefined. Apart from avoiding the implicitly return undefined problem, it is also useful for the case that some part of the code is still not covered by Flow or the data comes from IO boundary (eg. API calls) and, for some reason, doesn’t match the type definition (which I would suggest validating it beforehand using something like <a href="https://github.com/gcanti/io-ts">io-ts</a>).</p><p>I would recommend using <strong>throw </strong>so when such a case happens, it’s not failed silently.</p><p>But there is another way to avoid implicitly return undefined just to show you an interesting property of empty type.</p><p>Which is by returning emptiness.</p><pre><strong>const</strong> f = (x: X): number =&gt; {<br>  <strong>if</strong> (x === &#39;A&#39;) {<br>    <strong>return</strong> 0<br>  } <strong>else</strong> <strong>if</strong> (x === &#39;B&#39;) {<br>    <strong>return</strong> 1<br>  } <strong>else</strong> <strong>if</strong> (x === &#39;C&#39;) {<br>    <strong>return</strong> 2<br>  } <strong>else</strong> {<br>    <strong>return</strong> (x: empty)<br>  }<br>}</pre><p>After x being refined to this point, its type is no longer anything. It will work without explicitly asserting that x is empty as well, but the error will be a little bit more confusing since it will check type of x against number instead of empty. So, by returning x, the return type of this function will be</p><pre>number | empty</pre><p>since it could be either number or empty.</p><p>But for any type T, T | empty = T and empty | T = T because empty has no element, that’s why if we handle all the case before that last return, there should be no type error.</p><p>And you might notice that it’s the same as logic, for all proposition p, we can say that p v False = p and False v p = p and it’s not just a coincidence because empty type is corresponded to falsity and type also has strong correspondence to logic.</p><p>If you would like to go down the rabbit hole, you can have a look at <a href="https://en.wikipedia.org/wiki/Bottom_type">Bottom type</a> and <a href="https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence">Curry-Howard correspondance</a>.</p><h4>More example</h4><p>Let’s look at more practical example.</p><p>We are going to create a validator that consume rule as data and spit out the result and here is the shape of rules.</p><pre><strong>type</strong> MaxRule = {<br>  type: &#39;MAX&#39;,<br>  maxValue: number,<br>}</pre><pre><strong>type</strong> MinRule = {<br>  type: &#39;MIN&#39;,<br>  minValue: number,<br>}</pre><pre><strong>type</strong> ForAllRule = {<br>  type: &#39;FOR_ALL&#39;,<br>  rules: Rule[]<br>}</pre><pre><strong>type</strong> ForSomeRule = {<br>  type: &#39;FOR_SOME&#39;,<br>  rules: Rule[]<br>}</pre><pre><strong>type</strong> Rule = MinRule | MaxRule | ForAllRule | ForSomeRule</pre><p>Every rule has property type so we can refine the type using that property.</p><pre><strong>const</strong> validate = (value: number, rule: Rule): boolean =&gt; {<br>  <strong>switch</strong> (rule.type) {<br>    <strong>case</strong> &#39;MAX&#39;:<br>      <strong>return</strong> value &lt;= rule.maxValue<br>    <strong>case</strong> &#39;MIN&#39;:<br>      <strong>return</strong> value &gt;= rule.minValue<br>    <strong>case</strong> &#39;FOR_ALL&#39;:<br>      <strong>return</strong> rule.rules<br>        .reduce((acc, nextRule) =&gt; acc &amp;&amp; validate(value, nextRule), true)<br>    <strong>case</strong> &#39;FOR_SOME&#39;:<br>      <strong>return</strong> rule.rules<br>        .reduce((acc, nextRule) =&gt; acc || validate(value, nextRule), false)<br>    <strong>default</strong>:<br>      (rule.type: empty)<br>      <strong>throw</strong> Error(`rule ${rule.type} is not being handled properly`)<br>  }<br>}</pre><p>So now if we remove some <strong>case</strong> then it should have a type error.</p><h4>Conclusion</h4><p>Even though exhaustive checking with Flow might not be so beautiful comparing to some other language that has native support for it (eg. Scala, Haskell, Elm, OCaml) but at least we can make it work in JavaScript and it help us being explicit about what should be handled and let type system guide us where to fix or add stuffs.</p><p>For empty type itself, it also has some other use cases which we will discuss about it later in this series.</p><p>Thank you for reading. Feedback and comment are welcome.</p><p>Follow me on twitter <a href="https://twitter.com/ibossptk">@ibossptk</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a02e503cd3a0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Think first, test later]]></title>
            <link>https://medium.com/hackernoon/think-first-test-later-2a258bed05cf?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a258bed05cf</guid>
            <category><![CDATA[think-first-test-later]]></category>
            <category><![CDATA[tdd]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[test-later]]></category>
            <category><![CDATA[think-first]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Tue, 12 Sep 2017 15:41:49 GMT</pubDate>
            <atom:updated>2017-09-12T15:41:49.199Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*05buQX-OWGjI_nRD5ys2cQ.png" /><figcaption>photo by <a href="https://unsplash.com/@korabelnikova?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge">Elizaveta Korabelnikova</a></figcaption></figure><p>I have been doing Test-Driven Development (TDD) for quite a while and it’s great. It gives me a canvas (test file) to draft the design and way to think about how the interaction with other components should look like, what are the desired behaviors, and most of all, it gives me a very fast feedback loop.</p><p>When the time comes, you want to refactor. Doing TDD already gives you the safety net which is a bunch of test cases you have written to drive your implementation. When you refactor, according to Martin Fowler’s definition, you do not change the observable behavior.</p><blockquote>Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.</blockquote><p>So, when refactoring, do tests need to be changed?</p><p>It depends on what level are you saying you are not changing behavior. Who is the observer? Interface changes require altering tests. Here, everything remains the same; just the form of input and output change even if they are isomorphic to previous ones. Does that count as changing behavior?</p><p>End-user might not notice but other consumers (your fellow developers and some other parts of the code base) will notice the change of the interface.</p><p>Even worse, the tests might know too much about implementation. You neither change any behavior nor interface but you still need to change the test.</p><p>TDD is useful for driving design but does not mean it always yields good design. If it goes wrong, the safety net ends up being spider web that prevents you from moving away instead. It turns out that you spend more time on maintaining the test and it discourages people from refactoring because it requires a lot of work.</p><p>So how can we stay sane?</p><h3>Before anything else, think.</h3><p>Sometimes people take TDD too far, they might say “don’t think, just write a test first” and hope that TDD will eventually guide us to better design. If not, we can refactor later. That doesn’t always work.</p><p>The thing is if we don’t think enough before writing the first test, the poor problem modeling will leak into implementation and spread like wildfire.<br>At some point, you will realize that the thing you just wrote doesn’t fit well in the bigger picture and you will spend more and more time refactoring, or even worse, you don’t have enough time to refactor it because of the so-called delivery pressure. Your teammates start building stuff on top of it and it’s getting even costlier to refactor. Domain understanding is a very important key to successful software development.</p><p>So before writing any tests, ask yourself</p><blockquote>What problem are we trying to solve?</blockquote><p>We are solving problem not just building feature. So we should know what the problem is, and write it down. Once we know what it is, think about how to model it to fit in the context and constraints we have. While I am at work, I disturb business analyst and UX designer quite frequently (and other roles as well but that’s less frequent) to understand the logic and reason behind a user story before diving into technical details. Understanding the problem we are trying to solve is the very first step of good problem modeling.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*avT4HrsKwl1hwLKsPYo-5Q.png" /><figcaption>Photo by <a href="https://unsplash.com/@jdsimcoe">Jonathan Simcoe</a></figcaption></figure><p>Pen and paper or whiteboard are awesome tools for problem modeling. Computer tends to be a distraction since it gives us the urge to implement without thinking carefully enough.</p><p>So, to me, this is like a micro version of traditional analysis and design. Avoiding big design up front doesn’t mean you should ignore planning and just go code with blind eyes. You can’t be agile if you don’t plan for the design that is easy to change, evolve or even throw it away.</p><p>If you have never watch <a href="https://www.youtube.com/watch?v=f84n5oFoZBc">Hammock-driven development</a> by Rich Hickey (the guy who creates Clojure), I would recommend you to watch it. It will give you some interesting ideas about how to think about problems.</p><p>Now we understand more about the problem, let’s put our understanding into…</p><h3>Contract</h3><p>When we are coding, we need to think about how a function, module or class will be used, how do the inputs and outputs look like, what are the constraints we want to put on. We write down the contract in our code to filter out unnecessary possibility we need to handle.</p><p>One way of doing it is by using type.</p><p>Types represent set of possible inputs and outputs. With good type system, it gives you type-level feedback by the compiler which is even faster than test. At that time you are focusing more on designing interface, not the underlying implementation. You can use types to eliminate potential bugs, but how far you can go also depends on how sophisticated type system your language of choice is.</p><p>In typed-functional setting, people tend to use algebraic data types to model problem. The idea is quite simple and <a href="http://tpolecat.github.io/presentations/algebraic_types.html#1">can be encoded in class as well</a>.</p><p>But that’s not the only way. The goal is to put some constraints on the input and output and document it. For example, Clojure, which is a dynamically typed language, has <a href="https://clojure.org/about/spec">clojure.spec</a> which gives you ability to do so. And it comes with <a href="https://github.com/clojure/test.check">test.check</a> which can also generate tests by spec you defined. Or in JavaScript, there is a library called <a href="https://github.com/gcanti/tcomb">tcomb</a> which allows you to perform type checking at runtime and it’s quite flexible customizing the checks.</p><p>Even without all the tools, it’s good to understand how it should look like. At least think about it before you start writing test. Designing data structure to match the nature of the problem reduces the number of tests you need to write and also makes your implementation simpler.</p><p>If you would like to know more about this topic, I would recommend <a href="https://www.youtube.com/watch?v=IcgmSRJHu_8">Making Impossible States Impossible</a> and <a href="https://fsharpforfunandprofit.com/posts/designing-with-types-intro/">Designing with types</a>. They are all using typed-functional language to demonstrate but I think the idea is applicable to OOP as well.</p><h3>Then write the first test</h3><p>After we filter out lots of undesirable states by types, it’s time to be more specific. Guiding by examples, TDD is a good tool for driving design of the internal implementation of a function or a class. As I mentioned before, test file is like a canvas for us to paint our design. It will show you how it will be used and it’s the place to define the desired behavior that type can not express. You will sense the smell that if it takes too much effort to setup the test or it’s hard to assert the behavior.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UBSocVjkTCXwgjesHfxOtg.png" /><figcaption>Photo by <a href="https://unsplash.com/@aarondnbb">Aaron Mello</a></figcaption></figure><p>As we go step by step, from very basic cases to more complicated cases, our design grows within the boundary we have defined. We add tests. We add new code. We have all the tests for regression testing and then refactor. One thing to keep in mind along the way is that we should keep the test away from the implementation detail as much as possible or else we will end up in the state in which tests hinder you from refactoring.</p><p>One tip that makes me feel productive is listing all the cases even without any assertion (aka. pending tests) to have the milestones for the implementation. By doing this, you will see the clear outline of the function or class behavior.</p><p>More cases can be added along the way if we can think of other valuable ones. Keep in mind that more tests don’t always mean good, but always mean more code to maintain. Write tests just enough to be confident and keep them in the state that is maintainable like application code.</p><h3>It’s all about quality</h3><p>Good design is the cheapest way to prevent bugs. From careful thoughts to types and then tests provide more abstract picture of the system: how do the components communicate with each other, what are the interfaces, what are the behaviors. They all affect how we implement one small part of the system. Writing test before anything else might lead to wrong focus in the design process.</p><p>It’s about iterative and incremental change but at different level and different cycle time. TDD is the shortest one, while the rest are longer.</p><p>There are also times that TDD doesn’t work well. If that’s the case, try something else.</p><blockquote>TDD is not a means to an end, good quality software is.</blockquote><p>Follow me on twitter <a href="https://twitter.com/ibossptk">@ibossptk</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a258bed05cf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/think-first-test-later-2a258bed05cf">Think first, test later</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[8 กระบวนท่า ‘Optional’ ในภาษา Swift]]></title>
            <link>https://iboss.medium.com/8-%E0%B8%81%E0%B8%A3%E0%B8%B0%E0%B8%9A%E0%B8%A7%E0%B8%99%E0%B8%97%E0%B9%88%E0%B8%B2-optional-%E0%B9%83%E0%B8%99%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2-swift-6f715a125de9?source=rss-7ee6829f80e3------2</link>
            <guid isPermaLink="false">https://medium.com/p/6f715a125de9</guid>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[monads]]></category>
            <dc:creator><![CDATA[I'Boss Potiwarakorn]]></dc:creator>
            <pubDate>Wed, 29 Mar 2017 15:02:01 GMT</pubDate>
            <atom:updated>2017-03-30T04:37:57.649Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F49Y66uIc1tKGwapfm5_HA.png" /></figure><p>บังเอิญว่าผมอาจจะต้องเขียน mobile application เลยมาจับ Swift ซะหน่อย บังเอิญว่าทั่น Erik Meijer (ผู้สร้าง <a href="https://en.wikipedia.org/wiki/Language_Integrated_Query">LINQ</a> และ <a href="http://reactivex.io/">Rx</a>) แกบอกว่า</p><h3>Erik Meijer on Twitter</h3><p>At this point, @SwiftLang is probably a better, and more valuable, vehicle for learning functional programming than Haskell.</p><p>ถ้าเฮียจะพูดขนาดนี้ ไหนขอลอง functional Swift ซะหน่อยซิ</p><p>ลองไปลองมา ก็ไปสะดุดกับ Optional (หนึ่งในวิชามารของ functional programming) เพราะว่าหน้าตามันประหลาดกว่าชาวบ้าน อย่าง Scala, Java 8 อยู่พอสมควร แล้วมีวิธีจะใช้งานมันแบบประหลาดๆ เยอะมากเลย ไม่แน่ใจว่าดีหรือไม่ดีเหมือนกัน เดี๋ยวเรามาดูกัน</p><blockquote>related posts</blockquote><ul><li><a href="https://medium.com/funk-tional/hello-functional-programming-eacb0091a53c">Hello, Functional Programming!</a></li><li><a href="https://medium.com/funk-tional/map-reduce-%E0%B9%81%E0%B8%A5%E0%B8%B0%E0%B8%9C%E0%B8%AD%E0%B8%87%E0%B9%80%E0%B8%9E%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%99-7e5835f231c">ลาก่อย for loop: map, reduce และผองเพื่อน</a></li></ul><h3>แล้ว Optional มันคืออะไร?</h3><p>สำหรับใครที่ไม่รู้ว่า Optional มันคืออะไร ถ้าให้แปล Optional แล้วล่ะก็ คงจะแปลเป็นไทยได้ว่า type นี้มันอาจจะมีหรือไม่มีตัวตนอยู่ก็ได้</p><p>เรื่องนี้เกี่ยวข้องกับ null reference (ใน Swift คือnil) ซึ่งหลายคนอาจจะเคยได้ยินแล้วว่า Tony Hoare คนที่คิดค้น null reference ขึ้นมาเพื่อใช้ในภาษา ALGOL W (และเป็นคนเดียวกับคนสร้าง <a href="https://en.wikipedia.org/wiki/Communicating_sequential_processes">CSP</a> ซึ่งเป็น formal language เบื้องหลัง actor model และ go routine ด้วย) แกบอกว่า null reference เนี่ย</p><blockquote>I call it my billion-dollar mistake</blockquote><p>แกอดไม่ได้ที่จะใส่ null reference ลงไปเพราะมัน implement ง่าย แต่ผลที่ตามมาคือ error มากมาย, ช่องโหว่, crash ซึ่งคงจะทำให้สูญเสียกันเป็นพันล้านดอลล่า และผู้คนต้องปวดใจกันมาตลอด 40 ปี…</p><p>แล้วชาว functional แก้ปัญหานี้ยังไง?</p><p><strong>อะไรปัญหาเยอะ ก็เอามันไป “ห่อ” ซะสิ</strong></p><p>พอเราห่อมันแล้ว ชีวิตก็ไม่ต้องมาคอย if value == nil อยู่ตลอดเวลา ก็ใช้มันแบบที่มันห่อๆ ไว้แล้ว แล้วค่อยไปจัดการกับมันตอนปลายทางแล้วกัน</p><p><em>*จากนี้ไป แนะนำให้เปิด playground มาพิมพ์เล่นตามไปด้วยเพื่อเพิ่มอรรถรส!</em></p><p>หน้าตามันเป็นอย่างงี้ครับ</p><pre><strong>let</strong> optionalNumber: Int? = 1<br><strong>let</strong> optionalString: String? = nil</pre><p>ตอนแรกที่ผมเห็นผมก็งงๆ หน่อยว่ามันทำอะไรของมัน</p><p>สุดท้ายผมพบว่ามันเป็น syntactic sugar เฉยๆ ความจริงมันมีค่าเท่ากับแบบนี้</p><pre><strong>let</strong> optionalNumber: Optional&lt;Int&gt; = Optional(1)<br><strong>let</strong> optionalString: Optional&lt;String&gt; = Optional.none</pre><p>จะเห็นได้ว่าเจ้า ? เนี่ยมันไปแอบห่อเจ้าก้อนหลัง = ให้ด้วย Optional ซึ่งก็คิดซะว่า ไอที่ประกาศไว้นี่จะเป็น Int String หรือไม่มีอะไรอยู่ในกอไผ่ก็เป็นได้ ซึ่งทำให้มันเห็นได้ชัดมากๆ ว่าตรงไหนที่มันมีโอกาสจะไม่มีอะไรเลยได้บ้าง จะได้จัดการกับมันถูก</p><p>แถมถ้าลองแบบนี้ดู เราจะ assign nil ให้กับ type String</p><pre><strong>let</strong> optionalString: String = nil</pre><pre><em>// =&gt; error: nil cannot initialize specified type &#39;String&#39; <br>let optionalString: String = nil</em></pre><p>โดนด่าเลย :(</p><p>เราเลยมั่นใจได้ว่า ไม่ว่ายังไง ถ้ามันไม่ได้เขียน type แบบมี ? มา แม่งไม่ nil แน่ๆ</p><p>นอกจากเราจะแอบห่อตัวแปรได้แล้ว เรายังแอบห่อผลลัพธ์ของทั้ง function ได้อีกด้วย</p><pre><strong>func</strong> half(number: Int) -&gt; Int? {<br>    <strong>return</strong> number % 2 == 0 ? number / 2 : nil<br>}</pre><pre>half(number: 10) <em>// =&gt; Optional(2)</em><br>half(number: 1)<em>  // =&gt; Optional.none</em></pre><p>จะเห็นได้ว่า แม้ว่าเรา <strong>return</strong> ตัวเลข หรือ nil เปล่าๆ ไว้ แต่ return type บอกว่าเป็น Int? มันเลยห่อผลลัพธ์ด้วย Optional ให้เรียบร้อย</p><h3>ห่อเอาไว้แล้วจะใช้งานมันได้ยังไง</h3><p>โดยไอเดียแล้ว Optional มีไว้เพื่อให้ใช้งานแบบห่อๆ แล้วส่งต่อห่อไปเรื่อยๆ ตาม call stack แล้วค่อยไปแกะที่ปลายทาง ก่อนที่จะมาพูดเรื่องแกะห่อ เรามาพูดถึงเรื่องการแปลงร่างของในห่อโดยไม่ต้องแกะกันก่อนดีกว่า</p><p>อันนี้เป็นท่ามาตรฐานของบรรดาของที่ถูกห่อ บางคนคงเคยใช้กับพวก array มาแล้ว ซึ่งก็ไม่ต่างกันเท่าไหร่ นั่นก็คือ map และ flatMap นั่นเอง</p><h4><strong>1) map</strong></h4><p>สมมติว่าเรามี name: String? อยู่ เราสามารถทำแบบนี้ได้</p><pre>name.map { s <strong>in</strong> s.characters.count }</pre><p>จะเห็นได้ว่า function ที่เราใส่เข้าไปใน map รับ argument เป็น String ธรรมดา ถ้า name: String? = &quot;Boss&quot; map แล้วจะได้ Optional(4)ที่มี type เป็น Int?</p><p>สิ่งที่มันทำคือ มันแกะห่อ แล้วเอาของจากในห่อ ไปยัดใส่ function ให้ evaluate จากนั้นก็ยัดกลับเข้าไปในห่ออีกรอบ สุดท้ายแล้ว ผลลัพธ์ของ map จะกลายเป็นอะไรก็ตามที่เป็น return type ของ function ที่ pass ไป แล้วห่อด้วย Optional อีกทีนั่นเอง</p><p>แต่ถ้าเป็น name: String? = nil แล้ว name มีจะค่าเท่ากับ Optional.none พอเรา map แล้วจะได้ Optional.none เหมือนเดิม เพราะเมื่อเราจะทำอะไรกับความว่างเปล่า เราก็จะได้ความว่างเปล่ากลับมาเสมอ</p><h4><strong>2) flatMap</strong></h4><p>สมมติว่าเรามีเราอยากจะแบ่งครึ่ง 12 ซักสามรอบด้วยเจ้า half ที่เขียนไว้ข้างบน ทำยังไงดี</p><pre><strong>func</strong> half(number: Int) -&gt; Int? {<br>    <strong>return</strong> number % 2 == 0 ? number / 2 : nil<br>}</pre><p>ลอง map ดูแล้วกัน</p><pre>half(number: 12)<br>    .map(half)<br>    .map(half)</pre><pre><em>// error: cannot convert value of type &#39;(Int) -&gt; Int?&#39; to expected argument type &#39;(Int?) -&gt; _&#39;</em></pre><p>ปรากฏว่า โค้ดข้างบนนี้ใช้ไม่ได้ เพราะผลลัพธ์ของ half(number: 12).map(half) จะกลายเป็น typeInt?? เนื่องจาก ผลลัพธ์จาก type ของ half คือ Int -&gt; Int? พอเรา .map(half) ผลลัพธ์ที่เป็น Int? อยู่แล้วจะถูกห่อด้วย Optional อีกที กลายเป็น Int?? ก็เลยเอาไป .map(half) ต่อไม่ได้ เพราะพอแกะห่อ Int?? จะได้ Int? แต่ half ต้องการ Int เปล่าๆ เป็น argument</p><p>ในกรณีนี้ flatMap ช่วยคุณได้</p><pre>half(number: 12)     <em>// =&gt; Optional(6)</em><br>    .flatMap(half)   <em>// =&gt; Optional(3)</em><br>    .flatMap(half)   <em>// =&gt; Optional.none</em></pre><p>สิ่งที่มันทำก็เหมือน map เลยครับ แค่ตอนที่หลังจาก evaluate function ที่ใส่เข้าไปแล้ว มันจะเอาผลลัพธ์ที่ได้มาเนี่ย ไปสลายห่อทิ้ง (flatten) ทำให้ type หลังจาก flatmap ผลลัพธ์จบด้วยห่อชั้นเดียวเสมอ</p><p>อันนี้แถม โดยปกติแล้ว Optional จะมี function filter มาให้ โดย pass function ที่ return Bool (predicate function) คือถ้าผ่านเงื่อนไขก็โอเค return ตัวเดิม ไม่ผ่านก็จะกลายเป็น Optional.none</p><p>แต่ใน Swift ดันไม่มี!</p><p>แต่เราก็ทำให้มันมีได้ไม่ยากเพราะมันมี extension ให้เราใช้ implement เพิ่มเติมจากของที่มีอยู่แล้วได้ (เหมือน Open class ของ Ruby เลย)</p><pre><strong>extension</strong> Optional {<br>    <strong>func</strong> filter(_ predicate: (Wrapped) <strong>throws</strong> -&gt; Bool) <strong>rethrows</strong> -&gt; Wrapped? {<br>        <strong>switch</strong> self {<br>        <strong>case</strong> .some(let wrapped):<br>            <strong>return</strong> <strong>try</strong> predicate(wrapped) ? wrapped : nil<br>        <strong>case</strong> .none:<br>            return nil<br>        }<br>    }<br>}</pre><p>แล้วเราจะได้ของแบบนี้</p><pre><strong>let</strong> evenNum: Int? = 12<br><strong>let</strong> oddNum: Int? = 3<br><strong>let</strong> noNum: Int? = nil</pre><pre><strong>func</strong> isEven(num: Int) -&gt; Bool {<br>    <strong>return</strong> num % 2 == 0<br>}</pre><pre>evenNum.filter(isEven) <em>// =&gt; Optional(12)</em><br>oddNum.filter(isEven)  <em>// =&gt; Optional.none</em><br>noNum.filter(isEven)   <em>// =&gt; Optional.none</em></pre><p>ทั้งนี้ทั้งนั้นmap flatMap และ filter ไม่ได้ไปแก้ค่าของตัวแปร แต่จะ return Optional ตัวใหม่ออกมาทุกครั้ง เพื่อรักษาความ immutable เอาไว้</p><h4>3) Optional Chaining</h4><p>สมมติว่าเราต้องการอ้างอิงถึง attribute หรือ function ของของที่ถูกห่อ เราทำอะไรได้บ้าง ตัวอย่างเช่น</p><pre><strong>class</strong> Person {<br>   <strong>let</strong> name: String</pre><pre>   init(name: String) {<br>     <strong>self</strong>.name = name<br>   }<br>}</pre><pre><strong>class</strong> Dog {<br>    <strong>let</strong> owner: Person?</pre><pre>    init(owner: Person?) {<br>        <strong>self</strong>.owner = owner<br>    }<br>}</pre><pre><strong>let</strong> ownedDog = Dog(owner: Person(name: &quot;I&#39;Boss&quot;))<br><strong>let</strong> strayDog = Dog(owner: nil)</pre><p>เราสามารถไปถึงชื่อเจ้าของได้ด้วย map</p><pre>ownedDog.owner.map { person in person.name } <br><em>// =&gt; Optional(&quot;I&#39;Boss&quot;)</em></pre><p>แต่ถ้าใน map ไม่ได้จำเป็นต้องมีอะไรเพิ่มเติมนอกจากเรียก name แล้ว เราสามารถใช้ Optional Chaining แทนได้</p><pre>ownedDog.owner?.name <em>// =&gt; Optional(&quot;I&#39;Boss&quot;)</em><br>strayDog.owner?.name <em>// =&gt; Optional.none</em></pre><h3>ถึงเวลาต้องใช้แล้ว มาแกะห่อกันเถอะ!</h3><p>เราไม่สามารถให้มันอยู่ในห่อตลอดไปได้ วันนึงเราก็ต้องแกะมันออกมาใช้อยู่ดี ในภาษา Swift มีท่าแกะห่อให้เลือกใช้เยอะมาก ลองไปดูกัน</p><h4>4) การแกะห่อแบบไม่ปลอดภัย</h4><p>ถ้าเรามี</p><pre><strong>let</strong> optionalNumber: Int? = 1<br><strong>let</strong> optionalString: String? = nil</pre><p>เราสามารถทำแบบนี้ได้ครับ</p><pre>optionalNumber! <em>// =&gt; 1</em></pre><p>แต่ๆ ถ้าสมมติว่ามันเป็น nil ล่ะ</p><pre>optionalString!</pre><pre><em>// fatal error: unexpectedly found nil while unwrapping an Optional value</em></pre><p>แน่นอนว่ามันเป็น runtime error ไม่ใช่ compile time มันเลยน่ากลัวมาก มันอาจจะทำให้เกิดพฤติกรรมที่เราไม่คาดคิดได้ ถ้าจัดการกับมันไม่ดี</p><p>จริงๆ แล้วเจ้า ! นี่มี function ที่ทำหน้าที่เหมือนกัน แล้วชื่อมันสื่อสารออกมาได้ดีมาก นั่นคือ .unsafelyUnwrapped ชื่อก็บอกแล้วว่าไม่ปลอดภัย ถ้าจำเป็นต้องใช้ก็ใช้อย่างระมัดระวัง เลือกใช้ตัวเลือกถัดๆ ไปดีกว่านะครับ</p><pre>optionalString.unsafelyUnwrapped</pre><pre><em>// fatal error: unexpectedly found nil while unwrapping an Optional value</em></pre><h4>5) การแกะห่อโดยปริยาย</h4><p>เราสามารถเขียน ! ต่อท้ายจาก type ได้แบบนี้</p><pre><strong>let</strong> number: Int! = optionalNumber<br>number<em> // =&gt; 1</em></pre><p>มันก็ดูคล้ายๆ .unsafelyUnwrapped เนอะ แต่…</p><pre><strong>let</strong> string: String! = optionalString<br>string // =&gt; nil</pre><p>มันไม่ error? อะไรฟระ?</p><p>จริงๆ ผมหลอกคุณ เพราะค่าที่แท้จริงของ number และ string มันเป็นแบบนี้</p><pre>number<em> // =&gt; ImplicitlyUnwrappedOptional(1)<br></em>string <em>// =&gt; ImplicitlyUnwrappedOptional&lt;String&gt;(nil)</em></pre><p>ครับ เจ้า type ที่ตามด้วย ! อย่าง Int เนี่ย มันคือ ImplicitlyUnwrappedOptional&lt;Int&gt; นั่นเอง</p><p>แล้วมันมีประโยชน์อะไร?</p><p>เรียกได้ว่า มันคือ optional type ที่จะแกะห่อ (เหมือนที่เราเรียก ! ต่อท้าย) แทนเราให้เองตอนที่พยายามใช้มัน เช่น</p><pre>optionalNumber! + 1 <em>// =&gt; 2</em><br>number + 1          <em>// =&gt; 2</em></pre><pre>optionalString!.capitalized<em>  </em></pre><pre><em>// </em>fatal error: unexpectedly found nil while unwrapping an Optional value</pre><pre>string.capitalized<em> <br><br>// </em>fatal error: unexpectedly found nil while unwrapping an Optional value</pre><p>ซึ่งเจ้า ImplicitlyUnwrappedOptional เนี่ย มี use cases ที่น่าสนใจหลายอย่างเวลาที่เรา develop application จริงๆ ลองดูเพิ่มเติมได้<a href="https://krakendev.io/when-to-use-implicitly-unwrapped-optionals/">ที่นี่</a></p><h4>6) nil-coalescing operator `??`</h4><p>อันนี้ง่ายมาก ถ้าเป็น Java กับ Scala พวก Optional จะมี function orElse หรือ getOrElse อยู่ แปลว่าเราจะเอาค่ามันออกมาจากห่อนั่นแหละ แต่ถ้าไม่มี ก็ขอ default value ให้หน่อย</p><p>สำหรับ swift มี syntax น่ารักๆ แบบนี้</p><pre><strong>let</strong> optionalString: String? = nil<br>optionalString ?? &quot;string is missing&quot; <em>// =&gt; &quot;string is missing&quot;</em></pre><p>ซึ่งใน official documentation เขาบอกว่า มันคือตัวย่อของ</p><pre>optionalString != nil ? optionalString! : &quot;<em>string is missing</em>&quot;</pre><p>ซึ่งวิธีนี้ปลอดภัยในการใช้งาน เพราะยังไงก็ไม่ได้ nil ออกมาให้ fatal error แน่ๆ</p><h4>7) Optional Binding</h4><p>แบบแรก <strong>if let</strong></p><p>“ถ้าไม่ nil ขอเอาค่าไปใช้หน่อย”</p><pre><strong>if let </strong>string = optionalString {<br>    print(string.capitalized)<br>}</pre><p>ถ้าค่าใน optionalString เป็น nil ก็จะไม่ทำอะไรเลย แต่ถ้า มีค่าอยู่ block นี้ก็จะทำงาน เจ้า string (แกะห่อแล้ว และเปลี่ยนตัวแรกเป็นอักษรตัวใหญ่) ก็จะถูก print ออกมาทาง console</p><p>เราสามารถเพิ่ม condition ได้ด้วย เช่น</p><pre><strong>if let</strong> string = optionalString, string.characters.count &gt; 3 {<br>    print(string.capitalized)<br>} <strong>else</strong> {<br>    print(&quot;not long enough!&quot;)<br>}</pre><p>ขา functional (เหมือนผม)อาจจะหงุดหงิด อาจจะหงุดหงิดนิดหน่อยเพราะ if ไม่ใช่ expression ทำให้ เราเอาเจ้าก้อนนี้ไป assign หรือ เอาค่าไปใช้ต่อเลยไม่ได้ (เป็นสาเหตุที่ทำให้ผมใช้ตัวอย่างที่มี side-effect อย่าง print)</p><p>แน่นอนว่าเราก็ใช้ <strong>guard </strong>แบบนี้ได้เหมือนกัน วิธีคิดแบบ <strong>guard </strong>คือเคลียร์อันที่ไม่อยากได้ออกไปก่อน แล้วค่อยทำอันที่สนใจ ซึ่งเอาไว้ใช้กับ loop หรือ function</p><pre><strong>func</strong> guardShortString(optionalString: String?) -&gt; String {<br>    <strong>guard</strong> <strong>let</strong> string = optionalString, <br>          string.characters.count &gt; 3 <strong>else</strong> <br>    {<br>        <strong>return</strong> &quot;not long enough&quot;<br>    }<br>    <strong>return</strong> string.capitalized<br>}</pre><pre>guardShortString(optionalString: &quot;boss&quot;) <em>// =&gt; &quot;Boss&quot;</em><br>guardShortString(optionalString: &quot;me&quot;)   <em>// =&gt; &quot;not long enough&quot;</em></pre><h4>8) switch และ pattern matching</h4><p>เราสามารถใช้ switch เพื่อแกะห่อ Optional ออกมาได้แบบนี้</p><pre><strong>switch</strong> optionalString {<br><strong>case</strong> .some(<strong>let</strong> string):<br>    &quot;the wrapped string is \(string)&quot;<br><strong>case</strong> .none:<br>    &quot;there&#39;s nothing here&quot;<br>}</pre><p>บางคนก็อาจจะรู้สึกว่า อ๊ะ นี่มัน pattern matching นี่หว่า</p><p>บางคนอาจจะพอใจแล้วว่า เอ้อเราสามารถ switch แบบนี้ได้นะ แต่สำหรับขา functional อย่างผมจะหงุดหงิดนิดนึง</p><p>ถ้าใครเคยเขียน Scala มาจะเจอของแบบนี้</p><pre><strong>val</strong> s = optionalString <strong>match </strong>{<br>    <strong>case </strong>Some(string) =&gt; s&quot;the wrapped string is <strong>$</strong>string&quot;<br>    <strong>case</strong> None =&gt; &quot;there&#39;s nothing here&quot;<br>}</pre><p>จะเห็นได้ว่าผมสามารถเอาไปใส่ตัวแปรได้เลย if ก็ทำแบบนี้ได้เหมือนกันแต่ Swift ทำไม่ได้ เพราะฉะนั้น โค้ด Swift ข้างบนจะไม่มีประโยชน์อะไรเลย เพราะในแต่ละ case ไม่ได้เอาไปใช้อะไรเลย</p><p>จะทำยังไงให้มีประโยชน์โดยไม่ต้องไปแก้ค่าตัวแปร หรือสร้าง side-effect อื่นๆ ? เพราะอยากจะเขียนให้มัน functional</p><p>ถ้าเราเขียนโค้ดโดยยึด <a href="https://code.tutsplus.com/tutorials/solid-part-1-the-single-responsibility-principle--net-36074">Single Responsibility Principle</a> อยู่แล้ว สุดท้ายเราคงหนีไม่ค่อยพ้น function เล็กๆ หน้าตาแบบนี้</p><pre><strong>func</strong> describe(optionalString: String?) -&gt; String {<br>    <strong>switch</strong> optionalString {<br>    <strong>case</strong> .some(<strong>let</strong> string):<br>        <strong>return</strong> &quot;the wrapped string is \(string)&quot;<br>    <strong>case</strong> .none:<br>        <strong>return</strong> &quot;there&#39;s nothing here&quot;<br>    }<br>}</pre><p>ซึ่งสำหรับผมก็พอใจแล้วนะ แต่ถ้าอยาก treat มันเป็น expression แบบที่ Scala ทำข้างบน ก็อาจจะใช้ closure เข้ามาช่วย</p><pre><strong>let</strong> s: String = {<br>    <strong>switch</strong> optionalString {<br>    <strong>case</strong> .some(<strong>let</strong> string):<br>        <strong>return </strong>&quot;the wrapped string is \(string)&quot;<br>    <strong>case</strong> .none:<br>        <strong>return </strong>&quot;there&#39;s nothing here&quot;<br>    }<br>}()</pre><p>ซึ่งไอเดียคือเราสร้าง anonymous function ที่ในที่นี้มี type () -&gt; String ขึ้นมา แล้วเรียกใช้มันทันที ทุกอย่างจะจบในนั้น แล้วคืนค่าที่เราต้องการออกมาได้ ซึ่งเราก็เอาไปใช้กับ if ข้างบนได้เช่นกัน</p><h3>บทสรุป</h3><p>จบไปแล้วสำหรับ 8 กระบวนท่า Optional สำหรับผมแล้ว มันมีท่าให้ใช้เยอะ เหมือนจะสะดวก แต่แอบรู้สึกว่ามันซับซ้อนเกินความจำเป็นไปนิดนึง เพราะต้องทำความเข้าใจ syntax ที่มันไม่ค่อย consistent เท่าไหร่ ซึ่งบางคนก็อาจจะชอบ บางคนอาจจะไม่ชอบ</p><p>ในแง่ความสะดวกในการเขียน Swift ใน functional style ผมว่าก็ใช้ได้เลย ถึงแม้จะมีข้อจำกัดบางอย่าง แต่โดยรวมแล้วก็น่าสนใจ</p><p>ส่วนใครสงสัยว่า Optional มันเกี่ยวกับ functional programming ยังไง Optional คือ Maybe monad ใน Haskell ถ้าใครสนใจเรื่องนี้ ลองไปดู <a href="http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html">Functors, Applicatives, And Monads In Pictures</a> ได้ หรือ<a href="http://www.mokacoding.com/blog/functor-applicative-monads-in-pictures/">เวอร์ชั่นแปลเป็น swift</a> ก็มีครับ ลองไปดูกัน</p><p>ขอบคุณที่รับชม</p><p><em>functional programming FTW!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f715a125de9" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>