เมื่อใช้หลักการความรับผิดชอบเดี่ยวสิ่งใดที่ถือว่าเป็น“ ความรับผิดชอบ?”


198

ดูเหมือนชัดเจนว่า "หลักการความรับผิดชอบเดี่ยว" ไม่ได้หมายความว่า "ทำเพียงสิ่งเดียวเท่านั้น" นั่นคือวิธีการที่ใช้

public Interface CustomerCRUD
{
    public void Create(Customer customer);
    public Customer Read(int CustomerID);
    public void Update(Customer customer);
    public void Delete(int CustomerID);
}

บ็อบมาร์ตินกล่าวว่า "คลาสควรมีเหตุผลเดียวเท่านั้นที่จะเปลี่ยนแปลง" แต่นั่นเป็นเรื่องยากที่จะทำให้คุณคิดมากหากคุณเป็นโปรแกรมเมอร์ใหม่สำหรับ SOLID

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

แล้วคุณจะทำอย่างไร คุณจะกำหนดความรับผิดชอบอย่างไรในแต่ละชั้นเรียนและคุณกำหนดความรับผิดชอบอย่างไรในบริบทของ SRP


28
โพสต์เพื่อตรวจสอบโค้ดและแยกออกเป็น :-D
Jörg W Mittag

8
@ JörgWMittagเฮ้ตอนนี้ไม่ได้ทำให้ผู้คนแตกตื่นออกไป :)
Flambino

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

41
ฉันสงสัยว่าคำถามนี้จะได้รับการ downvoted + ทำเครื่องหมายซ้ำทันทีถ้ามันถูกโพสต์โดย Noob A :)
Andrejs

9
@rmunn: หรือพูดอีกอย่างคือ - ตัวแทนใหญ่ดึงดูดตัวแทนมากขึ้นเพราะไม่มีใครยกเลิกอคติพื้นฐานของมนุษย์ใน stackexchange
Andrejs

คำตอบ:


117

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

ตัวอย่างเช่น:

ข้อกำหนดทางธุรกิจใหม่: ผู้ใช้ที่อยู่ในแคลิฟอร์เนียจะได้รับส่วนลดพิเศษ

ตัวอย่างการเปลี่ยนแปลง "ดี": ฉันต้องการแก้ไขโค้ดในคลาสที่คำนวณส่วนลด

ตัวอย่างของการเปลี่ยนแปลงที่ไม่ดี: ฉันต้องแก้ไขโค้ดในคลาสผู้ใช้และการเปลี่ยนแปลงนั้นจะมีเอฟเฟกต์แบบซ้อนในคลาสอื่น ๆ ที่ใช้คลาสผู้ใช้รวมถึงคลาสที่ไม่มีส่วนเกี่ยวข้องกับส่วนลดเช่นการลงทะเบียนการแจงนับและการจัดการ

หรือ:

ข้อกำหนดใหม่ที่ไม่สามารถใช้งานได้: เราจะเริ่มใช้ Oracle แทน SQL Server

ตัวอย่างของการเปลี่ยนแปลงที่ดี: เพียงแค่ต้องปรับเปลี่ยนคลาสเดียวใน data access layer ที่กำหนดวิธีการคงอยู่ของข้อมูลใน DTOs

การเปลี่ยนแปลงไม่ถูกต้อง: ฉันต้องการแก้ไขคลาสเลเยอร์ธุรกิจของฉันทั้งหมดเนื่องจากมีตรรกะเฉพาะของเซิร์ฟเวอร์ SQL

แนวคิดคือการลดการเปลี่ยนแปลงที่อาจเกิดขึ้นในอนาคตให้น้อยที่สุดโดย จำกัด การแก้ไขโค้ดในส่วนของรหัสต่อพื้นที่การเปลี่ยนแปลง

อย่างน้อยที่สุดคลาสของคุณควรแยกข้อกังวลเชิงตรรกะออกจากข้อกังวลทางกายภาพ ชุดที่ดีของตัวอย่างที่สามารถพบได้ในSystem.IOnamespace: มีเราสามารถหาชนิดของกระแสทางกายภาพ (เช่นFileStream, MemoryStreamหรือNetworkStream) และผู้อ่านและนักเขียนต่าง ๆ ( BinaryWriter, TextWriter) การทำงานในระดับตรรกะที่ โดยแยกพวกเขาด้วยวิธีนี้เราหลีกเลี่ยงการระเบิด combinatoric: แทนที่จะต้องFileStreamTextWriter, FileStreamBinaryWriter, NetworkStreamTextWriter, NetworkStreamBinaryWriter, MemoryStreamTextWriterและMemoryStreamBinaryWriterคุณเพียงแค่ขอขึ้นนักเขียนและสตรีมและคุณสามารถมีสิ่งที่คุณต้องการ จากนั้นในภายหลังเราสามารถเพิ่มพูดXmlWriterโดยไม่จำเป็นต้องนำไปใช้ใหม่สำหรับหน่วยความจำไฟล์และเครือข่ายแยกจากกัน


34
ในขณะที่ฉันเห็นด้วยกับการคิดล่วงหน้ามีหลักการเช่น YAGNI และวิธีการเช่น TDD thar แนะนำสิ่งที่ตรงกันข้าม
Robert Harvey

87
YAGNI บอกเราไม่ให้สร้างสิ่งที่เราไม่ต้องการในวันนี้ มันไม่ได้บอกว่าจะไม่สร้างสิ่งต่าง ๆ ในลักษณะที่ยืดออกได้ ดูหลักการเปิด / ปิดซึ่งระบุว่า "เอนทิตีซอฟต์แวร์ (คลาส, โมดูล, ฟังก์ชั่น ฯลฯ ) ควรเปิดเพื่อขยาย แต่ปิดเพื่อการปรับเปลี่ยน"
John Wu

18
@JohnW: +1 สำหรับความคิดเห็น YAGNI ของคุณเพียงอย่างเดียว ฉันไม่อยากจะเชื่อเลยว่าฉันต้องอธิบายให้คนฟังมากแค่ไหนว่า YAGNI ไม่ใช่ข้อแก้ตัวในการสร้างระบบที่ยืดหยุ่นและไม่ยืดหยุ่นซึ่งไม่สามารถตอบสนองต่อการเปลี่ยนแปลงได้ - โดยเฉพาะอย่างยิ่งสิ่งที่ตรงกันข้าม
Greg Burghardt

36
@ JohnWu: ฉันไม่เห็นด้วย YAGNI บอกเราว่าไม่ต้องสร้างสิ่งที่เราไม่ต้องการในวันนี้ ยกตัวอย่างเช่นการอ่านและการทดสอบเป็นสิ่งที่โปรแกรมต้องการเสมอ "วันนี้" ดังนั้น YAGNI จึงไม่ใช่ข้อแก้ตัวที่จะไม่เพิ่มโครงสร้างและจุดฉีดยา อย่างไรก็ตามทันทีที่ "ความสามารถในการขยาย" เพิ่มค่าใช้จ่ายจำนวนมากซึ่งผลประโยชน์ไม่ชัดเจน "ในวันนี้" YAGNI หมายถึงการหลีกเลี่ยงความสามารถในการขยายตัวแบบนี้เนื่องจากภายหลังจะนำไปสู่การ overengineering
Doc Brown

9
@JohnWu เราเปลี่ยนจาก SQL 2008 เป็น 2012 มีทั้งหมดสองคำสั่งที่ต้องการเปลี่ยน และจาก SQL Auth ถึงความน่าเชื่อถือ? ทำไมถึงต้องเป็นรหัสที่เปลี่ยนไป การเปลี่ยนการเชื่อมต่อสายในไฟล์ปรับตั้งก็เพียงพอแล้ว อีกครั้ง YAGNI YAGNI และ SRP เป็นบางครั้งการแข่งขันที่มีความกังวลและคุณจำเป็นต้องตัดสินว่าสิ่งใดมีต้นทุน / ผลประโยชน์ที่ดี
Andy

76

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

มันเป็นเรื่องของสิ่งที่อยู่ในประสบการณ์ของคุณมีแนวโน้มที่จะเปลี่ยนแปลง

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

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

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

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

นักพัฒนาที่ดีและมีประสบการณ์จะมีความรู้สึกว่าการเปลี่ยนแปลงมีแนวโน้ม และรายการทางจิตนั้นจะแตกต่างกันไปตามอุตสาหกรรมและองค์กร

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


1. เพื่อความชัดเจนนั่นไม่ได้หมายความว่าพวกเขาเป็นแผนกที่ไม่ดี พวกเขาอาจเป็นแผนกที่ยอดเยี่ยมที่ปรับปรุงการอ่านโค้ดได้อย่างมาก มันหมายความว่าพวกเขาไม่ได้ถูกขับเคลื่อนโดย SRP


11
คำตอบที่ดีที่สุดและเสนอราคาความคิดของลุงบ็อบ สำหรับสิ่งที่มีแนวโน้มที่จะเปลี่ยนแปลงทุกคนทำเรื่องใหญ่กับ I / O "ถ้าเราเปลี่ยนฐานข้อมูลล่ะ?" หรือ "จะเป็นอย่างไรถ้าเราเปลี่ยนจาก XML เป็น JSON" ฉันคิดว่านี่มักจะเข้าใจผิด คำถามจริงควรเป็น "ถ้าเราต้องการเปลี่ยน int นี้เป็น float เพิ่มฟิลด์และเปลี่ยน String นี้เป็น List of Strings?"
user949300

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

6
@Basilevs ฉันกำลังพยายามที่จะพูดถึงข้อบกพร่องที่คุณเห็นในคำตอบนี้ - อย่าพูดถึงคำตอบของลุงบ๊อบ! แต่บางทีฉันจำเป็นต้องชี้แจงว่า SRP ไม่เกี่ยวกับการทำให้มั่นใจว่า "การเปลี่ยนแปลง" จะส่งผลกระทบต่อชั้นเรียนเดียวเท่านั้น มันเกี่ยวกับการทำให้แน่ใจว่าแต่ละชั้นจะตอบสนองต่อ "การเปลี่ยนแปลงเดียว" เท่านั้น ... มันเกี่ยวกับการพยายามวาดลูกธนูของคุณจากแต่ละชั้นไปยังเจ้าของคนเดียว ไม่ใช่จากเจ้าของแต่ละคนเป็นคลาสเดียว
svidgen

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

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

29

ฉันติดตาม "คลาสควรมีเหตุผลเดียวเท่านั้นที่จะเปลี่ยน"

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

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

ในทางปฏิบัติฉันพบว่าการทดสอบหน่วยช่วยได้ที่นี่ หากรหัสของคุณไม่ยืดหยุ่นก็คงเป็นเรื่องยากที่จะทดสอบ หากคุณไม่สามารถฉีด mocks หรือข้อมูลการทดสอบอื่น ๆ ได้คุณอาจไม่สามารถฉีดSupportChineseโค้ดนั้นได้

ตัวชี้วัดที่ขรุขระอีกอย่างหนึ่งคือระดับเสียงของลิฟต์ ลิฟต์ลิฟต์แบบดั้งเดิมคือ "ถ้าคุณอยู่ในลิฟต์กับนักลงทุนคุณสามารถขายเขาในความคิดได้ไหม?" ผู้เริ่มต้นต้องมีคำอธิบายสั้น ๆ ง่ายๆว่าพวกเขากำลังทำอะไร - สิ่งที่พวกเขาสนใจคือ ในทำนองเดียวกันการเรียน (และฟังก์ชั่น) ควรมีคำอธิบายง่ายๆของสิ่งที่พวกเขาทำ ไม่ใช่ "คลาสนี้ใช้ fubar บางอย่างที่คุณสามารถใช้ในสถานการณ์เฉพาะเหล่านี้" สิ่งที่คุณสามารถบอกนักพัฒนาซอฟต์แวร์คนอื่นได้: "คลาสนี้สร้างผู้ใช้" หากคุณไม่สามารถสื่อสารสิ่งนั้นกับผู้พัฒนารายอื่นได้คุณจะได้รับข้อบกพร่อง


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

16
ฉันเป็นผู้สนับสนุนที่สำคัญสำหรับแนวคิด "pitch pitch" หากเป็นการยากที่จะอธิบายว่าชั้นเรียนทำอะไรในประโยคหนึ่งหรือสองประโยคคุณอยู่ในพื้นที่เสี่ยง
Ivan

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

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

1
@KevinKrumwiede นั่นคือสิ่งที่ "ไก่วิ่งไปรอบ ๆ ด้วยการตัดหัว" และ "Wild Goose Chase" เป็นวิธีการ!

26

ไม่มีใครรู้ว่า. หรืออย่างน้อยเราไม่สามารถเห็นด้วยกับคำนิยามเดียว นั่นคือสิ่งที่ทำให้ SPR (และหลักการอื่น ๆ ของโซลิด) ขัดแย้งกันมาก

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

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


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

9
+42 สำหรับย่อหน้าสุดท้าย ดังที่ @RobertHarvey กล่าวว่าไม่ควรใช้ SPR, SOLID และ YAGNI เป็น " กฎเด็ดขาด " แต่เป็นหลักการทั่วไปของ "คำแนะนำที่ดี" ระหว่างพวกเขา (และคนอื่น ๆ ) คำแนะนำบางครั้งจะขัดแย้งกัน แต่ให้สมดุลคำแนะนำนั้น (เมื่อเทียบกับการปฏิบัติตามกฎที่เข้มงวด) จะ (เมื่อเวลาผ่านไปเมื่อประสบการณ์ของคุณเติบโตขึ้น) นำคุณไปสู่การสร้างซอฟต์แวร์ที่ดีขึ้น ควรมีเพียง "กฎสัมบูรณ์" ในการพัฒนาซอฟต์แวร์: " ไม่มีกฎเด็ดขาด "
TripeHound

นี่เป็นการชี้แจงที่ดีมากใน SRP ด้านเดียว แต่ถึงแม้ว่าหลักการของ SOLID ไม่ใช่กฎที่ยาก แต่ก็ไม่มีคุณค่ามากนักหากไม่มีใครเข้าใจสิ่งที่พวกเขาหมายถึง - แม้แต่น้อยดังนั้นถ้าคุณอ้างว่า "ไม่มีใครรู้" ก็จริง! ... มันสมเหตุสมผลสำหรับพวกเขาที่จะเข้าใจยาก เช่นเดียวกับทักษะใด ๆ มีบางสิ่งที่แยกความดีออกจากความดีน้อย แต่ ... "ไม่มีใครรู้" ทำให้พิธีกรรมซ้อม (และฉันไม่เชื่อว่านั่นเป็นเจตนาของ SOLID!)
svidgen

3
โดย "ไม่มีใครรู้" ฉันหวังว่า @Euphoric เพียงแค่หมายความว่าไม่มีคำจำกัดความที่แม่นยำที่จะใช้ได้กับทุกกรณีการใช้งาน มันเป็นสิ่งที่ต้องมีระดับการตัดสิน ฉันคิดว่าหนึ่งในวิธีที่ดีที่สุดในการกำหนดความรับผิดชอบของคุณที่วางคือการย้ำอย่างรวดเร็วและให้ codebase ของคุณบอกคุณ มองหา "กลิ่น" ที่รหัสของคุณไม่สามารถบำรุงรักษาได้ง่าย ตัวอย่างเช่นเมื่อการเปลี่ยนแปลงกฎธุรกิจเดียวเริ่มมีผลกระทบต่อคลาสที่ดูเหมือนไม่เกี่ยวข้องคุณอาจมีการละเมิด SRP
Michael L.

1
ฉันอย่างจริงจังที่สอง @TripeHound และคนอื่น ๆ ที่ชี้ให้เห็นว่า "กฎ" เหล่านี้ไม่ได้มีไว้เพื่อกำหนด One True ศาสนาแห่งการพัฒนา แต่เพื่อเพิ่มโอกาสในการพัฒนาซอฟต์แวร์ที่บำรุงรักษาได้ ระวังการปฏิบัติตาม "วิธีปฏิบัติที่ดีที่สุด" ถ้าคุณไม่สามารถอธิบายได้ว่ามันส่งเสริมซอฟต์แวร์ที่บำรุงรักษาได้หรือไม่ปรับปรุงคุณภาพหรือเพิ่มประสิทธิภาพการพัฒนา ..
Michael L.

5

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

  • ความรับผิดชอบนั้นสอดคล้องกับสิทธิอำนาจ
  • ไม่ควรรับผิดชอบสองสิ่งนี้ในสิ่งเดียวกัน

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

นอกเหนือจากสองข้อนี้หลักการที่สามยังดูสมเหตุสมผล:

  • ความรับผิดชอบสามารถมอบหมาย

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

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


ฉันไม่แน่ใจ 100% นี่อธิบายได้อย่างเต็มที่ แต่ฉันคิดว่าการอธิบาย "ความรับผิดชอบ" เกี่ยวกับ "อำนาจ" เป็นวิธีที่ชาญฉลาดในการพูดวลี! (+1)
svidgen

Pirsig กล่าวว่า "คุณมักจะสร้างปัญหาของคุณในเครื่อง" ซึ่งทำให้ฉันหยุดชั่วคราว

@nocomprende คุณมีแนวโน้มที่จะสร้างจุดแข็งของคุณในเครื่อง ฉันขอยืนยันว่าเมื่อจุดแข็งและจุดอ่อนของคุณเหมือนกันนั่นคือเมื่อมันน่าสนใจ
Cort Ammon

5

ในการประชุมที่เยลนี้ลุงบ๊อบยกตัวอย่างตลก ๆนี้:

ป้อนคำอธิบายภาพที่นี่

เขาบอกว่าEmployeeมีสามเหตุผลในการเปลี่ยนแปลงสามแหล่งที่มาของข้อกำหนดการเปลี่ยนแปลงและให้อารมณ์ขันนี้และลิ้นในแก้มแต่อธิบายอย่างไรก็ตาม: คำอธิบาย:

  • หากCalcPay()วิธีการมีข้อผิดพลาดและค่าใช้จ่าย บริษัท ล้าน US $ CFO จะยิงคุณ

  • หากReportHours()วิธีการมีข้อผิดพลาดและค่าใช้จ่าย บริษัท ล้าน US $ COO จะยิงคุณ

  • หากWriteEmmployee() วิธีมีข้อผิดพลาดที่ทำให้เกิดการลบข้อมูลจำนวนมากและค่าใช้จ่าย บริษัท ล้าน US $ ให้CTO จะยิงคุณ

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

เขาให้โซลูชันนี้ที่แก้การละเมิด SRP แต่ยังต้องแก้ปัญหาการละเมิดกรมทรัพย์สินทางปัญญาที่ไม่ได้แสดงในวิดีโอ

ป้อนคำอธิบายภาพที่นี่


ตัวอย่างนี้ดูเหมือนคลาสที่มีความรับผิดชอบผิด
Robert Harvey

4
@RobertHarvey เมื่อชั้นเรียนมีความรับผิดชอบมากเกินไปก็หมายความว่าความรับผิดชอบพิเศษนั้นเป็นความรับผิดชอบที่ผิด
Tulains Córdova

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

@ RobertHarvey ความแตกต่างคืออะไร? สถานการณ์เหล่านั้นดูเหมือนจะผิดปกติสำหรับฉัน
พอลเดรเปอร์

3

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

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

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

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


นี่คือคำแนะนำเสียง มันอาจคุ้มค่าที่จะชี้ให้เห็นว่าคุณแบ่งความรับผิดชอบตามเกณฑ์มากกว่า SRP
Jørgen Fogh

1
การเปรียบเทียบรถยนต์: ฉันไม่จำเป็นต้องรู้ว่ามีก๊าซอยู่ในถังของคนอื่นมากแค่ไหนหรือต้องการเปิดที่ปัดน้ำฝนของคนอื่น (แต่นั่นคือคำจำกัดความของอินเทอร์เน็ต) (Shh! คุณจะทำลายเรื่องราว)

1
@nocomprende - "ฉันไม่จำเป็นต้องรู้ว่ามีแก๊สอยู่ในถังของคนอื่นมากแค่ไหน" - เว้นแต่คุณจะเป็นวัยรุ่นที่พยายามจะตัดสินใจว่ารถยนต์คันใดของครอบครัวที่จะ "ยืม" สำหรับการเดินทางครั้งต่อไปของคุณ ... ;)
alephzero

3

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

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

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

ใช้การอ้อมมากเกินไปและกลายเป็นความยุ่งเหยิงอีกครั้ง ... สำหรับหลักการอื่น ๆ อันนี้จะขัดแย้งกับผู้อื่นเช่น KISS, YAGNI ฯลฯ ทุกอย่างเป็นเรื่องของความสมดุล


SRP ไม่ใช่แค่ Cohesion ของคอนสแตนตินเท่านั้นหรือ?
Nick Keighley

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

@ NickKeighley ฉันคิดว่ามันทำงานร่วมกันไม่ได้เขียนมากขนาดใหญ่ แต่มองจากมุมมองอื่น
sdenham

3

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

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

  • อัตราภาษีเปลี่ยนแปลงเนื่องจากการตัดสินใจทางการเมือง
  • ฝ่ายการตลาดตัดสินใจเปลี่ยนชื่อผลิตภัณฑ์ทั้งหมด
  • UI ต้องได้รับการออกแบบใหม่เพื่อให้สามารถเข้าถึงได้
  • ฐานข้อมูลมีความแออัดดังนั้นคุณต้องทำการเพิ่มประสิทธิภาพบางอย่าง
  • คุณต้องรองรับแอพมือถือ
  • และอื่น ๆ ...

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

ดังนั้นอย่าเพิ่งมุ่งความสนใจไปที่สิ่งที่สามารถเปลี่ยนแปลงได้ - สิ่งใด ๆ ที่อาจเปลี่ยนแปลงได้ในอนาคต มุ่งเน้นไปที่สิ่งที่อาจเปลี่ยนแปลงได้อย่างอิสระ โดยทั่วไปการเปลี่ยนแปลงจะเป็นอิสระหากเกิดจากนักแสดงคนอื่น

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

ในการอ้างถึงลุงบ็อบผู้คิดค้นคำนี้:

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

ดังนั้นในการสรุป: "ความรับผิดชอบ" ถูกจัดไว้ให้กับฟังก์ชั่นทางธุรกิจเดียว หากมีนักแสดงมากกว่าหนึ่งคนอาจทำให้คุณต้องเปลี่ยนชั้นเรียนชั้นเรียนก็อาจทำลายหลักการนี้


ตามหนังสือของเขาที่ชื่อว่า "Clean Architecture" นี่ถูกต้องแล้ว กฎเกณฑ์ทางธุรกิจควรมาจากแหล่งเดียวและแหล่งเดียวเท่านั้น ซึ่งหมายความว่าฝ่ายทรัพยากรบุคคลฝ่ายปฏิบัติการและฝ่ายไอทีทุกคนต้องร่วมมือกันกำหนดข้อกำหนดใน "ความรับผิดชอบเดี่ยว" และนั่นคือหลักการ +1
Benny Skogberg

2

บทความที่ดีที่อธิบายหลักการการเขียนโปรแกรม SOLID และให้ตัวอย่างของรหัสทั้งการติดตามและไม่ปฏิบัติตามหลักการนี้คือhttps://scotch.io/bar-talk/solid-the-first-five-principles-of-object-oriented- ออกแบบ .

ในตัวอย่างที่เกี่ยวข้องกับ SRP เขาให้ตัวอย่างของคลาสรูปร่างสองสาม (วงกลมและสี่เหลี่ยม) และคลาสที่ออกแบบมาเพื่อคำนวณพื้นที่ทั้งหมดของรูปร่างหลาย ๆ รูปร่าง

ในตัวอย่างแรกของเขาเขาสร้างพื้นที่การคำนวณระดับและมันได้กลับออกของเขาเป็น HTML ต่อมาเขาตัดสินใจว่าเขาต้องการที่จะแสดงมันเป็น JSON แทนและต้องเปลี่ยนพื้นที่การคำนวณระดับของเขา

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

นี่เป็นตัวอย่างง่ายๆ (และเข้าใจการอ่านบทความได้ง่ายขึ้นเนื่องจากมีโค้ดขนาดสั้น) แต่แสดงให้เห็นถึงแนวคิดหลักของ SRP


0

ก่อนอื่นสิ่งที่คุณมีคือปัญหาสองอย่างที่แยกจากกัน: ปัญหาของวิธีการที่จะใส่ในชั้นเรียนของคุณและปัญหาของอินเทอร์เฟซที่ขยายตัว

อินเตอร์เฟซ

คุณมีส่วนต่อประสานนี้:

public Interface CustomerCRUD
{
  public void Create(Customer customer);
  public Customer Read(int CustomerID);
  public void Update(Customer customer);
  public void Delete(int CustomerID);
}

สันนิษฐานได้ว่าคุณมีหลายคลาสที่สอดคล้องกับCustomerCRUDอินเทอร์เฟซ (มิฉะนั้นอินเทอร์เฟซไม่จำเป็น), และบางฟังก์ชันdo_crud(customer: CustomerCRUD)ที่ใช้ในวัตถุที่สอดคล้องกัน แต่คุณได้ทำลาย SRP ไปแล้ว: คุณได้ผูกการดำเนินการที่แตกต่างกันสี่รายการเข้าด้วยกัน

สมมติว่าคุณต้องการทำงานในมุมมองฐานข้อมูลในภายหลัง มุมมองฐานข้อมูลมีเพียงReadวิธีใช้ได้สำหรับมัน แต่คุณต้องการที่จะเขียนฟังก์ชั่นdo_query_stuff(customer: ???)ที่ตัวดำเนินการโปร่งใสบนทั้งตารางหรือมุมมองแบบเต็ม จะใช้Readวิธีการเท่านั้นหลังจากทั้งหมด

ดังนั้นสร้างส่วนต่อประสาน

ส่วนต่อประสานลูกค้าสาธารณะผู้อ่าน {ลูกค้าสาธารณะอ่าน (customerID: int)}

และCustomerCrudอินเทอร์เฟซของคุณเป็นปัจจัย:

public interface CustomerCRUD extends CustomerReader
{
  public void Create(Customer customer);
  public void Update(Customer customer);
  public void Delete(int CustomerID);
}

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

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

let do_customer_stuff customer = customer.read ... customer.update ...

ที่เรียกว่าวิธีใดก็ตามที่เราชอบ OCaml จะใช้การอนุมานแบบเพื่อกำหนดว่าเราสามารถส่งผ่านวัตถุใด ๆ ที่ใช้วิธีการเหล่านี้ ในตัวอย่างนี้ก็จะตรวจสอบว่ามีการพิมพ์customer<read: int -> unit, update: int -> unit, ...>

การเรียนการสอน

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


4
"ไร้ความหมาย" ค่อนข้างแข็งแกร่ง ฉันสามารถอยู่ข้างหลัง "ลึกลับ" หรือ "เซน" แต่ไม่แบนเรียบไม่มีความหมาย!
svidgen

คุณช่วยอธิบายอีกเล็กน้อยได้ไหมว่าทำไมการพิมพ์ย่อยโครงสร้างเป็นวิธีแก้ปัญหา
Robert Harvey

@RobertHarvey ปรับโครงสร้างคำตอบของฉันใหม่อีกครั้ง
gardenhead

4
ฉันใช้อินเทอร์เฟซแม้ว่าจะมีเพียงคลาสเดียวที่ใช้งาน ทำไม? การเยาะเย้ยในการทดสอบหน่วย
นิรันด

0

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

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


0

มันคือเพื่อให้บรรลุความต้องการที่มีการเปลี่ยนแปลงหลาย ๆ ไม่จำเป็นต้องมีองค์ประกอบของการเปลี่ยนแปลง

แต่โชคดีที่เข้าใจว่าในแวบแรกเมื่อคุณได้ยินเกี่ยวกับโซลิด


ฉันเห็นความคิดเห็นจำนวนมากที่บอกว่าSRPและYAGNIสามารถแย้งกันได้ แต่YAGNฉันบังคับโดย TDD (GOOS, London School)สอนให้ฉันคิดและออกแบบส่วนประกอบของฉันจากมุมมองของลูกค้า ฉันเริ่มต้นการออกแบบอินเตอร์เฟซของฉันโดยสิ่งที่เป็นอย่างน้อยที่ลูกค้าต้องการจะทำว่าเป็นวิธีการเล็ก ๆ น้อย ๆ ก็ควรจะทำอย่างไร และการออกกำลังกายนั้นสามารถทำได้โดยไม่ต้องมีความรู้เกี่ยวกับ TDD

ฉันชอบเทคนิคที่อธิบายโดยลุงบ๊อบ (ฉันจำไม่ได้ว่าอยู่ที่ไหนเศร้า) ซึ่งไปบางอย่างเช่น:

ถามตัวเองว่าคลาสนี้ทำอะไร

ไม่คำตอบของคุณมีทั้งของและหรือหรือ

ถ้าเป็นเช่นนั้นให้แยกส่วนของคำตอบนั้นเป็นความรับผิดชอบของตัวเอง

เทคนิคนี้เป็นแบบสัมบูรณ์และตามที่ @svidgen กล่าวว่าSRPเป็นคำพิพากษา แต่เมื่อเรียนรู้สิ่งใหม่สัมบูรณ์จะดีที่สุดมันง่ายกว่าที่จะทำอะไรบางอย่างเสมอ ตรวจสอบให้แน่ใจว่าเหตุผลที่คุณไม่แยกคือ การประเมินที่มีการศึกษาไม่ใช่เพราะคุณไม่รู้วิธีการ นี่คือศิลปะและต้องใช้ประสบการณ์


ผมคิดว่าหลายคำตอบดูเหมือนจะทำให้อาร์กิวเมนต์สำหรับการ decoupling เมื่อพูดคุยเกี่ยวกับSRP

SRPคือไม่ได้เพื่อให้แน่ใจว่าการเปลี่ยนแปลงที่ไม่ได้เผยแพร่ลงกราฟพึ่งพา

ในทางทฤษฎีหากปราศจากSRPคุณจะไม่ต้องพึ่งพา ...

การเปลี่ยนแปลงหนึ่งครั้งไม่ควรทำให้เกิดการเปลี่ยนแปลงหลายแห่งในแอปพลิเคชัน แต่เรามีหลักการอื่นสำหรับเรื่องนั้น SRPอย่างไรก็ตามปรับปรุงเปิดปิดหลักการ หลักการนี้เป็นเรื่องเกี่ยวกับสิ่งที่เป็นนามธรรมอย่างไรก็ตามabstractions ขนาดเล็กง่ายต่อการปรับใช้ใหม่

ดังนั้นเมื่อสอน SOLID โดยรวมให้ระมัดระวังในการสอนว่าSRPช่วยให้คุณสามารถเปลี่ยนรหัสได้น้อยลงเมื่อความต้องการเปลี่ยนแปลงในความเป็นจริงมันช่วยให้คุณสามารถเขียนรหัสใหม่ได้น้อยลง


3
When learning something new, absolutes are the best, it is easier to just always do something.- จากประสบการณ์ของฉันโปรแกรมเมอร์คนใหม่นั้นดื้อรั้นเกินไป ความสมบูรณ์แบบนำไปสู่การพัฒนาที่ไม่คิดและการเขียนโปรแกรมสินค้าลัทธิ การพูดว่า "แค่ทำสิ่งนี้" ก็โอเคตราบใดที่คุณเข้าใจว่าคนที่คุณพูดจะต้องเข้าใจสิ่งที่คุณสอนในภายหลัง
Robert Harvey

@ RobertHarvey เป็นความจริงโดยสมบูรณ์ซึ่งสร้างพฤติกรรมที่ไม่เชื่อฟังและคุณต้องปลดปล่อย / เรียนรู้ใหม่เมื่อคุณได้รับประสบการณ์ นี่คือประเด็นของฉัน หากโปรแกรมเมอร์คนใหม่พยายามโทรหาผู้พิพากษาโดยไม่มีเหตุผลใด ๆ ที่จะทำให้การตัดสินใจของพวกเขาดูเหมือนว่าไร้ประโยชน์เพราะพวกเขาไม่รู้ว่าทำไมมันถึงใช้ได้เมื่อมันทำงาน โดยการทำให้ผู้คนหักโหมมันจะสอนให้พวกเขามองหาข้อยกเว้นแทนที่จะคาดเดาอย่างไม่มีเงื่อนไข ทุกสิ่งที่คุณพูดเกี่ยวกับสมบูรณาญาสิทธิราชย์ถูกต้องซึ่งเป็นเหตุผลที่มันควรจะเป็นจุดเริ่มต้นเท่านั้น
Chris Wohlert

@RobertHarvey ตัวอย่างชีวิตจริงที่รวดเร็ว: คุณอาจสอนลูก ๆ ของคุณให้ซื่อสัตย์เสมอแต่เมื่อพวกเขาโตขึ้นพวกเขาอาจจะตระหนักถึงข้อยกเว้นบางประการที่ผู้คนไม่ต้องการได้ยินความคิดที่ซื่อสัตย์ที่สุดของพวกเขา การคาดหวังว่าเด็กอายุ 5 ปีในการตัดสินใจเกี่ยวกับความซื่อสัตย์นั้นเป็นสิ่งที่ดีที่สุด :)
Chris Wohlert

0

ไม่มีคำตอบที่ชัดเจนว่า แม้ว่าคำถามจะแคบ แต่คำอธิบายไม่ได้

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

นั่นหมายความว่าในทางปฏิบัติจริง ๆ ?

เมื่อเร็ว ๆ นี้ฉันใช้รูปแบบของการเข้ารหัสซึ่งส่วนใหญ่ประกอบด้วยสองขั้นตอน:

ขั้นตอนที่ดีที่สุดที่ฉันอธิบายว่าเป็นความโกลาหลความคิดสร้างสรรค์ ในขั้นตอนนี้ฉันเขียนโค๊ดเป็นความคิดที่ไหล - เช่นดิบและน่าเกลียด

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

ตอนนี้ฉันทำงานเป็นส่วนใหญ่ใน Python ซึ่งทำให้ฉันสามารถคิดถึงวัตถุและคลาสได้ในภายหลัง First Phase I - ฉันเขียนเฉพาะฟังก์ชั่นและกระจายมันโดยการสุ่มในโมดูลที่แตกต่างกัน ในระยะที่สองหลังจากที่ฉันเริ่มทำสิ่งต่าง ๆ ฉันจะได้เห็นอย่างชัดเจนว่าโมดูลเกี่ยวข้องกับส่วนใดของโซลูชัน และในขณะที่อ่านผ่านโมดูลต่างๆหัวข้อต่างๆก็ปรากฏขึ้นสำหรับฉัน ฟังก์ชั่นบางอย่างเกี่ยวข้องกับหัวเรื่อง เหล่านี้เป็นผู้สมัครที่ดีสำหรับการเรียน และหลังจากที่ฉันเปลี่ยนฟังก์ชั่นเป็นคลาส - ซึ่งเกือบจะเสร็จสิ้นด้วยการย่อหน้าและเพิ่มselfลงในรายการพารามิเตอร์ใน python;) - ฉันใช้SRPเช่น Occam's Razor เพื่อตัดการทำงานให้กับโมดูลและคลาสอื่น ๆ

ตัวอย่างปัจจุบันอาจกำลังเขียนฟังก์ชันการส่งออกขนาดเล็กในวันอื่น ๆ

มีความต้องการแผ่นcsv , excelและexcelรวมกันใน zip

ฟังก์ชั่นธรรมดานั้นทำในสามมุมมอง (= ฟังก์ชั่น) แต่ละฟังก์ชั่นใช้วิธีการทั่วไปในการกำหนดตัวกรองและวิธีที่สองเพื่อดึงข้อมูล จากนั้นในแต่ละฟังก์ชั่นการเตรียมการส่งออกจึงเกิดขึ้นและได้รับการตอบสนองจากเซิร์ฟเวอร์

มีสิ่งที่เป็นนามธรรมมากเกินไปในระดับที่ผสม:

I) จัดการกับคำขอ / ตอบกลับขาเข้า / ขาออก

II) การพิจารณาตัวกรอง

III) การดึงข้อมูล

IV) การเปลี่ยนแปลงข้อมูล

ขั้นตอนง่าย ๆ คือการใช้หนึ่งนามธรรม ( exporter) เพื่อจัดการกับเลเยอร์ II-IV ในขั้นตอนแรก

เพียงคนเดียวที่ยังคงได้รับการหัวข้อการจัดการกับการร้องขอ / การตอบสนอง ที่ระดับเดียวกันของ abstraction กำลังดึงพารามิเตอร์คำขอซึ่งก็โอเค ดังนั้นฉันจึงมีความรับผิดชอบ " มุมมอง " นี้

ประการที่สองฉันต้องแยกผู้ส่งออกออกซึ่งอย่างที่เราเห็นประกอบด้วยนามธรรมอย่างน้อยสามชั้น

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

ในขั้นตอนต่อไปฉันแยกกลไกการส่งออกที่แท้จริงออกจากกัน: เมื่อต้องการเขียนไปยังไฟล์ชั่วคราวฉันต้องแบ่งออกเป็นสอง "หน้าที่": หนึ่งสำหรับการเขียนข้อมูลลงดิสก์จริงและอีกส่วนหนึ่งซึ่งเกี่ยวข้องกับรูปแบบที่แท้จริง

ตามรูปของคลาสและโมดูลต่างๆสิ่งต่าง ๆ ก็ชัดเจนขึ้น และมักจะเป็นคำถามที่แฝงอยู่ไม่ว่าจะเป็นชั้นเรียนไม่มากเกินไป

คุณจะกำหนดความรับผิดชอบอย่างไรในแต่ละชั้นเรียนและคุณกำหนดความรับผิดชอบอย่างไรในบริบทของ SRP

ยากที่จะทำตามสูตร แน่นอนว่าฉันสามารถทำซ้ำสิ่งที่คลุมเครือ»ระดับหนึ่งของการเป็นนามธรรม« - กฎถ้าช่วยได้

ส่วนใหญ่สำหรับฉันมันเป็น "สัญชาตญาณศิลป์" ซึ่งนำไปสู่การออกแบบในปัจจุบัน ฉันจำลองรหัสเหมือนศิลปินอาจปั้นดินหรือทำสี

ลองนึกภาพฉันว่าเป็นรหัส Bob Ross ;)


0

สิ่งที่ฉันพยายามทำเพื่อเขียนโค้ดที่ตามหลัง SRP:

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

ตัวอย่าง:

ปัญหา: รับตัวเลขสองตัวจากผู้ใช้คำนวณผลรวมและส่งออกผลลัพธ์ไปยังผู้ใช้:

//first step: solve the problem right away
static void Main(string[] args)
{
    Console.WriteLine("Number 1: ");
    int firstNumber = Convert.ToInt32(Console.ReadLine());

    Console.WriteLine("Number 2: ");
    int secondNumber = Convert.ToInt32(Console.ReadLine());

    int result = firstNumber + secondNumber;

    Console.WriteLine("Hi there! The result is: {0}", result);

    Console.ReadLine();
}

จากนั้นลองกำหนดความรับผิดชอบตามงานที่ต้องดำเนินการ จากนี้แยกคลาสที่เหมาะสม:

//Responsible for getting two integers from the user
class Input {
    public int FirstNumber { get; set; }
    public int SecondNumber { get; set; }
    public void Read() {
        Console.WriteLine("Number 1: ");
        FirstNumber = Convert.ToInt32(Console.ReadLine());

        Console.WriteLine("Number 2: ");
        SecondNumber = Convert.ToInt32(Console.ReadLine());
    }
}

//Responsible for calculating the sum of two integers
class SumOperation {
    public int Result { get; set; }
    public void Calculate(int a, int b) {
        Result = a + b;
    }
}

//Responsible for the output of some value to the user
class Output {
    public void Write(int result) {
        Console.WriteLine("Hello! The result is: {0}", result);
    }
}

จากนั้นโปรแกรม refactored จะกลายเป็น:

//Program: responsible for main execution.
//Gets two numbers from user and output their sum.
static void Main(string[] args)
{
    var input = new Input();
    input.Read();

    var operation = new SumOperation();
    operation.Calculate(input.FirstNumber, input.SecondNumber);

    var output = new Output();
    output.Write(operation.Result);

    Console.ReadLine();
}

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


1
ตัวอย่างของคุณง่ายเกินไปที่จะอธิบาย SRP อย่างเพียงพอ ไม่มีใครทำเช่นนี้ในชีวิตจริง
Robert Harvey

ใช่ในโครงการจริงฉันเขียนรหัสเทียมแทนที่จะเขียนรหัสที่แน่นอนเหมือนในตัวอย่างของฉัน หลังจาก pseudocode ฉันพยายามแบ่งความรับผิดชอบเช่นเดียวกับที่ฉันทำในตัวอย่าง อย่างไรก็ตามนั่นเป็นเพียงวิธีที่ฉันทำ
Emerson Cardoso

0

จาก Robert C. Martins หนังสือสถาปัตยกรรมสะอาด: คู่มือช่างเพื่อโครงสร้างซอฟต์แวร์และการออกแบบเผยแพร่เมื่อวันที่ 10 กันยายน 2017 Robert เขียนในหน้า 62 ต่อไปนี้:

ประวัติศาสตร์ SRP ได้รับการอธิบายด้วยวิธีนี้:

โมดูลควรมีเหตุผลเพียงหนึ่งเดียวเท่านั้นที่จะเปลี่ยน

ระบบซอฟต์แวร์มีการเปลี่ยนแปลงเพื่อตอบสนองผู้ใช้และผู้มีส่วนได้เสีย; ผู้ใช้และผู้มีส่วนได้เสียเหล่านั้นคือ "เหตุผลในการเปลี่ยนแปลง" หลักการกำลังพูดถึง แน่นอนเราสามารถใช้ถ้อยคำใหม่เพื่อพูดสิ่งนี้:

โมดูลควรมีความรับผิดชอบต่อผู้ใช้หรือผู้มีส่วนได้เสียเพียงคนเดียว

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

ดังนั้นเวอร์ชันสุดท้ายของ SRP คือ:

โมดูลควรจะรับผิดชอบต่อหนึ่งและเพียงคนเดียวเท่านั้นที่นักแสดง

ดังนั้นนี่ไม่เกี่ยวกับรหัส SRP นั้นเกี่ยวกับการควบคุมการไหลของความต้องการและความต้องการทางธุรกิจซึ่งมาจากแหล่งเดียวเท่านั้น


ฉันไม่แน่ใจว่าทำไมคุณถึงทำให้แตกต่างว่า "มันไม่เกี่ยวกับรหัส" แน่นอนมันเกี่ยวกับรหัส นี่คือการพัฒนาซอฟต์แวร์
Robert Harvey

@ RobertHarvey จุดของฉันคือการไหลของความต้องการมาจากแหล่งเดียวนักแสดง ผู้ใช้และผู้มีส่วนได้ส่วนเสียไม่ได้เป็นรหัส แต่เป็นกฎเกณฑ์ทางธุรกิจที่เข้ามาหาเราตามข้อกำหนด ดังนั้น SRP จึงเป็นกระบวนการในการควบคุมข้อกำหนดเหล่านี้ซึ่งสำหรับฉันไม่ใช่รหัส เป็นการพัฒนาซอฟต์แวร์ (!) แต่ไม่ใช่รหัส
Benny Skogberg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.