ฉันจะรู้ได้อย่างไรว่าวิธีการของฉันควรใช้ซ้ำได้อย่างไร [ปิด]


133

ฉันกำลังคิดถึงธุรกิจของตัวเองที่บ้านและภรรยาของฉันมาหาฉันและพูดว่า

ที่รัก .. คุณสามารถพิมพ์ Day Light Saving ทั่วโลกสำหรับปี 2018 ในคอนโซลได้หรือไม่? ฉันต้องตรวจสอบบางอย่าง

และฉันก็มีความสุขสุด ๆ เพราะนั่นคือสิ่งที่ฉันรอมาตลอดทั้งชีวิตกับประสบการณ์ Java ของฉันและเกิดขึ้นกับ:

import java.time.*;
import java.util.Set;

class App {
    void dayLightSavings() {
        final Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        availableZoneIds.forEach(
            zoneId -> {
                LocalDateTime dateTime = LocalDateTime.of(
                    LocalDate.of(2018, 1, 1), 
                    LocalTime.of(0, 0, 0)
                );
                ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
                while (2018 == now.getYear()) {
                    int hour = now.getHour();
                    now = now.plusHours(1);
                    if (now.getHour() == hour) {
                        System.out.println(now);
                    }
                }
            }
        );
    }
}

แต่จากนั้นเธอบอกว่าเธอแค่ทดสอบฉันว่าฉันเป็นวิศวกรซอฟต์แวร์ที่ผ่านการฝึกอบรมอย่างมีจริยธรรมหรือไม่และบอกฉันว่าดูเหมือนว่าฉันไม่ได้เป็นแบบนั้น (เอามาจากที่นี่ )

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

และฉันก็ชอบดีโอเคคุณได้รับฉัน .. ผ่านปีที่คุณชอบที่นี่คุณไป:

import java.time.*;
import java.util.Set;

class App {
    void dayLightSavings(int year) {
        final Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        availableZoneIds.forEach(
            zoneId -> {
                LocalDateTime dateTime = LocalDateTime.of(
                    LocalDate.of(year, 1, 1), 
                    LocalTime.of(0, 0, 0)
                );
                ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
                while (year == now.getYear()) {
                    // rest is same..

แต่ฉันจะรู้ได้อย่างไรว่าจะเพิ่มพารามิเตอร์ ท้ายที่สุดเธออาจพูดว่า ..

  • เธอต้องการผ่านฟอร์แมตสตริงแบบกำหนดเองบางทีเธออาจไม่ชอบรูปแบบที่ฉันพิมพ์อยู่แล้ว: 2018-10-28T02:00+01:00[Arctic/Longyearbyen]

void dayLightSavings(int year, DateTimeFormatter dtf)

  • เธอสนใจเฉพาะช่วงเวลาบางเดือนเท่านั้น

void dayLightSavings(int year, DateTimeFormatter dtf, int monthStart, int monthEnd)

  • เธอสนใจในบางช่วงเวลา

void dayLightSavings(int year, DateTimeFormatter dtf, int monthStart, int monthEnd, int hourStart, int hourend)

หากคุณกำลังมองหาคำถามที่เป็นรูปธรรม:

ถ้าdestroyCity(City city)จะดีกว่าdestroyBaghdad()เป็นtakeActionOnCity(Action action, City city)ดียิ่งขึ้น? ทำไม / ทำไมไม่

หลังจากที่ทุกคนครั้งแรกที่ผมสามารถเรียกมันด้วยAction.DESTROYแล้วAction.REBUILD, ไม่ได้หรือไม่

แต่การกระทำในเมืองนั้นไม่เพียงพอสำหรับฉันแล้วtakeActionOnGeographicArea(Action action, GeographicalArea GeographicalArea)ล่ะ หลังจากทั้งหมดฉันไม่ต้องการโทร:

takeActionOnCity(Action.DESTORY, City.BAGHDAD);

แล้วก็

takeActionOnCity(Action.DESTORY, City.ERBIL);

และเมื่อฉันสามารถทำได้:

takeActionOnGeographicArea(Action.DESTORY, Country.IRAQ);

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



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

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

7
ภรรยาของคุณเป็นคนผิดจรรยาบรรณที่ทำให้คุณเสียเวลาโดยการโกหกคุณ เธอขอคำตอบและให้สื่อที่แนะนำ โดยสัญญานั้นวิธีการที่คุณได้รับผลลัพธ์ที่เป็นเพียงระหว่างคุณและตัวคุณเอง นอกจากนี้ยังdestroyCity(target)เป็นวิธีที่ผิดจรรยาบรรณมากกว่าdestroyBagdad()! สัตว์ประหลาดชนิดใดที่เขียนโปรแกรมเพื่อล้างเมืองให้เมืองใด ๆ ในโลกนี้อยู่คนเดียว? ถ้าระบบถูกบุกรุกล่ะ! นอกจากนี้การจัดการเวลา / ทรัพยากร (ความพยายามลงทุน) เกี่ยวข้องกับจริยธรรมอย่างไร? ตราบใดที่สัญญาทางวาจา / ลายลักษณ์อักษรเสร็จสมบูรณ์ตามที่ตกลงกันไว้
Tezra

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

คำตอบ:


114

มันเป็นเต่าตลอดทาง

หรือ abstractions ในกรณีนี้

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

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

ฉันจะรู้ได้อย่างไรว่าคุณสมบัติใดที่จะใช้?

เหตุผลที่ฉันพูดถึงข้างต้นเป็นเพราะคุณได้ตกอยู่ในกับดักนี้แล้ว:

แต่ฉันจะรู้ได้อย่างไรว่าจะเพิ่มพารามิเตอร์ (และอะไร) เท่าใด หลังจากที่ทุกคนที่เธออาจจะบอกว่า

"เธออาจพูดว่า" ไม่ใช่ความต้องการทางธุรกิจในปัจจุบัน เป็นการคาดเดาความต้องการทางธุรกิจในอนาคต ตามกฎทั่วไปอย่ายึดตัวเองกับการคาดเดาพัฒนาเฉพาะสิ่งที่จำเป็นในปัจจุบันเท่านั้น

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

ฉันจะรู้ได้อย่างไรว่าจะใช้สถาปัตยกรรมใด

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

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

ฉันจะรู้ได้อย่างไรว่าจะย่อโค้ดของฉันอีกเมื่อใด

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

ป้อนคำอธิบายรูปภาพที่นี่ XKCD # 764

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

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

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

ถ้าdestroyCity(City city)จะดีกว่าdestroyBaghdad()เป็นtakeActionOnCity(Action action, City city)ดียิ่งขึ้น? ทำไม / ทำไมไม่

นั่นขึ้นอยู่กับหลาย ๆ สิ่ง:

  • มีการกระทำหลายอย่างที่สามารถทำได้ในเมืองใด ๆ
  • การกระทำเหล่านี้สามารถใช้แทนกันได้หรือไม่? เพราะถ้าการกระทำ "ทำลาย" และ "สร้างใหม่" มีการดำเนินการที่แตกต่างกันโดยสิ้นเชิงดังนั้นจึงไม่มีประเด็นที่จะรวมสองสิ่งtakeActionOnCityนี้เข้าด้วยกันในวิธีการเดียว

โปรดทราบด้วยว่าหากคุณสรุปสิ่งนี้ซ้ำไปซ้ำมาคุณจะต้องจบด้วยวิธีที่เป็นนามธรรมจนไม่มีอะไรมากไปกว่าที่คอนเทนเนอร์จะเรียกใช้วิธีอื่นในซึ่งหมายความว่าคุณได้ทำให้วิธีการของคุณไม่เกี่ยวข้องและไร้ความหมาย
หากtakeActionOnCity(Action action, City city)ร่างกายวิธีการทั้งหมดของคุณจบลงด้วยการไม่มีอะไรมากไปกว่าaction.TakeOn(city);คุณควรสงสัยว่าtakeActionOnCityวิธีการมีวัตถุประสงค์อย่างแท้จริงหรือไม่เป็นเพียงชั้นพิเศษที่ไม่เพิ่มมูลค่าใด ๆ

แต่การกระทำในเมืองนั้นไม่เพียงพอสำหรับฉันแล้วtakeActionOnGeographicArea(Action action, GeographicalArea GeographicalArea)ล่ะ

คำถามเดียวกันปรากฏขึ้นที่นี่:

  • คุณมีกรณีการใช้งานสำหรับพื้นที่ทางภูมิศาสตร์หรือไม่?
  • การดำเนินการของการกระทำในเมืองและภูมิภาคเดียวกันหรือไม่?
  • สามารถดำเนินการใด ๆ กับภูมิภาค / เมืองได้หรือไม่?

หากคุณสามารถตอบ "ใช่" ทั้งสามข้อได้แน่นอนจะมีการรับประกันสิ่งที่เป็นนามธรรม


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

2
> "ฉันไม่รู้ว่าฉันอ่านที่ไหน [.. ]" คุณอาจจะได้รับการอ่านสยองขวัญ Coding: กฎสาม
Rune

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

4
การรอตัวอย่างมากกว่าสองตัวอย่างของ "ตรรกะเดียวกัน" ช่วยให้คุณเป็นผู้ตัดสินที่ดีขึ้นเกี่ยวกับสิ่งที่ควรจะเป็นนามธรรมและอย่างไร (และจริงๆแล้วมันเกี่ยวกับการจัดการการพึ่งพา / การมีเพศสัมพันธ์ระหว่างรหัสที่มี
Filip Milovanović

1
@ kukis: บรรทัดจริงควรวาดที่ 2 (ตามความคิดเห็นของ Baldrickk): zero-one-many (ตามที่เป็นกรณีของความสัมพันธ์ฐานข้อมูล) อย่างไรก็ตามนี่เป็นการเปิดประตูสู่การแสวงหารูปแบบที่ไม่จำเป็น สองสิ่งอาจดูคล้ายคลึงกัน แต่ไม่ได้หมายความว่าเหมือนกัน อย่างไรก็ตามเมื่ออินสแตนซ์ที่สามเข้าสู่การต่อสู้ซึ่งคล้ายกับอินสแตนซ์ที่หนึ่งและที่สองคุณสามารถทำการตัดสินใจที่แม่นยำยิ่งขึ้นว่าความคล้ายคลึงกันของพวกเขานั้นเป็นรูปแบบที่ใช้ซ้ำได้ ดังนั้นบรรทัดสามัญสำนึกจะถูกวาดที่ 3 ซึ่งปัจจัยในข้อผิดพลาดของมนุษย์เมื่อพบ "รูปแบบ" ระหว่างสองอินสแตนซ์เท่านั้น
Flater

44

การปฏิบัติ

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

แม้ว่ามันจะไม่เป็นประโยชน์มากในขณะนี้ดังนั้นแนวทางบางอย่าง?

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

หลักเกณฑ์ที่ 1: คุณไม่ต้องการมัน

อย่างจริงจัง. แค่หยุด บ่อยกว่านั้นปัญหาในอนาคตที่จินตนาการไม่ได้ปรากฏขึ้นและแน่นอนว่ามันจะไม่ปรากฏเช่นเดียวกับที่คุณจินตนาการไว้

หลักเกณฑ์ 2: ต้นทุน / ผลประโยชน์

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

หลักเกณฑ์ 3: มุ่งเน้นไปที่ค่าคงที่

มองย้อนกลับไปที่คำถาม ในรหัสดั้งเดิมของคุณมีค่าคงที่จำนวนมาก 2018, 1. ints คงที่, สตริงคงที่ ... พวกมันเป็นสิ่งที่น่าจะต้องเป็นแบบไม่คงที่มากที่สุด ยังดีกว่าพวกเขาใช้เวลาเพียงเล็กน้อยเพื่อแปร (หรือกำหนดอย่างน้อยเป็นค่าคงที่ที่เกิดขึ้นจริง) แต่สิ่งที่ต้องระวังก็คือคงพฤติกรรม System.out.printlnตัวอย่างเช่น. ข้อสันนิษฐานเกี่ยวกับการใช้เช่นนั้นมีแนวโน้มที่จะเป็นสิ่งที่เปลี่ยนแปลงในอนาคตและมีแนวโน้มที่จะมีค่าใช้จ่ายสูงในการแก้ไข ไม่เพียงแค่นั้น แต่ IO เช่นนี้ทำให้ฟังก์ชั่นไม่บริสุทธิ์ (พร้อมกับการดึงเขตเวลาค่อนข้าง) การกำหนดพารามิเตอร์ที่พฤติกรรมสามารถทำให้ฟังก์ชั่นนั้นบริสุทธิ์มากขึ้นนำไปสู่ความยืดหยุ่นและความสามารถในการทดสอบที่เพิ่มขึ้น ผลประโยชน์ที่ยิ่งใหญ่ด้วยค่าใช้จ่ายน้อยที่สุด (โดยเฉพาะถ้าคุณทำโอเวอร์โหลดที่ใช้เป็นSystem.outค่าเริ่มต้น)


1
เป็นเพียงแนวทาง 1s ใช้ได้ แต่คุณมองไปที่พวกเขาและไป "สิ่งนี้จะเปลี่ยนไปหรือไม่?" Nah และ println สามารถกำหนดพารามิเตอร์ด้วยฟังก์ชันการสั่งซื้อที่สูงขึ้น - แม้ว่า Java จะไม่ยอดเยี่ยมสำหรับสิ่งเหล่านั้น
Telastyn

5
@KorayTugay: หากโปรแกรมเป็นจริงสำหรับภรรยาของคุณมาที่บ้าน YAGNI จะบอกคุณว่ารุ่นเริ่มต้นของคุณสมบูรณ์แบบและคุณไม่ควรลงทุนอีกต่อไปเพื่อแนะนำค่าคงที่หรือพารามิเตอร์ YAGNI ต้องการ บริบท - โปรแกรมของคุณเป็นโซลูชันที่ถูกทิ้งหรือโปรแกรมโยกย้ายทำงานเพียงไม่กี่เดือนหรือเป็นส่วนหนึ่งของระบบ ERP ขนาดใหญ่ที่ตั้งใจจะใช้และดูแลรักษามานานหลายทศวรรษหรือไม่?
Doc Brown

8
@KorayTugay: การแยก I / O ออกจากการคำนวณเป็นเทคนิคการจัดโครงสร้างโปรแกรมพื้นฐาน แยกการสร้างข้อมูลจากการกรองข้อมูลจากการแปลงข้อมูลจากการใช้ข้อมูลจากการนำเสนอข้อมูล คุณควรศึกษาโปรแกรมการทำงานบางอย่างแล้วคุณจะเห็นสิ่งนี้ชัดเจนยิ่งขึ้น ในการเขียนโปรแกรมการทำงานมันเป็นเรื่องธรรมดามากที่จะสร้างข้อมูลจำนวนไม่ จำกัด กรองเฉพาะข้อมูลที่คุณสนใจแปลงข้อมูลเป็นรูปแบบที่คุณต้องการสร้างสตริงจากมันและพิมพ์สตริงนี้ใน 5 ฟังก์ชันที่แตกต่างกัน หนึ่งสำหรับแต่ละขั้นตอน
Jörg W Mittag

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

4
@Telastyn: ฉันขอแนะนำให้ขยายคำถามไปที่“ จะไม่เปลี่ยนแปลงและเป็นความตั้งใจของรหัสที่สามารถอ่านได้โดยไม่ตั้งชื่อค่าคงที่หรือไม่” แม้ว่าค่าที่ไม่เคยเปลี่ยนนั้นอาจเกี่ยวข้องกับการตั้งชื่อเพื่อให้สิ่งต่าง ๆ อ่านง่าย
Flater

27

ประการแรก: ผู้พัฒนาซอฟต์แวร์ที่ไม่มีความปลอดภัยจะเขียนวิธีการ DestroyCity โดยไม่ต้องผ่าน Token การอนุญาตด้วยเหตุผลใดก็ตาม

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

ประการที่สอง: รหัสทั้งหมดเมื่อดำเนินการจะต้องระบุอย่างเต็มที่

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

ซึ่งอาจอยู่ในไฟล์ออบเจ็กต์เดียวกันdestroyCity(xyz)และอาจอยู่ในไฟล์กำหนดค่า: destroy {"city": "XYZ"}"หรืออาจเป็นชุดของการคลิกและการกดคีย์ใน UI

ประการที่สาม:

ที่รัก .. คุณสามารถพิมพ์ Day Light Saving ทั่วโลกสำหรับปี 2018 ในคอนโซลได้หรือไม่? ฉันต้องตรวจสอบบางอย่าง

เป็นข้อกำหนดที่แตกต่างกันมากสำหรับ:

เธอต้องการที่จะผ่านการจัดรูปแบบสตริงที่กำหนดเอง ... สนใจในช่วงเวลาที่แน่นอนเท่านั้น ... [และ] สนใจในช่วงเวลาที่แน่นอน ...

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

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

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

ที่ถูกกล่าวว่าลูกค้าส่วนใหญ่พลาดการติดต่อเข้าใจหรือไม่รู้รายละเอียดบางอย่าง (aka การตัดสินใจ) ว่าพวกเขาต้องการที่จะทำให้ตัวเองหรือว่าพวกเขาไม่ต้องการที่จะทำให้ (แต่ฟังดูน่ากลัว) นี่คือเหตุผลที่วิธีการทำงานเช่นPDSA (การวางแผนพัฒนาศึกษาการกระทำ) มีความสำคัญ คุณได้วางแผนงานให้สอดคล้องกับข้อกำหนดแล้วคุณได้พัฒนาชุดการตัดสินใจ (รหัส) ตอนนี้ถึงเวลาที่จะศึกษามันไม่ว่าจะด้วยตัวเองหรือกับลูกค้าของคุณและเรียนรู้สิ่งใหม่ ๆ และสิ่งเหล่านี้จะแจ้งให้คุณคิดต่อไป สุดท้ายทำตามข้อมูลเชิงลึกใหม่ของคุณ - อัปเดตข้อกำหนดปรับกระบวนการรับเครื่องมือใหม่ ฯลฯ ... จากนั้นเริ่มวางแผนอีกครั้ง สิ่งนี้จะเปิดเผยข้อกำหนดที่ซ่อนอยู่เมื่อเวลาผ่านไปและพิสูจน์ความก้าวหน้าให้กับลูกค้าจำนวนมาก

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

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


+1 รักส่วนเกี่ยวกับคอมไพเลอร์!
ลี

4

มีคำตอบที่ยืดยาวมากมายที่นี่ แต่จริงๆแล้วฉันคิดว่ามันง่ายมาก

ข้อมูลฮาร์ดโค้ดใด ๆ ที่คุณมีในฟังก์ชั่นที่ไม่ใช่ส่วนหนึ่งของชื่อฟังก์ชั่นควรเป็นพารามิเตอร์

ดังนั้นในการทำงานของคุณ

class App {
    void dayLightSavings() {
        final Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        availableZoneIds.forEach(zoneId -> {
            LocalDateTime dateTime = LocalDateTime.of(LocalDate.of(2018, 1, 1), LocalTime.of(0, 0, 0));
            ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
            while (2018 == now.getYear()) {
                int hour = now.getHour();
                now = now.plusHours(1);
                if (now.getHour() == hour) {
                    System.out.println(now);
                }
            }
        });
    }
}

คุณมี:

The zoneIds
2018, 1, 1
System.out

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

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


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

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

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

สตรีม
Ewan

ไม่มีการOutputStreamไม่ได้เป็นผู้บริโภค
David Conrad

4

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

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


วัตถุไม่ใช่ขั้นตอน

แทนที่จะใช้คลาสเช่นโมดูลโรงเรียนเก่าที่มีกิจวัตรมากมายที่คุณต้องการเรียกใช้เพื่อดำเนินการในสิ่งที่ซอฟต์แวร์ของคุณควรทำให้พิจารณาการสร้างแบบจำลองโดเมนเป็นวัตถุที่โต้ตอบและร่วมมือเพื่อทำงานให้สำเร็จ วิธีการในกระบวนทัศน์เชิงวัตถุนั้นเดิมสร้างขึ้นเพื่อเป็นสัญญาณระหว่างวัตถุเพื่อที่Object1จะบอกObject2ให้ทำสิ่งนั้นไม่ว่าจะเป็นอะไรและอาจได้รับสัญญาณคืน เนื่องจากกระบวนทัศน์ Object-Oriented นั้นเกี่ยวกับการสร้างแบบจำลองวัตถุในโดเมนของคุณและปฏิสัมพันธ์ของพวกเขาแทนที่จะเป็นวิธีที่แปลกใหม่ในการจัดระเบียบฟังก์ชันเก่าและขั้นตอนเดียวกันของกระบวนทัศน์ที่จำเป็น ในกรณีของvoid destroyBaghdadตัวอย่างแทนที่จะพยายามเขียนวิธีการทั่วไปแบบไม่มีบริบทเพื่อจัดการกับการทำลายกรุงแบกแดดหรือสิ่งอื่น ๆ (ซึ่งสามารถเติบโตได้อย่างรวดเร็วซับซ้อนยากที่จะเข้าใจและเปราะ) ทุกสิ่งที่ถูกทำลายควรรับผิดชอบต่อการทำความเข้าใจว่า เพื่อทำลายตัวเอง ตัวอย่างเช่นคุณมีอินเทอร์เฟซที่อธิบายพฤติกรรมของสิ่งต่าง ๆ ที่สามารถทำลายได้:

interface Destroyable {
    void destroy();
}

ถ้างั้นคุณก็มีเมืองที่ใช้อินเทอร์เฟซนี้:

class City implements Destroyable {
    @Override
    public void destroy() {
        ...code that destroys the city
    }
}

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

การมอบหมายไม่ใช่ "การควบคุม"

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

interface Part extends Destroyable {
    ...part-specific methods
}

class Building implements Part {
    ...part-specific methods
    @Override
    public void destroy() {
       ...code to destroy a building
    }
}

class Street implements Part {
    ...part-specific methods
    @Override
    public void destroy() {
        ...code to destroy a building
    }
}

class City implements Destroyable {
    public List<Part> parts() {...}

    @Override
    public void destroy() {
        parts().forEach(Destroyable::destroy);            
    }
}

หากคุณต้องการที่จะคลั่งไคล้และนำแนวคิดของสิ่งBombที่ตกอยู่ในสถานที่นั้นมาใช้และทำลายทุกสิ่งภายในรัศมีที่กำหนดมันอาจมีลักษณะเช่นนี้:

class Bomb {
    private final Integer radius;

    public Bomb(final Integer radius) {
        this.radius = radius;
    }

    public void drop(final Grid grid, final Coordinate target) {
        new ObjectsByRadius(
            grid,
            target,
            this.radius
        ).forEach(Destroyable::destroy);
    }
}

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

ปฏิสัมพันธ์ไม่ใช่อัลกอริทึม

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

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

interface Result {
    String print();
}

class Caclulation {
    private final Parameter paramater1;

    private final Parameter parameter2;

    public Calculation(final Parameter parameter1, final Parameter parameter2) {
        this.parameter1 = parameter1;
        this.parameter2 = parameter2;
    }

    public Result calculate() {
        ...calculate the result
    }
}

class FormattedResult {
    private final Result result;

    public FormattedResult(final Result result) {
        this.result = result;
    }

    @Override
    public String print() {
        ...interact with this.result to format it and return the formatted String
    }
}

เนื่องจากตัวอย่างของคุณใช้คลาสจากไลบรารี Java ที่ไม่สนับสนุนการออกแบบนี้คุณสามารถใช้ API ของZonedDateTimeโดยตรง แนวคิดที่นี่คือการคำนวณแต่ละครั้งถูกห่อหุ้มภายในวัตถุของตัวเอง ไม่มีข้อสันนิษฐานเกี่ยวกับจำนวนครั้งที่ควรรันหรือควรจัดรูปแบบผลลัพธ์ มันเกี่ยวข้องเฉพาะกับการคำนวณรูปแบบที่ง่ายที่สุด ทำให้ทั้งง่ายต่อการเข้าใจและมีความยืดหยุ่นในการเปลี่ยนแปลง เช่นResultเดียวกับที่เกี่ยวข้องกับการห่อหุ้มผลลัพธ์ของการคำนวณและFormattedResultเกี่ยวข้องกับการโต้ตอบกับการจัดResultรูปแบบตามกฎที่เรากำหนดเท่านั้น ทางนี้,เราสามารถหาข้อโต้แย้งจำนวนที่สมบูรณ์แบบสำหรับแต่ละวิธีของเราเนื่องจากพวกเขาแต่ละคนมีงานที่กำหนดไว้อย่างดี นอกจากนี้ยังง่ายกว่ามากในการปรับเปลี่ยนการก้าวไปข้างหน้าตราบใดที่อินเทอร์เฟซไม่เปลี่ยนแปลง (ซึ่งพวกมันไม่น่าจะทำถ้าคุณลดความรับผิดชอบของวัตถุให้ถูกต้องน้อยที่สุด) main()วิธีการของเราอาจมีลักษณะเช่นนี้:

class App {
    public static void main(String[] args) {
        final List<Set<Paramater>> parameters = ...instantiated from args
        parameters.forEach(set -> {
            System.out.println(
                new FormattedResult(
                    new Calculation(
                        set.get(0),
                        set.get(1)
                    ).calculate()
                ).print()
            );
        });
    }
}

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


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

@maple_shaft บางทีฉันอาจพลาดเครื่องหมาย แต่ฉันคิดว่าคุณก็มีเหมือนกัน OP ไม่ได้ถามเกี่ยวกับการลงทุนด้านเวลากับการวางนัยทั่วไป เขาถามว่า "ฉันจะรู้ได้อย่างไรว่าวิธีการของฉันควรใช้ซ้ำได้อย่างไร" เขาถามต่อไปในเนื้อความของคำถามของเขาว่า "ถ้า destroyCity (เมืองในเมือง) ดีกว่า destroyBaghdad (), takeActionOnCity (Action action, City city) ดีกว่าทำไม? ฉันทำกรณีสำหรับวิธีการอื่นในการแก้ปัญหาทางวิศวกรรมที่ฉันเชื่อว่าแก้ปัญหาในการหาวิธีทั่วไปในการทำวิธีการและให้ตัวอย่างเพื่อสนับสนุนข้อเรียกร้องของฉัน ฉันขอโทษคุณไม่ชอบมัน
Stuporman

@maple_shaft ตรงไปตรงมามีเพียง OP เท่านั้นที่สามารถตัดสินใจได้หากคำตอบของฉันเกี่ยวข้องกับคำถามของเขาเนื่องจากพวกเราที่เหลือสามารถต่อสู้กับสงครามเพื่อปกป้องการตีความของเราเกี่ยวกับความตั้งใจของเขา
Stuporman

@maple_shaft ฉันได้เพิ่มอินโทรเพื่อพยายามอธิบายให้ชัดเจนว่าเกี่ยวข้องกับคำถามอย่างไรและให้คำอธิบายที่ชัดเจนระหว่างคำตอบและการใช้ตัวอย่าง มันดีกว่าไหม
Stuporman

1
หากคุณใช้หลักธรรมเหล่านี้ทั้งหมดคำตอบจะเป็นไปตามธรรมชาติราบรื่นและสามารถอ่านได้อย่างหนาแน่น นอกจากนี้อาจเปลี่ยนแปลงได้โดยไม่ต้องยุ่งยากมาก ฉันไม่รู้ว่าคุณเป็นใคร แต่ฉันหวังว่าจะมีคุณมากกว่า! ฉันคอยอ่านรหัสปฏิกิริยาสำหรับ OO ที่เหมาะสมและมันก็มีขนาดเล็กกว่าครึ่งอ่านง่ายขึ้นควบคุมได้มากขึ้นและยังมีเธรด / แยก / ทำแผนที่ ฉันคิดว่า React นั้นเหมาะสำหรับผู้ที่ไม่เข้าใจแนวคิด "พื้นฐาน" ที่คุณระบุไว้
สตีเฟ่น J

3

ประสบการณ์ , ความรู้โดเมนและความคิดเห็นเกี่ยวกับรหัส

และไม่คำนึงถึงวิธีการมากหรือว่าน้อยประสบการณ์ , ความรู้โดเมนหรือทีมที่คุณมีและคุณจะไม่สามารถหลีกเลี่ยงความจำเป็นที่จะต้องrefactor ความจำเป็น


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

(ประสบการณ์นี้อาจส่งผ่านไปยังวัตถุและวิธีการโดเมนของคุณโดยสัญชาตญาณด้วย)

ด้วยความรู้ของโดเมนคุณจะมีความรู้สึกว่าแนวคิดทางธุรกิจมีความสัมพันธ์กันอย่างใกล้ชิดแนวคิดใดที่มีตัวแปรซึ่งค่อนข้างคงที่ ฯลฯ

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


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

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

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

แต่นอกเหนือจากการมีประสบการณ์มากมายและอื่น ๆ ฉันขอแนะนำให้ใช้โค้ดที่ค่อนข้างเรียบง่าย DRY-ing มันไม่ยากเลยที่จะสร้างการละเมิดที่ชัดเจน และหากคุณกระตือรือร้นเกินไปคุณสามารถจบลงด้วยรหัส "over-DRY" ที่ยากต่อการอ่านเข้าใจและบำรุงรักษามากกว่า "WET" ที่เทียบเท่า


2
ดังนั้นจึงไม่มีคำตอบที่ถูกต้องIf destoryCity(City city) is better than destoryBaghdad(), is takeActionOnCity(Action action, City city) even better?? มันเป็นคำถามที่ใช่ / ไม่ใช่ แต่มันไม่มีคำตอบใช่ไหม? หรือสมมติฐานที่เริ่มต้นไม่ถูกต้องdestroyCity(City)อาจจะไม่ necessarly จะดีกว่าและเป็นจริงขึ้นอยู่ ? ดังนั้นไม่ได้หมายความว่าฉันไม่ได้เป็นวิศวกรซอฟต์แวร์ที่ไม่ผ่านการฝึกอบรมอย่างมีจริยธรรมเพราะฉันเริ่มใช้งานโดยตรงโดยไม่มีพารามิเตอร์ใด ๆ เลยใช่หรือไม่ ฉันหมายถึงคำตอบสำหรับคำถามที่เป็นรูปธรรมที่ฉันถามคืออะไร
Koray Tugay

คำถามของคุณเรียงคำถามสองสามข้อ คำตอบสำหรับคำถามชื่อคือ "ประสบการณ์ความรู้เกี่ยวกับโดเมนบทวิจารณ์โค้ด ... และ ... อย่ากลัวที่จะปรับโครงสร้างใหม่" คำตอบที่เป็นรูปธรรมใด ๆ "คือพารามิเตอร์ที่เหมาะสมสำหรับวิธีการ ABC" คำถามคือ ... "ฉันไม่รู้คุณจะถามทำไม? แก้ไขได้แล้ว " ... ฉันอาจแนะนำให้คุณรู้จักกับ"the POAP"เพื่อขอคำแนะนำเพิ่มเติม: คุณต้องเข้าใจว่าทำไมคุณถึงทำสิ่งที่คุณทำ!
svidgen

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

1
ดังนั้นคุณไม่เห็นด้วยกับคำพูดที่อ้างถึงในคำถามของฉันใช่ไหม It should be noted that no ethically-trained software engineer would ever consent to write a DestroyBaghdad procedure.ถ้าคุณอยู่ในห้องกับนาธาเนียลโบเรนสไตน์คุณจะเถียงเขาว่าจริง ๆ แล้วมันขึ้นอยู่กับคำพูดของเขาไม่ถูกต้อง? ฉันหมายความว่ามันสวยงามที่หลาย ๆ คนกำลังตอบรับใช้เวลาและพลังงานของพวกเขา แต่ฉันไม่เห็นคำตอบที่เป็นรูปธรรมใด ๆ เลย ความรู้สึกเกี่ยวกับโค้ดรีวิว .. แต่อะไรคือคำตอบis takeActionOnCity(Action action, City city) better? null?
Koray Tugay

1
@ svidgen แน่นอนอีกวิธีหนึ่งที่จะทำให้เป็นนามธรรมได้โดยไม่ต้องใช้ความพยายามพิเศษคือการคว่ำการพึ่งพา - ให้ฟังก์ชั่นส่งคืนรายชื่อเมืองแทนการดำเนินการใด ๆ กับพวกเขา (เช่น "println" ในรหัสต้นฉบับ) สิ่งนี้สามารถสรุปได้เพิ่มเติมหากจำเป็น แต่เพียงแค่การเปลี่ยนแปลงนี้ด้วยตัวเองจะดูแลประมาณครึ่งหนึ่งของข้อกำหนดเพิ่มเติมในคำถามเดิม - และแทนที่จะเป็นฟังก์ชั่นไม่บริสุทธิ์ที่สามารถทำสิ่งเลวร้ายได้ทุกประเภทคุณเพียงแค่มีฟังก์ชั่น ที่ส่งคืนรายการและผู้เรียกทำสิ่งที่ไม่ดี
Luaan

2

คำตอบเดียวกันกับคุณภาพการใช้งานหนี้ทางเทคนิคและอื่น ๆ :

ในฐานะที่คุณสามารถนำกลับมาใช้ใหม่ได้ในฐานะผู้ใช้1คน

โดยพื้นฐานแล้วมันคือการตัดสินที่เรียกว่า - ค่าใช้จ่ายในการออกแบบและบำรุงรักษาสิ่งที่เป็นนามธรรมจะได้รับการชำระคืนด้วยต้นทุน (= เวลาและความพยายาม) หรือไม่นั้นจะช่วยคุณประหยัดค่าใช้จ่าย

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

1 นี่คือการสร้างรหัสดังนั้นคุณคือ "ผู้ใช้" ในกรณีนี้ - ผู้ใช้ของซอร์สโค้ด


1

มีกระบวนการที่ชัดเจนที่คุณสามารถติดตามได้:

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

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

นอกจากนี้ยังให้คำแนะนำที่ชัดเจนแก่คุณเมื่อต้องทำสิ่งทั่วไปและเมื่อใดที่มีความเชี่ยวชาญ

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

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

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


เกี่ยวกับย่อหน้าที่สองของคุณ - ดูที่ "ข้อกำหนด" ในขั้นต้นที่ได้รับนั่นคือวิธีการแรกที่ใช้ มันระบุ 2018 ดังนั้นรหัสถูกต้องทางเทคนิค (และอาจจะตรงกับวิธีการที่ขับเคลื่อนด้วยคุณสมบัติของคุณ)
dwizum

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

1

ฉันเห็นว่ามีโค้ดที่สามารถใช้ซ้ำได้สองประเภท:

  • รหัสที่นำมาใช้ซ้ำได้เพราะมันเป็นพื้นฐานสิ่งพื้นฐาน
  • รหัสที่สามารถนำกลับมาใช้ใหม่ได้เนื่องจากมีพารามิเตอร์การแทนที่และ hooks สำหรับทุกที่

ความสามารถในการนำกลับมาใช้ใหม่มักเป็นความคิดที่ดี มันใช้กับสิ่งต่าง ๆ เช่นรายการ hashmaps ที่เก็บคีย์ / ค่าสตริงตัวจับคู่ (เช่น regex, glob, ... ), tuples, unification, ต้นไม้ค้นหา , ตัวแยกวิเคราะห์, แคช / memoisers, ตัวอ่าน / เขียนรูปแบบข้อมูล (s-expressions, XML, JSON, protobuf, ... ), คิวงาน ฯลฯ

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

การเรียงลำดับที่สองคือที่ที่เรามีรหัสที่เป็นรูปธรรมซึ่งสามารถแก้ไขปัญหาที่แท้จริง แต่ทำได้โดยการตัดสินใจทั้งหมด เราสามารถทำให้มันเป็นเรื่องทั่วไปมากขึ้น / นำมาใช้ซ้ำได้โดยการตัดสินใจแบบ "soft-coding" เช่นเปลี่ยนเป็นพารามิเตอร์ทำให้การใช้งานและการอบมีความซับซ้อนยิ่งขึ้นในรายละเอียดที่เป็นรูปธรรมมากขึ้น (เช่นความรู้ที่ว่า ตัวอย่างของคุณน่าจะเป็นของประเภทนี้ ปัญหาของการใช้ซ้ำได้เช่นนี้คือเราอาจจะพยายามเดากรณีการใช้งานของคนอื่นหรือองค์ประกอบในอนาคตของเรา ในที่สุดเราอาจพบว่ามีพารามิเตอร์มากมายจนรหัสของเราไม่สามารถใช้งานได้ให้นำมาใช้คนเดียว! กล่าวอีกนัยหนึ่งเมื่อเรียกมันต้องใช้ความพยายามมากกว่าเพียงแค่เขียนรุ่นของเราเอง นี่คือที่ YAGNI (คุณไม่ต้องการมัน) เป็นสิ่งสำคัญ หลายครั้งความพยายามในการใช้รหัส "reusable" นั้นไม่สามารถนำกลับมาใช้ใหม่ได้เนื่องจากมันอาจเข้ากันไม่ได้กับกรณีการใช้งานมากกว่าพื้นฐานที่พารามิเตอร์สามารถอธิบายได้หรือผู้ใช้ที่มีแนวโน้มจะม้วนตัวเอง (heck ดูที่ มาตรฐานและห้องสมุดออกมีผู้เขียนนำหน้าด้วยคำว่า "ง่าย" เพื่อแยกพวกเขาออกจากรุ่นก่อน!)

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


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

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

เราไม่สามารถพูดได้ว่า 'การทำลายเมือง' ใดที่ "ดีกว่า" โดยไม่มีข้อมูลเพิ่มเติม: destroyBaghdadเป็นสคริปต์ใช้ครั้งเดียว (หรืออย่างน้อยก็เป็น idempotent) บางทีการทำลายเมืองใด ๆ จะเป็นการปรับปรุง แต่จะเกิดอะไรขึ้นถ้าdestroyBaghdadทำงานโดยน้ำท่วม Tigris? นั่นอาจใช้ซ้ำได้สำหรับ Mosul และ Basra แต่ไม่ใช่สำหรับ Mecca หรือ Atlanta
Warbo

ฉันเห็นว่าคุณไม่เห็นด้วยกับนาธาเนียล Borenstein เจ้าของคำพูด ฉันพยายามที่จะเข้าใจอย่างช้าๆฉันคิดว่าโดยการอ่านคำตอบและการอภิปรายทั้งหมด
Koray Tugay

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

1

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

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

ไม่ว่าวิธีหนึ่งสามารถเลียนแบบวิธีอื่นได้หรือไม่

เกี่ยวกับตัวอย่างจากคำถาม: จินตนาการว่าวิธีการ

void dayLightSavings()

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

publicvoid dayLightSavings()

สามารถดำเนินการได้ตามที่คุณแสดงในคำตอบของคุณ ตอนนี้มีคนต้องการตั้งค่าพารามิเตอร์ให้กับปี ดังนั้นคุณสามารถเพิ่มวิธีการ

publicvoid dayLightSavings(int year)

และเปลี่ยนการใช้งานดั้งเดิมให้เป็นเพียงแค่

public void dayLightSavings() {
    dayLightSavings(2018);
}

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

public void dayLightSavings() {
    dayLightSavings(2018, 0, 12, 0, 12, new DateTimeFormatter(...));
}

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

tl; dr :

คำถามนี้จริง ๆ แล้วไม่มาก "วิธีการใช้ซ้ำวิธีควร" คำถามคือความสามารถในการนำกลับมาใช้ใหม่นี้ได้รับการเปิดเผยและลักษณะของ API การสร้าง API ที่เชื่อถือได้ซึ่งสามารถยืนการทดสอบของเวลา (แม้ว่าจะมีข้อกำหนดเพิ่มเติมเกิดขึ้นในภายหลัง) เป็นงานศิลปะและงานฝีมือและหัวข้อนั้นซับซ้อนเกินกว่าที่จะครอบคลุมได้ที่นี่ ดูการนำเสนอนี้โดย Joshua Blochหรือwiki book design APIสำหรับการเริ่มต้น


dayLightSavings()การโทรdayLightSavings(2018)ดูเหมือนจะเป็นความคิดที่ดีสำหรับฉัน
Koray Tugay

@KorayTugay เมื่อคำขอเริ่มแรกคือควรพิมพ์ "การปรับเวลาตามฤดูกาลสำหรับปี 2018" ก็ถือว่าใช้ได้ อันที่จริงนี่เป็นวิธีการที่คุณนำมาใช้จริง ถ้ามันควรจะพิมพ์ "การประหยัดเวลากลางวันสำหรับปีปัจจุบันแน่นอนว่าคุณจะโทรหาdayLightSavings(computeCurrentYear());...
Marco13

0

กฎง่ายๆคือวิธีการของคุณควรใช้ซ้ำได้เหมือน ... นำมาใช้ซ้ำได้

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

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

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


0

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

ตัวอย่างของคุณขึ้นอยู่กับ

import java.time.*;
import java.util.Set;

ดังนั้นในทางทฤษฎีมันสามารถนำมาใช้ซ้ำได้อย่างมาก

ในทางปฏิบัติฉันไม่คิดว่าคุณจะมี usecase ที่สองที่ต้องการรหัสนี้ดังนั้นตามหลักการyagniฉันจะไม่ทำให้มันสามารถนำมาใช้ซ้ำได้หากมี projets ไม่เกิน 3 ที่ต้องการรหัสนี้

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


0

นี่เป็นโอกาสที่ดีที่จะระบุกฎที่ฉันเพิ่งประกาศใช้เมื่อไม่นานมานี้:

การเป็นโปรแกรมเมอร์ที่ดีหมายถึงความสามารถในการทำนายอนาคต

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

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

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

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


0

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

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

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

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

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

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

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

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

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


มีคนอื่นที่ทำ 10,000 ครั้งแล้วทำไมฉันต้องทำ 10,000 ครั้งและได้รับประสบการณ์เมื่อฉันสามารถเรียนรู้จากคนอื่นได้? เพราะคำตอบจะแตกต่างกันไปสำหรับแต่ละคนดังนั้นคำตอบจากประสบการณ์ไม่สามารถใช้ได้กับฉัน? แล้วYour customer will tell you how much flexibility and how many layers of generalization you should seek.โลกนี้คืออะไร?
Koray Tugay

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

ในกรณีเฉพาะของคุณหากคุณล้มเหลวที่จะนำถังขยะออกเพราะคุณยุ่งเกินไปที่จะเขียนรหัสปัญหาทั่วไปของโซนเวลานี้แทนการแฮ็ควิธีแก้ไขปัญหาเฉพาะกันลูกค้าของคุณจะรู้สึกอย่างไร
Cort Ammon

คุณเห็นด้วยหรือไม่ว่าวิธีแรกของฉันคือวิธีที่ถูกต้องใช้ hardcoding 2018 ในการใช้ครั้งแรกแทนที่จะเป็นพารามิเตอร์ปี (btw, นั่นไม่ใช่การฟังลูกค้าของฉันฉันคิดว่า, ตัวอย่างขยะ, นั่นคือการรู้จักลูกค้าของคุณ .. แม้ว่าจะได้รับการสนับสนุนจาก Oracle แต่ก็ไม่มีข้อความที่จะฟังเมื่อเธอบอกว่าฉันต้องการรายการของเวลากลางวัน การเปลี่ยนแปลงในปี 2018) ขอขอบคุณสำหรับเวลาของคุณและตอบ btw
Koray Tugay

@KorayTugay โดยไม่ทราบรายละเอียดเพิ่มเติมใด ๆ ฉันจะบอกว่าการเข้ารหัสเป็นวิธีที่เหมาะสม คุณไม่มีทางรู้ว่าคุณจะต้องใช้รหัส DLS ในอนาคตหรือไม่รู้ว่าเธอจะขออะไรต่อไป และหากลูกค้าของคุณพยายามทดสอบคุณพวกเขาจะได้รับสิ่งที่พวกเขาได้รับ = D
Cort Ammon

0

ไม่มีวิศวกรซอฟต์แวร์ที่ผ่านการฝึกอบรมอย่างมีจริยธรรมจะไม่ยินยอมให้เขียนขั้นตอน DestroyBaghdad จรรยาบรรณทางวิชาชีพขั้นพื้นฐานจะต้องการให้เขาเขียนขั้นตอนการทำลาย (DestroyCity) เพื่อให้แบกแดดเป็นพารามิเตอร์

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

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

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

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

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

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

ดังนั้นคุณต้องการฟังก์ชั่นที่สามารถส่งออกการประหยัดเวลากลางวันสำหรับปีใด ๆเพียงแค่ส่งออกข้อมูลสำหรับปี 2018 หรือไม่? อาจ แต่แน่นอนว่ามันจะต้องใช้ความพยายามเล็กน้อยในการรวบรวมกรณีทดสอบ อาจต้องใช้ความพยายามอย่างมากในการรับฐานข้อมูลเขตเวลาที่ดีกว่าที่คุณมี ตัวอย่างเช่นในปี 1908 เมืองพอร์ตอาร์เทอร์ออนแทรีโอมีช่วงเวลาที่เริ่มตั้งแต่วันที่ 1 กรกฎาคม นั่นคือในฐานข้อมูลเขตเวลาของระบบปฏิบัติการของคุณหรือไม่ คิดได้ดังนั้นฟังก์ชั่นทั่วไปของคุณจะไม่ถูกต้อง ไม่มีอะไรที่มีจริยธรรมโดยเฉพาะอย่างยิ่งเกี่ยวกับการเขียนโค้ดที่ทำให้สัญญาไม่สามารถรักษาไว้ได้

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

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

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


0

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

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

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

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

นายจ้างของคุณยินดีจ่ายให้ทั้งหมดหรือไม่? ฉันจะบอกว่าไม่

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

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

ในกรณีนี้ฉันจะให้อภัยผู้เขียน Abstraction นั้นจำเป็นจริง ๆเพราะนี่คือรหัสเฟรมเวิร์กที่กำหนดเป้าหมายการเรนเดอร์เป้าหมายที่แตกต่างกันห้าแบบ: WinForms, WPF, dotnet Core, Mono และ PdfSharp

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

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

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

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


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


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

@ Marco13 - เนื่องจากการคัดค้านของคุณสมเหตุสมผลฉันจะขยายจุด
Peter Wone

-3

หากคุณใช้อย่างน้อย java 8 คุณจะต้องเขียนคลาส WorldTimeZones เพื่อให้สิ่งที่ปรากฏเป็นคอลเลกชันของเขตเวลา

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

ในสาระสำคัญวิธีการกรองเดียวรองรับการกรองสิ่งที่มีอยู่ในค่าที่ส่งผ่านไปยังภาคแสดง

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


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

ดังนั้นฉันจึงบอกว่าคุณควรชั่งน้ำหนักพวกเขาตามจำนวนกรณีการใช้งานที่พวกเขาสนับสนุนแก้ไขโดยความซับซ้อนของการสร้าง วิธีการที่สนับสนุนกรณีการใช้งานหนึ่งครั้งนั้นไม่ได้มีค่าเท่ากับวิธีการที่รองรับกรณีการใช้งาน 20 กรณี ในทางกลับกันหากสิ่งที่คุณรู้คือกรณีใช้งานเพียงครั้งเดียวและใช้เวลาในการรหัส 5 นาที - ไปเลย บ่อยครั้งที่วิธีการเข้ารหัสที่สนับสนุนการใช้งานเฉพาะจะแจ้งให้คุณทราบถึงวิธีพูดคุยทั่วไป
Rodney P. Barbati
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.