ฉันดูคำพูดของสจ็วตเซียร์เซียร์ " คิดในข้อมูล " และนำหนึ่งในแนวคิดจากนั้นเป็นหลักการออกแบบในเกมนี้ที่ฉันทำ ความแตกต่างคือเขาทำงานใน Clojure และฉันทำงานใน JavaScript ฉันเห็นความแตกต่างที่สำคัญระหว่างภาษาของเราในเรื่องนั้น:
- Clojure เป็นการเขียนโปรแกรมที่ใช้งานง่าย
- รัฐส่วนใหญ่ไม่เปลี่ยนรูป
ฉันใช้ความคิดจากสไลด์ "ทุกอย่างคือแผนที่" (จาก 11 นาที, 6 วินาทีถึง> 29 นาที) บางสิ่งที่เขาพูดคือ:
- เมื่อใดก็ตามที่คุณเห็นฟังก์ชั่นที่ใช้อาร์กิวเมนต์ 2-3 ข้อคุณสามารถทำให้เป็นกรณีสำหรับเปลี่ยนเป็นแผนที่และเพิ่งผ่านแผนที่มามีข้อดีมากมายดังนี้:
- คุณไม่ต้องกังวลกับคำสั่งโต้แย้ง
- คุณไม่ต้องกังวลกับข้อมูลเพิ่มเติมใด ๆ หากมีกุญแจพิเศษนั่นไม่ใช่ความกังวลของเรา พวกเขาไหลผ่านพวกเขาไม่ได้ยุ่ง
- คุณไม่จำเป็นต้องกำหนดสคีมา
- ตรงข้ามกับการส่งผ่านวัตถุไม่มีการซ่อนข้อมูล แต่เขาทำให้กรณีที่การซ่อนข้อมูลสามารถทำให้เกิดปัญหาและ overrated:
- ประสิทธิภาพ
- ใช้งานง่าย
- ทันทีที่คุณสื่อสารผ่านเครือข่ายหรือข้ามกระบวนการคุณจะต้องให้ทั้งสองฝ่ายเห็นพ้องกับการแสดงข้อมูลต่อไป นั่นเป็นงานพิเศษที่คุณสามารถข้ามได้ถ้าคุณแค่ทำงานกับข้อมูล
ส่วนใหญ่เกี่ยวข้องกับคำถามของฉัน นี่คือ 29 นาทีใน: "ทำให้ฟังก์ชั่นของคุณประกอบได้" นี่คือตัวอย่างโค้ดที่เขาใช้อธิบายแนวคิด:
;; Bad (defn complex-process [] (let [a (get-component @global-state) b (subprocess-one a) c (subprocess-two a b) d (subprocess-three a b c)] (reset! global-state d))) ;; Good (defn complex-process [state] (-> state subprocess-one subprocess-two subprocess-three))
ฉันเข้าใจว่าโปรแกรมเมอร์ส่วนใหญ่ไม่คุ้นเคยกับ Clojure ดังนั้นฉันจะเขียนมันใหม่ในลักษณะที่จำเป็น:
;; Good def complex-process(State state) state = subprocess-one(state) state = subprocess-two(state) state = subprocess-three(state) return state
นี่คือข้อดี:
- ทดสอบง่าย
- แยกฟังก์ชั่นเหล่านั้นได้ง่าย
- ง่ายต่อการคอมเม้นต์หนึ่งบรรทัดของสิ่งนี้และดูว่าผลลัพธ์คืออะไรโดยการลบขั้นตอนเดียว
- แต่ละกระบวนการย่อยสามารถเพิ่มข้อมูลเพิ่มเติมให้กับรัฐ หากกระบวนการย่อยจำเป็นต้องสื่อสารบางสิ่งกับกระบวนการย่อยที่สามมันง่ายพอ ๆ กับการเพิ่มคีย์ / ค่า
- ไม่มีต้นแบบสำเร็จรูปที่จะแยกข้อมูลที่คุณต้องการออกจากสถานะเพียงเพื่อให้คุณสามารถบันทึกกลับเข้าไปเพียงแค่ผ่านสถานะทั้งหมดและปล่อยให้กระบวนการย่อยกำหนดสิ่งที่ต้องการ
ตอนนี้กลับไปที่สถานการณ์ของฉัน: ฉันใช้บทเรียนนี้และนำไปใช้กับเกมของฉัน นั่นคือฟังก์ชั่นระดับสูงเกือบทั้งหมดของฉันจะรับและส่งคืนgameState
วัตถุ วัตถุนี้มีข้อมูลทั้งหมดของเกม EG: รายการ badGuys รายการเมนูของขวัญบนพื้น ฯลฯ นี่คือตัวอย่างของฟังก์ชั่นอัพเดทของฉัน:
update(gameState)
...
gameState = handleUnitCollision(gameState)
...
gameState = handleLoot(gameState)
...
สิ่งที่ฉันถามที่นี่คือฉันได้สร้างสิ่งที่น่ารังเกียจบางอย่างที่บิดเบือนความคิดที่เป็นประโยชน์ในภาษาการเขียนโปรแกรมที่ใช้งานได้จริงหรือไม่? JavaScript ไม่idiomaticallyทำงาน (แม้ว่ามันจะสามารถเขียนวิธีการที่) และก็จริงๆที่ท้าทายความสามารถในการเขียนโครงสร้างข้อมูลไม่เปลี่ยนรูป สิ่งหนึ่งที่เกี่ยวข้องกับฉันคือเขาคิดว่าแต่ละกระบวนการย่อยนั้นบริสุทธิ์ ทำไมต้องมีการสันนิษฐานที่ว่า? เป็นเรื่องยากที่ฟังก์ชันใด ๆ ของฉันจะบริสุทธิ์ (โดยที่ฉันหมายความว่าพวกเขามักจะปรับเปลี่ยนgameState
ฉันไม่ได้มีผลข้างเคียงที่ซับซ้อนอื่น ๆ นอกเหนือจากนั้น) แนวคิดเหล่านี้แตกสลายหรือไม่ถ้าคุณไม่มีข้อมูลที่ไม่เปลี่ยนรูปแบบ?
ผมกังวลว่าวันหนึ่งผมจะตื่นขึ้นและตระหนักถึงการออกแบบทั้งหมดนี้คือการเสแสร้งและฉันเพิ่งจริงๆรับการดำเนินการลูกบิ๊กโคลนต่อต้านรูปแบบ
สุจริตฉันทำงานกับรหัสนี้มาหลายเดือนแล้วและมันก็ยอดเยี่ยมมาก ฉันรู้สึกว่าฉันได้รับประโยชน์ทั้งหมดที่เขาอ้างว่า รหัสของฉันนั้นง่ายมากสำหรับฉันที่จะให้เหตุผล แต่ฉันเป็นทีมชายคนหนึ่งดังนั้นฉันจึงมีคำสาปของความรู้
ปรับปรุง
ฉันได้รับการเข้ารหัส 6+ เดือนด้วยรูปแบบนี้ โดยปกติแล้วในเวลานี้ฉันลืมสิ่งที่ฉันทำและนั่นคือสิ่งที่ เข้ามาเล่น ถ้าฉันไม่มีฉันก็จะต้องดิ้นรนจริงๆ จนถึงตอนนี้ฉันไม่ดิ้นรนเลย
ฉันเข้าใจว่าต้องมีดวงตาอีกข้างหนึ่งในการตรวจสอบความสามารถในการบำรุงรักษาของมัน ทั้งหมดที่ฉันพูดได้คือฉันใส่ใจเรื่องการบำรุงรักษาเป็นอันดับแรก ฉันเป็นผู้เผยแพร่ศาสนาที่ดังที่สุดสำหรับรหัสที่สะอาดไม่ว่าฉันจะทำงานที่ไหน
ฉันต้องการตอบกลับโดยตรงกับผู้ที่มีประสบการณ์ส่วนตัวที่ไม่ดีด้วยวิธีการเข้ารหัสนี้ ตอนนั้นฉันไม่ทราบ แต่ฉันคิดว่าเรากำลังพูดถึงวิธีการเขียนโค้ดสองวิธี วิธีที่ฉันทำดูเหมือนว่ามีโครงสร้างมากกว่าสิ่งอื่นที่มีประสบการณ์ เมื่อมีคนมีประสบการณ์ส่วนตัวที่ไม่ดีกับ "ทุกอย่างเป็นแผนที่" พวกเขาพูดถึงความยากลำบากในการรักษาเพราะ:
- คุณไม่มีทางรู้โครงสร้างของแผนที่ที่ฟังก์ชั่นต้องการ
- ฟังก์ชั่นใด ๆ สามารถกลายพันธุ์อินพุตในรูปแบบที่คุณไม่คาดคิด คุณต้องมองไปทั่วฐานของรหัสเพื่อค้นหาว่ามีรหัสเฉพาะลงในแผนที่ได้อย่างไรหรือทำไมมันหายไป
สำหรับผู้ที่มีประสบการณ์เช่นนี้อาจเป็นรหัสฐานได้ว่า "ทุกอย่างต้องใช้ 1 ประเภทของแผนที่ N" Mine คือ "ทุกอย่างต้องใช้แผนที่ 1 ใน 1 ประเภท" ถ้าคุณรู้ว่าโครงสร้างของ 1 ประเภทนั้นคุณรู้โครงสร้างของทุกอย่าง แน่นอนว่าโครงสร้างนั้นมักจะเติบโตเมื่อเวลาผ่านไป นั่นเป็นเหตุผลที่ ...
มีที่สำหรับค้นหาการใช้งานอ้างอิง (เช่น: schema) การใช้การอ้างอิงนี้เป็นรหัสที่เกมใช้เพื่อไม่ให้ล้าสมัย
สำหรับจุดที่สองฉันไม่ได้เพิ่ม / ลบคีย์ไปยังแผนที่นอกเหนือจากการใช้งานอ้างอิงฉันเพิ่งกลายพันธุ์สิ่งที่มีอยู่แล้ว ฉันยังมีชุดการทดสอบอัตโนมัติขนาดใหญ่อีกด้วย
หากสถาปัตยกรรมนี้พังลงในที่สุดภายใต้น้ำหนักของมันเองฉันจะเพิ่มการอัปเดตครั้งที่สอง มิฉะนั้นสมมติว่าทุกอย่างเป็นไปด้วยดี :)