เมื่อความหลงใหลดั้งเดิมไม่ได้กลิ่นรหัสคืออะไร?


22

ฉันได้อ่านบทความจำนวนมากเมื่อเร็ว ๆ นี้ที่อธิบายครอบงำจิตใจดั้งเดิมเป็นกลิ่นรหัส

มีประโยชน์สองประการในการหลีกเลี่ยงความหลงใหลดั้งเดิม:

  1. ทำให้โมเดลโดเมนชัดเจนยิ่งขึ้น ตัวอย่างเช่นฉันสามารถพูดคุยกับนักวิเคราะห์ธุรกิจเกี่ยวกับรหัสไปรษณีย์แทนที่จะเป็นสตริงที่มีรหัสไปรษณีย์

  2. การตรวจสอบทั้งหมดอยู่ในที่เดียวแทนที่จะใช้ข้ามแอปพลิเคชัน

มีบทความมากมายที่อธิบายเมื่อมันเป็นกลิ่นรหัส ตัวอย่างเช่นฉันสามารถเห็นประโยชน์ของการลบความหลงใหลดั้งเดิมสำหรับรหัสโพสต์เช่นนี้:

public class Address
{
    public ZipCode ZipCode { get; set; }
}

นี่คือตัวสร้างของรหัสไปรษณีย์:

public ZipCode(string value)
    {
        // Perform regex matching to verify XXXXX or XXXXX-XXXX format
        _value = value;
    }

คุณจะทำลายหลักการDRYโดยวางตรรกะการตรวจสอบความถูกต้องทุกที่ที่ใช้รหัสไปรษณีย์

อย่างไรก็ตามสิ่งที่เกี่ยวกับวัตถุต่อไปนี้:

  1. วันเดือนปีเกิด: ตรวจสอบว่ามากเกินใจและน้อยกว่าวันนี้วันที่

  2. เงินเดือน: ตรวจสอบว่ามากกว่าหรือเท่ากับศูนย์

คุณจะสร้างวัตถุ DateOfBirth และวัตถุเงินเดือนหรือไม่ ประโยชน์คือคุณสามารถพูดคุยเกี่ยวกับพวกเขาเมื่ออธิบายรูปแบบโดเมน อย่างไรก็ตามนี่เป็นกรณีของการ overengineering เนื่องจากมีการตรวจสอบไม่มาก มีกฎที่อธิบายว่าเมื่อใดและเมื่อใดที่จะไม่ลบความหลงไหลแบบดั้งเดิมหรือคุณควรจะทำมันถ้าเป็นไปได้

ฉันเดาว่าฉันสามารถสร้างนามแฝงประเภทแทนชั้นเรียนซึ่งจะช่วยในจุดหนึ่งข้างต้น


8
"คุณจะทำลายหลักการ DRY โดยวางตรรกะการตรวจสอบความถูกต้องทุกที่ที่ใช้รหัสไปรษณีย์" นั่นไม่เป็นความจริง การตรวจสอบควรจะทำเร็วที่สุดเท่าที่ข้อมูลจะถูกป้อนเข้าสู่โมดูลของคุณ หากมี "จุดเข้าใช้งาน" มากกว่าหนึ่งรายการการตรวจสอบควรอยู่ในหน่วยที่สามารถนำมาใช้ซ้ำได้และไม่จำเป็นต้องเป็น DTO (หรือควรจะ) DTO ...
Timothy Truckle

1
คุณให้ "ใจถึง" และ "วันนี้วันที่" แก่DateOfBirthผู้สร้างเพื่อตรวจสอบได้อย่างไร
Caleth

11
ประโยชน์ของการสร้างประเภทที่กำหนดเองก็คือความปลอดภัยประเภท หากคุณมีSalaryและDistanceวัตถุคุณไม่สามารถใช้พวกเขาโดยไม่ได้ตั้งใจ doubleคุณสามารถถ้าพวกเขาทั้งสองประเภท
Scroog1

3
@ w0051977 คุณแถลง (ตามที่ฉันเข้าใจ) บอกเป็นนัยว่าไม่มีอะไรอื่นนอกจากการตรวจสอบความถูกต้องใน Constructor DTOs จะเป็นการละเมิด DRY ในความเป็นจริงการตรวจสอบควรอยู่นอก DTO ...
ทิโมธียอมจำนน

2
สำหรับฉันมันเป็นเรื่องของขอบเขต หากคุณให้ขอบเขตแบบดั้งเดิมมันมีวิธีมากมายที่พวกมันสามารถใช้ผิดและผิดพลาดได้ โดยทั่วไปแล้วคุณต้องการให้ขอบเขตที่แคบกว่าแก่พวกเขาและวิธีหนึ่งในการทำเช่นนั้นคือการออกแบบคลาสที่แสดงแนวคิดโดยใช้แบบดั้งเดิมที่เก็บไว้เป็นส่วนตัวภายในเพื่อนำมาใช้ ตอนนี้ขอบเขตของดั้งเดิมนั้นแคบและไม่น่าจะถูกใช้ในทางที่ผิด / ผิดพลาดและคุณสามารถรักษาค่าคงที่ได้อย่างมีประสิทธิภาพ แต่ถ้าขอบเขตของดั้งเดิมนั้นแคบลงเริ่มต้นนี่อาจจะเกินความจริงและแนะนำข้อต่อเสริมและรหัสจำนวนมากเพื่อรักษา

คำตอบ:


17

Primitive Obsession ใช้ชนิดข้อมูลดั้งเดิมเพื่อแสดงแนวคิดของโดเมน

สิ่งที่ตรงกันข้ามคือ "การสร้างแบบจำลองโดเมน" หรือ "เหนือวิศวกรรม"

คุณจะสร้างวัตถุ DateOfBirth และวัตถุเงินเดือนหรือไม่

แนะนำวัตถุเงินเดือนอาจเป็นความคิดที่ดีด้วยเหตุผลดังต่อไปนี้: ตัวเลขไม่ค่อยโดดเดี่ยวในรูปแบบโดเมนพวกเขามักจะมีมิติและหน่วย ปกติแล้วเราจะไม่ทำตัวเป็นประโยชน์อะไรเลยถ้าเราเพิ่มความยาวให้กับเวลาหรือมวลชนและเราไม่ค่อยได้ผลที่ดีเมื่อเราผสมเมตรกับเท้า

สำหรับ DateOfBirth น่าจะเป็น - มีสองประเด็นที่ต้องพิจารณา ก่อนอื่นการสร้างวันที่ไม่ใช่แบบดั้งเดิมจะช่วยให้คุณมีศูนย์รวมของข้อกังวลแปลก ๆ เกี่ยวกับคณิตศาสตร์วันที่ มีหลายภาษาให้บริการหนึ่งกล่อง DateTime , java.util.Date สิ่งเหล่านี้คือการประยุกต์ใช้โดเมนที่ไม่เชื่อเรื่องพระเจ้าของวันที่ แต่ไม่ได้เป็นพื้นฐาน

ประการที่สองDateOfBirthไม่ใช่วันเวลาจริง ๆ ที่นี่ในสหรัฐอเมริกา "วันเดือนปีเกิด" เป็นนวนิยายสร้างทางวัฒนธรรม / กฎหมาย เรามักจะวัดวันเดือนปีเกิดจากท้องถิ่นวันที่เกิดคน; บ๊อบเกิดในแคลิฟอร์เนียอาจมีวันเกิดที่ "เร็วกว่า" อลิซเกิดในนิวยอร์กแม้ว่าเขาจะอายุน้อยกว่าทั้งสองก็ตาม

มีกฎที่อธิบายว่าเมื่อใดและเมื่อใดที่จะไม่ลบความหลงไหลแบบดั้งเดิมหรือคุณควรจะทำมันถ้าเป็นไปได้

ไม่แน่นอนเสมอไป; ที่ขอบเขตของการใช้งานที่ไม่ได้เชิงวัตถุ มันเป็นเรื่องธรรมดาที่จะเห็น primitives ใช้เพื่ออธิบายพฤติกรรมในการทดสอบ


1
ความคิดเห็นแรกหลังจากอ้างที่ด้านบนน่าจะไม่ใช่ sequitur นอกจากนี้มันเพิ่งเรียกคืนหัวข้อของคำถาม มันเป็นคำตอบที่ดี แต่ฉันคิดว่ามันน่ารำคาญจริงๆ
JimmyJames

C # DateTime และ java.util.Date ไม่ใช่ชนิดพื้นฐานที่เหมาะสมสำหรับ DateOfBirth
วินไคลน์

อาจแทนที่java.util.Dateด้วยjava.time.LocalDate
Koray Tugay

7

ความซื่อสัตย์: ขึ้นอยู่กับ

มีความเสี่ยงที่จะทำให้รหัสของคุณ overengineering DateOfBirth และเงินเดือนจะใช้กันอย่างแพร่หลายแค่ไหน? คุณจะใช้มันในชั้นเรียนที่มีการเชื่อมต่อกันสามชั้นอย่างแน่นหนาเท่านั้น คุณจะ "เพียงแค่" ห่อหุ้มพวกเขาใน Type / Class ของพวกเขาเองเพื่อบังคับใช้ข้อ จำกัด นั้นหรือคุณสามารถคิดถึงข้อ จำกัด / ฟังก์ชันเพิ่มเติมที่เป็นของจริงได้หรือไม่?

ลองทำเงินเดือนตัวอย่าง: คุณมีการดำเนินการกับ "เงินเดือน" (เช่นการจัดการสกุลเงินที่แตกต่างกันหรืออาจจะเป็นฟังก์ชั่น toString ())? พิจารณาว่าเงินเดือนคืออะไร / ทำเมื่อคุณไม่มองว่ามันเป็นแบบดั้งเดิมอย่างง่ายและมีโอกาสที่ดีสำหรับเงินเดือนที่จะเป็นระดับของตัวเอง


นามแฝงประเภทเป็นทางเลือกที่ดีหรือไม่?
w0051977

@ w0051977 ฉันเห็นด้วยกับ charonx และนามแฝงประเภทอาจเป็นทางเลือก
techagrammer

@ w0051977 นามแฝงประเภทอาจเป็นทางเลือกถ้าเป้าหมายหลักคือการบังคับใช้การพิมพ์ที่เข้มงวดเพื่อระบุอย่างชัดเจนว่าค่าที่แน่นอนคืออะไร (เงินเดือน) เพื่อหลีกเลี่ยงการมอบหมายโดยไม่ตั้งใจของ "ดอลลาร์ลอย" (ต่อชั่วโมงสัปดาห์หรือเดือน? "เงินเดือนลอยตัว" (ต่อเดือนหรือไม่ปี?) ขึ้นอยู่กับความต้องการของคุณ
CharonX

@ CharlieX ฉันเชื่อว่าทศนิยมควรใช้เป็นเงินเดือนไม่ใช่แบบลอย คุณเห็นด้วยไหม?
w0051977

@ w0051977 หากคุณมีประเภททศนิยมที่ดีแสดงว่าเป็นประเภทที่เลือกได้ใช่ (ฉันทำงานในโครงการ c ++ ตอนนี้ดังนั้น booleans จำนวนเต็มและลอยอยู่ในระดับแนวหน้าของใจของฉัน)
CharonX

5

กฎของหัวแม่มือที่เป็นไปได้อาจขึ้นอยู่กับเลเยอร์ของโปรแกรม สำหรับDomain (DDD) aka Entities Layer (Martin, 2018) สิ่งนี้อาจเป็น "เพื่อหลีกเลี่ยงการใช้สิ่งที่เป็นตัวแทนสำหรับสิ่งใดก็ตามที่แสดงถึงแนวคิดของโดเมน / ธุรกิจ" การให้เหตุผลตามที่ระบุไว้โดย OP: โมเดลโดเมนที่ชัดเจนยิ่งขึ้นการตรวจสอบความถูกต้องของกฎทางธุรกิจทำให้เกิดแนวคิดที่ชัดเจน (Evans, 2004)

นามแฝงประเภทอาจเป็นทางเลือกที่มีน้ำหนักเบา (Ghosh, 2017) และปรับให้เป็นคลาสเอนทิตีเมื่อต้องการ ยกตัวอย่างเช่นครั้งแรกที่เราอาจจำเป็นต้องให้Salaryผู้ใด>=0และต่อมาก็ตัดสินใจที่จะไม่อนุญาตให้มี $100.33333และสิ่งที่เหนือ$10,000,000(ซึ่งจะล้มละลายลูกค้า) การใช้ Nonnegativeแบบดั้งเดิมในการเป็นตัวแทนSalaryและแนวคิดอื่น ๆ จะทำให้การปรับโครงสร้างนี้ซ้ำซ้อน

การหลีกเลี่ยงสิ่งดั้งเดิมอาจช่วยหลีกเลี่ยงการใช้วิศวกรรมมากเกินไป สมมติว่าเราต้องรวม เงินเดือน และวันเดือนปีเกิดเข้ากับโครงสร้างข้อมูลเช่นมีพารามิเตอร์วิธีการน้อยลงหรือส่งผ่านข้อมูลระหว่างโมดูล แล้วเราสามารถใช้ tuple (Salary, DateOfBirth)กับประเภท อันที่จริง tuple ที่มีแบบดั้งเดิม, (Nonnegative, Nonnegative)ไม่เป็นที่รู้แจ้ง, ในขณะที่บางคนclass EmployeeDataก็ป่อง จะซ่อนเขตข้อมูลที่จำเป็นในหมู่คนอื่น ๆ ลายเซ็นในการพูดcalcPension(d: (Salary, DateOfBirth))จะเน้นกว่าในcalcPension(d: EmployeeData)ซึ่งละเมิดหลักการการแยกส่วนต่อประสาน ผู้เชี่ยวชาญพิเศษ class SalaryAndDateOfBirthดูน่าอึดอัดใจและอาจเป็นเรื่องเกินความจริง ต่อมาเราอาจเลือกกำหนดคลาสข้อมูล tuples และประเภทโดเมนองค์ประกอบให้เราเลื่อนการตัดสินใจดังกล่าว

ในเลเยอร์ภายนอก (เช่น GUI) มันอาจสมเหตุสมผลที่จะ "ดึง" เอนทิตีลงไปในองค์ประกอบดั้งเดิม (เช่นใส่ลงใน DAO) สิ่งนี้จะช่วยป้องกันการรั่วไหลของโดเมนในชั้นนอกสุดซึ่งได้รับการสนับสนุนใน Martin (2018)

การอ้างอิง
อีอีแวนส์ "การออกแบบที่ขับเคลื่อนด้วยโดเมน", 2004
D. Ghosh, "การสร้างแบบจำลองโดเมนที่ใช้งานได้และตอบสนอง", 2017
RC Martin, "สถาปัตยกรรมสะอาด", 2018


+1 สำหรับการอ้างอิงทั้งหมด
w0051977

4

ทนทุกข์ทรมานจากความหลงใหลดั้งเดิมหรือเป็นนักบินอวกาศสถาปัตยกรรมดีกว่า?

ทั้งสองกรณีเป็นพยาธิวิทยาในกรณีหนึ่งคุณมี abstractions น้อยเกินไปนำไปสู่การทำซ้ำและทำให้แอปเปิ้ลเป็นสีส้มผิดพลาดได้ง่ายและในอีกกรณีหนึ่งคุณลืมที่จะหยุดมันแล้วเริ่มทำสิ่งต่าง ๆ ให้สำเร็จ .

เกือบทุกครั้งที่คุณต้องการการกลั่นกรองซึ่งเป็นทางสายกลางที่มีการพิจารณาเป็นอย่างดี

โปรดจำไว้ว่าสถานที่ให้บริการมีชื่อนอกเหนือจากประเภท นอกจากนี้การย่อยสลายที่อยู่ในส่วนที่เป็นส่วนประกอบของมันอาจจะทำให้เกิดปัญหามากเกินไปหากทำในลักษณะเดียวกัน ไม่ใช่ทุกคนในโลกที่จะเข้าสู่ตัวเมืองนิวยอร์ก


3

หากคุณมีชั้นเงินเดือนก็อาจมีวิธีการเช่น ApplyRaise

ในทางกลับกันคลาส ZipCode ของคุณไม่จำเป็นต้องมีการตรวจสอบภายในเพื่อหลีกเลี่ยงการทำซ้ำการตรวจสอบทุกที่ที่คุณสามารถมีคลาส ZipCodeValidator ที่สามารถฉีดได้ดังนั้นหากระบบของคุณทำงานทั้งในสหรัฐอเมริกาและสหราชอาณาจักร เครื่องมือตรวจสอบที่ถูกต้องและเมื่อคุณต้องจัดการกับที่อยู่ AUS คุณก็สามารถเพิ่มเครื่องมือตรวจสอบความถูกต้องใหม่ได้

ข้อกังวลอีกอย่างคือถ้าคุณต้องเขียนข้อมูลไปยังฐานข้อมูลผ่าน EntityFramework คุณจะต้องรู้วิธีจัดการเงินเดือนหรือรหัสไปรษณีย์

ไม่มีคำตอบที่ชัดเจนว่าจะดึงเส้นแบ่งระหว่างวิธีการเรียนที่ชาญฉลาดอย่างไร แต่ฉันจะบอกว่าฉันมักจะย้ายตรรกะทางธุรกิจเช่นการตรวจสอบความถูกต้องไปยังคลาสตรรกะทางธุรกิจที่มีชั้นข้อมูลเป็นข้อมูลที่บริสุทธิ์ เพื่อให้ทำงานได้ดีขึ้นด้วย EntityFramework

สำหรับการใช้นามแฝงประเภทชื่อสมาชิก / คุณสมบัติควรให้ข้อมูลทั้งหมดที่จำเป็นเกี่ยวกับเนื้อหาดังนั้นฉันจะไม่ใช้นามแฝงประเภท


นามแฝงประเภทเป็นทางเลือกที่ดีหรือไม่?
w0051977

2

(คำถามที่น่าจะเป็นจริงๆคืออะไร)

เมื่อใดที่การใช้งานแบบดั้งเดิมนั้นไม่มีกลิ่นรหัส?

(ตอบ)

เมื่อพารามิเตอร์ไม่มีกฎอยู่ให้ใช้ประเภทดั้งเดิม

ใช้ประเภทดั้งเดิมสำหรับสิ่งที่ชอบของ:

htmlEntityEncode(string value)

ใช้วัตถุสำหรับสิ่งที่ชอบ:

numberOfDaysSinceUnixEpoch(SimpleDate value)

ตัวอย่างหลังมีกฎในนั้นคือวัตถุที่SimpleDateประกอบด้วยYear, และMonth Dayผ่านการใช้วัตถุในกรณีนี้แนวคิดของSimpleDateความถูกต้องสามารถห่อหุ้มภายในวัตถุ


1

นอกเหนือจากตัวอย่างที่เป็นที่ยอมรับของที่อยู่อีเมลหรือรหัสไปรษณีย์ที่ให้ไว้ที่อื่นในคำถามนี้ที่ฉันพบว่าการปรับโครงสร้างใหม่จากการครอบงำแบบดั้งเดิมจะมีประโยชน์เป็นพิเศษคือด้วยรหัสเอนทิตี (ดูhttps://andrewlock.net/using-strongly-typed-entity -ids-to-Avoid-primitive-obsession-part-1 /สำหรับตัวอย่างของวิธีการทำใน. NET)

ฉันได้สูญเสียจำนวนครั้งที่ข้อผิดพลาดพุ่งขึ้นเพราะวิธีการที่มีลายเซ็นเช่นนี้

int leaveId = 12345;
int submitterId = 23456;
int approverId = 34567;

SubmitLeaveApplication(leaveId, approverId, submitterId);

public void SubmitLeaveApplication(int leaveId, int submitterId, int approverId) {
  // implementation here
}

รวบรวมได้ดีและถ้าคุณไม่เข้มงวดกับการทดสอบหน่วยของคุณก็อาจผ่านได้เช่นกัน อย่างไรก็ตาม refactor ID นิติบุคคลเหล่านั้นลงในคลาสเฉพาะโดเมนและข้อผิดพลาด hey presto เวลาคอมไพล์:

LeaveId leaveId = 12345;
SubmitterId submitterId = 23456;
ApproverId approverId = 34567;

SubmitLeaveApplication(leaveId, approverId, submitterId);

public void SubmitLeaveApplication(LeaveId leaveId, SubmitterId submitterId, ApproverId approverId) {
  // implementation here
}

ลองจินตนาการถึงวิธีการที่ปรับขนาดพารามิเตอร์ได้มากถึง 10 ตัวขึ้นไปintชนิดข้อมูลทั้งหมด(ไม่คำนึงถึงกลิ่นรหัสรายการพารามิเตอร์แบบยาว ) ยิ่งแย่ลงเมื่อคุณใช้บางอย่างเช่น AutoMapper เพื่อสลับระหว่างวัตถุโดเมนกับ DTO และการปรับโครงสร้างที่คุณทำ ไม่ได้รับโดยการทำแผนที่อัตโนมัติ


0

คุณจะทำลายหลักการ DRY โดยวางตรรกะการตรวจสอบความถูกต้องทุกที่ที่ใช้รหัสไปรษณีย์

ในทางกลับกันเมื่อต้องรับมือกับหลาย ๆ ประเทศและระบบรหัสไปรษณีย์ที่แตกต่างกันนั่นหมายความว่าคุณไม่สามารถตรวจสอบรหัสไปรษณีย์ได้จนกว่าคุณจะทราบประเทศที่เป็นปัญหา ดังนั้นZipCodeชั้นเรียนของคุณต้องจัดเก็บประเทศด้วย

แต่คุณแยกเก็บประเทศเป็นส่วนหนึ่งของAddress(ซึ่งรหัสไปรษณีย์นี้ยังเป็นส่วนหนึ่งของ) และส่วนหนึ่งของรหัสไปรษณีย์ (สำหรับการตรวจสอบ)

  • หากคุณเป็นเช่นนั้นคุณกำลังละเมิด DRY เช่นกัน แม้ว่าคุณจะไม่เรียกว่าเป็นการละเมิดแบบ DRY (เนื่องจากแต่ละอินสแตนซ์มีจุดประสงค์ที่แตกต่างกัน) แต่ก็ยังจำเป็นต้องใช้หน่วยความจำเพิ่มเติมโดยไม่จำเป็นนอกจากการเปิดประตูสู่ข้อบกพร่องเมื่อค่าประเทศทั้งสองแตกต่างกัน จะ)
    • หรือมิฉะนั้นจะทำให้คุณต้องซิงโครไนซ์จุดข้อมูลสองจุดเพื่อให้แน่ใจว่าจุดเหล่านั้นเหมือนกันเสมอซึ่งแนะนำว่าคุณควรเก็บข้อมูลนี้ไว้ในจุดเดียวจริงๆ
  • ถ้าคุณไม่มีก็ไม่ใช่ZipCodeคลาส แต่เป็นAddressคลาสซึ่งอีกครั้งจะมีคลาสstring ZipCodeซึ่งหมายความว่าเรามาเต็มวงกลมแล้ว

ตัวอย่างเช่นฉันสามารถพูดคุยกับนักวิเคราะห์ธุรกิจเกี่ยวกับรหัสไปรษณีย์แทนที่จะเป็นสตริงที่มีรหัสไปรษณีย์

ประโยชน์คือคุณสามารถพูดคุยเกี่ยวกับพวกเขาเมื่ออธิบายรูปแบบโดเมน

ฉันไม่เข้าใจคำยืนยันพื้นฐานของคุณว่าเมื่อข้อมูลชิ้นหนึ่งมีประเภทของตัวแปรที่กำหนดคุณจะต้องกล่าวถึงประเภทนั้นเมื่อใดก็ตามที่คุณพูดคุยกับนักวิเคราะห์ธุรกิจ

ทำไม? ทำไมคุณถึงไม่สามารถพูดถึง "รหัสไปรษณีย์" และละเว้นประเภทเฉพาะได้อย่างสมบูรณ์ คุณกำลังทำการสนทนาประเภทใดกับนักวิเคราะห์ธุรกิจของคุณ (ไม่ใช่ด้านเทคนิค!) โดยที่ประเภทของทรัพย์สินนั้นมีความสำคัญต่อการสนทนา

ฉันมาจากไหนรหัสไปรษณีย์เป็นตัวเลขเสมอ ดังนั้นเราจึงมีทางเลือกที่เราจะได้เก็บไว้เป็นหรือเป็นint stringเรามักจะใช้สตริงเพราะไม่มีความคาดหวังของการดำเนินการทางคณิตศาสตร์กับข้อมูล แต่ไม่เคยมีนักวิเคราะห์ธุรกิจบอกฉันว่ามันต้องเป็นสตริง การตัดสินใจนั้นขึ้นอยู่กับนักพัฒนา (หรือนักวิเคราะห์ทางเทคนิคเนื้อหาแม้ว่าในประสบการณ์ของฉันพวกเขาไม่ได้จัดการกับ nitty gritty โดยตรง)

นักวิเคราะห์ธุรกิจไม่สนใจประเภทข้อมูลตราบใดที่แอปพลิเคชันทำในสิ่งที่คาดหวังไว้


การตรวจสอบความถูกต้องเป็นสัตว์หากินเพื่อจัดการเพราะมันขึ้นอยู่กับสิ่งที่มนุษย์คาดหวัง

สำหรับหนึ่งฉันไม่เห็นด้วยกับข้อโต้แย้งการตรวจสอบเป็นวิธีที่จะแสดงว่าทำไมความหลงใหลครอบงำดั้งเดิมควรหลีกเลี่ยงเพราะฉันไม่เห็นด้วยว่าข้อมูล (เป็นความจริงสากล) จะต้องได้รับการตรวจสอบตลอดเวลา

ตัวอย่างเช่นจะเกิดอะไรขึ้นถ้านี่เป็นการค้นหาที่ซับซ้อนกว่านี้ แทนที่จะเป็นการตรวจสอบรูปแบบที่ง่ายจะเกิดอะไรขึ้นถ้าการตรวจสอบของคุณเกี่ยวข้องกับการติดต่อ API ภายนอกและรอการตอบกลับ คุณต้องการบังคับให้แอปพลิเคชันของคุณเรียก API ภายนอกนี้สำหรับZipCodeวัตถุทุกชิ้นที่คุณสร้างอินสแตนซ์หรือไม่
อาจเป็นข้อกำหนดทางธุรกิจที่เข้มงวดและแน่นอนว่ามันสมเหตุสมผล แต่นี่ไม่ใช่ความจริงสากล จะมีกรณีการใช้งานมากมายซึ่งเป็นภาระมากกว่าที่เป็นวิธีแก้ปัญหา

ตัวอย่างที่สองเมื่อป้อนที่อยู่ของคุณในแบบฟอร์มการป้อนรหัสไปรษณีย์ของคุณอยู่หน้าประเทศของคุณ ในขณะที่มันเป็นเรื่องดีที่จะมีข้อเสนอแนะการตรวจสอบทันทีใน UI จริง ๆ แล้วมันจะเป็นอุปสรรคต่อฉัน (ในฐานะผู้ใช้) ถ้าแอปพลิเคชันแจ้งเตือนฉันในรูปแบบ zipcode "ผิด" เพราะแหล่งที่แท้จริงของปัญหาคือ (เช่น) ประเทศของฉันไม่ใช่ประเทศที่เลือกตามค่าเริ่มต้นและทำให้การตรวจสอบเกิดขึ้นสำหรับประเทศที่ไม่ถูกต้อง
มันเป็นข้อความแสดงข้อผิดพลาดที่ผิดซึ่งกวนใจผู้ใช้และทำให้เกิดความสับสนโดยไม่จำเป็น

เช่นเดียวกับวิธีการตรวจสอบความถูกต้องไม่สิ้นสุดไม่ใช่ความจริงสากลและไม่ใช่ตัวอย่างของฉัน มันเป็นบริบท บางโดเมนแอปพลิเคชันต้องการการตรวจสอบความถูกต้องของข้อมูลเหนือสิ่งอื่นใด โดเมนอื่นไม่มีการตรวจสอบความถูกต้องที่อยู่ในรายการลำดับความสำคัญเนื่องจากความยุ่งยากที่เกิดขึ้นขัดแย้งกับลำดับความสำคัญที่แท้จริงของตน (เช่นประสบการณ์ผู้ใช้หรือความสามารถในการเก็บข้อมูลที่ผิดพลาดในขั้นต้นเพื่อให้สามารถแก้ไขได้ เก็บไว้)

วันเดือนปีเกิด: ตรวจสอบว่ามีมากกว่าจิตใจและน้อยกว่าวันที่วันนี้
เงินเดือน: ตรวจสอบว่ามากกว่าหรือเท่ากับศูนย์

ปัญหาเกี่ยวกับการตรวจสอบความถูกต้องเหล่านี้คือพวกเขาไม่สมบูรณ์ซ้ำซ้อนหรือบ่งบอกถึงปัญหาที่ใหญ่กว่ามาก

การตรวจสอบว่าวันที่มีค่ามากกว่าความคิดนั้นซ้ำซ้อน ใจจริงหมายถึงว่ามันเป็นวันที่เล็กที่สุดที่เป็นไปได้ นอกจากนี้คุณจะวาดเส้นของความเกี่ยวข้องที่ไหน มีจุดประสงค์อะไรในการป้องกันDateTime.MinDateแต่ยอมให้DateTime.MinDate.AddSeconds(1)? คุณกำลังกระตุ้นให้มีค่าเฉพาะที่ไม่ผิดโดยเฉพาะเมื่อเทียบกับค่าอื่น ๆ

วันเกิดของฉันคือ 2 มกราคม 1978 (ไม่ใช่ แต่ลองคิดดูนะ) แต่สมมุติว่าข้อมูลในใบสมัครของคุณผิดและมันบอกว่าวันเกิดของฉันคือ:

  • 1 มกราคม 1978
  • 1 มกราคม 1722
  • 1 มกราคม 2355

วันที่เหล่านี้ทั้งหมดไม่ถูกต้อง ไม่มีใครในพวกเขา "ถูกกว่า" กว่าคนอื่น แต่กฎการตรวจสอบของคุณจะจับได้เพียงหนึ่งในสามตัวอย่างนี้เท่านั้น

คุณได้ละเว้นบริบทของการใช้ข้อมูลนี้อย่างสมบูรณ์ หากมีการใช้งานในเช่นบอทเตือนความจำวันเกิดฉันจะบอกว่าการตรวจสอบนั้นไม่มีประโยชน์เพราะไม่มีผลที่ไม่ดีเป็นพิเศษในการกรอกวันที่ผิด
ในทางตรงกันข้ามถ้านี้เป็นข้อมูลของรัฐบาลและคุณจำเป็นต้องวันเกิดเพื่อเป็นตัวตนของใครบางคนรับรองความถูกต้อง (และล้มเหลวในการทำเช่นนั้นจะนำไปสู่ผลกระทบที่ไม่ดีเช่นการปฏิเสธการรักษาความปลอดภัยคนสังคม) แล้วความถูกต้องของข้อมูลเป็นสิ่งสำคัญยิ่งและคุณจำเป็นต้องได้อย่างเต็มที่ตรวจสอบข้อมูล การตรวจสอบความถูกต้องที่คุณเสนอตอนนี้ไม่เพียงพอ

สำหรับเงินเดือนมีสามัญสำนึกบางอย่างที่ไม่สามารถลบได้ แต่ถ้าคุณคาดหวังว่าจะมีการป้อนข้อมูลที่ไร้สาระจริงแนบเนียนฉันขอแนะนำให้คุณตรวจสอบแหล่งที่มาของข้อมูลไร้สาระนี้ เพราะหากพวกเขาไม่สามารถเชื่อถือได้ในการป้อนข้อมูลที่มีเหตุผลคุณจึงไม่สามารถเชื่อถือได้เพื่อป้อนข้อมูลที่ ถูกต้อง

หากคุณคำนวณเงินเดือนโดยใช้ใบสมัครของคุณแทนและอาจเป็นไปได้ที่จะมีตัวเลขติดลบ (และถูกต้อง) ดังนั้นวิธีที่ดีกว่าคือMath.Max(myValue, 0)การเปลี่ยนตัวเลขติดลบให้เป็น 0 แทนที่จะตรวจสอบล้มเหลว เพราะถ้าตรรกะของคุณตัดสินใจว่าผลลัพธ์นั้นเป็นจำนวนลบการไม่ผ่านการตรวจสอบหมายความว่ามันจะต้องทำการคำนวณซ้ำและไม่มีเหตุผลที่จะคิดว่ามันจะเกิดขึ้นกับตัวเลขที่แตกต่างกันในครั้งที่สอง
และหากมีตัวเลขที่แตกต่างกันมันจะทำให้คุณสงสัยว่าการคำนวณไม่สอดคล้องกันดังนั้นจึงไม่น่าเชื่อถือ

นี่ไม่ได้เป็นการบอกว่าการตรวจสอบไม่มีประโยชน์ แต่การตรวจสอบที่ไม่มีจุดหมายนั้นไม่ดีทั้งคู่เพราะต้องใช้ความพยายามในขณะที่ไม่ได้แก้ปัญหาจริงๆและให้ความรู้สึกที่ผิด ๆ กับความปลอดภัย


วันเดือนปีเกิดของใครบางคนสามารถผ่านวันที่ปัจจุบันได้หากทารกเกิดในเขตเวลาที่ข้ามไปแล้วในวันถัดไป และโรงพยาบาลสามารถเก็บ "วันเกิดที่คาดหวัง" ไว้ในฐานข้อมูลซึ่งอาจเป็นเดือนในอนาคต คุณต้องการให้เป็นแบบอื่นหรือไม่?
gnasher729

@ gnasher729: ฉันไม่แน่ใจว่าฉันทำตามดูเหมือนว่าคุณเห็นด้วยกับฉัน (การตรวจสอบเป็นบริบทและไม่ถูกต้องในระดับสากล) แต่คำพูดของความคิดเห็นของคุณแสดงให้เห็นว่าคุณคิดว่าฉันไม่เห็นด้วย หรือฉันอ่านผิด
Flater
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.