The Twelve-Factor App ในปี 2011
(12factor.net)- The Twelve-Factor App คือแนวทางสำหรับการดำเนินงานและขยายเว็บแอป·SaaS ในระยะยาว โดยครอบคลุมทั้งการทำงานอัตโนมัติของการตั้งค่า ความสามารถในการพกพา การดีพลอยบนคลาวด์ และการดีพลอยอย่างต่อเนื่อง
- ไม่ยึดติดกับการผสมผสานของ ภาษาโปรแกรม ใดภาษาโปรแกรมหนึ่ง หรือ บริการสนับสนุน เช่น ฐานข้อมูล คิว หรือเมมโมรีแคช จึงสามารถนำไปใช้กับแอปพลิเคชันแบบบริการได้อย่างหลากหลาย
- ตั้งอยู่บนพื้นฐานของประสบการณ์จากการมีส่วนร่วมโดยตรงในการพัฒนา·ดีพลอยแอปหลายร้อยตัวบนแพลตฟอร์ม Heroku และการสังเกตการพัฒนา·การดำเนินงาน·การขยายตัวของแอปหลายแสนตัวโดยอ้อม
- ประเด็นสำคัญคือการมอบคำศัพท์ร่วมที่ช่วยลดต้นทุนการทำงานร่วมกันและการสึกกร่อนของซอฟต์แวร์เมื่อแอป เติบโตแบบเป็นธรรมชาติ
- ไม่เพียงแต่นักพัฒนาที่สร้างแอปพลิเคชันแบบบริการเท่านั้น แต่ยังใช้เป็นมาตรฐานเชิงปฏิบัติสำหรับวิศวกรปฏิบัติการที่นำไปดีพลอยและดูแลจัดการได้ด้วย
หลักการดำเนินงาน 12 ข้อสำหรับแอป SaaS
- ซอฟต์แวร์สมัยใหม่มักให้บริการในรูปแบบ เว็บแอป หรือ SaaS และ Twelve-Factor App คือแนวทางสำหรับการสร้างแอปพลิเคชันลักษณะนี้
- เป้าหมายคือทำให้กระบวนการพัฒนา·ดีพลอย·ดำเนินงานของแอปคาดการณ์ได้มากขึ้น
- ใช้ การทำงานอัตโนมัติของการตั้งค่าแบบประกาศชัดเจน เพื่อลดเวลาและต้นทุนเมื่อมีนักพัฒนาใหม่เข้าร่วมโปรเจกต์
- สร้างข้อตกลงที่ชัดเจนกับระบบปฏิบัติการพื้นฐาน เพื่อเพิ่ม ความสามารถในการพกพา ระหว่างสภาพแวดล้อมการรัน
- ออกแบบให้ลดภาระของการดูแลเซิร์ฟเวอร์และระบบ และเหมาะกับการดีพลอยบน คลาวด์แพลตฟอร์ม สมัยใหม่
- ลดความแตกต่างระหว่างสภาพแวดล้อมพัฒนาและโปรดักชัน เพื่อให้เกิด การดีพลอยอย่างต่อเนื่อง
- ทำให้สามารถขยายได้โดยไม่ต้องเปลี่ยนเครื่องมือ สถาปัตยกรรม หรือแนวปฏิบัติการพัฒนาอย่างมาก
- ขอบเขตการใช้งานไม่ได้จำกัดอยู่กับเทคโนโลยีสแตกเฉพาะ
- ใช้ได้กับแอปที่เขียนด้วยภาษาโปรแกรมใดก็ได้
- บริการสนับสนุนครอบคลุมฐานข้อมูล คิว เมมโมรีแคช เป็นต้น
ภูมิหลังที่สรุปจากประสบการณ์ของ Heroku
- ผู้มีส่วนร่วมได้มีส่วนเกี่ยวข้องโดยตรงกับการพัฒนา·ดีพลอยแอปหลายร้อยตัวบนแพลตฟอร์ม Heroku และสังเกตการพัฒนา·การดำเนินงาน·การขยายตัวของแอปหลายแสนตัวโดยอ้อม
- ได้สรุปแนวปฏิบัติอันเหมาะสมสำหรับการพัฒนาแอปจากประสบการณ์และการสังเกตที่ได้จากแอป SaaS จริง
- ให้ความสำคัญกับกระแสที่แอป เติบโตแบบเป็นธรรมชาติ เมื่อเวลาผ่านไป
- กล่าวถึงวิธีที่นักพัฒนาหลายคนทำงานร่วมกันบนโค้ดเบสเดียวกัน
- มอง การหลีกเลี่ยงต้นทุนจากการสึกกร่อนของซอฟต์แวร์ เป็นเป้าหมายสำคัญ
- รูปแบบได้รับแรงบันดาลใจจาก Patterns of Enterprise Application Architecture และ Refactoring ของ Martin Fowler
12 องค์ประกอบ
- I. Codebase: มีโค้ดเบสเดียวที่อยู่ภายใต้การควบคุมเวอร์ชันและมีหลายการดีพลอย
- II. Dependencies: ประกาศและแยกการพึ่งพาอย่างชัดเจน
- III. Config: เก็บการตั้งค่าไว้ใน environment
- IV. Backing services: ปฏิบัติต่อบริการสนับสนุนเสมือนเป็นทรัพยากรที่เชื่อมต่ออยู่
- V. Build, release, run: แยกขั้นตอน build กับขั้นตอน run ออกจากกันอย่างเคร่งครัด
- VI. Processes: รันแอปเป็นหนึ่งหรือหลายโปรเซสแบบไร้สถานะ
- VII. Port binding: ให้บริการแก่ภายนอกผ่านการ bind พอร์ต
- VIII. Concurrency: scale-out ด้วยโมเดลโปรเซส
- IX. Disposability: เพิ่มความทนทานด้วยการเริ่มต้นที่รวดเร็วและการปิดระบบอย่างนุ่มนวล
- X. Dev/prod parity: รักษาให้ development, staging, production ใกล้เคียงกันมากที่สุด
- XI. Logs: ปฏิบัติต่อ log เสมือนเป็นสตรีมของเหตุการณ์
- XII. Admin processes: รันงานดูแลระบบเป็นโปรเซสแบบครั้งเดียว
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
12-Factor App เป็นแนวทางแนะนำที่สร้างขึ้นในปี 2011 โดยอิงกับ Heroku และข้อจำกัดของโครงสร้างพื้นฐานแบบคอนเทนเนอร์ในยุคนั้นมากกว่า ไม่ได้ดูเหมือนเอกสารที่ตั้งอยู่บนหลักวิศวกรรมอย่างลึกซึ้ง
เช่น ข้อเสนอที่ว่าให้ใส่การตั้งค่าไว้ใน environment variables นั้นเป็นเพราะผู้เขียนทำงานที่ Heroku และ Heroku ใช้วิธีเติม environment variables ผ่านช่องอินพุตของเว็บแอป
ถ้าคุณอยากติดตามประวัติการตั้งค่าด้วย version control, ใช้ GitOps, ใช้ k8s ConfigMap หรือวางไฟล์ตั้งค่าไว้บน mounted volume ทั้งหมดนี้โดยรวมก็เป็นตัวเลือกที่ใช้ได้ เพราะช่วยแยกสถานะของการตั้งค่าออกจากสถานะการ deploy ของแอป
ผมมองว่าเอกสารนี้สับสนระหว่างภาพรวมกับรายละเอียด และแนะนำสิ่งที่เข้ากับฟีเจอร์ของผลิตภัณฑ์ของบริษัทผู้เขียนมากกว่าหลักวิศวกรรมจริง ๆ จึงเป็น แนวทางที่เป็นอันตราย
ถ้าต้องการจัดเก็บการตั้งค่าอย่างปลอดภัยใน Kubernetes สุดท้ายก็ต้องใช้ Secrets ซึ่งมีรูปแบบ key-value คล้าย environment variables หากต้องการความปลอดภัยแบบเดียวกันใน Git ก็ต้องมีชั้นการเข้ารหัส และนั่นทำให้การเปรียบเทียบ diff พังลง รวมถึงต้องใช้เครื่องมือเพิ่มเติม
สุดท้ายก็วนกลับมาที่เหตุผลว่าทำไมเครื่องมือ deploy ระดับสูงอย่าง Heroku ถึงถูกสร้างขึ้นมา
หลักการที่ว่าควรจัดการ log เป็น stream ยังถูกต้องอยู่ ให้เขียน log ไปที่ STDOUT ไม่ใช่ไฟล์ แล้วให้ออร์เคสเตรเตอร์อ่านและจัดเก็บ
การตั้งค่ามาจาก environment แอปมักอ่านการตั้งค่าจากแหล่งที่ต่างกันตามวิธี deploy เช่น ในเครื่องใช้ .env ส่วน production ใช้ secret store
port binding ก็เช่นกัน แอปเปิดพอร์ต แล้ววางของอย่าง nginx ไว้ด้านหน้าเพื่อทำ reverse proxy ส่วน K8S service และ ingress ทำหน้าที่นั้น
คำวิจารณ์ใหญ่ที่สุดที่พูดได้กับ 12-Factor ในปัจจุบันคือ เอกสารถูกเขียนไว้ไม่ดีนัก และเหมือนสมมติว่าผู้อ่านรู้อยู่แล้วอย่างแม่นยำว่ากำลังพูดถึงอะไร
แต่ก็ยอมรับว่า Heroku มีเครดิตในการทำให้แนวคิดนี้เป็นที่รู้จักกว้างขวางและแพร่หลาย
ไม่ใช่วิธีเพิ่ม settings.json ลงในเครื่องก่อนเริ่มแอป แต่เป็นแนวทางที่ว่า ถ้า source เดียวกันถูก deploy ไปยังคลัสเตอร์ AKS ของ Azure EU north ก็ใช้ค่าที่ตั้งไว้ในคลัสเตอร์นั้น และถ้า deploy ไปยังคลัสเตอร์ RPi Zero Docker Swarm ในกรอบรูป Ikea ก็ใช้การตั้งค่าของคลัสเตอร์นั้น
ชื่อคลัสเตอร์นั้นเรียกว่า Gibson
ผมรู้สึกว่าแต่ละข้อนี้สามารถโต้แย้งได้ค่อนข้างสมเหตุสมผล
ข้อแรก หลักการที่ว่าแอปหนึ่งตัวต่อ repository หนึ่งตัวไม่ได้ผิดในระดับพื้นฐาน ถ้ามีหลายแอปที่ผูกกันแน่นในเชิงฟังก์ชันและใช้ release cycle ร่วมกัน แต่ต้อง deploy แยกกันเพื่อให้ได้ข้อดีของการเป็น process แยกและ scale ได้อิสระ ก็ไม่ได้มีปัญหาอะไรที่จะพัฒนาแอปเหล่านั้นใน repository เดียวกัน ตัวอย่างที่นึกถึงคือการแยก public API กับ worker process เช่น Sidekiq ของ Ruby, Celery ของ Python หรือ consumer ของ Kafka ทั่วไป
ข้อสอง คำว่า “12-Factor app ไม่พึ่งพาการมีอยู่โดยนัยของแพ็กเกจระดับระบบ” นั้นในทางปฏิบัติทำได้ยากมากถ้าไม่ได้ใช้ของอย่าง Nix dependency ต่อ API ของ system call ใน kernel ก็ยังรั่วออกมา และแอป Rust ส่วนใหญ่ก็พึ่งพา glibc โดยนัย ยกเว้นกรณีใช้ musl ซึ่งมีอยู่ใน Linux distribution หลัก ๆ ถ้าไม่นับ distribution แบบ slim อย่าง Alpine ผมมองว่าเครื่องค้ำอย่าง Docker ก็จำเป็นเพื่อบรรเทาปัญหานี้
ข้อสาม การเก็บการตั้งค่าไว้ใน environment variables ดูเปราะบางกว่า อาจลดความปลอดภัยเพราะบังคับให้ใส่ secret ไว้ใน environment และทำให้ต้องยอมทิ้ง config แบบไฟล์ที่มีโครงสร้าง ซึ่งได้ประโยชน์จาก type safety, autocomplete ใน IDE และการ parse อัตโนมัติ ใน environment variables ต้อง implement parser สำหรับค่าการตั้งค่าซับซ้อนที่ไม่ใช่ string เอง ในความเป็นจริงก็มีหลายกรณีที่ถูกเก็บเป็นไฟล์ .env แล้ว commit เข้า repository ทำให้ประเด็นเรื่องความปลอดภัยของการ commit แทบไม่มีความหมาย
ไม่ได้หมายความว่าอย่าพึ่งพา operating system รวมถึง glibc แต่หมายความว่าอย่าทำให้ต้องมีแพ็กเกจจาก package manager ของภาษาหนึ่ง ๆ ติดตั้งอยู่บนเครื่องก่อนเท่านั้น
ส่วนข้อชี้แนะที่เหลือเห็นด้วย โดยเฉพาะเรื่อง environment variables นั้นดูใกล้เคียงกับการที่ผู้เขียนนำวิธีที่พบได้บ่อยในการพัฒนา Ruby ตอนนั้นมาเขียนโดยสมมติว่าเป็นวิธีที่ดีที่สุด มากกว่าจะเป็นคำแนะนำที่มีหลักฐานจริงรองรับ
ดังนั้นต้องเตรียมรับมือสถานการณ์แบบนั้น และถ้าต้องการทดสอบชุดเวอร์ชันต่าง ๆ ร่วมกันได้ง่าย ผมมองว่าใช้ repository แยก ดีกว่า
ภาษา high-level ส่วนใหญ่ไม่ได้พึ่งพา glibc เวอร์ชันเฉพาะ ถ้า runtime ของภาษานั้นทำงานถูกต้อง แอปก็ทำงานบน runtime นั้นได้ แน่นอนว่าบางกรณีก็จะใช้ของอย่าง Docker ยากไม่ได้แปลว่าไม่มีคุณค่า
ภาษาแบบ dynamic หรือ managed มักละความยุ่งยากเกี่ยวกับ system package ไปได้เป็นส่วนใหญ่
โดยรวมแล้วผมชอบนะ แต่มีหลายครั้งเกินไปที่คนที่ไม่ใช่สายเทคนิคหรือเป็นสายเทคนิคครึ่ง ๆ กลาง ๆ หยิบ “12 factor” ขึ้นมาเหมือนเป็นใบเหลืองสารพัดประโยชน์เพื่อทำให้การปล่อยรีลีสช้าลง จนแทบจะเลิกสนใจมันไปโดยสิ้นเชิง
จริง ๆ แล้ว “agile” ก็คล้ายกัน ผมเข้าใจเจตนาของแนวทางพวกนี้ แต่คุณค่าจริง ๆ ของมันดูจะเป็นประโยชน์กับคนที่ให้ได้แค่ ภาวะผู้นำทางเทคนิคแบบหอคอยงาช้าง มากกว่ามาก
เคยเจอกรณีที่วิศวกรจูเนียร์ที่ไฟแรงเกินไป หรือคนที่อยากเป็นสถาปนิก ใช้บทความ 12-Factor เหมือนเป็นข้อกำหนดบังคับสำหรับทุกการปล่อยผลิตภัณฑ์
สิ่งเหล่านี้เป็นเป้าหมายที่ดีและควรพยายามไปให้ถึง แต่ในโลกจริงต้องอธิบายอย่างหนักแน่นและสม่ำเสมอว่า เพื่อให้ปล่อยได้ เราต้องประนีประนอม และต้องเลือกว่าจะชะลอหรือเลื่อนส่วนไหนออกไป
คงไม่ถึงกับบล็อกรีลีสเพราะการเบี่ยงเบนเล็กน้อย แต่ถ้าโดยรวมไม่สอดคล้องกัน อย่างน้อยก็ควรถูกจัดเป็นหนี้ทางเทคนิค หากรีลีสใดถอยหลังอย่างมากในข้อใดข้อหนึ่ง การบล็อกไว้ หรืออย่างน้อยบังคับให้มีการทบทวนละเอียดขึ้นว่าทำไมจึงเห็นว่าการแลกเปลี่ยนนั้นคุ้มค่า ก็ถือว่ายุติธรรม
ถ้าองค์กรนำ 12FA มาใช้เป็นแนวปฏิบัติที่ดี ก็ต้องทำให้ได้ตามนั้น แต่ไม่ควรนำมาใช้บล็อกการ deploy
12FA ไม่ใช่ช่องเดียวที่ต้องติ๊กให้ครบ สามารถ และส่วนใหญ่ก็ควร จะนำแต่ละข้อมาใช้กับผลิตภัณฑ์ทีละข้อ และถ้าจำเป็นก็แตกย่อยเพิ่ม เมื่อผลิตภัณฑ์เติบโตเต็มที่ขึ้น
ถ้าทำวิศวกรรมที่ดีไว้ตั้งแต่ต้น กล่าวคือมี abstraction และ interface ที่เหมาะสม และไม่ได้ hardcode ทุกอย่างไว้ ก็ไม่ควรเป็นปัญหา
YAGNI ก็ถูกใช้ผิด ๆ มากพอ ๆ กับ 12FA สิ่งที่ 12FA ขาดไปมากที่สุดคือ ตัวอย่างที่เป็นรูปธรรม ให้จูเนียร์วิศวกรใช้อ้างอิง
ผมเรียนรู้ที่จะตีความปัญหาแบบนี้ด้วยความเชื่อในเจตนาดี ต้องดูว่าทำไมเขาถึงหยิบประเด็นขึ้นมา กระบวนการเดิมไม่ชัดเจนหรือไม่ มีข้อบกพร่องหรือไม่ หรือขาดความน่าเชื่อถือหรือไม่
ถ้าพบข้อกังวลที่สมเหตุสมผล ก็ปรับกระบวนการและอัปเดตเอกสารก็พอ
Twelve-Factor App บอกให้ใช้ environment สำหรับ config ส่วน Docker บอกว่าอย่าใช้ environment สำหรับ config เพราะไม่ปลอดภัย
ผมชอบและใช้แพตเทิร์นหลายอย่างของ 12-Factor แต่บางข้อถูกเขียนขึ้นในบริบทของ VPS ตอนนั้น environment มีเสถียรภาพ ปลอดภัย และคงที่มากกว่า แต่ใน container นั้น environment อาจถูกพ่วงติดไปกับเลเยอร์ใดเลเยอร์หนึ่งได้
ในยุค container ข้อนี้โดยเฉพาะเป็นเรื่องชวนปวดหัวพอสมควร Docker secrets ก็ไม่ได้เข้ากันได้ดีเสมอไป ต้องทำท่ากายกรรมหลายอย่างถึงจะทำให้ทำงานได้
การฉีดค่าลับเข้าแอปผ่าน environment variable ไม่ได้หมายความว่าการจัดการภายนอกทั้งหมดจะไม่ปลอดภัย ตัวอย่างเช่น container ของ AWS ECS มีการรองรับในตัวสำหรับดึงค่าลับจาก Secret Manager ตอนเริ่มต้น แล้วส่งต่อเป็น environment variable: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/...
ค่าลับจะถูกดึงมาตอน container เริ่มต้น และดึงจาก Secret Manager ด้วย IAM credential ของแอปพลิเคชันที่กำลังรันอยู่ ดังนั้นจึงต้องมีสิทธิ์ต่อค่าลับนั้น
ข้อดีของการใช้ environment variable ดูเหมือนจะขึ้นอยู่ทั้งหมดว่าสุดท้ายแล้วมันถูกตั้งค่าอย่างไร ถ้าเป็นกลไกแบบนี้ ก็ไม่ค่อยเห็นข้อเสียใหญ่ ๆ
ข้อเสียหลักที่เห็นคือมัลแวร์ทั่วไปที่พยายาม dump environment variable อาจจับค่านั้นได้ แต่ถ้าไม่ได้ถึงขั้นไม่เก็บค่าลับไว้ในหน่วยความจำแบบถาวร การป้องกันภัยคุกคามแบบนั้นโดยมากก็ใกล้เคียงกับการทำให้สับสนมากกว่า
การที่ private key ถูกเปิดเผยแบบนั้นเป็นสิ่งที่ควรหลีกเลี่ยงจริง ๆ
วิธีที่ k8s mount ค่าลับเข้าใน file system นั้นไม่ได้มีปัญหาอะไรเป็นพิเศษ แน่นอนว่าทั้งหมดนี้ขึ้นอยู่กับสภาพแวดล้อมการ deploy
บางครั้ง environment variable ก็เป็นตัวเลือกที่แย่น้อยกว่า เพราะค่าลับเป็นเรื่องยากเสมออยู่แล้ว
ถ้าเชื่อ input อย่างมืดบอดเพียงเพราะเป็น single-tenant วันหนึ่งเมื่อเงื่อนไขเปลี่ยนเพราะการ pivot ทางธุรกิจตามอำเภอใจ ก็จะเจอบั๊กที่ตามยากและค่ำคืนอันยาวนาน
ในช่วงไม่กี่ปีที่ผ่านมา มีการพูดคุยเรื่องแอป 12-Factor กันมาก และก็เห็นความสับสนอยู่ไม่น้อย เว็บไซต์ 12-Factor นั้นยอดเยี่ยม แต่โดยหลักแล้วเหมาะกับคนที่เข้าใจอยู่แล้วว่าทำไมแต่ละข้อถึงสำคัญ
สำหรับคนที่ไม่รู้เหตุผลเบื้องหลังกฎเหล่านั้น จำเป็นต้องมีคำอธิบายที่ลึกกว่านี้ ดังนั้นจึงทำวิดีโอ “What are 12 Factor Apps and Why Should You Care?”[1] ขึ้นมา และได้ยินมาว่าบางบริษัทนำไปใช้ในการอบรมวิศวกร/DevOps ที่เพิ่งเข้ามาใหม่แล้วช่วยได้มาก
ไม่ว่าจะเรียนจากที่ไหน แอป 12-Factor ก็คุ้มค่าที่จะใช้เวลาสักหนึ่งหรือสองชั่วโมงศึกษา “กฎ” ส่วนใหญ่เป็นเรื่องที่ต้องอาศัยการตระหนักรู้ และไม่ได้ชัดเจนในทันทีจนกว่าจะได้ทำพลาดเองและเจ็บเอง
[1] https://youtu.be/REbM4BDeua0
แนวคิด “unit test” เริ่มได้รับ traction ราวปลายยุค 90 และรู้สึกโล่งใจที่มีคนมีอิทธิพลออกมาสนับสนุน
เหตุผลที่ผมไม่ได้ทำเองจนกระทั่ง Kent Beck เปิดตัว JUnit คือโค้ดที่ทำอยู่ไม่ได้มีโครงสร้างที่เหมาะให้โค้ดอื่นมาควบคุมได้ ตัวแปร global, state ที่กระจายไปทั่ว, การพึ่งพาระบบภายนอกและ layout ของ file system เฉพาะ, รวมถึงการไม่สนใจ modularity ทำให้ไม่สามารถรันอะไรนอกบริบทที่มันถูกออกแบบไว้ได้เลย
ทั้งหมดนี้คือ “การออกแบบที่แย่” แต่ก็ส่งงานทันกำหนด และทุกคนจึงทำแบบนั้นกัน หวังว่าเมื่อ unit test ได้ traction โปรแกรมเมอร์จะหลุดพ้นจากการออกแบบแบบก้อนเดียว
หลังจาก 25 ปีที่ได้เห็น unit test สำหรับ getter/setter และ unit test ขนาดมหึมาเพียงตัวเดียวที่สร้างฐานข้อมูล in-memory เพราะทุกฟังก์ชันในแอปต้องใช้ฐานข้อมูลจริงแค่เพื่อจะพยายามรัน แล้วสุดท้ายก็ล้มเหลวและถูกคอมเมนต์ทิ้ง ผมก็หมดศรัทธาว่า unit test จะเป็นอะไรมากกว่าช่อง checkbox ที่ไร้ความหมาย ทุกคนกรอกมันเพราะเป็น “best practice” แต่ไม่หยุดคิดว่าทำไปทำไม
ผมไม่เคยเห็นด้วยกับคำแนะนำเรื่องการตั้งค่ามากที่สุดเสมอมา configuration มักถูกกำหนดโดยหลายฝ่าย และบ่อยครั้งนักพัฒนาก็เป็นคนกำหนด ดังนั้นการแพ็กค่า default ที่สมเหตุสมผลมากับแอปพลิเคชัน แล้วให้ไฟล์ตาม environment และ environment variable override เอา มักเป็นวิธีที่ดีที่สุด
สำหรับแอปพลิเคชันฝั่งเซิร์ฟเวอร์ส่วนใหญ่ วิธีนี้ยืดหยุ่นที่สุด ในหลายกรณีเรารู้อยู่แล้วว่าควรมี configuration แบบไหน และควรอยู่ใน source control แต่ค่า secret ควรถูก inject ตอนรัน
ถ้าไม่อยากเสียเวลาตั้งค่าอย่างมหาศาลใน dev, test และ production configuration จำเป็นต้องมี hierarchical override
ถ้าบอกว่าเป็นของ development สุดท้ายก็จะทำ production พัง และค่า default ของ production ก็อาจไม่มีความหมายเลยใน development
วิธีหนึ่งในการคิดถึงหมวด configuration คือ “กลยุทธ์การตั้งค่านี้เข้ากับ container ได้ดีไหม?” เมื่อ build image แล้ว จะมีสถานะดิสก์แบบ static ที่การเปลี่ยนแปลงจะไม่คงอยู่ เว้นแต่จะสร้าง image ใหม่
ถ้า configuration เป็นแบบอิงไฟล์เท่านั้น ก็ต้อง build image ใหม่ทั้งหมดเพื่อสลับพฤติกรรมระหว่าง test กับ production
การทำให้เปลี่ยน configuration ได้โดยไม่ขึ้นกับดิสก์พื้นฐานช่วยแยกการเปลี่ยนแปลงออกจากกัน ต้องแยกให้ได้ว่าเหตุที่แอปพังคือ deployment หรือการสร้าง image พัง หรือเป็นเพราะ configuration ผิด
ถ้าแยกการสร้าง image กับการเปลี่ยน configuration ออกจากกัน คำถามนั้นก็หายไปเอง
เช่น ไม่ควรปล่อยให้เกิดความผิดพลาดของมนุษย์ที่คาดเดาได้ง่ายอย่างการให้ QA ยิง retry การปฏิเสธการยืนยันตัวตน 100,000 ครั้งไปยังคิวส่งงานของ production
อย่างไรก็ตาม configuration จำนวนมากไม่ได้เกี่ยวกับ infrastructure แต่เป็นเรื่องอย่างเช่นจะ wire bean ของ ResolverStrategy ตัวไหนในแต่ละ environment
configuration ควรถูกจัดการด้วย version control แต่ควรแยกจาก source code เพราะ configuration อธิบาย ตัว deployment เอง ไม่ใช่ image ที่ใช้ deploy
มันเป็น บรรทัดฐานทางวิศวกรรม ที่มีอิทธิพลอย่างชัดเจน ตอนนี้มี abstraction ที่ใช้ง่ายจาก hosting อย่าง Render หรือ Vercel อยู่มากมาย แต่เมื่อคิดว่าเอกสารนี้เขียนในปี 2012 และตอนนั้นเว็บแอปยังเหมือนยุคบุกเบิกตะวันตกมากกว่านี้มากในแง่แนวปฏิบัติร่วมที่เป็นที่ยอมรับ ก็ให้ความรู้สึกแปลกอยู่เหมือนกัน
สิ่งที่ขาดไปมากในเอกสารนี้คือ การให้เหตุผลรองรับ กฎเกือบทั้งหมดเป็นแค่กฎ
ยากที่จะตัดสินว่ากฎนั้นดีหรือไม่ และเอกสารนี้ก็ไม่ได้ช่วยให้เข้าใจเรื่องนั้น
เห็นแค่ชื่อเรื่องแล้วนึกว่าเป็นบทวิจารณ์เกี่ยวกับการยืนยันตัวตนสองขั้นตอน หมายถึงแอปประเภทที่ต้องขอรูปพาสปอร์ต, สแกนใบหน้า, ใบขับขี่, SMS, Google Authenticator, ลิงก์อีเมล, รหัสผ่าน และลายนิ้วมือทั้งหมดเพื่อจะล็อกอินสักครั้ง
ในยุคแรกของ Docker ผมทำงานค่อนข้างเยอะเพื่อให้ WordPress ทำตัวเหมือน Twelve-Factor App
ตามธรรมเนียมแล้ว WordPress ไม่ได้ทำงานแบบนั้น และในระดับหนึ่งก็เป็นเรื่องสมเหตุสมผล เพราะ WordPress เติบโตมาในโลกที่เซิร์ฟเวอร์อายุยาวซึ่งมีดิสก์ local ที่เขียนได้และคงอยู่ถาวรเป็นเรื่องปกติ
หลังจากนั้นสถานการณ์คงเปลี่ยนไปมากแล้ว นี่เป็นเรื่องราวราวปี 2016 แต่เป็นความท้าทายที่สนุกจริง ๆ
แปลกใจมากว่าสิ่งต่าง ๆ ง่ายขึ้นแค่ไหน และทำให้ load balance หลาย node ได้โดยไม่ต้องกังวลเรื่อง session stickiness
แน่นอนว่ามันก็ยากขึ้นในอีกแบบหนึ่ง เช่น ต้องมี DB แยกสำหรับ session