- บันทึกเทคโนโลยีที่เลือกใช้เมื่อ 2 ปีก่อนเพื่อสร้างแอปมือถือ/เว็บ/แบ็กเอนด์ พร้อมทั้งทบทวนผลลัพธ์ของการตัดสินใจเหล่านั้น
- เป็น SaaS ทั่วไปที่เรียบง่ายมาก จึงตั้งเป้าให้บูตสแตรปได้เร็วที่สุดด้วยแรงและทรัพยากรให้น้อยที่สุด
ด้วยข้อจำกัดด้านความสามารถในการออกแบบ จึงไม่ได้พัฒนาแอปมือถือเองแต่จ้างภายนอก และพัฒนาเฉพาะแบ็กเอนด์กับเว็บ
ตัวเลือกเทคโนโลยี
แอปมือถือ
- แม้จะเป็นนักพัฒนา .NET มายาวนาน แต่ก็ไม่ได้อยากพัฒนาด้วย Xamarin
- เลือก Flutter เพื่อรองรับ iOS/Android พร้อมกัน
- ภายในไม่กี่สัปดาห์ก็ได้แอปที่ทำงานได้บนทั้งสองแพลตฟอร์ม จึงยอดเยี่ยมมากในมุมมอง Time to Market
- UI มีข้อบกพร่องอยู่บ้างเล็กน้อย แต่สำหรับยูสเคสแบบ B2B อย่างเรา ก็ถือว่ามองข้ามได้
- ตัว Flutter เองมีบั๊กและปัญหาอยู่มาก แต่ไม่ถึงขั้นเป็น show-stopper
- Dart ในฐานะภาษาไม่ค่อยถูกใจนัก แต่ก็ไม่ใช่ปัญหา (เพราะยังไงผมก็ไม่ได้เป็นคนพัฒนาเอง)
- การยึด Xamarin ต่อไป หรือเลือก React Native อาจจะดีกว่าก็ได้
API
- สเกลไม่ใช่สิ่งสำคัญ เพราะแค่ให้บริการกับลูกค้ากลุ่มแรกเพียงบางส่วนก็พอ
- ดังนั้นจึงมองข้าม Kubernetes/serverless ทั้งหมด แล้วพัฒนาเป็น monolith ตรง ๆ
- เป็นแอป .NET เดี่ยวแต่แยกโมดูล ใช้ F# เขียนโค้ด และตามสถาปัตยกรรม Onion (แพตเทิร์น Ports & Adapters)
- มองข้ามของอย่าง GraphQL แล้วใช้วิธี REST แบบดั้งเดิมแทน
- ผลลัพธ์
- API แข็งแรงและเร็วมาก ระหว่างการดีพลอยแทบไม่เกิดปัญหาเลย
- แม้จะพิสูจน์ไม่ได้ แต่คิดว่าความสำเร็จส่วนใหญ่เกิดจากแนวทาง "Applied Functional Programming" ที่ผมใช้
- อีกทั้งโค้ด F# ก็สวยงาม อ่านง่าย และทำความเข้าใจง่ายมาก
- เนื่องจากพึ่งพาไลบรารีโอเพนซอร์สจำนวนน้อยมาก การที่ ecosystem ของ F# ค่อนข้างเล็กและเคลื่อนไหวช้าจึงไม่ใช่ปัญหา
Persistence
- แม้จะใช้ SQL Server มานาน แต่ไม่อยากจ่ายค่าไลเซนส์ให้ฐานข้อมูล
- จึงเลือก PostgreSQL และให้ API ใช้งานผ่าน DB server ตัวเดียว พร้อมมีกลไกคิวเล็กน้อย
- เมื่อโปรดักต์เริ่มต้องการ BLOB storage ก็เลยตัดสินใจใช้ file system ของเซิร์ฟเวอร์ไปเลย
- ผลลัพธ์
- มันใช้งานได้เลยแบบตรงไปตรงมา (It just works) การใช้ Postgres เป็นเรื่องที่น่าพอใจ
- ชนิดข้อมูล JSONB เปิดให้ใช้เทคนิคแบบ relational ผสมกับ NoSQL ได้อย่างมั่นคงและสบายใจมาก
- แต่คงไม่จำเป็นต้องท่องจำไวยากรณ์การ query JSON
- การเก็บ BLOB ลงดิสก์ตรง ๆ เป็นการตัดสินใจใหญ่ แต่การใช้สิ่งอย่าง AWS S3 ก็คงไม่ได้ช่วยอะไรมากนักเมื่อมีผู้ใช้น้อย
Web App
- การตัดสินใจด้านเทคโนโลยีสำหรับเว็บแอปใช้เวลาค่อนข้างนาน
- สัญชาตญาณบอกให้เลือก Fable กับ F# แต่สุดท้ายก็ตัดสินใจใช้ React และ TypeScript เพื่อสร้าง SPA
- หนึ่งในการตัดสินใจสำคัญช่วงแรกคือการนำ Tailwind CSS มาใช้
- ผลลัพธ์
- React ก็ใช้งานได้ดี TypeScript ก็ใช้งานได้ดี
- เช่นเดียวกับ Dart ผมไม่ได้ชอบเขียน TypeScript มากนัก และก็ไม่ได้ชอบอ่านมันเท่าไร
- แต่ TS ก็มีฟีเจอร์ที่ยอดเยี่ยมอยู่ เช่น discriminated unions ที่อยากให้ F# มีเหมือนกัน
- โดยรวมแล้วประสบการณ์นักพัฒนายอดเยี่ยม เวลา build สั้นมาก (เมื่อเทียบกับ F#) และสำหรับปัญหา UI ซับซ้อนส่วนใหญ่ก็มีแพ็กเกจรองรับอยู่แล้ว
- แม้มองจากมุมของ functional programming โมเดลแอปพลิเคชันโดยรวมของ React ก็ยังเข้าใจได้
- Tailwind CSS ช่วยลดภาระได้มหาศาล
Infrastructure
- เมื่อตัดสินใจจะไปทาง monolith แล้ว การเลือกจึงง่ายขึ้น
- เช่าเครื่อง Linux จาก Hetzner แล้วรัน Docker container 3 ตัว: Postgres, DotNet API, Nginx
- ทุกอย่างถูก build ด้วย GitHub Actions และ deploy อัตโนมัติ
- ผลลัพธ์
- หาก deploy ฝั่งไคลเอนต์และแบ็กเอนด์พร้อมกันจะมี downtime แต่ตอนนี้สั้นมากและมองข้ามได้
- กระบวนการทั้งหมด lean และเสถียร โครงสร้างต้นทุนก็เช่นกัน Hetzner ถูกมากจริง ๆ
สรุป
- พอใจกับการตัดสินใจในปัจจุบันมาก
- ลงทุนกับ F# และงานสาย functional programming ในสเกลที่กว้างกว่าโปรเจกต์ก่อนหน้า
- สำหรับโปรเจกต์หนึ่ง มีภาษา F#, TypeScript, Dart ถึงสามภาษาก็ดูจะมากไปหน่อย
แม้ Dotnet MAUI จะยังไม่สุกงอมเท่า Flutter แต่ก็น่าจะเป็นตัวเลือกได้แทนการใช้ภาษาอื่นที่ไม่ได้ใช้บ่อย
3 ความคิดเห็น
ในระยะยาว จะจัดหาบุคลากรได้อย่างราบรื่นหรือไม่?
นั่นน่าจะเป็นบริการที่ดำเนินการคนเดียว คิดว่าน่าจะเลือกทางที่ตัวเองดูแลรักษาได้สะดวกมากกว่าการพึ่งกำลังคน
แม้จะมีบางส่วนที่ไม่ค่อยเข้ากับผมอยู่บ้าง.. แต่ก็ดูเหมือนว่าเป็นตัวเลือกที่ค่อนข้างใช้งานได้จริงและเหมาะกับคนนี้ในแบบของเขาเองครับ