ดูเหมือนว่าเพื่อนของคุณจะเผชิญกับความยากลำบากมากมายจากเรื่องเล็ก ๆ น้อย ๆ ของเขา นั่นเป็นโชคร้ายและอาจเป็นสภาพแวดล้อมที่ยากลำบากในการทำงานแม้จะมีความยากลำบาก แต่เขาก็อยู่บนเส้นทางที่ถูกต้องในการใช้รูปแบบเพื่อทำให้ชีวิตของเขาง่ายขึ้นและมันเป็นความอัปยศที่เขาทิ้งเส้นทางนั้นไว้ รหัสสปาเก็ตตี้เป็นผลลัพธ์ที่ดีที่สุด
เนื่องจากมีปัญหาที่แตกต่างกันสองด้านคือด้านเทคนิคและความสัมพันธ์ระหว่างบุคคลฉันจะพูดคุยแยกกัน
ความสัมพันธ์ระหว่างบุคคล
ปัญหาที่เพื่อนของคุณกำลังเผชิญอยู่คือความต้องการที่เปลี่ยนแปลงอย่างรวดเร็วและสิ่งที่ส่งผลต่อความสามารถในการเขียนโค้ดที่สามารถบำรุงรักษาได้ ก่อนอื่นฉันจะบอกว่าความต้องการที่เปลี่ยนไปวันละสองครั้งทุกวันเป็นเวลานานเช่นนี้เป็นปัญหาที่ใหญ่กว่าและมีความคาดหวังโดยปริยาย ความต้องการกำลังเปลี่ยนแปลงเร็วกว่ารหัสที่สามารถเปลี่ยนแปลงได้ เราไม่สามารถคาดหวังรหัสหรือโปรแกรมเมอร์เพื่อให้ทัน การเปลี่ยนแปลงที่รวดเร็วนี้เป็นอาการของความไม่สมบูรณ์ของผลิตภัณฑ์ที่ต้องการในระดับที่สูงขึ้น นี่คือปัญหา. หากพวกเขาไม่รู้ว่าสิ่งที่พวกเขาต้องการจริง ๆ พวกเขาจะเสียเวลาและเงินจำนวนมากเพื่อไม่ให้ได้มา
มันอาจเป็นการดีที่จะกำหนดขอบเขตของการเปลี่ยนแปลง รวมกลุ่มเปลี่ยนเป็นชุดทุกสองสัปดาห์จากนั้นตรึงไว้สองสัปดาห์ในขณะที่นำไปใช้ สร้างรายการใหม่ในช่วงสองสัปดาห์ถัดไป ฉันมีความรู้สึกว่าการเปลี่ยนแปลงเหล่านี้ซ้อนทับหรือขัดแย้งกัน (เช่นวาฟเฟิลไปมาระหว่างตัวเลือกสองตัว) เมื่อการเปลี่ยนแปลงเกิดขึ้นอย่างรวดเร็วและรุนแรงพวกเขาล้วนมีความสำคัญสูงสุด หากคุณปล่อยให้พวกเขารวมอยู่ในรายการคุณสามารถทำงานร่วมกับพวกเขาเพื่อจัดระเบียบและจัดลำดับความสำคัญที่สำคัญที่สุดเพื่อเพิ่มความพยายามและประสิทธิภาพสูงสุด พวกเขาอาจเห็นว่าการเปลี่ยนแปลงบางอย่างของพวกเขาโง่หรือสำคัญน้อยกว่าทำให้เพื่อนของคุณมีห้องหายใจ
ปัญหาเหล่านี้ไม่ควรหยุดคุณจากการเขียนรหัสที่ดี รหัสไม่ถูกต้องนำไปสู่ปัญหาที่เลวร้ายยิ่ง อาจต้องใช้เวลาในการปรับโครงสร้างจากโซลูชันหนึ่งไปยังอีกโซลูชันหนึ่ง แต่ความจริงที่เป็นไปได้แสดงให้เห็นถึงประโยชน์ของวิธีการเข้ารหัสที่ดีผ่านรูปแบบและหลักการ
ในสภาพแวดล้อมที่มีการเปลี่ยนแปลงบ่อยครั้งหนี้ทางเทคนิคจะถึงกำหนดในบางประเด็น เป็นการดีกว่าที่จะจ่ายเงินให้กับมันแทนที่จะโยนผ้าเช็ดตัวและรอจนกว่ามันจะใหญ่เกินไปที่จะเอาชนะ หากรูปแบบไม่มีประโยชน์อีกต่อไปให้ปรับโครงสร้างใหม่อีกครั้ง แต่อย่ากลับไปใช้วิธีเข้ารหัสคาวบอย
วิชาการ
เพื่อนของคุณดูเหมือนจะเข้าใจดีเกี่ยวกับรูปแบบการออกแบบพื้นฐาน วัตถุ Null เป็นวิธีการที่ดีในการแก้ไขปัญหาที่เขาเผชิญ ความจริงมันยังคงเป็นวิธีการที่ดี ที่ซึ่งเขาดูเหมือนจะมีความท้าทายคือการทำความเข้าใจหลักการที่อยู่เบื้องหลังรูปแบบสาเหตุของสิ่งที่พวกเขา ไม่เช่นนั้นฉันไม่เชื่อว่าเขาจะละทิ้งแนวทางของเขา
(สิ่งต่อไปนี้คือชุดของการแก้ปัญหาทางเทคนิคที่ไม่ได้ถามในคำถามเดิม แต่แสดงให้เห็นว่าเราสามารถยึดตามรูปแบบเพื่อวัตถุประสงค์ในการอธิบาย)
หลักการที่อยู่เบื้องหลังวัตถุว่างเปล่าคือแนวคิดของการห่อหุ้มสิ่งที่แตกต่างกันไป เราซ่อนสิ่งที่เปลี่ยนแปลงดังนั้นเราจึงไม่ต้องจัดการกับมันในที่อื่น ที่นี่วัตถุ null ถูกห่อหุ้มความแปรปรวนในproduct.Price
อินสแตนซ์ (ฉันจะเรียกมันว่าPrice
วัตถุและราคาวัตถุ null จะเป็นNullPrice
) Price
เป็นวัตถุโดเมนแนวคิดธุรกิจ บางครั้งในตรรกะทางธุรกิจของเราเรายังไม่ทราบราคา สิ่งนี้เกิดขึ้น กรณีการใช้งานที่สมบูรณ์แบบสำหรับวัตถุ null Price
s มีToString
เมธอดที่ส่งออกราคาหรือสตริงว่างถ้าไม่ทราบ (หรือNullPrice#ToString
ส่งคืนสตริงว่าง) นี่เป็นพฤติกรรมที่สมเหตุสมผล จากนั้นความต้องการเปลี่ยนแปลง
เราต้องส่งออกnull
ไปยังมุมมอง API หรือสตริงที่แตกต่างกันไปยังมุมมองของผู้จัดการ สิ่งนี้ส่งผลกระทบต่อตรรกะทางธุรกิจของเราอย่างไร ก็ไม่เป็นไร ในข้อความข้างต้นฉันใช้คำว่า 'มุมมอง' สองครั้ง คำนี้อาจไม่พูดอย่างชัดเจน แต่เราต้องฝึกตัวเองให้ได้ยินคำที่ซ่อนอยู่ในข้อกำหนด เหตุใด 'มุมมอง' จึงสำคัญมาก เพราะมันบอกเราว่าการเปลี่ยนแปลงจะเกิดขึ้นจริง : ในมุมมองของเรา
นอกเหนือ : ไม่ว่าเราจะใช้กรอบงาน MVC หรือไม่ก็ตาม ในขณะที่ MVC มีความหมายที่เฉพาะเจาะจงมากสำหรับ 'มุมมอง' ฉันใช้มันในความหมายทั่วไป (และอาจจะใช้ได้มากกว่า) ของรหัสการนำเสนอ
ดังนั้นเราจึงจำเป็นต้องแก้ไขในมุมมอง เราจะทำเช่นนั้นได้อย่างไร วิธีที่ง่ายที่สุดในการทำเช่นนี้คือif
คำแถลง ฉันรู้ว่าวัตถุที่เป็นโมฆะตั้งใจจะกำจัด ifs ทั้งหมด แต่เราต้องปฏิบัติ เราสามารถตรวจสอบสตริงเพื่อดูว่าว่างหรือไม่และสลับ:
if(product.Price.ToString("c").Length == 0) { // one way of many
writer.write("Price unspecified [Change]");
} else {
writer.write(product.Price.ToString("c"));
}
สิ่งนี้มีผลต่อการห่อหุ้มอย่างไร ส่วนที่สำคัญที่สุดที่นี่คือมุมมองตรรกะจะห่อหุ้มในมุมมอง เราสามารถแยกลอจิกธุรกิจ / วัตถุโดเมนออกจากการเปลี่ยนแปลงในมุมมองตรรกะด้วยวิธีนี้ มันน่าเกลียด แต่มันได้ผล นี่ไม่ใช่ตัวเลือกเดียวเท่านั้น
เราสามารถพูดได้ว่าตรรกะทางธุรกิจของเรามีการเปลี่ยนแปลงเพียงเล็กน้อยที่เราต้องการที่จะส่งออกสตริงเริ่มต้นหากไม่มีการตั้งราคา เราสามารถปรับแต่งเล็กน้อยกับPrice#ToString
วิธีการของเรา(จริง ๆ แล้วสร้างวิธีการโอเวอร์โหลด) เราสามารถยอมรับค่าส่งคืนเริ่มต้นและส่งคืนได้หากไม่มีการกำหนดราคา:
class Price {
...
// A new ToString method
public string ToString(string c, string default) {
return ToString(c);
}
...
}
class NullPrice {
...
// A new ToString method
public string ToString(string c, string default) {
return default;
}
...
}
และตอนนี้รหัสมุมมองของเรากลายเป็น:
writer.write(product.Price.ToString("c", "Price unspecified [Change]"));
เงื่อนไขหายไป อย่างไรก็ตามการทำเช่นนี้มากเกินไปสามารถเพิ่มวิธีการกรณีพิเศษลงในวัตถุโดเมนของคุณดังนั้นจึงเหมาะสมถ้ามีเพียงไม่กี่กรณี
เราสามารถสร้างIsSet
วิธีการPrice
ที่คืนค่าบูลีนแทน:
class Price {
...
public bool IsSet() {
return return true;
}
...
}
class NullPrice {
...
public bool IsSet() {
return false;
}
...
}
ดูตรรกะ:
if(product.Price.IsSet()) {
writer.write(product.Price.ToString("c"));
} else {
writer.write("Price unspecified [Change]");
}
เราเห็นการกลับมาของเงื่อนไขในมุมมอง แต่กรณีมีความแข็งแกร่งสำหรับตรรกะทางธุรกิจที่บอกว่าราคาถูกตั้งไว้ เราสามารถใช้Price#IsSet
ที่อื่นตอนนี้ที่เรามีให้
สุดท้ายเราสามารถสรุปแนวคิดในการนำเสนอราคาทั้งหมดในผู้ช่วยเพื่อดู สิ่งนี้จะซ่อนเงื่อนไขในขณะที่รักษาวัตถุโดเมนไว้เท่าที่เราต้องการ:
class PriceStringHelper {
public PriceStringHelper() {}
public string PriceToString(Price price, string default) {
if(price.IsSet()) { // or use string length to not change the Price class at all
return price.ToString("c");
} else {
return default;
}
}
}
ดูตรรกะ:
writer.write(new PriceStringHelper().PriceToString(product.Price, "Price unspecified [Change]"));
มีหลายวิธีที่จะทำการเปลี่ยนแปลง (เราสามารถพูดคุยPriceStringHelper
เป็นวัตถุที่ส่งกลับค่าเริ่มต้นหากสตริงว่างเปล่า) แต่สิ่งเหล่านี้เป็นวิธีที่รวดเร็วสองสามอย่างที่เก็บรักษาไว้ (ส่วนใหญ่) ทั้งรูปแบบและหลักการตามที่ เช่นเดียวกับในทางปฏิบัติของการเปลี่ยนแปลงดังกล่าว