Quantcast
Channel: cc :: somkiat
Viewing all 2000 articles
Browse latest View live

App หมอชนะ เข้าใช้งานไม่ได้ เพราะว่า Certificate หมดอายุ

$
0
0

หลังจากที่ App หมอชนะนั้น เปิดขึ้นมาแล้วค้างหน้าแรก
ก็เลยเข้าไปดูหน่อยว่า เกิดจากอะไร
ตอนแรกคิดว่าระบบจะล่มหรือไม่นะ ?
แต่พอลองไปดูพบว่า Certificate หมดอายุนั่นเอง

แต่วันนี้ลองไปดูที่ API ของระบบคือ API.THAIALERT.COM นั้น

ทำการต่ออายุของ Certificate ไปแล้วดังรูป

แต่ APP ก็ยังเข้าไม่ได้ ก็เลยลองไปดู code จาก GitHub ของ app
พบว่ามีการทำ sslPinning ด้วยการชี้ไปยังไฟล์ .cer นั่นเอง

นั่นหมายความว่าใน app จะมีการ bundle ไฟล์ .cer เข้ามาด้วย

ดังนั้น การแก้ไขคือ ต้องทำการ build app ใหม่
จากนั้นก็ต้องทำการ upload/publish ของ App Store ทั้ง iOS และ Android ต่อไป
ทำให้ตอนนี้ app ยังไม่สามารถใช้งานได้

ล่าสุดที่ตรวจสอบนั้น App บน Android ทำการแก้ไขและ deploy แล้ว

ในวันที่ 28 เมษายน คือวันนี้นั่นเอง
โดยต่ออายุไปอีก 1 ปี


ส่วนใน iOS ยังไม่เห็นการ update นะครับ


สรุปสถิติการ copy ใน Stack Overflow

$
0
0

คำถามที่น่าสนใจเกี่ยวกับระบบ Stack Overflow
คือผู้ใช้งานทำการ copy ข้อมูลไปใช้งานกันเยอะไหม
ทางทีมพัฒนาก็เลยสร้างระบบ analytic
เพื่อเก็บข้อมูลของการกดปุ่ม command+c หรือ ctrl+c
ของผู้ใช้งานเป็นเวลา 2 สัปดาห์

มาดูกันว่าเจอะไรที่น่าสนใจบ้างโดยสรุปมาจากบทความ
How often do people actually copy and paste from Stack Overflow? Now we know.

ในบทความบอกว่า You are not alone

เพราะว่ามีคนทำการ copy ไปมากกว่า 40 ล้านครั้ง
จาก post และ comment ประมาณ 7 ล้าน
สิ่งที่น่าสนในคือ

  • มีการ copy ทั้งจาก post และ comment หรือ question และ answer
  • จำนวนการ copy จาก answer มากกว่า question จำนวน 35 เท่า
  • จำนวนการ copy code มากกว่า text ปกติ จำนวน 10 เท่า
  • สิ่งที่ประหลาดมาก ๆ คือ มีการ copy จาก question ที่ไม่มี accepted answer อีกด้วย นั่นคือ copy question ไปใช้งาน !!
  • ไม่ว่า question นั้น ๆ จะมีหรือไม่มี accepted answer จะมีอัตราการ copy เท่า ๆ กัน

ในบทความบอกว่า การ copy ในระบบนี้ มันคือ Knowledge reuse

you’re reusing what others have already learned, created, and proven.
Knowledge reuse isn’t a bad thing
– it helps you learn, get working code faster, and reduces your frustration.

Our whole site runs on knowledge reuse
– it’s the altruistic mentorship that makes Stack Overflow such a powerful community.

เรื่องที่ 1 High reputation users จะ copy สูง ?

เรื่องที่ 2 ยิ่ง scrore ของ post ยิ่งมาก ก็ copy สูงขึ้น ?

เรื่องที่ 3 มีทั้ง copy question และ answer ?

โดย question น่าจะถูก copy ไปเพื่อ reproduce ปัญหานะ

เรื่องที่ 4 Code ที่ถูก copy มากที่สุดคือ HTML/CSS, JavaScript และ Python

เป็นชุดข้อมูลที่น่าสนใจมาก ๆ

RabbitMQ :: ทำการ route message ด้วย key แบบ dynamic

$
0
0

คำถามที่น่าสนใจเกี่ยวการจัดการ message ด้วย RabbitMQ
ถ้าต้องการ route message ด้วย key ที่ต้องการ
แต่ key นั้นมัน dynamic เราไม่สามารถกำหนดได้
ต้องการให้ message ที่มี key เดียวกันเข้าไปทำงานที่ consumer เดียวกัน
เพื่อให้สามารถทำงานได้ตามที่ต้องการทาง business นั่นเอง

แนวทางใน RabbitMQ คือการทำ routing นั่นเอง

ซึ่งจะมีรูปแบบต่าง ๆ ให้เลือกใช้งานดังนี้

  • Fanout
  • Direct
  • Topic
  • Header
  • Consistent Hashing

แต่จาก use case นั้น น่าจะต้องใช้งาน Consistent Hashing

เนื่องจากเราไม่สามารถรู้เลยว่า key ที่ส่งเข้ามามีค่าอะไรบ้าง
ดังนั้นจำเป็นต้องใช้ Hashing function เข้ามาช่วย
สำหรับการ route message ไปยัง consumer ต่าง ๆ
ส่วนฝั่ง consumer จะต้องทำการ binding key ด้วยตัวเลขเท่านั้น
กำหนดได้เท่าที่เราต้องการ สามารถเพิ่มหรือลดได้เสมอ

ทำให้มั่นใจได้ว่า message ที่มี key เดียวกัน

จะเข้าทำงานที่ consumer เดียวกันแน่นอน
และถ้าต้องการให้เรียงลำดับการทำงานแบบ FIFO
โดยไม่ทำงานสลับกันทั้งเริ่มและสิ้นสุด
จำเป็นต้องกำหนดค่า prefetch=1
และกำหนด noAck=false เพื่อกำหนดการส่ง acknowledge กลับเอง

แต่การใช้งานจำเป็นต้องติดตั้ง plugin เพิ่ม
ชื่อว่า RabbitMQ Consistent Hash Exchange
เพียงเท่านี้ก็สามารถกำหนดให้ RabbitMQ ทำงานตามที่ต้องการแล้ว

ปล. ถ้าเป็น Apache Kafka จบไปนานแล้ว !!

Go 1.17 เล็กและเร็วขึ้น

$
0
0

วันนี้ลอง build Go 1.17 ที่อยู่ใน branch หลักของการพัฒนา
เพื่อลองให้ความสามารถใหม่ ๆ ก่อน
สิ่งหนึ่งที่พบเจอได้ในทุก ๆ version ที่ผ่านมาคือ
ขนาดของ binary เล็กลง
รวมทั้ง performance ก็เร็วและเสถียรขึ้นกว่าเดิม

โดยลองสร้าง server ด้วย Echo framework ดู

[gist id="82818fd58c1342e52a9c8534773f3411" file="server.go"]

จากนั้นลองทำการ build เป็นไฟล์ binary พบว่า
ขนาดลดลงดังนี้

  • Go 1.16.3 มีขนาด 7.327568 mb
  • Go 1.17-cb34026a95 มีขนาด 6.586128 mb

ต่อมาทำการยิง load test ด้วย wrk อย่างละ 3 ครั้ง พบว่า

  • Go 1.16.3 ผลที่ได้จะแกว่งไปมา ไม่นิ่ง
  • Go 1.17-cb34026a9 ผลที่ได้จะ stable และมีความเร็วสูงกว่าเดิมเล็กน้อย

โดยผลการทำงานถือว่าปรับปรุงได้ค่อนข้างดี

ใครว่าง ๆ ลองไปแก้ไขโจทย์กันดูนะครับ

$
0
0

พอดีเห็นว่าในกลุ่ม Python Thailand
มีสมาชิกมาถามปัญหาและมีการตั้งโจทย์ทุกวันเลย
ใครสนใจจะแก้ไขปัญหาด้วยภาษา Python หรือภาษาอื่น ๆ
ก็ลองไปอ่านปัญหาและแก้ไขดูได้นะครับ

ผมก็ไม่รู้นะว่า เป็นโจทย์ของระบบอะไร
แต่เห็นว่าเป็นโจทย์ที่คน post คิดมาเอง
ดังนั้นลองมาช่วยกันคิดและแก้ไขปัญหาดูครับ

ยกตัวอย่างเช่น

และ

ปล. วันนี้ก็มี post คำถามใหม่มาอีกแล้วครับ
Work From Home กันแล้ว ลองมาแก้ไขปัญหาดูครับ

ลาก่อน IE 11 และ Microsoft Edge Legacy

$
0
0

เห็นข่าวว่า framework ต่าง ๆ ใน version ใหม่ ๆ
จะเลิกสนับสนุน IE 11 และ Microsoft Edge Legacy กันแล้ว
ไม่ว่าจะเป็น

ซึ่งเป็นตามแผนของการ support ของ Microsoft เช่นกัน
ที่จะเลิก support IE 11 และ Microsoft Edge Legacy ไปแล้ว
แม้แต่ตัว Microsoft 365 ยังจะเลิก support ในเดือนสิงหาคมนี้เลย

โดยใน Windows 10 ตัว update ใหม่
จะทำการเปลี่ยนไปติดตั้ง Microsoft Edge ตัวใหม่แทน

ไม่น่ามีใครใช้ IE แล้วใช่ไหม ?

[Open Data] ข้อมูลการฉีดวัคซีน COVID-19 จาก Our World in Data

$
0
0

ช่วงนี้มีข่าวเรื่องการจองฉีดวัคซีนกันเยอะ
เลยไปหาดูข้อมูลเกี่ยวกับฉีดวัคซีนของแต่ละประเทศ
ว่าเป็นอย่างไรบ้าง
พบว่ามีหลายแหล่ง แต่ก็มีที่ Our World in Data
ทำการสรุปข้อมูล รายงานรวมทั้ง share ข้อมูลของการฉีดวัคซีนทั้งโลกไว้

ประกอบไปด้วย

  • ที่มาของข้อมูลในแต่ละประเทศ
  • วัคซีนที่แต่ละประเทศใช้
  • ข้อมูลการฉีดรายวันของแต่ละประเทศ
  • ข้อมูลแยกเป็นประเทศและทวีปให้

โดยที่นักพัฒนาหรือผู้ใช้งาน
สามารถนำข้อมูลนี้ไปใช้ได้เลย (Open Data)
ซึ่งอยู่ในรูปแบบทั้ง CSV และ JSON
ลองไป Download มาให้ใช้กันดูครับ

ว่าด้วยเรื่อง Chain of Services ที่อาจะก่อให้เกิดปัญหา

$
0
0

ในการออกแบบ service ของระบบงานนั้น
มีรูปแบบหนึ่งที่เจอบ่อยมาก ๆ คือเรามักจะแยกเป็น service ย่อย ๆ
โดยแต่ละ service ทำงานอย่างใดอย่างหนึ่งไปเลย (Single Responsibility)
เป็นสิ่งที่ดีมาก ๆ เพราะว่าแต่ละ service มีขอบเขตการทำงานชัดเจน
แต่เมื่อนำ service ต่าง ๆ มาทำงานร่วมกัน
จะเกิดรูปแบบต่าง ๆ มากมาย
หนึ่งในรูปแบบคือ Chain of Responsibility หรือ Chain of Services

แสดงดังรูป

คำอธิบาย

การทำงานจะเริ่มจาก Main API หรือ product หรือระบบงานหลักนั่นเอง
จากนั้นจะเรียกใช้งาน service 1
จากนั้น service 1 ก็ไปเรียกใช้งาน service อื่น ๆ ต่อไปเรื่อย ๆ
ในรูปแบบของ chain of service นั่นเอง

ผลที่ตามมาคือ

ความซับซ้อนซ่อนเงื่อนของการทำงานที่สูงขึ้น
จำนวน service ที่เรียกใช้งานกันเยอะมาก ๆ
ผลกระทบต่อการทำงานและเปลี่ยนแปลง
ที่ต้องพูดคุยและวางแผนมากขึ้น
ผลกระทบของ response time ที่มีแนวโน้มว่าสูงขึ้น
จุดของการพังมากขึ้น
พังตรงไหน หาเจอง่ายหรือไม่
หรือมีระบบแจ้งและระบุจุดเกิดปัญหาให้เลย
ยิ่งติดต่อสื่อสารกับแบบ synchronous ยิ่งอาจจะทำให้เกิดปัญหาได้อีกมาก
แต่ก็พอทุเลาได้ด้วย Circuit Breaker pattern

ดังนั้นต้องเลือกรูปแบบการติดต่อสื่อสารให้ดี
รวมทั้งลดจำนวนของ service หรือความลึกของ service ลงไปอีกด้วย
ถามว่าลึกเท่าไรดี บอกได้เลยแค่เกิน 2-3 ชั้น ก็บรรลัยแล้วนะ !!

ใครเจอปัญหานี้อยู่บ้าง ?
คำถามต่อมาคือ ถ้าเจอปัญหาแบบนี้ แล้วจะแยกไปทำไม ?


[Dart] เปลี่ยนมาใช้งาน Dio package สำหรับเรียกใช้งาน API

$
0
0

สำหรับการพัฒนาระบบด้วยภาษา Dart และ Flutter
ต้องมีการทำงานร่วมกับ REST API
ซึ่งก็มี package ต่าง ๆ ให้ใช้งาน รวมทั้ง http package ที่ Dart official เตรียมไว้ให้
แต่พอใช้ไปสักพักอาจจะเบื่อกับการเขียนซ้ำ ๆ
ดังนั้น ทำให้ต้องหา package อื่น ๆ มาใช้งานบ้าง
หนึ่งใน package ที่ใช้อยู่ในปัจจุบันคือ Dio

โดยท่ี Dio มีความสามารถที่น่าสนใจและใช้งานง่าย ๆ คือ

  • Interceptor
  • Global configuration
  • Request cancellation
  • Request retry

เมื่อใช้งานไปเรื่อย ๆ จะมีลักษณะคล้าย Axios ใน JavaScript
ส่งผลให้การพัฒนามี productivity เพิ่มมากขึ้นกว่าเดิม

ตัวอย่าง code ของการใช้งานกับ interceptor

[gist id="d3750a904b55e4194f2d66a4a84f8320" file="demo.dart"]

หรือจะมีส่วนของ plugin เพิ่มเข้ามาด้วย

ทำให้เพิ่มความสามารถได้ง่ายตอนนี้มี plugin อยู่ 2 ตัวคือ

  • Cookie manager
  • HTTP 2 adapter

ลองใช้งานกันดูนะ

ประโยชน์ของ Anti-patterns !!

$
0
0

ถ้าเรามีความรู้และเข้าใจเกี่ยวกับสิ่งที่ไม่ดีแล้ว
เราสามารถนำมันมาใช้ให้เกิดประโยชน์ได้
ถ้าเราใช้มันอย่างถูกต้องและเหมาะสมรวมทั้งสิ่งที่ดีก็เช่นกัน
ถ้าไม่เข้าใจและนำมาใช้ผิด ๆ แล้ว
แทนที่จะเกิดประโยชน์กลับเกิดโทษมากกว่าไปอีก
มาตัวแนวทางที่ไม่ดีกันหน่อย (ชอบทำกันไหม ?)

เริ่มจากปัญหาแรกคือ Depedency Hell

การดูแลรักษามันยากไหมนะหรือต้องมีอะไรมาช่วยจัดการหรือไม่

เรื่องที่สองคือ ทำให้การเปลี่ยนแปลงยากมากขึ้นเรื่อย ๆ

ถ้ามันยากขึ้น เราน่าจะหยุดคิดก่อนไหม
มิใช่เร่งแต่จะสร้างให้มันเสร็จ ๆ อย่างเดียวแล้วค่อยกลับมาแก้ไข

เรื่องที่สาม ไม่ทำตามกรอบหรือขอบเขตหน้าที่รับผิดชอบ (Boundary)

ที่ทำเพราะว่ามันง่ายดี !!

เรื่องที่สี่คือ การ share ส่วนการทำงานในทุก ๆ ส่วน กลายเป็น common

ที่ทำเพราะว่า reuse !!
สิ่งที่ต้องคิดคือ ส่วนที่ reuse นั้นมันแยกเป็นอิสระจริง ๆ หรือไม่

ยิ่งถ้ามีการจัดการ vesrsion ด้วยแล้ว
ยิ่งต้องระวังเรื่องของการจัดการและ compatability !!

เรื่องที่ห้า การตั้งชื่อสำคัญมาก ๆ

ถ้าเราเข้าใจแล้ว จะสามารถนำมาใช้ให้เกิดประโยชน์ได้

บันทึกปัญหาเรื่อง Network ใน Docker compose

$
0
0

ปัญหา

ทำการพัฒนาระบบงานด้วย NodeJS
ทำงานร่วมกับ MySQL ผ่าน ORM library ชื่อว่า Sequelize
ในการ build และ run สำหรับการพัฒนา จะใช้งาน Docker compose
แต่ตอน run เจอปัญหา การเชื่อมต่อไปยัง MySQL ดังนี้

[gist id="c46ad8902e80c47ed2d9d88cdd45b83a" file="1.txt"]

เพิ่มเติมเกี่ยวกับ config การเชื่อมต่อไปยัง MySQL จาก NodeJS ดังนี้

[gist id="c46ad8902e80c47ed2d9d88cdd45b83a" file="config.json"]

ส่วน Docker compose file เป็นดังนี้

[gist id="c46ad8902e80c47ed2d9d88cdd45b83a" file="docker-compose.yml"]

Environment ที่ใช้งาน ประกอบไปด้วย

  • Mac OS
  • Docker Desktop 3.3.1

วิธีการแก้ไขเบื้องต้น

เป็นปัญหาที่แปลกดี เพราะว่า
การใช้ docker compose นั้น ทุก ๆ service นั้น
จะใช้งาน network เดียวกันอยู่แล้ว
น่าจะติดต่อสื่อสารกันได้สิ
เพราะว่าใน configuration file ก็อ้างถึงชื่อ service เลย

แต่จาก error message แล้ว แสดงว่า
ตัว sequlize พยายาม resolve IP ไปยัง 127.0.0.1 เสมอ
หรือว่าเป็นเพราะตัว sequlize เอง !!

ส่วนการแก้ไขปัญหาเฉพาะหน้าหรือง่าย ๆ คือ
การเพิ่ม network_mode ใน Docker compose file ไปเลย
ซึ่งทำการ config ได้หลายรูปแบบ ดังนี้

  • container:<container id>
  • service:<service name>
  • bridge/host/none

ส่วนที่เลือกใช้คือ service ไปเลย ดังนี้

[gist id="c46ad8902e80c47ed2d9d88cdd45b83a" file="docker-compose1.yml"]

ทำให้สามารถทำงานต่อไปได้แล้ว

แนวทางในการจัดการ Dependency/library ของระบบงาน

$
0
0

จากการพัฒนาระบบงาน พบว่ามีการใช้งาน dependency/library ต่าง ๆ มากมาย
แต่บ่อยครั้งพบว่า มีปัญหาในการใช้งานและจัดการมาก ๆ
ไม่ว่าจะใช้ version เก่า ๆ ไม่ยอม update สักที
แก้ไข dependency นั้น ๆ ตามต้องการ
บางคนบอกว่า hack มันไปเลย
ทำให้ไม่สามารถ update version ได้อีก
ดังนั้นจึงทำการแนะนำการจัดการไปดังนี้

ขั้นตอนในการดูแลหรือจัดการ dependency ของระบบงานมีดังนี้

  • Analyze หรือ วิเคราะห์ หรือ ควรสอบด้วยว่า depednency ที่นำมาใช้ปลอดภัยหรือไม่
  • ลบสิ่งที่ไม่ถูกใช้งาน หรือ ซ้ำซ้อนออกไป มันเปลือง
  • Up-to-date อย่างสม่ำเสมอ
  • เลือกใช้ให้เหมาะสมกับงาน หรืองานหนึ่ง ๆ ควรใช้ ตัวเดียวไปเลย
  • อย่าลืมทำการดูเรื่องของจำนวนและขนาดของ depednency ที่ใช้งานด้วย
  • ทำการ Fork หรือ ทำการแก้ไขเมื่อยามจำเป็นเท่านั้น หรือจะให้ดี ทำการส่ง PR ไปยังทีมดูแล dependency นั้น ๆ เลย

แต่ต้องมั่นใจด้วยว่า update ต่าง ๆ แล้ว
ระบบยังคงทำงานเหมือนเดิมด้วยนั่นคือการทดสอบนั่นเอง
เป็นสิ่งที่จำเป็นอย่างมาก

สรุปข้อผิดพลาดที่เกิดกับการพัฒนาด้วย ReactJS

$
0
0

เพิ่งทำการสอนและ review ระบที่พัฒนาด้วย React
พบว่ามีข้อผิดพลาดบางอย่างที่มักเกิดขึ้นกับทุก ๆ ระบบ
ซึ่งบ่อยครั้งมันทำงานได้ปกติ แต่ยากต่อการดูแลรักษา
หรือยากต่อการทำความเข้าใจ
จึงสรุปไว้นิดหน่อย

เรื่องแรกคือ การออกแบบและสร้าง component

โดย React นั้นจะยึดตามแนวทางของ Web component
คือแยกการทำงานเป็น component ไป
ซึ่งเลือกพัฒนาได้ทั้ง Class และ function component
แต่ปัจจุบันน่าจะเป็น function component + Hook กันเป็นส่วนใหญ่

ปัญหาที่พบบ่อย ๆ คือ component จะมีขนาดใหญ่
มีหน้าที่รับผิดชอบหรือทำงานเยอะ
แน่นอนว่า ทำงานได้ปกติ และ ตรงตามที่ต้องการ
แต่เมื่อกลับมาแก้ไขหรือหาข้อผิดพลาด
กลับทำให้เสียเวลามากยิ่งขึ้น

ดังนั้นแนวทางที่น่าจะดีกว่าคือ
การแบ่งเป็น component เล็ก ๆ ตามหน้าที่รับผิดชอบ
แต่ไม่ใช่ว่าจะเล็กมากเกินไป ทำให้ยากกว่าเดิมไปอีก
ยิ่งถ้าใครสร้างแบบ function component แล้ว
จะพบว่า มันเอื้อให้ component มีขนาดเล็กลง

ระวัง God component ไว้ให้มาก ๆ

เรื่องที่สอง อย่าทำการแก้ไข state ของ component ตรง ๆ

ให้ใช้ผ่าน method setState() หรือ useState() ของ Hook
ซึ่งจะทำให้เรามั่นใจได้ว่า
ถ้าเปลี่ยน state ผ่านทั้งสองทางแล้วReact
จะทำการ re-render DOM ให้แบบอัตโนมัติและถูกต้อง

แต่อย่าลืมว่าจะทำงานแบบ asynchronous ด้วยนะ
นั่นคือ จะไม่ได้เปลี่ยนและ re-render ทันทีดังนั้น

  • ใช้งาน setState() ต้องทำงานร่วมกับ callback ด้วย
  • ใช้งาน useState() ต้องทำงานร่วมกับ useEffect() ด้วย

เรื่องที่สาม ในการจัดการ state แบบ Global

แนะนำให้เริ่มจาก Hook context
ก่อนที่จะไปใช้ตัวอื่น ๆ เช่น Redux เป็นต้น

เรื่องอื่น ๆ ที่สำคัญ เช่น

  • project structure ที่เหมาะสมกับงาน บางครั้ง project เล็ก ๆ ก็ออกแบบซะเยอะและซับซ้อนไป
  • การทดสอบตั้งแต่ unit, component, integration และ end-to-end
  • รูปแบบของการตั้งชื่อ
  • performance ในการ render และการทำงาน

Stateless และ Stateful widget ของ Flutter

$
0
0

ในการพัฒนาระบบงานด้วย Flutter
ไม่ว่าจะเป็น web app, mobile app และ native app ก็ตาม
พื้นฐานที่เหมือนกันก็คือ เรื่องของ Widget
หรือถ้าเทียบในฝั่ง web ก็คือ web component
ตามที่คนเขียน ReactJS, Angular และ VueJS ใช้งานกันปกติ

การออกแบบหน้าตาของระบบด้วย Flutter นั้น

จะใช้งานผ่าน widget นี่เอง
แนวคิดหลัก ๆ คือ การแบ่งเป็น widget เล็ก ๆ ตามหน้าที่การทำงาน
จากนั้นนำ widget ต่าง ๆ มารวมกัน เพื่อทำงานตามที่เราต้องการ
หรือจะเรียกว่า composition widget ก็ได้

รูปแบบของ widget ที่รวมกันมักจะอยู่ในรูปแบบของ tree ดังรูป

โดยที่ Widget จะแบ่งออกเป็น 2 ประเภทคือ

  • Stateless widget (Immutable)
  • Stateful widget (Mutable)

Stateless widget (Immutable)

เป็น widget ที่ไม่มีการเปลี่ยนค่าหรือ state ตอน runtime
โดยทุก ๆ widget จะรับค่าผ่าน property ได้เลย (constructor)
จะทำการ extends จาก class StatelessWidget
ดังนั้นถ้าต้องการเปลี่ยนค่า จะต้องทำการสร้าง instance ของ widget ใหม่เท่านั้น

Stateful widget (Mutable)

เป็นสิ่งที่ตรงข้ามกัย Stateless นั่นก็คือ
ถ้าต้องการเปลี่ยน state หรือ property แล้ว
ต้องเปลี่ยนมาเป็น stateful widget
ซึ่งจะทำการ extends จาก class StatefulWidget
ดังนั้น เมื่อค่าของ state เปลี่ยนแล้ว widget นั้น ๆ จะทำการ re-draw ให้อัตโนมัติทันที

ดังนั้นเรื่องพื้นฐานสำคัญมาก ๆ นะครับ
ของศึกษากันก่อนครับ

ว่าด้วยเรื่องของ Widget testing ใน Flutter

$
0
0

สำหรับระบบงานที่พัฒนาด้วย Flutter นั้น
เมื่อทำการสร้าง project ใหม่ขึ้นมา
จะพบว่าจะมี folder test มาให้ด้วยเสมอ
พร้อม test case เริ่มต้นมาให้

แต่จากที่เห็นหลาย ๆ project ก็จะไม่มี test case อะไรเพิ่มขึ้นเลย
หนักกว่านั้นทำการลบทิ้งไปอีก !!
ทำไมนะ ?
ทดสอบระบบงานกันแบบไหนนะ ?

ใน Flutter นั้นจะเตรียมเอกสารในการทดสอบไว้ให้แล้ว

อยู่ที่ Flutter Testing มีใครอ่านและทำบ้างยกมือขึ้น !!!
ประกอบไปด้วย

  • Unit testing
  • Widget testing
  • Integration testing

รวมไปถึง Continuous Integration กันเลยทีเดียว ครบถ้วนมาก ๆ

แต่จากที่พัฒนาระบบงานมาพบว่า Widget testing นั้นมีประโยชน์มากพอสมควร

ไม่ช้าจนเกินไป
สร้างความเชื่อมั่นในระดับที่ดี
เขียนไม่ยากเท่าไร
อีกอย่างในการออกแบบจะแยกเป็น component หรือ widget เล็ก ๆ อยู่แล้ว
เลยพยายามจะทดสอบในส่วนของ Widget ไปเลยว่า
ในแต่ละ widget ทำงานถูกต้องตามที่เราต้องการหรือไม่
เพราะเชื่อว่า ถ้าแต่ละ widget ทำงานได้อย่างถูกต้อง
เมื่อมารวมกันน่าจะทำงานได้ถูกเช่นกัน
หรือถ้าไม่ถูกต้อง น่าจะมีปัญหาเรื่องการรวมกันแล้ว
ช่วยให้เราหาและแก้ไขปัญหาได้ง่ายขึ้น

สิ่งที่ทำได้ใน Widget testing ประกอบไปด้วย

  • การทดสอบในแต่ละ widget แยกกันไปเลย
  • ตรวจสอบการแสดงผล
  • สามารถ interact กับ widget ได้ เช่น tab, drag และ กรอกข้อมูล

โดยการทำงานต่าง ๆ ด้วย class WidgetTester ที่ทาง Flutter เตรียมไว้ให้แล้ว

ตัวอย่างของ Test ที่เตรียมไว้ให้เมื่อสร้าง project ใหม่

[gist id="0c54da80f30a01d467a006678f7d2dff" file="widget_test.dart"]

คำอธิบาย

  • จะสร้าง test case ผ่าน method testWidgets()
  • ในแต่ละ test case จะม่การ inject WidgetTester มาให้เสมอ
  • การทำงานจะเป็นแบบ asynchronous ดังนั้นรูปแบบการเขียนจึงเป็น async-await
  • WidgetTester จะทำการจำลอง environment ของ flutter ขึ้นมา โดยไม่ใช้งาน device จริง ๆ
  • ปัญหาของการจำลองคือ เรื่องของ state จะพบว่าไปเปลี่ยน ดังนั้นในการทดสอบต้องใช้ method pump() เข้ามา เพื่อให้ widget ทำการ render ตามค่าที่เปลี่ยนแปลงไปนั่นเอง
  • การทดสอบจะมี 3 ขั้นตอนคือ หา และสร้าง widget ที่ต้องการทดสอบ ต่อมาทำการ interact กับ UI นั้น ๆ สุดท้ายก็ตรวจสอบผลการทำงาน ว่าเป็นไปตามที่คาดหวังหรือไม่

ทำการ run test ง่าย ๆ ด้วยคำสั่ง testและมี coverage ให้ด้วย

[gist id="0c54da80f30a01d467a006678f7d2dff" file="1.txt"]

โดยในแต่ละ test case นั้น เราสามารถควบคุมได้เหมือนปกติ

ยกตัวอย่างเช่น

  • Skip test
  • Timeout ของการ test
  • ใส่ tag เพื่อแยกกลุ่มของ test ได้ ทั้งระดับไฟล์และ test case
[gist id="0c54da80f30a01d467a006678f7d2dff" file="widget_test2.dart"]

ส่วน Life cycle ของ test นั้นก็เหมือนกับ test framework ทั่วไปคือ

  • setupAll() ทำเพียงครั้งเดียว ก่อนที่จะเริ่มทดสอบ
  • tearDownAll() ทำเพียงครั้งเดียวเมื่อทดสอบทุก ๆ test case แล้ว
  • setup() ทำก่อนที่จะทดสอบแต่ละ test case
  • tearDown() ทำหลังจากที่แต่ละ test case ถูกทดสอบแล้ว
[gist id="0c54da80f30a01d467a006678f7d2dff" file="widget_lifecycle_test.dart"]

สิ่งที่ต้องเจอแน่ ๆ คือ การจัดการ dependency

ที่แต่ละ widget ใช้งาน
นั่นสามารถจัดการด้วย Mockito
หรืออาจจะสร้างจำลองขึ้นมาก็ได้ เช่นพวก Mock server หรือใช้ Nock เป็นต้น

ในการพัฒนาระบบงาน จะขาดการทดสอบไปได้อย่างไร ?
ขอให้สนุกกับการ coding ครับ


คำถามเรื่อง Java Stream vs For loop

$
0
0

เจอคำถามเกี่ยวกับ Java Stream vs For loop ใน facebook group
ถ้าเป็น Java developer/programmer ที่เรียนรู้ความสามารถภาษา Java ใหม่ ๆ
น่าจะใช้ Java stream และ Lambda กันหมดแล้ว
หรือหลาย ๆ คนก็ไปสาย Reactive กันหมดเล้ว
แต่แน่นอนว่า คำถามนี้ก็ยังน่าสนใจ
เพราะว่า ผมก็เจอคำถามแบบนี้บ่อยมาก ๆ
สิ่งที่ต้องพิจารณานั้น ควรดูให้ครบทุกมุมยกตัวอย่างเช่น

  • Readability
  • Performance

เรื่องแรก Performance ของการทำงาน

performance มักจะตรงข้ามกับ readability อย่างมากนั่นคือ

  • กรณีที่ข้อมูลแบบ List ที่มีขนาดไม่ใหญ่มาก For loop จะเร็วกว่า
  • กรณีที่ข้อมูลแบบ List ที่มีขนาดใหญ่ Stream จะเร็วกว่า แถมทำงานแบบ parallel ได้ด้วย ดังนั้นยิ่ง CPU มีหลาย core ยิ่งเร็วขึ้นไปอีก

แต่ที่น่าสนใจคือ JVM สมัยใหม่ตั้งแต่ JDK 1.8 หรือ 8 ขึ้นไป
พยายามทำการ optimize ให้ Stream มีการทำงานที่ดีขึ้นอย่างมาก

อาจจะต้องเลือกว่าcost ของ performance vs cost ของ readability และ maintain อะไรดีกว่ากันในแต่ละบริบทจะต่างกันไป

ลองทำการ benchmark ด้วย JMH (Java Microbenchmark Harness)

เรื่องที่สองคือ readability

ระหว่าง loop ซ้อน loopหรือใน loop
มี if ซ้อน if ไปเรื่อย ๆ
กับใช้งาน Stream ร่วมกับ operation ต่าง ๆ และ Lambda
อะไรน่าจะอ่านและเข้าใจง่ายกว่ากัน
แต่ถ้าปกติก็เริ่มที่ for loop นี่แหละ ง่ายที่สุดแล้ว

จากที่ผมทำงานมาหลัง ๆ ก็ไป Stream กันเลย ตามความเคยชิน !!

ตัวอย่าง code แบบง่าย ๆ
แน่นอนว่า ใช้ for loop เลยง่าย ๆ

[gist id="572a0870847c8a8cb5c6a0ec176f1079" file="1.java"]

แต่ถ้าซับซ้อนกว่าละ !!
ต้องลองกันดูครับแบบนี้อ่านง่ายขึ้นไหม ?

[gist id="572a0870847c8a8cb5c6a0ec176f1079" file="2.java"]

จะแบบไหนลองเลือกดูครับ
แต่ควรต้องรู้และเข้าใจทั้ง for i, for each และ stream
เพื่อให้เราเลือกใช้ได้เหมาะสมครับ

ปล. 1
ตอนนี้ Java 16 แล้วนะครับเรื่อง Java Stream และ Lambda
น่าจะเป็นพื้นฐานของภาษา Java ไปแล้ว
จะใช้งาน for loop หรือ stream ก็ต้องเลือกให้เหมาะสม

ปล. 2
อย่าหนีปัญหาด้วยการเปลี่ยนภาษา เช่นเรายังเขียน Java ต่ำกว่า 1.8 หรือ 8
ดังนั้นเพื่อความ modern เราจะไปภาษา Kotlin เลย !!

ลองไปดู Library ทีใช้ในพัฒนา Club House app บน Android กันหน่อย

$
0
0

เห็นว่า Club House app for Android เป็น version beta
ปล่อยให้ใช้งานในบางประเทศแล้วจะค่อย ๆ ขยายพื้นที่ไปเรื่อย ๆ
แต่ด้วยเป็นสาย Android Developer ก็ไปดูคร่าว ๆ กันหน่อยว่า
Android app ตัวนี้ใช้ภาษาและ library อะไรในการพัฒนาบ้าง ?
ใช้เยอะดีเลยสรุปไว้นิดหน่อย

เริ่มที่ตัวภาษาก็ Kotlin นั่นเอง

ส่วนพวก library หลัก ๆ ก็สาย Jetpack ทั้งนั้น
เช่น การจัดการ scheduler ก็ใช้ WorkManager เป็นต้น

  • ใช้งาน MvRx (Mavericks) จากทาง airbnb ซึ่งเป็น Android MVI framework (Model-View-Intent)การจัดการรูปใช้งาน Picaso
  • พวกการ crop หรือ customize รูปจะใช้งาน Android Image Cropper
  • ใช้งาน REST API ก็เป็น OkHTTP 3 และ Retrofit 2 ตามระเบียบ
  • จัดการ logging ใน app ด้วย Timber
  • ส่วน Dependency Injection ก็ใช้งาน Dagger
  • จัดการ Android runtime permission ด้วย Assent
  • แน่นอนว่าต้องมี PubNub อยู่แล้ว

ในส่วนของ UI ใช้งาน

พวกระบบ Analytic/Monitoring

เพื่อดู performance/bug/exception tracking
รวมถึงการใช้งาน Appประกอบไปด้วย

  • Amplitude
  • InstaBug
  • Sentry.io
  • ActionTrail ของ Alibaba cloud

น่าจะพอมีประโยชน์ สำหรับชาว Android Developer นะครับ
มี library ให้ลองใช้งานเพียบเลย

สรุปจากงาน QCon Plus 2020 เรื่อง The Journey from Monolith to Microservices at GitHub

$
0
0

จากงาน QCon Plus 2020 :: The Journey from Monolith to Microservices at GitHub

ระบบของ GitHub นั้นมีอายุมากกว่า 12 ปี
โดยพัฒนาในรูปแบบของ Monolith architecture เป็นหลัก
พัฒนาด้วย RoR หรือ Ruby on Rails
ทำการ deploy หลายครั้งต่อวัน
ระบบต้อง scale เพื่อรองรับจำนวน request มากกว่า 1,000 ล้านครั้งต่อวัน
โดยระบบสามารถทำงานได้ตามที่ต้องการเป็นอย่างดี

แต่ในช่วงหลัง ๆ มานั้นทีมของ GitHub โตขึ้นแบบก้าวกระโดด

นั่นคือภายใน 18 เดือนหรือปีครึ่ง จำนวนคนมากกว่า 2,000 คน
ซึ่งมีจำนวนมากกว่าเดิม 2 เท่าตัว
โดยจำนวนพนักงานที่เพิ่มมา มีสองส่วนคือ

  • การรับคนแบบปกติ (Organic)
  • จากบริษัทที่ซื้อเข้ามา ทั้ง NPM, Dependabot, Pull panda และ Semmle เป็นต้น

อีกอย่าง พนักงานกว่า 70% ทำงานแยกกันไปตามแต่ละที่
ต่าง timezone กันไป (Distributed team)

จากที่กล่าวมาข้างต้น

ทำให้เทคโนโลยีที่ใช้ภายในของ GitHub มีความหลากหลายมาก ๆ
จะให้ทุกคนมาเรียนรู้ภาษา Ruby และ RoR ก็ไม่น่าเหมาะสม
ทั้งในแง่ของ productivity, efficient และ scale

รวมทั้ง code ของ GitHub ก็ใหญ่ขึ้นมาก
จะทำอะไรสักอย่างประชุมวางแผนก็เยอะ
คนที่เกี่ยวข้องก็เยอะ การตัดสินใจในแต่ละเรื่อง ก็ลำบากซับซ้อนขึ้นเรื่อย ๆ
ผลกระทบมากมายทั้ง logic และ data ที่ใช้งานร่วมกัน
ดังนั้นการแก้ไขแต่ละครั้งต้องระมัดระวังอย่างมาก
นี่คือปัญหาหรือไม่นะ ?

จึงเป็นที่มาของ Monolith vs Microservices ?

ซึ่งทั้งคู่มีข้อดีและข้อเสียต่างกันไป
จะ migrate ไปทั้งหมดเลย ?
ถ้าจะทำ ต้องทำอย่างไรบ้าง ?
ซึ่งต้องรู้และเข้าใจก่อน

ก่อนที่ GitHub จะทำการเปลี่ยนแปลงระบบนั้น

ต้องใช้เวลาในการคิด วิเคราะห์ ไตร่ตรองว่า
ทำไมต้องเปลี่ยนแปลง
เป้าหมายของการเปลี่ยนแปลงคืออะไร


ในการเปลี่ยนแปลงนั้น เรื่อง culture สำคัญมาก ๆ
แน่นอนว่า มันไม่ง่าย มีงานต่าง ๆ ให้ทำมากมาย

โดยจะทำอะไรนั้น ต้องให้ความสนใจ ใส่ใจ
ในเรื่องของปัญหา และ pain point เป็นหลัก

เป้าหมายหลักที่ GitHub ต้องการคือ การ enable ไม่ใช่การ replace

ซึ่งต้องยอมรับก่อนว่าในอนาคตจะมีทั้ง monolith และ microservices ทำงานร่วมกัน
ดังนั้นเรื่อง environment จะต้องมีทั้งสองแบบ
การปรับปรุง code ใน monolith ก็ยังไม่ความสำคัญ
ไม่แพ้กับการสร้าง microservices ขึ้นมา

Good Architecture start with Modularity

ในขั้นตอนแรกของการแยกการทำงานของ monolith ออกมา
คือการแยกส่วนการทำงานต่าง ๆ ทั้ง business logic, data ออกมา
ในรูปแบบของ module (Logical)
ก่อนที่จะแยกกันจริง ๆ ในแง่ physical ในรูปแบบ microservices ต่อไป

ดังนั้นสิ่งที่สำคัญมาก ๆ คือ
ต้องทำให้ code มันจัดการได้ง่าย
ก่อนที่จะไปคิดเรื่องอื่น ๆ
ถ้าพื้นฐานมันแย่แล้ว ต่อไปมันจะแย่ลงเรื่อย ๆ

จากนั้นเรื่อง data หรือข้อมูลที่ต้องใช้งาน

ต้องกำหนดให้ชัดเจนเรื่องการเข้าถึงข้อมูลต่าง ๆ
เนื่องจากในแต่ละ service ต้องมีหน้าที่ในการดูแลและจัดการข้อมูลของตัวเอง
ไม่ไปยุ่งเกี่ยวกับข้อมูลของ service อื่น ๆ โดยปราศจากเหตุผลที่เหมาะสม

ซึ่งช่วยทำให้แต่ละ service มีการกำหนด API หรือ contract
ระหว่างกันได้ชันเจนมากขึ้น

สิ่งหนึ่งที่เห็นบ่อยมาก ๆ และไม่ถูกต้องคือ

มักแยกเพียง logic ออกมาเป็น service เท่านั้น
แต่ data ยัง share กัน !!
เหมือนใน monolith เลย !!
นำไปสู่ปัญหาที่เรียกกันว่า Distributed Monolith

ผลที่ตามมาคือ แย่ทั้ง monolith และ microservices นั่นเอง
ทำให้เราได้ microservices ที่มีความซับซ้อน
แต่ไม่ได้ประโยชน์อะไรจากมันเลย

การแยก data ที่ GitHub ทำอย่างไร ?

มีขั้นตอนดังนี้

ขั้นตอนที่ 1

ทำการระบุ boundary ของ function การทำงานต่าง ๆ
พร้อมระบุว่ามี table อะไรบ้างที่ใช้งาน
จะเห็นว่ามี table อะไรที่ใช้ร่วมกัน และ แยกกันไปในแต่ละ function การทำงาน
และยังมีการพัฒนาเครื่องช่วย monitor ด้วยว่า
มี query อะไร ที่ทำการดึงข้อมูลจาก table จากกลุ่มการทำงานอื่น ๆ บ้าง
เพื่อทำให้เห็นว่าต้องแก้ไขตรงไหนบ้าง

ขั้นตอนที่ 2

แยก schema ออกมาในแต่ละกลุ่มการทำงานให้ชัดเจน
พร้อมกับใส่ partition key เข้ามาด้วยเพื่อให้ง่ายต่อการ scale
เมื่อแยก schema ไว้แล้ว
ทำให้ง่ายต่อการแยกในระดับ database server ต่อไป

เนื่องจากระบบงานมีขนาดใหญ่ จะเริ่มตรงไหนดี ?

สิ่งที่ GitHub เริ่มคือ

  • Core service หรือ service หลักของระบบ เช่น Authentication and Authorization
  • Share resource หรือ อะไรก็ตามที่ใช้งานร่วมกันเสมอ เช่น เครื่องมือในการพัฒนาให้ง่ายขึ้น เช่น feature flag เป็นต้น

การติดต่อสื่อสารระหว่าง service จะใช้งาน gRPC
อีกอย่างเมื่อแยกการทำงานอะไรออกไปแล้ว
code ในระบบเดิมต้องเอาออกไปด้วยเสมอ
รวมทั้งยังสร้างเครื่องมือ
สำหรับการดูว่า traffic วิ่งไปยังที่ใหม่ทั้งหมดหรือไม่อีกด้วย
เป็นการสร้างเครื่องมือ เพื่อตอบโจทย์ความต้องการ

เรื่องของ Operation ก็เปลี่ยนไปเช่นกัน ขาดไม่ได้เลย

ทั้งเรื่องเดิม ๆ คือ Monitoring, CI/CD และ containerization
ต้องเปลี่ยนไปเพื่อให้รองรับ microservices ด้วย
เพราะว่ามีจำนวน service เยอะขึ้น
ความหลากหลายของ technology มากขึ้น
ต้องมีการ customize pipeline ให้เหมาะสมกับ monolith และ microservices

ระบบ Monitoring ก็ต้องเพิ่มอีก
ทั้งเรื่องของ metric, contract interface ของ API ระหว่าง service

สิ่งที่ทาง GitHub ทำขึ้นมาคือ template ของ pipeline
เพื่อให้สามารถ reuse ได้ง่าย
แต่เกิดมาจากการทำงานจริง ๆ ถึงจะมี template ได้

ยกตัวอย่างเช่น

Self-service runtime platform สำหรับการ deliver microservices
ช่วยลด overhead ของการทำงานในฝั่ง operation
ซึ่งประกอบไปด้วย

  • Kubernetes manefest template
  • Ingress สำหรับ load balancing
  • การเก็บ log
  • การ integrate กับส่วนการทำงานอื่น ๆ

ทำให้ทีมง่ายต่อการทดลองสร้าง microservices ขึ้นมาซึ่งเป็นสิ่งที่ดีมาก ๆ

ปิดท้ายด้วยประโยคนี้

Start Small and Think about product/business value

น่าจะพอมีประโยชน์สำหรับใครก็ตามที่กำลังจะทำ
เป็นอีกหนึ่งแนวทางที่น่าสนใจครับ
ก่อนจะทำอะไรก็ตาม ให้เริ่มด้วยคำว่า why ไม่ใช่ how

[Go] บันทึกแก้ไขปัญหาในการจัดการ JSON นิดหน่อย (JSON Serialization)

$
0
0

ปัญหา
ในงานที่ทำ มีกรณีของการทำงานร่วมกับข้อมูลในรูปแบบ JSON
ซึ่งในบาง field/property อาจจะมีข้อมูลมาบ้าง ไม่มีบ้าง
แถมเป็น null/nill ได้อีก
ทำให้การแปลงข้อมูล JSON มาเป็น Struct
ไม่ตรงตามที่ต้องการเท่าไร
จึงลองหาวิธีการแก้ไขนิดหน่อย

แนวทางการแก้ไข

เริ่มจาก code ปกติงานได้ปกติ

[gist id="56a87e374f87ebcf988f5ab06f89fa56" file="1.go"]

แต่เมื่อถ้าบาง property ไม่ได้กำหนดค่า

จะมีค่าเป็น zero value
ยกตัวอย่างที่ property Amount

[gist id="56a87e374f87ebcf988f5ab06f89fa56" file="2.go"]

สิ่งที่ต้องการคือ ถ้าไม่ทำการกำหนดค่าของ property Amount

จะไม่แสดง property Amount มาด้วย
โดยเพิ่ม json literal ชื่อว่า omitempty
ก็ทำตามนี้

[gist id="56a87e374f87ebcf988f5ab06f89fa56" file="3.go"]

แต่ก็มีบางกรณี ที่มีกำหนดค่าเป็น nil มาด้วย มันจะซับซ้อนไปไหน ?

จัดการข้อมูลต้นทางดี ๆ ไม่ได้หรือไง ?
ตอบเลย ไม่ได้ เศร้า !!
ดังนั้นแก้ไขกันหน่อย
ด้วยการให้ property ที่มีชนิดเป็น int ให้สามารถรับค่า nil ได้
ด้วยการเปลี่ยนเป็น pointer ดังนี้

[gist id="56a87e374f87ebcf988f5ab06f89fa56" file="4.go"]

ก็พอแก้ไขให้ทำงานที่ต้องการได้บ้าง

มาดูการปรับปรุง code ของระบบ Airtable

$
0
0

อ่านเจอบทความเรื่อง The continual evolution of Airtable’s codebase: Migrating a million lines of code to TypeScript
ทำการอธิบายว่าที่ Airtable ทำการปรับปรุง code กันอย่างไรบ้าง ?
กับ code ที่มีกว่า 1 ล้านบรรทัด
จาก Vanilla JavaScript ไปยัง TypeScript
ตั้งแต่เริ่มจนถึงปัจจุบัน และในอนาคต

โดย history ของการพัฒนาเป็นดังนี้

  • เริ่มจาก Vanilla JavaScript
  • นำ Browserify มาใช้งาน ซึ่งทำการ import CommonJS มาใช้งาน
  • ทำการแปลงรูปแบบของการเขียน class จาก Backbone style มาเป็น ES6 style
  • ทำการ custom เป็น component เพื่อ convert ไปยัง ReactJS component
  • แน่นอนว่าเลือก Flow ซึ่งทำงานกับ ReactJS ได้ดี เข้าสู่ยุคของ Static type
  • ต่อมาทีมคิดว่า Flow ไม่ตอบโจทย์แล้ว ทั้งในแง่ของ productivity, community และ tool ต่าง ๆ
  • ทำการแปลงจาก Flow มายัง TypeScript

แนวทางของ Airtable สำหรับทุก ๆ การเปลี่ยนแปลง

ประกอบไปด้วย

  • ต้องไม่ส่งผลกระทบต่อ product และผู้ใช้งานในเชิงลบ
  • ในการเปลี่ยนต้องไม่ลด type safty ลง จะเห็นได้จากการเปลี่ยนจาก Flow มายัง TypeScript
  • พยายามทำให้มันง่ายที่สุด เนื่องจากการเปลี่ยนแปลงมีจำนวนมาก ดังนั้นต้องค่อย ๆ เปลี่ยนแปลงและปรับปรุงไปทีละส่วนเล็ก ๆ (Incremental) เช่น type-by-tpye หรือ file-by-file เป็นต้น

แต่ถ้าทำการเปลี่ยนแปลงเยอะ ๆ
จะสร้างเครื่องมือในการ migrate เป็น TypeScript ขึ้นมา
เพื่อช่วยจัดการเรื่องที่ซ้ำ ๆ หรือมี patternคือ
GitHub :: Airtable’s TypeScript Migration Codemod

ในการเปลี่ยนแปลง จะทำการสร้าง branch แยกออกไปทำ

จากนั้นทำการตรวจสอบเรื่อง type checking
รวมทั้งมี automated test เพื่อทำให้มั่นใจว่ายังคงทำงานตามที่คาดหวัง
เมื่อทุกอย่างผ่านเรียบร้อยจึงทำการ merge มายัง main branch
เพื่อทำการ deploy ต่อไป

ในการทำงานก็มีเรื่องราวและแนวคิดมากมาย ที่น่าสนใจ

ทั้งการแปลงจาก createReactClass component มาเป็น ES6 class component

ในส่วนของ Automation team ทำการสร้าง helper method
สำหรับการ generate TypeScript type ออกมา
เพื่อใช้ในการกำหนดและ validate schema

ในส่วนของ Enterprise team ทำการเปลี่ยนจาก ts file มาเป็น tsx file ให้หมด
เพราะว่า จะได้ใช้เพียงแนวทางเดียวไปเลย

จะเห็นได้ว่าที่ Airtable จะค่อย ๆ ทำการเปลี่ยนแปลง

พร้อมกับสร้างเครื่องมือมาลดงานที่ซ้ำ ๆ
ช่วยทำงานให้ทำงานได้เร็วขึ้น
พร้อมทั้งยังต้องมี automated test เพื่อช่วยตรวจสอบความถูกต้องด้วยเสมอ
รวมทั้งยังชี้ให้เห็นข้อดีของ static type ด้วยว่า
ถ้า code มีขนาดใหญ่แล้ว เรื่อง type จะสำคัญมาก ๆ
เพื่อลดความเสี่ยงและความผิดพลาดได้มากขึ้น
และเน้นที่เรื่องของ code quality และ การพัฒนาอย่างต่อเนื่อง

ปล. ในปัจจุบัน Airtable ก็ยังมี code เก่า ๆ อยู่เช่นกันยังย้ายไปไม่หมด

Viewing all 2000 articles
Browse latest View live