สิ่งที่นักพัฒนาน่าจะต้องรู้สำหรับการพัฒนาระบบงานในปัจจุบัน
นั่นก็คือ The Twelve Factor App
ซึ่งเป็นคำแนะนำสำหรับการพัฒนาระบบที่ดี โดยเฉพาะ Cloud Native App
มีเป้าหมายเพื่อ

  • Portability ระหว่าง environment ต่าง ๆ
  • Scale ได้ง่ายทั้งขยายและลด
  • ลดค่าใช้จ่ายและเวลาด้วยการทำงานแบบอัตโนมัติ
  • Continuous Deployment

สามารถนำมาปรับใช้กับระบบอื่น ๆ ได้
ดังนั้นมาดูกันดีกว่า ว่ามีอะไรบ้าง ?

Factor 1 : Codebase

One codebase tracked in revision control, many deploys

นั่นคือ codebase ของระบบ
ต้องถูกจัดการ version ใน Version Control System (VCS)
โดยที่ 1 codebase อาจจะหมายถึง 1 ระบบ หรือ service/process ก็ได้
หัวใจของข้อนี้คือ การจัดการ version ของ source code
และสามารถ deploy ได้ตลอดเวลา ในทุก ๆ environment

Factor 2 : Dependencies

Explicit declare and isolate dependencies

เป้าหมายของข้อนี้คือ การแยก dependency ต่าง ๆ ออกมาจากระบบงาน
เพื่อลดปัญหาเรื่องของ dependency hell
ทำให้สามารถ deploy ระบบงานได้บ่อยและง่ายขึ้น

โดยที่การแยก dependency ออกมามีหลายแบบเช่น
Developer ทำการกำหนดไว้ในการ build process ของการพัฒนา
Platform ทำการกำหนดไว้ที่ platform ที่จะ deploy เลย

ยกตัวอย่างของ Spring boot
ปกติจะ embedded runtime ให้เลย
แต่เราก็สามารถเอาออกไปได้เช่นกัน
ถ้า runtime นั้นถูกเตรียมจาก platform ที่จะติดตั้ง

Factor 3 : Config

Store the config in the environment

ก่อนอื่นมาดูก่อนว่า configuration มีอะไรบ้าง ?

  • ข้อมูลการใช้งาน database และ service ต่าง ๆ
  • พวก credential สำหรับการติดต่อไปยังระบบข้างนอก
  • สิ่งที่ต้องกำหนดสำหรับการ deploy ในแต่ละ environment
  • อะไรก็ตามที่ต้องเปลี่ยนแปลงในแต่ละ environment เช่น dev, test, staging และ production เป็นต้น

ที่สำคัญระบบงานของเราต้องไม่เก็บ configuration ต่าง ๆ ไว้ใน

  • Code
  • Properties file
  • Build process
  • Application/Web server

ดังนั้นจึงแนะนำให้เก็บไว้ใน Environment variable ของเครื่องที่จะ deploy ไปเลย
หรือในระบบ cloud สามารถจัดเก็บไว้บน Cloud configuration ก็ได้ (Centralize configuration)

ยกตัวอย่างการใช้งานใน Spring Boot app

Factor 4 : Backing service

Treat backing services as Attached resources

Service ต่าง ๆ ต้องสามารถเข้าถึงได้ง่าย
เช่นด้วยชื่อ ด้วย url
ที่สำคัญต้องสามารถ้แลี่ยนแปลงได้ง่ายอีกด้วย
แน่นอนว่าต้องทำงานร่วมกับ Factor 3 : Config ด้วย

ยกตัวอย่างเช่นการใช้งาน docker compose

ทำให้แต่ละ service อ้างอิงกันด้วยชื่อในทุก ๆ environment
ซึ่งส่งผลดีต่อทุกฝ่าย
ที่สำคัญไม่ต้องมาแก้ไข configuration กับทุก ๆ environment

Factor 5 : Design, Build, Release, Run

Strictly separate stages

ปกติจะแยกเป็น stage ดังนี้

  • Design/Develop นักพัฒนาจะเป็นคนทำในส่วนนี้ ว่าใช้เครื่องมืออะไรบ้าง มี dependency อะไรบ้าง
  • Build ในส่วนนี้จะเป็นหน้าที่ของ Continuous Integration Server ทำการ build/compile/package โดยผลที่ได้เช่นไฟล์ EAR/WAR/JAR ซึ่งสามารถนำไป deploy ต่อไป
  • Release เป็นขั้นตอนในการ release เช่นการสร้าง image เพื่อใช้ในการสร้าง container ต่อไป
  • Run เป็นขั้นตอนในการ run หรือสร้าง container จาก image ที่ต้องการ ซึ่งมีความเร็วสูงมาก ๆ

เมื่อเราแยก stage ออกมาได้แล้ว
เราต้องออกแบบ pipeline ของการทำงานในรูปแบบอัตโนมัติ
เพื่อให้ได้รับ feedback ได้อย่าวรวดเร็วเมื่อมีการเปลี่ยนแปลง
ซึ่งเราเรียก pipeline นี้ว่า Deployment pipeline
ยกตัวอย่างเช่น

  1. Commit code/test
  2. Run unit test
  3. Run integration test
  4. Create and keep deployable artifact
  5. Deploy to Dev environment
  6. Run UI/Acceptance test
  7. Deploy to Test environment
  8. Deploy to Production environment

Factor 6 : Processes

Execute the app as one or more stateless processes

นี่คือแนวคิดของ Microservice คือ Design for Failure
เราไม่กลัวว่าระบบจะ failure
เนื่องจากความเร็วของการ deploy ของ app เร็วเหมือนกับ process
ที่สำคัญมีการทำงานแบบ stateless
ทำให้สามารถ scale ได้ง่ายขึ้น
และเมื่อเกิดปัญหาขึ้นมาก็สามารถเอาของเก่ากลับคืนมาได้อย่างรวดเร็ว

ซึ่งเรื่องนี้คือ ความเจ็บปวดของการ deploy ระบบ !!

Factor 7 : Port Binding

Export services via port bindings

นี่คือแนวคิดของ containerization เลย
นั่นคือระบบงานทำการ deploy ในรูปแบบ container
โดยในแต่ละเครื่องสามารถมีได้มากกว่า 1 container
จากนั้นเครื่องหลักหรือ host ของเราต้องสามารถจัดการเรื่อง port binding ได้
ซึ่งอาจจะต้องมี service มาช่วยเช่น load balance/routing เป็นต้น

Factor 8 : Concurrency

Scale out via the process model

จากข้อ 6 และ 7 นั้นช่วยทำให้เราสามารถ scale ระบบได้ง่ายขึ้น
และทำการ scale เฉพาะส่วนที่ต้องการได้ เช่น frontend, backend, database และ queue เป็นต้น

Factor 9 : Disposability

Maximize robustness with fast startup and graceful shutdown

สิ่งที่น่าสนใจคือ
เราไม่สามารถทำการ scale, deploy, release และ recovery ได้เร็ว
ถ้าไม่สามารถ start service หรือระบบได้อย่างรวดเร็ว

อีกเรื่องของการ shutdown มันต้องคืน resource ต่าง ๆ ก่อน shutdown เสมอ
มิเช่นนั้นจะไม่สามารถ start ใหม่ได้เลย เช่น
connection ของ database ?
มี job รอทำงานหรือกำลังทำงานของ service/process นั้นหรือไม่ ?
ไม่เช่นนั้นระบบพังแน่นอน !!

Factor 10 : Dev/Prod parity

Keep development, staging and production as similar as possible

เมื่ออ่านข้อนี้แล้ว อาจจะบอกว่าเราทำไม่ได้หรอกนะ !!
ด้วยเหตุผลร้อยแปด
แต่ถ้าทำได้ มันจะช่วยลดปัญหาต่าง ๆ ไปมากมาย
ที่สำคัญ Twelve Factor App นั้นออกแบบมาเพื่อ Continuous Deployment
ดังนั้นถ้า environment ต่าง ๆ ไม่เหมือนกันแล้ว
ก็อาจจะทำให้การ deploy พังบ่อยก็ได้
หรือเกิดปัญหาที่ไม่สามารถคาดเดาได้เลย

ดังนั้นแต่ละ environment ควรเหมือนกันให้มากที่สุด
เนื่องจากมันควรเหมือนกันเท่านั้นเอง

ถ้าไม่เหมือน ก็ทำให้เหมือน แค่นั่นเอง

Factor 11 : Logs

Treat logs as Event streams

เราคงต้องเก็บ log ของระบบตามแต่ละระบบไป
โดยที่ Log นั้นต้องการสามารถเปลี่ยน configuration ได้ง่ายตาม Factor ที่ 3

Factor 12 : Admin processes

Run admin/management processes as one-off processes

มี process สำหรับการจัดการการ release ต่าง ๆ
จะมีชุดคำสั่งหรือ command ต่าง ๆ ให้ใช้งาน
สามารถใช้งานได้ในทุก ๆ environment เช่น

  • Database migration
  • REPL shell (Read Eval Print Loop) สำหรับการ run code บน environment
  • ทำการ run คำสั่ง adhocs ต่าง ๆ เช่น fix bug และแก้ไขข้อมูล

ยังมีเพิ่มเติมจาก 12 ข้อข้างต้นอีกนะ ประกอบไปด้วย

  • การ Audit
  • การ Authentication และ Authorization
  • API-first

สุดท้ายและท้ายสุด

ลองกลับมาดูระบบงานของเราสิว่า
เมื่อมาตรวจสอบด้วย Twelve Factor App แล้วเป็นอย่างไรบ้าง ?

ขอให้สนุกกับการ coding ครับ

Reference Websites
https://www.infoq.com/presentations/12factor-spring
https://dzone.com/articles/the-12-factor-app-a-java-developers-perspective