ข้ามไปยังเนื้อหา

การจัดระเบียบข้อมูล

กลุ่ม organizing data ว่าด้วย รูปร่าง ของค่าที่โปรแกรมขนไปมา และ เส้นทาง ที่ code ใช้เข้าถึงค่าเหล่านั้น โปรแกรมจะชัดเจนได้มากที่สุดเท่าที่ข้อมูลชัดเจนเท่านั้น เมื่อ field หนึ่งถูกแตะได้จากทุกที่ เมื่อเลข 0.07 ดิบ ๆ ลอยผ่านสามโมดูลโดยไม่มีชื่อ หรือเมื่อ string ธรรมดาแอบแบกกฎการจัดรูปแบบของตัวเองไว้ ข้อมูลนั้นกำลังทำงานต่อต้านคุณ refactoring กลุ่มนี้ขีดขอบเขตล้อมข้อมูล ตั้งชื่อให้ และปล่อยให้ข้อมูลโตขึ้นพร้อม behavior ที่เรียกร้องมาตลอดอย่างเงียบ ๆ

ข้อมูลที่ยุ่งเหยิงโผล่มาในรูปแบบเล็ก ๆ ที่เกิดซ้ำ ๆ ค่าคงที่ตัวเดียวกันปรากฏในห้าไฟล์โดยไม่มีใครจำได้ว่าแปลว่าอะไร field ที่เป็น list ถูกส่งต่อออกไป แล้ว caller ไกล ๆ ก็ push ลงไป ทำลาย invariant ที่เจ้าของไม่เคยตกลงด้วย เบอร์โทรถูกเก็บเป็น string ทุกการ validate และการจัดรูปแบบจึงถูก copy-paste ซ้ำที่จุดใช้งานทุกแห่ง แต่ละอย่างไม่ร้ายแรงเลย แต่พอรวมกันก็ทำให้ codebase เปราะ เพราะเปลี่ยน วิธีเก็บ ข้อมูลทีเดียว แรงกระเพื่อมจะไปถึงทุกจุดที่อ่านข้อมูลนั้นโดยตรง

Smell (Fowler บทที่ 3)อาการที่บ่งชี้ท่าที่แนะนำ
Primitive Obsessionprimitive ที่สะสม validation และ formatting ไว้รอบตัวReplace Primitive with Object
Mysterious Nameliteral ไม่มีชื่ออย่าง 0.07 โผล่ซ้ำในหลายไฟล์Replace Magic Literal
Mutable Datafield ลิสต์ถูก mutate จากข้างนอก ทำให้ invariant พังEncapsulate Collection
Global Dataตัวแปรที่ถูกอ่านและเขียนจากทุกที่โดยไม่มีจุดควบคุมEncapsulate Variable
Repeated Switchesswitch บน type code ตัวเดียวกันกระจายอยู่ในหลาย functionReplace Type Code with Subclasses
flowchart TD
  A["Data that is awkward to work with"] --> B{"What is wrong?"}
  B -->|"A field is read and written everywhere"| C["Encapsulate Variable"]
  B -->|"A bare number or string has no name"| D["Replace Magic Literal"]
  B -->|"A list or map field is mutated from outside"| E["Encapsulate Collection"]
  B -->|"A primitive is sprouting behaviour"| F["Replace Primitive with Object"]
  B -->|"A type code drives branching logic"| G["Replace Type Code with Subclasses"]
  C --> H["Data with a clear, guarded shape"]
  D --> H
  E --> H
  F --> H
  G --> H
การเลือกท่า organizing-data ตามว่าอะไรกำลังผิดพลาด

refactoring สิบท่า แต่ละท่ากระชับความสัมพันธ์ระหว่างข้อมูลกับ code ที่ใช้ข้อมูลนั้น

  • Encapsulate Variable — ห่อหุ้มการเข้าถึงข้อมูลโดยตรงไว้หลัง function accessor เพื่อให้คุณมีจุดเดียวสำหรับตรวจสอบความถูกต้อง บันทึก log หรือเปลี่ยนวิธีแทนค่าในภายหลัง
  • Replace Magic Literal — ให้ชื่อเชิงสัญลักษณ์แก่ตัวเลขหรือ string ที่ไม่มีคำอธิบาย เพื่อให้ค่าคงที่อธิบายความหมายของตัวเอง และเปลี่ยนแปลงได้ในจุดเดียว
  • Encapsulate Collection — หยุดเปิดเผย field ลิสต์หรือแมปที่เปลี่ยนแปลงได้ คืนค่าเป็น view แบบอ่านอย่างเดียว และเสนอ method add กับ remove อย่างชัดเจน เพื่อให้เจ้าของยังควบคุมเนื้อหาได้
  • Replace Primitive with Object — เมื่อค่า primitive เริ่มดูดกฎ validate และกฎจัดรูปแบบเข้ามา ให้ยกระดับเป็น value type เล็ก ๆ ที่ถือทั้งข้อมูลและ behavior
  • Replace Type Code with Subclasses — เมื่อ field Type Code ขับเคลื่อนการแตกกิ่งแบบ switch ให้แทนที่ logic เงื่อนไขด้วย polymorphism ที่กระจายอยู่ทั่วลำดับชั้น class ขนาดเล็ก
  • Self-Encapsulate Field — ให้แม้แต่การอ่านและเขียน field ภายใน class ตัวเองก็วิ่งผ่าน getter และ setter ของ field นั้น subclass และการ validate จะได้มีจุดเดียวให้เกาะ
  • Split Variable — เมื่อตัวแปรหนึ่งถูกกำหนดค่าใหม่เพื่อหมายถึงสองสิ่งที่ต่างกัน ให้แต่ละจุดประสงค์มีตัวแปรที่กำหนดค่าครั้งเดียวเป็นของตัวเอง
  • Rename Field — เมื่อชื่อ field ของ record หรือ struct ไม่ตรงกับข้อมูลอีกต่อไป ให้เปลี่ยนชื่อแล้วอัปเดตทุกจุดที่ใช้ ชื่อจะได้กลับมาบอกความจริง
  • Change Reference to Value (and back) — ทำให้ object ขนาดเล็กเป็น value ที่ไม่เปลี่ยนแปลงและเปรียบเทียบกันด้วยเนื้อหา เมื่อการแบ่งปันไม่ได้ให้ประโยชน์อะไร หรือกลับท่าตรงข้ามเมื่อหลาย ๆ ที่ต้องแบ่งปัน instance เดียวที่อัปเดตได้
  • Replace Type Code with State/Strategy — เมื่อ Type Code ขับเคลื่อน behavior และเปลี่ยนแปลงได้ขณะ runtime ให้ถือ object State หรือ Strategy ที่สลับเปลี่ยนได้ แทนที่จะใช้ subclass ตายตัว

แต่ละบทเรียนแสดงรูปแบบก่อน-และ-หลังเดียวกันในภาษา TypeScript, Python, Go และ Rust จากนั้นจึงเดินผ่านกลไกที่ปลอดภัยและเป็นลำดับ — โดยรัน test ระหว่างทุกขั้นตอน

การรีแฟคเตอร์แบบ "organizing data" เปลี่ยนแปลงอะไรเป็นหลัก?
การรีแฟคเตอร์ใดที่ให้ชื่อเชิงสัญลักษณ์แก่ตัวเลขหรือ string ที่ไม่มีคำอธิบาย?
แนวคิดที่เกิดซ้ำใดที่ร้อยเรียงโมดูลนี้เข้าด้วยกัน?