ฟังก์ชั่นสั้นเกินไปหรือไม่


125

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

function conditionMet(){
   return x == condition;
}

หรือ

function runCallback(callback){
   if($.isFunction(callback))
     callback();
}

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


3
ไม่สั้นเกินไป ใน C # ฉันจะทำสภาพพบ Assert.AreEqual<int>(expected, actual, message, arg1, arg2, arg3, ...);'เป็นทรัพย์สินซึ่งเป็นสง่าและจะพิจารณาการใช้ อย่างที่สองก็ดีเหมือนเดิม ฉันอาจจะรวมธงบูลเสริมซึ่งจะกำหนดว่าจะโยนข้อยกเว้น / etc ในกรณีที่โทรกลับไม่ใช่ฟังก์ชั่น
งาน

38
ใช่เพียงหนึ่งกรณี: function myFunction () {}
Spooks

5
def yes(): return 'yes'
dietbuddha

3
@Spooks - ฉันขนแยกนี่ แต่ฟังก์ชั่นที่ว่างเปล่าที่ถูกต้องสำหรับการเรียนอย่างน้อยอะแดปเตอร์เช่น MouseMotionAdapter ในdownload.oracle.com/javase/6/docs/api/java/awt/event/... แน่นอนว่านี่เป็นวิธีการแก้ไขข้อ จำกัด ด้านภาษา
Aleksi Yrttiaho

3
@dietbuddha: ข้อกำหนดเพิ่งเปลี่ยนไป - ตอนนี้ต้องรองรับสองภาษาสำหรับการสาธิตในสัปดาห์หน้า คนที่เขียนว่า "def yes ()" รู้สึกดีใจมากที่เขาเปลี่ยนมาเป็น "def yes (: (IsFrench ())? 'Oui': 'ใช่')"
Andrew Shepherd

คำตอบ:


167

Hehe โอ้ Mr Brown ถ้าเพียง แต่ฉันสามารถชักชวนนักพัฒนาทั้งหมดที่ฉันพบเพื่อรักษาฟังก์ชั่นเล็ก ๆ เช่นนี้เชื่อฉันสิโลกซอฟต์แวร์จะเป็นที่ที่ดีกว่า!

1) การอ่านรหัสของคุณเพิ่มขึ้นสิบเท่า

2) ง่ายต่อการเข้าใจกระบวนการของรหัสของคุณเนื่องจากความสามารถในการอ่าน

3) แห้ง - อย่าทำซ้ำตัวเอง - คุณทำตามนี้ได้ดีมาก!

4) ทดสอบได้ ฟังก์ชั่นเล็ก ๆ นั้นง่ายกว่าในการทดสอบมากกว่า 200 เท่าของวิธีการ 200 บรรทัดที่เราเห็นบ่อยเกินไป

โอ้และไม่ต้องกังวลกับ "การกระโดดฟังก์ชั่น" ในแง่ของประสิทธิภาพ "Release" build และ optimisation คอมไพเลอร์ดูแลสิ่งนี้ให้กับเราอย่างมากและประสิทธิภาพคือ 99% ของเวลาในที่อื่นในการออกแบบระบบ

ขี้เกียจนี่เหรอ? - ตรงกันข้ามมาก!

นี่คือการปฏิบัติที่ไม่ดีหรือไม่? - ไม่ได้อย่างแน่นอน. ดีกว่าที่จะดึงวิธีการทำวิธีนี้กว่าลูก tar หรือ "God Objects" ซึ่งเป็นเรื่องธรรมดาเกินไป

ติดตามการทำงานที่ดีช่างฝีมือเพื่อนของฉัน;)


40
คุณไม่ได้ตอบคำถามคุณแค่เทศนากฎที่มีแอปพลิเคชันที่ต้องถามอีกมากมายที่นี่

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

4
+5 ... โอ้ทำได้เพียง +1 ได้ดี! และให้การสนับสนุน MeshMan ผมขอแนะนำหนังสือเล่มต่อไปนี้โดยโรเบิร์ตซีมาร์ตินรหัสสะอาด หนังสือเล่มนี้เปลี่ยนวิธีการเขียนโปรแกรมของฉันจริงๆ
Eric-Karl

10
คำตอบที่น่าพอใจมาก แต่ฉันไม่เห็นด้วยกับส่วนใหญ่ของมัน: 1) ฟังก์ชั่นขนาดเล็กมากส่งผลให้รหัสโดยรวมมากขึ้นเนื่องจากการประปาทั้งหมดที่จำเป็นสำหรับแต่ละฟังก์ชั่น สิ่งนี้อาจลดความสามารถในการอ่านโดยเฉพาะอย่างยิ่งสำหรับโครงการขนาดใหญ่จริงๆ นอกจากนี้ยังขึ้นอยู่กับภาษา 2) ขึ้นอยู่กับจุดที่ 1 และดังนั้นจึงไม่มีอะไรเกี่ยวข้องกับคำถาม 3) อะไร runCallback ทำซ้ำ "callback" สี่ครั้งและสามครั้งอ้างถึงตัวแปรเดียวกันเพื่อเรียกใช้ฟังก์ชันเดียว 4) วิธี 200 + บรรทัดนั้นแน่นอนว่าไม่สามารถทดสอบได้ แต่มีวิธียาวจากนั้นเป็นหนึ่งบรรทัด
l0b0

10
-1: สิ่งที่น่ากลัวที่สุดในที่นี้คือจำนวนโหวตที่ให้กับคำตอบนี้
Luca

64

ฉันจะบอกว่าวิธี refactored สั้นเกินไปถ้าอย่างใดอย่างหนึ่ง:

  • มันทำซ้ำการดำเนินการดั้งเดิมโดยไม่มีวัตถุประสงค์อื่นนอกเหนือจากที่จะทำให้วิธีการ:

Ex:

boolean isNotValue() {
   return !isValue();
}

หรือ...

  • รหัสนี้ใช้เพียงครั้งเดียวและความตั้งใจนั้นง่ายต่อการเข้าใจได้อย่างรวดเร็ว

Ex:

void showDialog() {
    Dialog singleUseDialog = new ModalDialog();
    configureDialog(singleUseDialog);
    singleUseDialog.show();
}

void configureDialog(Dialog singleUseDialog) {
    singleUseDialog.setDimensions(400, 300);
}

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


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

2
เมธอด "isNotValue ()" มีชื่อไม่ดีและควรได้รับการปรับโครงสร้างใหม่เพื่อตั้งชื่อคำถามโดเมนจริง

4
@Aleksi: ฉันไม่เห็นด้วย; รายละเอียดถูกซ่อนอยู่ในเมธอด showDialog () ในตัวอย่างนี้ ไม่จำเป็นต้องทำการปรับซ้ำสองครั้ง ตัวอย่างมีไว้เพื่อแสดงกรณีใช้งานแบบแยกตัว หากจำเป็นต้องใช้รูปแบบที่มีการกำหนดค่าการโต้ตอบที่แตกต่างกันในกรณีที่แตกต่างกันมันจะทำให้รู้สึกถึงการกลับไปและ refactor เมื่อรูปแบบการจัดตั้ง
RMorrisey

1
@Thorbjorn: ฉันเห็นกรณีนี้เมื่อคุณตอบคำถามเกี่ยวกับโดเมนธุรกิจซึ่งอาจมีเหตุผลที่ไม่ชัดเจน ฉันแค่ชี้ให้เห็นว่ามีบางกรณีที่ overkill
RMorrisey

3
บางทีนี่อาจเป็น nitpicking แต่ฉันขอยืนยันว่าในตัวอย่างของคุณปัญหาไม่ได้ว่าฟังก์ชันสั้นเกินไป แต่พวกเขาไม่ได้เพิ่มคุณค่าเชิงอธิบาย
keppla

59

ฟังก์ชั่นสั้นเกินไปหรือไม่ โดยทั่วไปไม่มี

ในความเป็นจริงเป็นวิธีเดียวที่จะทำให้มั่นใจได้ว่า:

  1. คุณพบชั้นเรียนทั้งหมดในการออกแบบของคุณ
  2. หน้าที่ของคุณกำลังทำสิ่งเดียวเท่านั้น

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

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

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

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

มีอีกมากมายเกี่ยวกับสิ่งนี้ใน Episode III of Clean Code ที่ cleancoders.com


5
ลุงบ๊อบ! ดีใจที่ได้พบคุณบนเรือที่นี่ ตามที่คาดหวังคำแนะนำที่ยอดเยี่ยม ฉันไม่เคยได้ยินคำว่า "ดึงข้อมูลจนกว่าคุณจะลดลง" มาก่อนและจะใช้คำนี้รอบสำนักงานเมื่อวันจันทร์;)
Martin Blore

1
คุณยินดีที่จะอธิบายรายละเอียดในประเด็นที่ 1 ของคุณหรือไม่ อธิบายว่าโดยตัวอย่างจะดีมาก
Daniel Kaplan

53

ว้าวคำตอบส่วนใหญ่ไม่ได้มีประโยชน์อะไรเลย

ไม่มีฟังก์ชั่นควรจะเขียนมีตัวตนคือความหมายของมัน นั่นคือถ้าชื่อฟังก์ชั่นเป็นเพียงบล็อกโค้ดของฟังก์ชันที่เขียนเป็นภาษาอังกฤษดังนั้นอย่าเขียนเป็นฟังก์ชัน

พิจารณาฟังก์ชั่นของคุณconditionMetและฟังก์ชั่นอื่น ๆaddOne(ยกโทษให้ฉันด้วย JavaScript ที่เป็นสนิมของฉัน):

function conditionMet() { return x == condition; }

function addOne(x) { return x + 1; }

conditionMetเป็นคำจำกัดความของแนวคิดที่เหมาะสม addOneเป็นซ้ำซาก conditionMetเป็นเรื่องที่ดีเพราะคุณไม่รู้ว่าสิ่งใดconditionMetเกิดขึ้นเพียงแค่พูดว่า "condition met" แต่คุณสามารถเห็นว่าทำไมaddOneโง่ถ้าคุณอ่านเป็นภาษาอังกฤษ:

"For the condition to be met is for x to equal condition" <-- explanatory! meaningful! useful!

"To add one to x is to take x and add one." <-- wtf!

สำหรับความรักในสิ่งใดก็ตามที่อาจยังคงศักดิ์สิทธิ์โปรดอย่าเขียนฟังก์ชั่นซ้ำซาก!

(และด้วยเหตุผลเดียวกันอย่าเขียนความคิดเห็นสำหรับรหัสทุกบรรทัด !)


โครงสร้างภาษาที่ซับซ้อนบางอย่างอาจไม่คุ้นเคยหรืออ่านยากทำให้นี่เป็นกลอุบายที่มีประโยชน์

3
ตกลงสิ่งที่ควรทำในฟังก์ชั่นจะขึ้นอยู่กับภาษาที่ถูกเขียนมาอย่างมากฟังก์ชั่นเช่น addOne จะมีประโยชน์ถ้าคุณใช้ภาษาเช่น VHDL ที่คุณกำหนดความหมายของการเพิ่มหนึ่งใน ระดับทฤษฎีไบนารีหรือจำนวน ฉันอยากจะคิดว่าไม่มีภาษาออกมาเป็นความลับที่ยากต่อการอ่านแม้สำหรับโปรแกรมเมอร์ที่มีประสบการณ์ (อาจเป็น brainf # ck) แต่ถ้าเป็นเช่นนั้นความคิดเดียวกันจะคงอยู่เนื่องจากฟังก์ชันแปลได้อย่างมีประสิทธิภาพจากภาษาอังกฤษ สำหรับภาษานั้นดังนั้นชื่อจึงไม่เหมือนกับคำจำกัดความ
Rei Miyasaka

1
ผมกำลังพูดถึงสิ่งที่ฟังก์ชั่นตัวตนจากห้องสมุดมาตรฐาน Haskell - ฉันไม่คิดว่าคุณจะได้รับมากขึ้น "ซ้ำ" แล้วที่ :)
hugomg

1
@missingno Bah นั่นคือการโกง: D
Rei Miyasaka

5
หากคุณตั้งชื่อฟังก์ชั่นตามวัตถุประสงค์แทนที่จะเป็นเนื้อหาพวกเขาหยุดทันทีที่โง่ ดังนั้นตัวอย่างของคุณอาจเป็นเช่นนั้นfunction nametoolong() { return name.size > 15; }หรือfunction successorIndex(x) { return x + 1; } ดังนั้นปัญหาเกี่ยวกับหน้าที่ของคุณจึงเป็นเพียงแค่ชื่อของพวกเขาไม่ดี
Hans-Peter Störr

14

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

ตัวอย่างเช่นหากรหัสของคุณมีลักษณะดังนี้:

if x == 1 { ... } // is pixel on?

ทำให้มันเป็นแบบนี้แทน:

if pixelOn() { ... }

กับ

function pixelOn() { return x == 1; }

หรือในคำอื่น ๆ มันไม่ได้เกี่ยวกับความยาวของวิธีการ แต่เกี่ยวกับรหัสเอกสารด้วยตนเอง


5
เพื่อนร่วมงานที่ฉันนับถือชี้ให้เห็นว่าคุณสามารถเขียนif x == PIXEL_ONได้ การใช้ค่าคงที่สามารถอธิบายได้โดยใช้วิธีการและเป็นผู้ที่ไม่ค่อยมีความรู้
Tom Anderson

7

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


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

ฟังก์ชั่นไม่เติบโตด้วยตัวเอง IMHO ตัวอย่างเป็นหมัด conditionMetชื่อสามัญเกินไปและไม่มีการโต้แย้งดังนั้นจึงทดสอบบางรัฐ (x == xCondition) เป็นภาษาและสถานการณ์ส่วนใหญ่ที่แสดงออกว่า 'xConditition'
ผู้ใช้ที่ไม่รู้จัก

ใช่และนั่นคือเหตุผลที่คุณต้องการให้มี 75% + ค่าใช้จ่ายในรหัสของคุณ? Singe liner เขียนเป็น 3 บรรทัดจริง ๆ แล้ว 300%
Coder

5

ฉันเห็นด้วยกับโพสต์อื่น ๆ ทั้งหมดที่ฉันได้เห็น นี่เป็นสไตล์ที่ดี

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

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

รหัสเช่นนี้มีแนวโน้มที่จะมีการทำงานร่วมกันสูงและการมีเพศสัมพันธ์ต่ำซึ่งเป็นวิธีการเข้ารหัสที่ดี

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


+1 สำหรับการกล่าวถึง inlining, imo พิจารณาหลักในการทำงานและฟังก์ชั่นสั้น ๆ
Garet Claborn

4

การกำหนดรหัสใหม่หนึ่งบรรทัดลงในฟังก์ชันดูเหมือนจะมากเกินไป อาจมีกรณีพิเศษเช่น ver loooooong / comples line หรือ expiration แต่ฉันจะไม่ทำสิ่งนี้จนกว่าฉันจะรู้ว่าฟังก์ชั่นจะเติบโตในอนาคต

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

function conditionMet(x, condition){
   return x == condition;
}
....
conditionMet(1,(3-2));
conditionMet("abc","abc");

conditionMetตัวอย่างเช่นอาจจะมีประโยชน์ถ้าเงื่อนไขเป็นเวลานานและซ้ำเช่น:

function conditionMet(x, someObject){
   return x == ((someObject.valA + someObject.valB - 15.4) / /*...whole bunch of other stuff...*/);
}

1
ตัวอย่างแรกของเขาไม่ได้บ่งบอกถึงความกลมกลืน หากมีสิ่งใดมันเป็นวิธีการที่เหนียวแน่นในชั้นที่มีความเหนียวแน่นสูงซึ่งตัวแปรส่วนใหญ่อยู่บนวัตถุ
Martin Blore

7
ที่conditionMetฟังก์ชั่นเป็นเพียง verbose ==ผู้ประกอบการ มันไม่มีประโยชน์เลย

1
ฉันไม่ได้ใช้รูปทรงกลมแน่นอน @MeshMan นั่นคือตัวอย่างที่มาจาก ... วิธีการในชั้นเรียน
มาร์คบราวน์

1
@ Mark Brown: @MeshMan: โอเคฉันเดาว่าตัวอย่างโค้ดนั้นคลุมเครือเกินกว่าจะรู้ได้อย่างแน่นอน ...
FrustratedWithFormsDesigner

ฉันกำลังดมกลิ่นอยู่conditionMet (x, relation condition) {ที่นี่ซึ่งคุณผ่าน x, '==' และความสัมพันธ์ จากนั้นคุณไม่จำเป็นต้องทำซ้ำรหัสสำหรับ '<', '>', '<=', '! =' และอื่น ๆ ในอีกด้านหนึ่ง - ภาษาส่วนใหญ่มีโครงสร้างเหล่านี้สร้างในฐานะผู้ประกอบการ (x == เงื่อนไข) ทำเช่นนั้น ฟังก์ชั่นสำหรับข้อความปรมาณูเป็นขั้นตอนเดียวที่ไกลเกินไป
ผู้ใช้ที่ไม่รู้จัก

3

พิจารณาสิ่งนี้:

ฟังก์ชั่นตรวจจับการชนที่เรียบง่าย:

bool collide(OBJ a, OBJ b)
{
    return(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) <= pow(a.radius + b.radius, 2));
}

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


หากเราจัดการกับ C ที่นี่เราสามารถทำผิดกฎได้#define)
โคลจอห์นสัน

คุณยังอาจต้องการที่จะแลกเปลี่ยนนี้ออกมาให้ช้าลง แต่ล้นหลักฐานhypotถ้าขนาดหรือระยะทางที่คุณจะมีขนาดใหญ่มาก เห็นได้ชัดว่าเป็นเรื่องง่ายมากที่จะทำครั้งเดียว
Matt Krause

2

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


ฉันจะไม่นับในบรรทัดของรหัส แต่ในการแสดงออก "(x == สภาพ)" คืออะตอมดังนั้นฉันจะใส่ลงในวิธีการ / ฟังก์ชั่นเท่านั้นหากมีการใช้หลายครั้งและอาจมีการเปลี่ยนแปลงเช่นแต่แน่นอนไม่ได้function isAdult () = { age >= 18; } isAtLeast18
ผู้ใช้ที่ไม่รู้จัก

2

ฉันจะบอกว่ามันสั้นเกินไป แต่นี่เป็นความเห็นส่วนตัวของฉัน

เพราะ:

  • ไม่มีเหตุผลในการสร้างฟังก์ชั่นหากใช้เพียงครั้งเดียวหรือสองครั้ง กระโดดเพื่อ defs ดูด โดยเฉพาะอย่างยิ่งกับรหัส VS และ C ++ ที่รวดเร็วอย่างน่าอัศจรรย์
  • ภาพรวมของชั้นเรียน เมื่อคุณมีฟังก์ชั่นเล็ก ๆ น้อย ๆ มันทำให้ฉันโกรธ ฉันสนุกเมื่อฉันสามารถดูคำจำกัดความของชั้นเรียนได้อย่างรวดเร็วและดูว่ามันทำอะไรไม่ว่า SetXToOne, SetYToVector3, MultiplyNumbers, + 100 setters / getters
  • ในโครงการส่วนใหญ่ผู้ช่วยเหล่านี้จะกลายเป็นน้ำหนักตายหลังจากขั้นตอนการเปลี่ยนโครงสร้างอีกสองครั้งจากนั้นคุณทำการ "ค้นหาทั้งหมด" -> ลบเพื่อกำจัดรหัสที่ล้าสมัยโดยปกติ ~ 25% + ของมัน

ฟังก์ชั่นที่มีความยาวไม่ดี แต่ฟังก์ชั่นที่สั้นกว่า 3 บรรทัดและทำงานเพียง 1 อย่างนั้นไม่ดีเท่า IMHO

ดังนั้นฉันจะพูดเพียงเขียนฟังก์ชันเล็ก ๆ ถ้ามัน:

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

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


1

ฉันไม่ชอบตัวอย่างที่ไม่มี 1 เพราะชื่อสามัญมี

conditionMetดูเหมือนจะไม่ธรรมดาดังนั้นจึงหมายถึงเงื่อนไขที่เฉพาะเจาะจงหรือไม่ ชอบ

isAdult () = { 
  age >= 18 
}

นี่คงโอเคนะ มันเป็นความแตกต่างทางความหมายในขณะที่

isAtLeast18 () { age >= 18; } 

จะไม่เป็นไรสำหรับฉัน

อาจใช้บ่อยและอาจเปลี่ยนแปลงได้ในภายหลัง:

getPreferredIcecream () { return List ("banana", "choclate", "vanilla", "walnut") }

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

isXYZ (Foo foo) { foo.x > 15 && foo.y < foo.x * 2 }

ไม่ใช่อะตอมและควรให้โอกาสทดสอบที่ดีแก่คุณ

หากคุณต้องการส่งผ่านฟังก์ชั่นแน่นอนส่งผ่านสิ่งที่คุณต้องการและเขียนฟังก์ชั่นดูโง่ ๆ

แต่โดยทั่วไปแล้วฉันเห็นฟังก์ชั่นมากมายซึ่งยาวเกินไปกว่าฟังก์ชั่นที่สั้นเกินไป

คำสุดท้าย: บางฟังก์ชั่นดูเหมาะสมเท่านั้นเพราะมันถูกเขียนอย่างละเอียดเกินไป:

function lessThan (a, b) {
  if (a < b) return true else return false; 
}

หากคุณเห็นว่ามันเป็นเช่นเดียวกับ

return (a < b); 

คุณจะไม่มีปัญหากับ

localLessThan = (a < b); 

แทน

localLessThan = lessThan (a, b); 

0

ไม่มีรหัสที่ไม่มีรหัส!

ทำให้มันง่ายและไม่ซับซ้อนเกินไป

มันไม่ขี้เกียจทำหน้าที่ของคุณ!


0

ใช่มันก็โอเคที่จะมีฟังก์ชั่นรหัสสั้น ๆ ในกรณีที่วิธีการเป็น "getters", "setters", "accesors" เป็นเรื่องธรรมดามากตามคำตอบก่อนหน้านี้ที่กล่าวถึง

บางครั้งฟังก์ชั่น "accesors" สั้น ๆ เหล่านี้เป็นเสมือนจริงเพราะเมื่อ overriden ในคลาสย่อยฟังก์ชั่นจะมีรหัสมากขึ้น

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

function int CalculateSomething() {
  int Result = -1;

   // more code, maybe, maybe not

  return Result;
}

0

สั้นเกินไปไม่เคยมีปัญหา เหตุผลบางประการสำหรับฟังก์ชั่นสั้น ๆ คือ:

สามารถนำมาใช้

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

การบำรุงรักษา

คุณอาจใช้คำสั่งบางอย่างที่คุณคิดว่าในอนาคตอาจมีการเปลี่ยนแปลง เช่นตอนนี้คุณแสดงสัญลักษณ์ในคอลัมน์ แต่หลังจากนั้นอาจเปลี่ยนเป็นอย่างอื่น (หรือแม้แต่เสียงบี๊บ)

เอกรูป

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


0

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

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


0

ไม่ แต่มันสั้นเกินไป

เตือนความจำ: เขียนรหัสครั้งเดียว แต่อ่านหลายครั้ง

อย่าเขียนรหัสสำหรับคอมไพเลอร์ เขียนสำหรับนักพัฒนาในอนาคตที่จะต้องรักษารหัสของคุณ


-1

ใช่ฟังก์ชั่นอาจมีขนาดเล็กลงและเล็กลงและไม่ว่าจะดีหรือไม่ดีขึ้นอยู่กับภาษา / กรอบงานที่คุณใช้

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

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

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

data => initScroll(data)

เป็นฟังก์ชั่นที่ไม่ระบุชื่อใน ES 2017 JavaScript และ Typescript

getMarketSegments() {
 this.marketService.getAllSegments(this.project.id)
  .subscribe(data => this.segments = data, error => console.log(error.toString()));
}

ในรหัสข้างต้นคุณสามารถเห็นการประกาศฟังก์ชั่น 3 และการเรียกใช้ฟังก์ชั่น 2 ครั้งนี่เป็นการเรียกการบริการที่เรียบง่ายใน Angular 4 พร้อมด้วย typescript คุณสามารถคิดได้ตามความต้องการของคุณ

([] 0)
([x] 1)
([x y] 2)

ด้านบนเป็น 3 ฟังก์ชั่นนิรนามในภาษา clojure

(def hello (fn [] "Hello world"))

หนึ่งข้างต้นเป็นการประกาศฟังก์ชั่นใน clojure

ดังนั้นใช่ฟังก์ชั่นอาจมีขนาดเล็กลง แต่ไม่ว่าจะดีหรือไม่ดีถ้าคุณมีฟังก์ชั่นเช่น:

incrementNumber(numb) { return ++numb; }

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

ลองอีกตัวอย่างหนึ่ง

insertInArray(array, newKey) {
 if (!array.includes(newKey)) {
   array.push(newKey);
 }
}

ตัวอย่างข้างต้นเป็นสิ่งที่จำเป็นเมื่อเล่นเมื่ออาร์เรย์ภายในเทมเพลต HTML เชิงมุม ดังนั้นบางครั้งคุณต้องสร้างฟังก์ชั่นเล็ก ๆ


-2

ฉันไม่เห็นด้วยกับคำตอบที่ได้รับเกือบในเวลานี้

เมื่อเร็ว ๆ นี้ฉันพบเพื่อนร่วมงานที่เขียนสมาชิกทุกคนในคลาสเช่น

 void setProperty(int value){ mValue=value; }
 int getProperty() const { return (mValue); }

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

อาจโปรแกรมเมอร์พลาดตรรกะโดยรวมกลัวเกี่ยวกับการเปลี่ยนแปลงในอนาคตและเกี่ยวกับการปรับโครงสร้างรหัสใหม่

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

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


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

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

2
ทะเยอทะยานและ setters แย่การใช้งานที่ถูกต้องแม้จะมี หากจำเป็นต้องใช้ฉันคิดว่าเป็นภาษาที่ล้มเหลว
Carson Myers

@Rei: ทำไมคลาสภายนอกจะต้องตรวจสอบค่าของตัวส่วน? ที่ควรจะทำโดยฟังก์ชั่นหาร () ของคลาสเศษส่วนหรือคลาสเศษส่วนควรจัดให้มี isDivisible () เพื่อตรวจสอบหาส่วนที่เป็นโมฆะ ต้องการ getters / setters มักจะมีกลิ่นรหัสที่ชั้นเรียนของคุณมีการมีเพศสัมพันธ์สูงและ / หรือการทำงานร่วมกันในระดับต่ำ (เช่นไม่ดี)
โกหกที่

@ อยู่อะไร ฉันไม่เคยบอกว่าควรใช้คลาสภายนอกเพื่อตรวจสอบตัวส่วน ฉันกำลังบอกว่าคลาสภายนอกอาจตั้งค่าส่วนเป็น 0 โดยบังเอิญ วัตถุประสงค์ของการมีการตรวจสอบความถูกต้องเกิดขึ้นที่ setters คือการสนับสนุนข้อบกพร่องใด ๆ ในรหัสผู้บริโภคที่จะพบก่อนหน้านี้ การให้ isDivisible () ฟังก์ชั่นที่อาจจะเรียกว่าอาจจะหรืออาจจะไม่ได้ก็ไม่ได้ผล และความต้องการของ getters / setters นั้นบ่งบอกได้อย่างไรว่าการมีเพศสัมพันธ์สูง?
Rei Miyasaka
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.