TipMe Tech Stack 2019

เห็นช่วงนี้หลายๆ ที่ share stack กัน ก็เลยอยากเล่าบ้าง…

Design

แต่ละที่ stack มี tradeoff แตกต่างกันไป ก่อนจะเข้าใจ stack ก็เลยจะต้องเล่าถึง design goals ก่อนว่าจะทำอะไร

  1. เราพยายามไม่ใช้ microservice ให้มากที่สุด เพราะเขียนคนเดียวไม่มีปัญญาดูหลาย service (และใน environment ที่เขียนหลายคนเราก็เห็นแล้วว่า service บางตัวก็ไม่ได้ถูกดูแลจนเราพอใจ)
  2. คุม budget เป็นเรื่องสำคัญค่อนข้างมาก เนื่องจากว่าเราพอมีไอเดียแล้วว่า market cap ของวงการนี้มันมีเท่าไร และไม่ได้มีเงินให้เผาเหมือน startup ก็เลยจะต้องรัดเข็มขัดอยู่ตลอดเวลา
  3. เนื่องจากว่ามันเป็น environment ที่ไม่มีใครค้านอะไรใน design เราได้นอกจากด้านบน ก็เลยพยายามจะใช้เทคโนโลยี cutting edge อยู่เสมอ

Frontend

jQuery

ย้อนกลับไปตอนที่สร้างเว็บ เวลานั้นเราตั้งคำถามว่าเราจะใช้ jQuery แล้ว iterate ได้เร็ว หรือใช้ React แล้วได้โค้ดที่สวยงามแต่ iterate ได้ช้า แน่นอนคำตอบเราคือใช้ jQuery สิ! ถึงเวลานี้ก็ยังคิดว่าคิดถูก 100%

เราว่าสิ่งที่คน Design พลาดกันเยอะคือเราไปมอง stack บริษัทเทพๆ (หรือโดนเค้า hype มา) แล้วบอกว่าเราจะทำแบบนั้น แต่นั่นคือ Design ที่เวิร์คกับเค้าใน scale นั้น มันไม่ได้แปลว่ามันจะเวิร์คใน scale ของเรา

React

React มาพร้อมกับเพื่อนของมันคือ Babel, Webpack และ MobX ซึ่งปัจจุบันโค้ด TipMe ฝั่งที่เป็น jQuery ก็ใช้ ES6 ผ่าน Babel และ build ด้วย Webpack

ในปี 2017 เราก็เอารายได้ส่วนหนึ่งบริจาคให้ Babel และ webpack Open Collective (เสียดายว่าเปิดบริษัทแล้วจะทำอะไรแบบนี้ก็ยากขึ้น เพราะมันไม่มีใบเสร็จหักค่าใช้จ่าย)

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

วิธีที่เราใช้ React ก็จะไม่ค่อยเหมือนชาวบ้านเท่าไรนัก แต่ก็ไม่ใช่ท่าแปลก คือตัวหน้าเว็บจะเป็น Django Template แล้วส่วนที่เป็น interactive ก็ค่อยเอา React ไป enhance โดยใช้ MobX เป็น state store

พอใช้ MobX แล้วเราก็เริ่มค้นพบว่า inheritance ทำให้โค้ดอ่านเข้าใจง่ายขึ้นมาก ก็เลยเอามาใช้กับ controller component ด้วย ตอนนี้เริ่มเจอปัญหาเพราะ inheritance กับ decorator (HOC) ไม่ค่อยจะกินเส้นกันเท่าไรนัก อาจจะต้องเริ่มถอดออกเพราะ community จะมาทางนี้

ถ้าถามเราเราก็ยังคิดว่า controller component ควรใช้ inheritance เพราะ React มันไม่มีวิธีสวยๆ ที่ทำให้ controller (นอกจาก root) ไม่ใช่ component

Developer tools

เครื่องมืออื่นๆ ที่ใช้ก็มี

  • Gulp – โค้ดใช้ Gulp build มานานมากเพราะต้อง compress CSS, JavaScript ด้วย ก่อนที่จะมี Webpack เข้ามา ช่วงต้นปีที่แล้ว Gulp จะมี custom plugin อันนึงที่เขียนเองแล้วบอกได้ว่า file นี้ include React vendor chunk หรือเปล่า แต่พอ Webpack 4 ออกก็เลิกใช้ไปใช้ Code split ตัวใหม่แทน
  • Storybook – เราทำ storybook ไว้สำหรับทุก Component อยู่ แต่ก็ไม่ได้อัพเดตนานแล้วเพราะไม่ค่อยได้แตะโค้ดตรงนั้น

Backend

Django

เฟรมเวิร์คที่เราชื่นชอบคือ Django ทั้งเว็บก็เลยอยู่บน Django monolithic เลย ตั้งแต่ระบบตกแต่ง ส่งเอกสาร ไปจนถึงบัญชี

แน่นอนว่าต้องใช้ Django REST Framework ด้วย สำหรับ API Endpoint ต่างๆ ในช่วงแรกๆ คิดว่าเราไม่ใช่ proper API ไม่จำเป็นต้องใช้ แต่ตอนหลังก็มา port เป็น DRF อยู่ดี ทำให้โค้ดส่วนที่เป็น validation ถูกแยกออกไปเป็นสัดส่วนชัดเจน

ตอนที่ย้าย DRF นี่ก็เป็นส่วนหนึ่งของ Great refactoring of 2017 ที่เราอ่าน Two scoops of Django แล้วก็ list มาว่าจะต้อง refactor อะไรบ้าง ถึงทุกวันนี้ก็ยังไม่หมด เพราะบางอันก็ยากมาก เช่น redesign ส่วน payment ใหม่หมด

Celery

เนื่องจากเราดีลกับระบบ 3rd party เยอะมาก ดังนั้น Celery จึงหลีกเลี่ยงไม่ได้ ปัญหาหลักตอนนี้คือมีบาง operation ที่ไม่ threadsafe อยู่เราจึงจะเปิด Celery ได้แค่ตัวเดียว แต่ก็ยังไม่เป็นปัญหาเท่าไรนักเพราะ operation ที่ทำอยู่ไม่ค่อยหนัก

ในปี 2017 เราบริจาครายได้ส่วนหนึ่งให้ python-social-auth, Celery, PyPy และในปี 2018 เราเป็น Python Foundation Supporting Member

Go

แม้เราจะยันไม่ยอมเป็น microservice อยู่นานมาก แต่พอเราจะต้องเก็บบัตรประชาชนลูกค้าแล้วก็เลยต้องยอมแยก service มาเพื่อแยก access level ให้ชัดเจน ถ้า app ตัวนอกถูกเจาะก็จะต้องไม่สามารถทะลุ Access Control เข้ามาได้ เลยเลือกใช้ Go เพราะมันกินทรัพยากรระบบน้อยที่สุด เหมาะสำหรับ service ที่ idle อยู่เฉยๆ เป็นส่วนมาก จะกินแรมเยอะก็ไม่เหมาะ

อีก service หนึ่งที่ใช้ Go คือ QR generator ที่ qr.tipme.in.th ซึ่งแต่เดิมเป็นส่วนหนึ่งของ monolithic แล้วก็คิดว่าควรจะแยกออกมา มันไม่ได้เกี่ยวพันกับระบบที่เหลือเลย

หลังจากแยกมาแล้วก็พบว่าเราเอา service นี้ไปลองเล่นอะไรได้เยอะมาก เช่น Cloud Run ก็ลองด้วย QR service มาแล้ว

TypeScript

TypeScript ค่อนข้างเป็นของใหม่ ในฝั่ง frontend เลยยังไม่ได้แปลงมาใช้ ใน backend จะมีใช้เพราะเราใช้ socket.io ทำ realtime

แต่เดิม realtime เราใช้ Django Channels ซึ่งมันก็ทำให้ก้อน monolithic ทำ WebSocket ได้ด้วย แต่พอใช้ๆ ไป เค้าก็ออกมาบอกว่าจะเปลี่ยน design ใหม่แล้วและจะไม่ compatible กับของเดิม พอลอง port ดูพบว่าใช้ effort มาก ก็เลยตัดสินใจว่าจะย้ายออก

แต่ย้ายออกก็ไม่ยาก เราใช้เวลาวางแผนอยู่ปีหนึ่งจึงจะนึกออกว่าจะเอาออกมาได้ยังไง เนื่องจาก design เดิมผูกติดกับ authentication system อยู่มาก และมันรู้ว่า user connect เข้ามาแล้วจะส่ง message ต้อนรับให้ด้วย

จากโจทย์นี้ วิธีที่ง่ายที่สุดคือก็เมื่อมีคน join แล้วให้ยิงข้อความเข้า message queue จากนั้นตัวแอพก็ read message มาแล้วตอบกลับไปว่าให้ส่งว่าอะไร ปัญหาก็คือเราพยายามหนีจาก message queue อยู่ เนื่องจากว่า RabbitMQ ใช้ทรัพยากรระบบมาก และ Cloud Pubsub ก็เคยมีกรณี latency 5 วินาที ทำเว็บเราล่มไปแล้ว

วิธีที่ทำอยู่คือให้ client ต่อเข้า WS service ก่อน แล้วจึงยิงไปบอก Main server ว่าต่อแล้ว จากนั้น main server จึงค่อยบอก WS ว่าให้ join ห้องได้และส่งข้อความแรกให้ไปด้วย วิธีนี้ทำให้บน server กลายเป็น one way communication

Sentry

Sentry เป็นโปรแกรมจับ Error และเป็น monitoring หลักที่เราดูเลย รายละเอียดเล่าบ่อยมากแล้ว ดูจากสไลด์แล้วกัน

Infrastructure

gRPC

ระหว่าง service ข้างในคุยกันเป็น gRPC ทั้งหมด ตอนนี้รู้สึกว่าคิดผิด ยังมองอยู่ว่าจะย้ายไป Twirp หรือลง Linkerd ดี แต่ Istio นี่ทดลองหลายหนแล้วยังไม่เวิร์ค

รายละเอียดตามสไลด์นี้

Kubernetes

ทั้งหมดทั้งปวงที่เล่ามารันอยู่บน Kubernetes แต่ก็มีส่วนที่รันอยู่ด้านนอกเช่นกัน (ของที่มี state กับต้องการ Fix IP)

เราคิดว่าระบบมี hard dependency กับ Kubernetes อยู่ เช่น เรา design ระบบให้ crash ตอน error เพื่อให้ Kubernetes restart ให้ จะได้ไม่ต้อง handle retry เอง และเราใช้ CronJob ด้วย

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

Cloudflare

จำไม่ได้ว่าย้ายมา Cloudflare ตอนไหน แต่ก็น่าจะหลังมาใช้ Google Cloud ซึ่งเราเอาไปใช้ serve static เป็นหลักก่อน เนื่องจากเราใช้ WebSocket มากแล้วกลัวจะเกิน usage quota ของแพลนฟรี (Cloudflare เสียเงินน่าจะเป็นอย่างถัดไปที่ซื้อ แต่ต้องคิด budget ดูก่อน)

ช่วงปีที่แล้วมีช่วงที่โดน DDoS บ่อยมากจนปวดหัว ก็เลยตัดสินใจย้ายโดเมนทั้งหมดขึ้น Cloudflare เพราะปกติจะโดนแค่ DoS ซึ่งใช้ Cloud Armor กันก็ได้ แต่รอบนั้น IP มันเยอะเขียน rule ไม่ทัน

Google Cloud

ทุกบริการเราอยู่บน Google Cloud ซึ่งก็ใช้หลายบริการเหมือนกัน คือ

  • Google Kubernetes Engine
  • Google Compute Engine (มีเครื่องที่ไม่ใช่ Kubernetes ด้วย)
  • Google Cloud Storage
  • Google Container Builder
  • Google Cloud Function ไว้แจ้งเตือนตอน Container Builder build เสร็จแล้ว
  • Google Cloud Vision
  • Stackdriver Logging
  • Stackdriver Monitoring

ก็ไม่รู้สึกว่า Stackdriver Monitoring มันดีสักเท่าไร ยังสงสัยว่า Google เค้า Monitoring ด้วยไอ้นี่ได้จริงหรอ (ถามคนรู้จักที่เป็น Google SRE เค้าบอกว่าไม่) แต่ที่ใช้เพราะมันเกือบได้ฟรี

CircleCI

ตัว Monolithic จะ build ด้วย Container Builder แต่พอใช้ๆ ไปพบว่ามัน build git submodule ยุ่งยากมาก ต้องมี service account เพิ่ม แล้วเราก็ต้องไป secure มันอีก ตอนนั้นพวก service เกิดใหม่เลย build บนเครื่องอย่างเดียว จนกระทั่งปีนี้มาลองหาดูแล้วก็พบว่า CircleCI มันดีมาก

เคยแกะ CircleCI ดู พบว่ามันใช้ GCE นี่แหละ โซน us-central ก็สงสัยว่าทำไมมัน build ไวกว่า Container Builder อีก….

Debian

ที่ชอบ GCP อีกอย่างคือ Google ค่อนข้าง prefer Debian เหมือนเรา เลือกมาเป็น default และ support ค่อนข้างดี ต่างกับ AWS ที่จะหา image Debian ต้องไปหาเบอร์ AMI มาใส่

เหตุผลที่ชอบ Debian ก็มาจากประสบการณ์ homelab แล้วเราก็พบว่า Ubuntu มัน upgrade version ทีไรก็พังทุกที พอมาใช้ Debian แล้ว มันไม่ค่อยออกใหม่ แถมตอนอัพก็ไม่พัง เลยแบน Ubuntu ตั้งแต่นั้นมา

อ้อ สำหรับเครื่อง Kubernetes แน่นอนว่าเป็น Container Optimized OS

Helm

Helm เป็นอะไรที่ไม่ชอบมากๆ แต่ถูกบังคับใช้เพราะ service หลายตัวมันใช้ จะไปนั่งเขียน manifest เองก็ขี้เกียจ เลยต้องยอมๆ มัน

Kapitan

สำหรับ Kubernetes templating solution ที่เราชอบก็คือ Kapitan จาก Deepmind เลย มันใช้ Jsonnet ในการ config ทำให้สามารถใส่ลูกเล่นได้พอสมควร

ทีแรกที่เอา Kapitan มาใช้ใช้คู่กับ Ksonnet แล้วรำคาญมากเพราะมันเขียนยุ่งยาก เลยโยนทิ้งไปแล้วกลับไปเขียน Kubernetes YAML ธรรมดา จนกระทั่งบ่นลง Twitter แล้วเค้ามาเห็นเลยชวนให้ไปนั่งคุยใน Slack เค้าก็คิดว่าปัญหาเราคือ Ksonnet นี่แหละ ที่ Deepmind ก็ไม่ได้ใช้ แต่เขียนเหมือน Manifest ธรรมดาๆ มากกว่า พอเราลองทำตามดูแล้วก็พบว่ามันง่ายดีแต่ทรงพลังมาก

Ansible

สำหรับเครื่องที่ไม่ใช่ Kubernetes ก็ยังจำเป็นจะต้องใช้ Ansible manage อยู่ แต่เนื่องจากเครื่องพวกนั้นไม่ได้ scale ออก ก็เลยจะไม่ได้ถึงขนาดจะต้องใช้ Packer ทำ image ด้วย

nginx

ระบบเรามี nginx อยู่หลายหน้าที่มาก อันแรกสุดคือเป็น ingress controller สำหรับ Kubernetes ซึ่งการที่มันสามารถใส่ snippet ได้ทำให้ปรับแต่งได้เยอะมาก

อีกหน้าที่หนึ่งคือเรามี nginx ที่เป็น proxy ขาออก เนื่องจาก partner หลายๆ เจ้าต้องการ fix IP ก็เลยจะให้วิ่งออกทาง nginx ตัวนี้ แล้วก็เอาไปรันในเครื่อง g1 ก็จะไม่เสียเงินเยอะมากเมื่อเทียบกับซื้อ Cloud NAT

Gunicorn

สัปดาห์นี้เพิ่งย้ายออกจาก Django Channels เป็น Gunicorn หมาดๆ เลย โดยลองใช้ aiohttp worker ดูด้วย

Sendgrid

ตอนเปิดใหม่ๆ เลี่ยงไม่ส่งอีเมลได้อยู่สักพัก ก็จนมีคนทักว่าคุณไม่มีข้อมูลติดต่อลูกค้าเลย ก็เลยทำระบบยึนยันอีเมลขึ้นมา แต่ก็ไม่ได้ใช้ทำอะไรจนกระทั่งตอนปิด True Wallet แล้วต้องส่งเมลหาลูกค้าทุกคน

ตอนนั้นก็พบว่า Sendgrid Marketing แพงมาก ต้องไปใช้เจ้าไหนจำไม่ได้แล้ว ยิงผ่าน SES ของเราอีกที

Haraka

พอเปิด True Wallet ตัวใหม่แล้วก็พบว่าต้องทำแจ้งเตือนโดเนททางเมลให้ลูกค้า แต่จะยิงผ่าน Sendgrid ก็จะเกินโควต้าฟรีแน่นอน (ถึงจะได้โควต้าสูงกว่าปกติแล้วก็ตาม) เลยตัดสินใจจะยิงเมลเอง ส่วนเมลไหนที่สำคัญและไม่ใช่ bulk ก็จะไปใช้ Sendgrid เหมือนเดิม

Mail server ที่ใช้คือ Haraka เขียนด้วย Node.js และใช้ใน Craiglist มาก่อน เราใช้เป็น mail server @whs.in.th นานแล้ว ก็เลยไว้ใจ ทีนี้มันยิงเมลออกทาง Google Cloud ไม่ได้อยู่แล้ว วิธีที่ทำคือเครื่องขาออกจะมี Haraka ซึ่งจะ relay มาเครื่องที่รันบล็อคนี้อีกที (มี TLS + whitelist กันเพื่อความชัวร์) เครื่องนี้ก็จะ sign แล้วส่งออกไปอีกที มี custom plugin เล็กน้อยเพื่อ strip routing ภายในออก

หลังๆ มารู้สึกว่า IP reputation ของเราดีกว่า Sendgrid เสียอีก เพราะลูกค้าหลายคนบอกว่าเมลยึนยันตก spam ไปแล้ว

Backoffice

Crisp

Support เพิ่งย้ายมาใช้ Crisp หลังจากไปลอง Freshdesk แล้วก็โดนเมลมาขายเรื่อยๆ

ปัญหาหลักที่ต้องการแก้คือลูกค้าเคยชินกับการ support ทาง Facebook แต่ระบบ support ส่วนมากเป็น ticket-based ไม่เหมาะสักเท่าไร จนมาใช้ Crisp ซึ่งมัน build ทุกอย่างเป็นแชต ก็ชอบมากๆ

นอกจากนี้ราคายังโหดมากเพราะ Unlimit plan แค่เหมาจ่าย $95 ใช้ได้ทุกอย่าง ไม่จำกัดจำนวนคน แถมเรายังได้ส่วนลดอีกเพราะเป็นบริษัทเปิดใหม่ คุ้มค่าแก่การอวยมากๆ

Crisp ยังมีระบบ Support site รวม article ต่างๆ ไว้ด้วย และ Status page ซึ่งแปลกใจมาก เท่าที่ใช้มา Status page อาจจะฟีเจอร์สู้ statuspage.io ไม่ได้ แต่ถ้าคิดว่ามันเป็นของแถมแล้วมันก็เวิร์คมากเลย ตอนนี้ก็เลยย้าย text ยุบยับในเว็บบางส่วนไปอยู่บน Crisp แทน

ฟีเจอร์ที่คาดหวังจาก Crisp ตอนนี้คือ custom slash command จะได้ integrate กับตัวเว็บเพิ่มไปได้อีก

GTK

ใช่แล้ว GTK บนลินุกซ์นั่นแหละ เราเอามาทำ Desktop app สำหรับพิมพ์ใบเสร็จส่งให้บัญชี รันได้ทั้งใน Windows และ Linux เขียนด้วย Go

Asana

พวก feature ต่างๆ จะ note ไว้ใน Asana ติดมาจากที่วงใน ใช้ง่ายดีและไม่มีอะไร distract ให้เสียเวลาเหมือน Trello (ไปนั่งลากการ์ดเล่น) หรือ issue tracker (ใส่ field เยอะๆ เล่น)

G Suite

สุดท้าย เมลติดต่องานต่างๆ ก็ใช้ G Suite รวมถึงทำเอกสารต่างๆ ด้วย

Things I don’t Know

เห็น Dan Abramov เขียนบทความว่าเค้าไม่รู้อะไรบ้าง ก็คิดว่าอยากเขียนบ้าง แต่ก็คิดว่าไม่อยากไปเทียบชั้นเค้า ก็จนกระทั่งเห็น MicroBenz เขียนแล้วก็เลยคิดว่ามันไม่ได้จำเป็นว่าจะอยากเทียบชั้นเค้าแล้วถึงเขียนก็ได้นี่นา…

จริงๆ เราก็เจอปัญหาคล้ายๆ Dan อยู่เหมือนกัน คือคนชอบคิดว่าเรารู้อะไรมากกว่าที่เรารู้ คิดว่าอาจจะเพราะเราชอบอ่านอะไรที่เป็นระบบลึกๆ แต่จริงๆ คือเราอ่านอะไรที่มัน entertain เรา (คล้ายๆ คนที่ชอบอ่านข่าวซุบซิบดาราน่ะ เราก็ชอบอ่านซุบซิบ Container อะไรแบบนี้ 555) บางเรื่องมันก็ลึกแต่มันไม่ entertain เรา เราก็ไม่อ่าน แต่คนก็คิดว่าเรารู้


  • Deep Learning – เคยลอง Machine Learning ผ่านๆ ใน iLeave เราว่าอันนั้นทำได้ดี แต่ Deep Learning นี่อ่านแล้วไม่รู้เรื่องเลย

  • Math – ตอนเด็กๆ คนคิดว่าเราเก่งแล้วพยายามให้เราหัดอะไรยากๆ ซึ่งมันเสียเวลาเล่นคอม ก็เลย shut off สมองส่วนนั้นไปแล้ว เราไม่สามารถคิดเลขเยอะๆ ในใจได้ เช่น 24+9 ต้องนับนิ้วเอา แล้วถ้าเป็นเลขสามหลักคือต้องกดเครื่องคิดเลขหรือมีกระดาษทดอย่างเดียว เคยรวมเงินค่าข้าวแบบไม่มีกระดาษทด นับแบงค์อยู่ 15 นาทีก็ยังไม่เสร็จเพราะจำไม่ได้ว่ากองไหนมีเท่าไรต้องนับใหม่เรื่อยๆ

    คิดว่าการเรียนโปรแกรมมิ่งตั้งแต่เด็กโดยไม่สนใจอย่างอื่นทำให้เกิด brain damage หลายๆ อย่าง รวมถึงเรื่องนี้ด้วย เพราะในโปรแกรมมิ่งเราไม่จำเป็นต้องจำอะไรที่เรามองขึ้นไปอ่านหรือ Go to definition ได้ แต่เราต้องจำภาพใหญ่ของระบบแทน ซึ่ง mental model แบบนี้ไม่มีประโยชน์ในชีวิตจริงเลย

  • Data Science – รวมๆ จากข้างบนแล้วก็เลยคิดว่าไม่รู้เรื่อง Data Science เยอะมากและอาจจะไม่สามารถเข้าถึงได้ด้วย ที่บริษัทเองก็มีทีม Data Science แต่เราก็รู้สึกว่าเวลามีคนมาถามว่าอยากเป็น Data Science ต้องทำยังไง จะจำคำตอบของคนในบริษัทไปบอกคนอื่นก็ไม่รู้ว่าถูกหรือเปล่า เพราะคิดว่าบริษัทบางที่อาจจะไม่ได้เน้น AI มากเท่าที่นี่ อาจจะเน้นทำ data visualization หรือหา insight มากกว่า

  • Algorithm – ตอนจบใหม่เคยคิดว่าจะหางานที่เหมาะสมกับสกิลเราได้มั้ย เพราะคิดว่าแทนที่คนจะวัดจากฝีมือตรงๆ ดันไปสอบ Algorithm แล้วเราไม่ชอบท่องอะไรไปสอบ (เราชอบไม่ท่องอะไรเลยไปสอบ ตอนสอบ GAT/PAT ยังแทบไม่ได้อ่านหนังสือเลย)

    แล้ววิธีที่เราเข้าใจ algorithm มันไม่ใช่ความเข้าใจแบบ textbook (เพราะเรามาจากสาย self taught) เช่น ตอนเรียนเรื่อง Big O เราพยายาม map กลับในหัวแทนว่า O(n^2) เวลาเขียน loop จะหน้าตาอย่างไร

    ส่วนพวกโจทย์ programming problem (แบบ codejam) เรามองว่ามันคือ math problem ที่บังเอิญ solve ด้วยมือไม่ได้มากกว่า เวลาทำโจทย์ codejam ก็เลยจะเขียนแต่ solution ที่ตรงไปตรงมาตามโจทย์โดยไม่ได้สนใจว่ามันคิดเป็นสูตรออกมาได้แล้วเร็วขึ้น แล้วเวลา optimize ก็จะ optimize ในมุม engineering มากกว่า science เช่นเขียนเป็นภาษาที่เร็วขึ้น (ซึ่งช่วย เจ็บมาแล้ว…) หรือพยายาม utilize multicore (ซึ่งไม่เคยช่วยได้เลย)

  • Java EE – เรื่องตลกร้ายคือทำงานในบริษัทที่ stack หลักเป็น Spring แต่ Achilles’s heel เราคือเราไม่รู้และไม่คิดจะเรียนรู้มันเลย

    ก็ยังรู้สึกว่ามันปิดกั้นเราอยู่ แต่เห็น indirection และความขัดต่อ KISS ของคนเขียน Java แล้วก็คิดว่าเรียนไปก็คงไม่ได้ทำให้ spark joy ขึ้น

    ความรู้สึกเรากับ Java คือคิดว่า type system ของมันล้าหลังและเป็นปัญหามาก ทำให้ Java community เขียนโค้ดเวอร์วังโดยไม่จำเป็น (ถ้าใช้ภาษาอื่น) หลักๆ ที่นึกออกคือ interface ควรจะเป็น Duck typing และภาษาควรจะมี first class map syntax หรืออย่างน้อยๆ ก็ inline struct creation แบบ C/Go

  • Haskell, Erlang – สองภาษานี้จะแตกต่างกับภาษาอื่นๆ ที่เขียนคือมีแนวความคิดเฉพาะตัว Haskell จะเน้น Functional programming ส่วน Erlang จะเน้น Actor ก็ยังไม่คิดว่าจะได้ใช้ แต่ถ้ารู้ก็อาจจะเอาสิ่งที่เรียนรู้มา adapt ใช้ในการ design แอพภาษาอื่นๆ ได้

  • iOS – เคยพยายามเขียนแอพ iOS อยู่หลายครั้งแต่ก็ยังไม่เก็ตสักที รู้สึกว่าสไตล์ message passing ของ Objective C จะไม่มีภาษาอื่นๆ ที่เป็นที่นิยมใช้เลย

  • Android – เคยเขียนแอพ Android อยู่บ้าง Kotlin ก็เคยเอามาขายสมัยเวอร์ชั่นแรกๆ ก่อนที่ Google จะ adopt แล้วใครๆ ก็ขาย แต่ตั้งแต่ทำงานมาก็ไม่ได้แตะ Android แล้ว คิดว่าความรู้น่าจะเก่าไปแล้ว และมันน่าจะมี design pattern ที่ซับซ้อนแต่เราไม่เคยเขียนเลย เอาง่ายๆ คือไม่เคยเขียน custom widget หรือ RecyclerView เลย

  • Desktop application development – แอพ Desktop ตัวเดียวที่เขียนคือ Juiz (เราไม่นับ Electron เป็น Native เนอะ…) ซึ่งมันใช้ wxWidget อีกที แล้วพอเป็น Python มันก็ใช้งานยากสำหรับคนใช้ Windows เพราะต้องโหลด Python หลายสิบเม็ก คิดว่าเราควรจะรู้การเขียนแอพ Desktop ที่มันใช้งานได้จริงจังสักที ปัญหาคือใน Windows นั้น .NET อาจจะง่ายสุด แต่มันไม่ cross platform เราเลยไม่สนใจมันเพราะงานตอนนี้ไม่ได้ใช้ Windows เลย แต่ภาษาอื่นๆ นั้นก็ดันไปใช้กับ Windows ได้ยากอีก…

    จริงๆ ภาษาแรกที่เขียนคือ Visual Basic ที่เป็น RAD แต่ไม่เคยเขียนอะไรใหญ่ๆ ก็เลยไม่อยากนับ รวมถึง stigma ของภาษานี้ด้วยก็เลยไม่อยากเอามาใช้แล้ว

  • 3D – เคยเขียน WebGL นิดหน่อยสมัยทำ CoreAnime/project Kyou Unity 2D ก็เคยใช้ แต่ให้เขียนเกมอะไรพวกนี้คงไปไม่รอดและคิดว่าต้องศึกษาอีกเยอะมากถึงจะเขียนเกมได้

    รู้สึกว่าเกมมันต้องใช้ Math ด้วยแหละ ถ้าเขียนแบบทื่อๆ เข้าไป FPS เสียหมด

  • CSS Grid – Grid ยังใหม่มากและเรารู้สึกว่า layout อื่นก็แทนกันได้ (ไม่น่าจะจริงหรอก) เลยยังไม่สนใจ ช่วงนี้ยังไม่ค่อยมีโอกาสได้เขียน frontend ด้วยแหละ

  • CSS Methodologies – จะ BEM, OOCSS หรืออะไรก็ไม่เคยสนใจ ตอนนี้ก็ยังตั้งแบบที่คนเขียนเว็บ 10 ปีก่อนทำอยู่ ยังไม่รู้สึกว่าเป็นปัญหา โดยเฉพาะพอมี CSS Module แล้วเลยไม่คิดว่าจำเป็นต้องรู้แล้ว

  • React Hook – ไม่ค่อยได้เขียน frontend แล้ว ก็เลยได้แต่อ่านผ่านๆ ไม่เคยใช้ได้จริง ความเห็นเรากับ hook คือ Facebook กำลังพยายามหาท่า code reuse อยู่หลังจากการทดลอง HOC ล้มเหลวไป สำหรับเราแล้วคำตอบนั้นคือ Inheritance และ Mixin แบบ Python ซึ่งไม่เป็นที่นิยมใน React เราคิดว่า TypeScript น่าจะยิ่งกลบจุดอ่อนของ OOP patterns เหล่านี้ไปได้อีกมาก

    เรารู้สึกว่า React team at Facebook จะปฏิเสธ OOP แล้วพยายามหาทางใหม่ไปเรื่อยๆ เพียงเพราะว่า OOP done wrong มันห่วยมาก ซึ่งเราว่าสุดท้ายจะใช้ท่าไหน done wrong ก็จะแย่ทั้งนั้น

    โค้ด React ใน TipMe ใช้ inheritance บน controller component อยู่ คิดว่าถ้าเขียนเพิ่มอยากจะลองเอา Mixin เข้ามาใช้ดู แต่ยังไงก็ตามก็ควรจะศึกษา industry standard pattern ไว้ด้วยอยู่ดีเพราะเราคงไม่ได้อยู่ในสถานการณ์ที่เป็น team lead ตลอดเวลา

  • Vim – เราไม่ชอบเรียน Hotkey ก็เลยรู้สึกว่าแค่ VS Code ที่ใช้อยู่มันก็มีฟีเจอร์มากกว่าที่ใช้เป็นอยู่มากแล้ว เลยไม่จำเป็นจะต้องเรียน Vim

    เราไม่รู้สึกว่าการเขียนโค้ดโดยไม่จับเมาส์มันจะมีประโยชน์ขนาดนั้น ใช่ มันเท่ และมันอาจจะช่วยให้ productivity สูงขึ้นก็จริง แต่เทียบกับวิธี get productive อื่นๆ แล้วมันน่าจะได้ gain น้อยนิดมาก

    ที่รู้สึกว่า get by เรื่องนี้ได้ด้วยการที่เราพิมพ์ได้ 128 WPM เวลาจะทำอะไรเรียก command palette พิมพ์ชื่อคำสั่งเต็มยังเร็วเลย แต่ก็จะติดปัญหาคือเวลา ssh ไปแล้วไม่มี visual editor ก็ต้องใช้ nano

  • nano text manipulation – ถึงจะบอกว่าใช้ nano แทน vim แต่จริงๆ เราก็ไม่เคยจะสนใจเรียน nano เลยเหมือนกัน… ตอนนี้ที่รู้มากที่สุดคือ ctrl+k cut line, ctrl+u paste line แค่นั้นแต่ถ้าจะ copy paste selection ก็ยังทำไม่เป็น มันกลายเป็นว่าจะแก้อะไรยากๆ ก็ต้องโหลดไฟล์ลงมาแก้ในเครื่อง ซึ่งบางทีก็ไม่ได้ง่ายเพราะ shell เราอาจจะต่อเข้าไปหลายชั้น

  • Shell text manipulation – นอกจากใช้ text editor ไม่เป็นแล้วยังใช้ pipe แก้ text ไม่เป็นด้วย พวกคำสั่ง tr/awk/cut นี่ไม่รู้เรื่องเลย sed ก็ใช้เป็นอยู่แค่ replace ที่จะเก่งหน่อยคือ grep แต่ grep ก็มีท่าพิสดารที่เราไม่รู้อีกเยอะมาก

  • Touch typing – ถึงจะบอกว่าภาษาอังกฤษได้ 128 คำต่อนาที แต่วิธีที่พิมพ์มันไม่ใช่พิมพ์สัมผัสเลย คือมือซ้ายเนื่องจากอยู่กับคีย์บอร์ดตลอดก็น่าจะเรียกว่า touch typing พอได้ แต่มือขวานี่กึ่งๆ hunt and peck แล้วเพราะใช้นิ้วชี้พิมพ์แทบทุกปุ่ม

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

  • C++ – สองเดือนก่อนเขียน ListMap ใน C++ ลง ESP32 พบว่า free ผิดๆ ถูกๆ แล้ว crash อยู่ เขียนอยู่ 4-5 รอบกว่าจะรันได้

    คือ C++ นี่ถามว่าเขียนได้มั้ยก็พอได้นะ แต่เรายังรู้สึกว่า memory management เราทำได้ห่วยมากโดยเฉพาะ RAII ที่คิดว่ายังทำไม่ถูกหลัก แล้วในขั้น advance มันจะมี template ท่ายุบยับอีกที่แค่เห็นก็ไม่อยากอ่านแล้ว

  • Debugging Native Code – เนื่องจากมหาลัยสอน MIPS ก็เลยอ่าน x86 Assembly ไม่เป็นเลย แล้วอุปกรณ์ debug native ก็ใช้ไม่เป็นสักอย่างเลย รวมไปถึงโปรแกรมพวก decompiler ด้วย เคยโหลดมาลองแล้วก็ไม่รู้จะเริ่มตรงไหนเลย

  • OS principles – สุดท้ายแล้ว root ของปัญหาใน CS ก็เป็น algorithm อยู่ดี เช่น OS task scheduler, Semaphore พวกนี้รู้จักแต่ไม่เคยพยายามทำความเข้าใจเลยว่ามันทำงานยังไง (ถึงจะออกสอบก็ตาม)

  • System tuning – เห็นคนสาย sysadmin หลายคนจะชอบจูน sysctl แล้วก็จะมีคนคาดหวังว่าเรารู้วิธีจูนพวกนี้ แต่จริงๆ เราแทบไม่รู้อะไรเลยเพราะว่ารู้สึกว่ามันเป็น cult คนบอกว่าจูนแบบนี้เร็วแล้วทุกคนก็จูนตามๆ กันมาโดยไม่ได้ทำความเข้าใจเลยว่าทำไมมันเร็วขึ้น (แล้วเร็วจริงหรือเปล่า) บางทีมี comment บอกว่าอันนี้ทำแบบนี้ก็คิดว่าเข้าใจโดยไม่ได้ตั้งคำถามว่าแล้วทำไมเค้าตั้งค่าเดิมมาแบบนั้น ครั้นจะไปศึกษาก็พบว่า tunables ของ kernel มีเยอะมาก ไม่รู้จะปรับอะไรก่อนดี และมันต้องปรับในสภาวะที่มี load จึงจะเห็นผลชัดเจน แต่จะไปปรับใน production ก็ไม่ควร สุดท้ายเลยไม่ทำอะไรเลย

    สมัยหนึ่งก็เลย assume ว่าจริงๆ kernel dev เค้ารู้มากกว่าเรา มันควรจะ tune มาแล้ว มีแต่คนที่อยาก footgun เท่านั้นแหละที่อยากปรับ แต่ก็มารู้ไม่นานว่าจริงๆ แล้วไม่ใช่ หลายๆ ค่าเลือกมาเพราะมันเป็นค่า legacy มากกว่า และอุปกรณ์ที่รัน Linux kernel มีเยอะมากตั้งแต่บอร์ดเล็กๆไปจนกระทั่ง server ขนาดใหญ่ มันไม่มี config อันไหนที่ใช้ได้ทุกขนาด

  • On Premises Infrastructure – เราถูก Cloud สอนให้เสียนิสัย บางครั้งเวลาไปบรรยายก็จะมีคนถามว่าผมจะเอา Docker/Kubernetes ไปลงแต่เป็น on prem จะทำอย่างไร ก็ไม่รู้จะตอบเค้าอย่างไรเพราะไม่เคยมีโอกาสได้ทำ on prem ในสเกลเท่ากับที่ใช้บน Cloud

    จริงๆ คิดว่า Cloud สอนให้เสียนิสัยอีกอย่างหนึ่งคือมันพยายามให้เราออกแบบระบบที่ overkill มากๆ เช่น 1 เครื่อง 1 application ซึ่งทำได้เพราะเราสามารถซื้อเครื่องเล็กมากๆ ได้ แต่พอทำแบบนั้นแล้วก็จะเริ่มเกิดปัญหาซับซ้อนตามมา เช่น Autoscaling, Service discovery, Load balancing ซึ่งเค้าก็จะมาเสนอขายต่อไปอีก ในขณะที่ on prem นั้นคงจะใช้เครื่องใหญ่ตั้งแต่แรกอยู่แล้ว ปัญหาพวกนี้จะมาเกิดก็ต้องมี scale จริงๆ

    นอกจากนี้คิดว่า networking ของ on prem ก็น่าจะมีปัญหาอื่นๆ อีกมากมายที่เราถูก VPC ทำให้เสียนิสัยไปหมดแล้ว

  • Database Operation – ตอนนี้คิดว่า SELECT ท่ายากก็เขียนได้แล้ว หรือ Index optimization ก็พอเข้าใจ ซึ่งพวกนี้เป็นสกิลฝั่ง Developer แต่ในฝั่ง Ops แล้วคิดว่าเราไม่รู้วิธี operate database เลย เช่น Postgres จะต้องรัน VACUUM และ ANALYZE ซึ่งก็ไม่เคยทำเลย

    ทุกวันนี้ก็เลยใช้แต่ managed database ตลอด เพราะเรารู้ว่าเราไม่รู้และ data บนนั้นสำคัญมากเลยยอมจ่ายแพงเพื่อแก้ปัญหาไป (ตอนนี้ค่า database server ของ TipMe แพงกว่า infra ที่เหลือทั้งหมดซะอีก เพราะจุดที่เหลือเรา optimize cost ได้) ข้อดีของ managed database คือมันมี autobackup, failover, replication และ point in time recovery ให้ด้วย พวกนี้ให้ทำเองก็ทำไม่เป็นหรอก backup แล้วเปิดกลับมาไม่ได้ข้อมูลหายหมดก็เคยทำมาแล้ว 555

  • Database Admin – อีกมุมนึงของ Database คือมันมีคำสั่งบางพวกที่ Application dev เมินไปเลย เช่น Stored procedure, triggers ซึ่ง DBA บางคนก็บอกว่าปัญหาที่เราพยายามแก้ใน application code น่ะ ใช้พวกนี้แก้แล้วจะได้ผลดีกว่าเยอะเลย แต่คิดว่าในฝั่ง Ops อาจจะเจอว่ามัน deploy, control ยุ่งยากกว่า

    ตอนนี้ก็เห็นความจำเป็นต้องใช้อยู่บ้างนะ แต่นโยบายเราตอนนี้คือแอพที่ใช้ ORM ควรจะไม่ใช้ database specific features เพื่อให้ setup dev environment ง่าย ก็เลยเลี่ยงจะไม่ใช้พวกนี้เลย

  • TCP/UDP internals – TCP นี่พอเข้าใจได้ไม่ยาก ฝั่งหนึ่งส่งฝั่งหนึ่งรับ จบ แต่จังหวะ Handshake ไม่เคยนั่งจำ รวมไปถึง SSL handshake ด้วย

    UDP นี่ยังไม่รู้เลยว่าตกลงมันส่ง data ได้มากสุดเท่าไรที่อีกฝั่งจะ read ได้เลย คือเวลาเราใช้ UDP เราพยายามคิดว่ามันเป็น frame เหมือน WebSocket แต่ในความจริง UDP packet ไม่ได้ reliable ขนาดนั้น (รวมถึงมันจะโดน network fragmentation) แล้วเราก็เลยไม่รู้ว่าเราควรจะทำอย่างไร ตอนนี้ก็เลยรู้อย่างเดียวว่าอย่าส่งอะไรเยอะๆ ไปทาง UDP แล้วมันน่าจะ read ได้เป็น frame เอง…

  • GraphQL – เราต่อต้าน GraphQL มาสักพักเพราะมันขัดต่อหลายๆ หลักที่เราเชื่อ เช่น Infra ก็จะใช้ nginx ทำ rate limit ไม่ได้แล้วเพราะมันเป็น endpoint เดียว แถม Security ก็ยุ่งยากขึ้นเยอะ แต่ตอนหลังพอเปิดใจแล้วก็พบว่ามันแก้ปัญหาใน Frontend และปัญหา microservice API Gateway ของ backend ได้ดีมาก เลยทำให้ Dev ที่ไม่เข้าใจ/ไม่สนใจมุมอื่นๆ ชอบ

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

  • API Gateway – API Gateway ก็มีอยู่หลายเจ้า เช่น Loopback หรือ Kong แต่เนื่องจากวงในเขียน API Gateway เองไปแล้วก็เลยไม่เคยได้ลองเล่นของคนอื่นสักตัว เท่าที่ศึกษาผ่านๆ ก็ยังไม่เห็นว่า API Gateway แบบที่คนอื่นเค้าทำมันใช้งานยังไง แล้วทำไมเค้าแก้ปัญหาบางอย่างที่ layer นี้ เรื่องนี้ก็มีคนถามอยู่บ้างเหมือนกัน ก็ได้แต่บอกว่าเรา custom ไปแล้วช่วยแนะนำอะไรไม่ได้


จากที่เขียนมารู้สึกว่าจะต่างกับของคนอื่นๆ คือหลายๆ เรื่องมันเป็นเรื่องที่เราเลือกที่จะไม่รู้เพราะ reject ความคิด mainstream ออกไป ก็เป็นความเสี่ยงพอสมควรว่าการเลือกแบบนี้มันจะยังถูกต้องใน long run มากน้อยแค่ไหน

อีกจุดหนึ่งคือเราไม่ใช่คนชอบอ่านหนังสือ ปีที่แล้วรู้สึกว่าไม่ได้อ่านหนังสือ physical เลยสักเล่ม

เหตุผลคือเวลาจะอ่านอะไรมันต้องดึงเราเข้าไป ซึ่งบทความในเว็บมันง่ายเพราะคอมพิวเตอร์ดึงเราอยู่หน้าจอไปแล้ว 50% แต่การอ่านหนังสือเป็นเล่มมันต้องมีเหตุผลว่าทำไมเราอยากจะเปลี่ยนไปใช้ format ที่ไม่สะดวกด้วย

และอีกอย่างหนึ่งคือวิธีที่เราเรียนไม่ได้เกิดจากการอ่านหนังสือหรือเรียนในห้อง อ่านหนังสือแล้วสิ่งเดียวที่จำได้คือ Trivia ต่างๆ ที่เอาไปอวดรู้กับชาวบ้านได้ ยิ่งเรียนในห้องนี่หลับเลย แต่ skill จริงๆ มันเกิดจากประสบการณ์ใช้งานจริงเท่านั้น

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

โชคดีว่างานที่ทำมันทำให้เราได้เรียนอะไรใหม่ๆ ตลอดเวลาที่ทำ เราเห็นบางคนมาสัมภาษณ์งานกับเราแล้วก็บอกว่าเทคโนโลยีใหม่ๆ ไม่รู้เรื่องเลย เพราะบริษัทไม่ได้ใช้ ก็รู้สึกเสียดายเพราะเค้ากำลังจะพาตัวเองออกจากตรงนั้นแต่ skill bar ฝั่งเราก็สูงจนเค้าก็ต้องกลับไปอยู่ตรงนั้น