Một chức năng có thể quá ngắn?


125

Bất cứ khi nào tôi thấy mình viết cùng một logic nhiều lần, tôi thường gắn nó vào một hàm vì vậy chỉ có một nơi trong ứng dụng của tôi, tôi phải duy trì logic đó. Một tác dụng phụ là đôi khi tôi kết thúc với một hoặc hai hàm dòng như:

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

HOẶC LÀ

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

Đây là lười biếng hay một thực hành xấu? Tôi chỉ hỏi bởi vì điều này dẫn đến một số lượng lớn hơn các hàm gọi cho các đoạn logic rất nhỏ.


3
Không, không quá ngắn. Trong C # tôi sẽ làm 'điều kiện đáp ứng' như một tài sản, đó là thanh lịch và sẽ xem xét sử dụng Assert.AreEqual<int>(expected, actual, message, arg1, arg2, arg3, ...);. Thứ hai là tốt như là. Tôi có khả năng sẽ bao gồm một cờ bool tùy chọn để ra lệnh có nên ném ngoại lệ / v.v. trong trường hợp gọi lại không phải là một chức năng.
Công việc

38
Có, chỉ trong một trường hợp: chức năng myFunction () {}
Spooks

5
def yes(): return 'yes'
dietbuddha

3
@Spooks - Tôi đang chia tóc ở đây nhưng các hàm trống có giá trị cho ít nhất các lớp bộ điều hợp, ví dụ như MouseMotionAd CHƯƠNG trong download.oracle.com/javase/6/docs/api/java/awt/event/ . Tất nhiên đây chỉ là một cách để khắc phục những hạn chế về ngôn ngữ.
Aleksi Yrttiaho

3
@dietbuddha: Các yêu cầu vừa thay đổi - bây giờ nó phải hỗ trợ hai ngôn ngữ cho bản demo vào tuần tới. Anh chàng đã viết "def yes ()" cảm thấy rất vui mừng trước khi đổi nó thành "def yes (: (IsFbler ()? 'Oui': 'Yes')"
Andrew Shepherd

Câu trả lời:


167

Hehe, oh ông Brown, nếu tôi có thể thuyết phục tất cả các nhà phát triển tôi gặp để giữ cho các chức năng của họ nhỏ như thế này, tin tôi đi, thế giới phần mềm sẽ là một nơi tốt hơn!

1) Khả năng đọc mã của bạn tăng gấp mười lần.

2) Rất dễ để tìm ra quy trình mã của bạn vì tính dễ đọc.

3) DRY - Đừng lặp lại chính mình - Bạn đang tuân thủ điều này rất tốt!

4) Có thể kiểm tra. Các hàm nhỏ dễ kiểm tra hơn một triệu lần so với các phương thức 200 dòng mà chúng ta thấy quá thường xuyên.

Ồ và đừng lo lắng về "chức năng nhảy" về mặt hiệu suất. Các bản dựng "phát hành" và tối ưu hóa trình biên dịch đảm nhận việc này cho chúng tôi rất độc đáo và hiệu suất là 99% thời gian ở một nơi khác trong thiết kế hệ thống.

Đây có phải là lười biếng? - Rất nhiều điều ngược lại!

Đây có phải là thực hành xấu? - Tuyệt đối không. Tốt hơn là nên sử dụng phương pháp chế tạo này so với các quả bóng nhựa hoặc "Đối tượng của Chúa" quá phổ biến.

Giữ thành tốt công việc thợ thủ công của tôi;)


40
Bạn không trả lời câu hỏi, bạn chỉ đang giảng về quy tắc có nhiều ứng dụng cực đoan hơn được hỏi ở đây.

4
Nó không thường xuyên mà tôi thấy giới hạn của chỉ 1 upvote bực bội. Nhưng, đối với câu trả lời này, +1 dường như không thực hiện công lý.
Bevan

4
+5 ... oh chỉ có thể làm +1, ồ! Và để hỗ trợ cho Gridman, tôi đề xuất cuốn sách sau đây của Robert C. Martin Clean code . Cuốn sách này thực sự thay đổi cách tôi lập trình bây giờ.
Eric-Karl

10
Câu trả lời rất thích, nhưng tôi không đồng ý với hầu hết câu trả lời: 1) Các hàm cực nhỏ dẫn đến tổng thể nhiều mã hơn, vì tất cả các hệ thống ống nước cần thiết cho mỗi chức năng. Điều này có thể làm giảm khả năng đọc, đặc biệt đối với một dự án thực sự lớn. Ngoài ra, phụ thuộc ngôn ngữ. 2) Phụ thuộc hoàn toàn vào điểm 1, và do đó không liên quan gì đến câu hỏi. 3) Cái gì? runCallback lặp lại "gọi lại" bốn lần và ba lần đề cập đến cùng một biến để chạy một hàm duy nhất. 4) Hơn 200 phương thức dòng tất nhiên không thể kiểm tra được, nhưng có một chặng đường dài từ đó đến một dòng.
l0b0

10
-1: Điều đáng sợ nhất ở đây là số lượt bình chọn cho câu trả lời này.
Luca

64

Tôi muốn nói rằng một phương thức tái cấu trúc là quá ngắn nếu:

  • Nó sao chép một hoạt động nguyên thủy, không nhằm mục đích nào khác ngoài việc biến nó thành một phương thức:

Ví dụ:

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

hoặc là...

  • Mã chỉ được sử dụng một lần và ý định của nó rất dễ hiểu trong nháy mắt.

Ví dụ:

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

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

Đây có thể là một mẫu hợp lệ, nhưng tôi sẽ chỉ nội tuyến phương thức configureDialog (), trong ví dụ này, trừ khi tôi có ý định ghi đè lên nó hoặc sử dụng lại mã này ở nơi khác.


7
Việc tách một phương thức đường đơn trong trường hợp thứ hai có thể có lợi để giữ cho mức độ trừu tượng của phương thức gọi phù hợp. Ví dụ được cung cấp nằm trên hàng rào nếu lý do này được sử dụng: chiều rộng pixel chính xác và chiều cao có quá nhiều chi tiết để hiển thị hộp thoại không?
Aleksi Yrttiaho

2
Phương thức "isNotValue ()" được đặt tên xấu và nên được cấu trúc lại để đặt tên cho câu hỏi miền thực tế.

4
@Aleksi: Tôi không đồng ý; các chi tiết đã được ẩn trong phương thức showDialog () trong ví dụ này; không cần phải tái cấu trúc lại nó. Ví dụ này nhằm hiển thị một trường hợp sử dụng bị cô lập; nếu một mẫu là cần thiết với các cấu hình hộp thoại khác nhau trong các trường hợp khác nhau, thì sẽ quay trở lại và tái cấu trúc một khi mẫu được thiết lập.
RMorrisey

1
@Thorbjorn: Tôi có thể thấy một trường hợp cho nó, khi bạn trả lời một câu hỏi về lĩnh vực kinh doanh mà logic của nó có thể không rõ ràng. Tôi chỉ chỉ ra rằng có một số trường hợp mà nó quá mức cần thiết.
RMorrisey

3
Có thể đây là trò đùa, nhưng tôi sẽ cho rằng trong các ví dụ của bạn, vấn đề không phải là hàm này quá ngắn, mà là chúng không thêm giá trị mô tả.
keppla

59

Một chức năng có thể quá ngắn? Nói chung là không.

Trong thực tế, cách duy nhất để đảm bảo rằng:

  1. Bạn đã tìm thấy tất cả các lớp trong thiết kế của bạn
  2. Chức năng của bạn chỉ làm một việc.

Là để giữ cho chức năng của bạn càng nhỏ càng tốt. Hay nói cách khác, trích xuất các hàm từ các chức năng của bạn cho đến khi bạn không thể giải nén được nữa. Tôi gọi đây là "Trích xuất cho đến khi bạn thả."

Để giải thích điều này: Hàm là một phạm vi với các khối chức năng giao tiếp bằng các biến. Một lớp cũng là một phạm vi với các khối chức năng giao tiếp bằng các biến. Vì vậy, một hàm dài luôn có thể được thay thế bằng một hoặc nhiều lớp bằng phương thức nhỏ.

Ngoài ra, một chức năng đủ lớn để cho phép bạn trích xuất một chức năng khác từ nó, đang thực hiện nhiều hơn một điều theo định nghĩa . Vì vậy, nếu bạn có thể trích xuất một chức năng từ một chức năng khác, bạn nên trích xuất chức năng đó.

Một số người lo lắng rằng điều này sẽ dẫn đến sự gia tăng các chức năng. Họ nói đúng. Nó sẽ. Đó thực sự là một điều tốt. Điều đó tốt bởi vì các chức năng có tên. Nếu bạn cẩn thận về việc chọn tên tốt, thì các hàm này hoạt động như các bài đăng ký chỉ dẫn người khác thông qua mã của bạn. Thật vậy, các hàm được đặt tên tốt bên trong các lớp được đặt tên tốt bên trong các không gian tên được đặt tên tốt là một trong những cách tốt nhất để đảm bảo rằng độc giả của bạn KHÔNG bị lạc.

Có nhiều hơn về điều này trong Phần III của Clean Code tại Cleancoders.com


5
Chú Bob! Thật tuyệt khi gặp bạn trên tàu ở đây. Như mong đợi, lời khuyên tuyệt vời. Tôi chưa bao giờ nghe cụm từ "Trích xuất cho đến khi bạn thả" trước đây và chắc chắn sẽ sử dụng thuật ngữ này quanh văn phòng vào thứ Hai;).
Martin Blore

1
Bạn có sẵn sàng giải thích về quan điểm số 1 của bạn không? Giải thích rằng bằng ví dụ sẽ là tuyệt vời.
Daniel Kaplan

53

Ồ, hầu hết những câu trả lời này không hữu ích chút nào.

Không có chức năng nên được viết mà danh tính của nó là định nghĩa của nó . Đó là, nếu tên hàm đơn giản là khối mã của hàm được viết bằng tiếng Anh, thì đừng viết nó dưới dạng hàm.

Hãy xem xét chức năng của bạn conditionMetvà chức năng khác này, addOne(tha thứ cho tôi về JavaScript rỉ sét của tôi):

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

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

conditionMetlà một định nghĩa khái niệm đúng đắn; addOnelà một tautology . conditionMetlà tốt bởi vì bạn không biết những gì conditionMetđòi hỏi chỉ bằng cách nói "điều kiện đáp ứng", nhưng bạn có thể thấy tại sao addOnethật ngớ ngẩn nếu bạn đọc nó bằng tiếng Anh:

"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!

Vì tình yêu của bất cứ điều gì vẫn có thể là thánh, xin vui lòng, đừng viết các hàm tautological!

(Và vì lý do tương tự, đừng viết bình luận cho mỗi dòng mã !)


Một số cấu trúc ngôn ngữ phức tạp hơn có thể không quen thuộc hoặc khó đọc, làm cho điều này trở thành một thủ thuật hữu ích.

3
Đồng ý, chính xác những gì nên được tạo thành một hàm sẽ phụ thuộc phần lớn vào ngôn ngữ mà nó được viết. Một hàm như addOne sẽ hữu ích nếu bạn sử dụng ngôn ngữ như VHDL, nơi bạn thực sự xác định nghĩa của việc thêm một ngôn ngữ vào mức độ lý thuyết nhị phân hoặc số. Tôi muốn nghĩ rằng không có ngôn ngữ nào ngoài đó khó hiểu đến mức khó đọc ngay cả đối với các lập trình viên thực hành (có thể là brainf # ck), nhưng nếu đó là trường hợp, thì ý tưởng tương tự sẽ có nghĩa là chức năng dịch từ tiếng Anh với ngôn ngữ đó - vì vậy tên không giống với định nghĩa.
Rei Miyasaka

1
Tôi đang nói về những thứ chức năng nhận dạng từ thư viện tiêu chuẩn Haskell - Tôi không nghĩ bạn có thể nhận được nhiều "tautological" hơn thế :)
hugomg

1
@missingno Bah, đó là gian lận: D
Rei Miyasaka

5
Nếu bạn đặt tên cho các chức năng theo mục đích của chúng thay vì theo nội dung của chúng, chúng sẽ ngay lập tức ngừng ngớ ngẩn. Vì vậy, ví dụ của bạn có thể là ví dụ function nametoolong() { return name.size > 15; }hoặc function successorIndex(x) { return x + 1; } Vì vậy, vấn đề với các chức năng của bạn thực sự chỉ là tên của họ rất tệ.
Hans-Peter Störr

14

Tôi muốn nói rằng nếu bạn nghĩ rằng ý định của một số mã có thể được cải thiện bằng cách thêm một nhận xét, thì thay vì thêm nhận xét đó, hãy trích xuất mã vào phương thức riêng của nó. Bất kể mã nhỏ như thế nào.

Vì vậy, ví dụ nếu mã của bạn sẽ trông như sau:

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

làm cho nó trông như thế này thay vào đó:

if pixelOn() { ... }

với

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

Hay nói cách khác, đó không phải là về độ dài phương thức, mà là về mã tự viết tài liệu.


5
Đồng nghiệp quý của tôi chỉ ra rằng bạn cũng có thể viết if x == PIXEL_ON. Sử dụng một hằng số có thể được mô tả như sử dụng một phương pháp, và là một ít hơn.
Tom Anderson

7

Tôi nghĩ rằng đây là chính xác những gì bạn muốn làm. Ngay bây giờ chức năng đó có thể chỉ là một hoặc hai dòng nhưng theo thời gian nó có thể phát triển. Ngoài ra có nhiều cuộc gọi chức năng hơn cho phép bạn đọc các cuộc gọi chức năng và hiểu những gì đang xảy ra bên trong đó. Điều này làm cho mã của bạn rất KHÔ (Đừng lặp lại chính mình) dễ bảo trì hơn nhiều.


4
Vì vậy, có gì sai khi bao thanh toán nó sau này, khi bạn có thể chứng minh rằng bạn cần, thay vì bây giờ, khi nó chỉ là trọng lượng chết?
dsimcha

Các chức năng không tự phát triển. IMHO các ví dụ là tệ hại. conditionMetlà một tên quá chung chung và không có đối số, vì vậy nó kiểm tra một số trạng thái? (x == xCondition) trong hầu hết các ngôn ngữ và tình huống có tính biểu cảm như 'xConditition'.
người dùng không xác định

Có, và đó là lý do tại sao bạn muốn có 75% + chi phí trong mã của mình? Singe lót được viết là 3 dòng thực sự là 300%.
Coder

5

Tôi đồng ý với tất cả các bài viết khác mà tôi đã thấy. Đây là phong cách tốt.

Chi phí hoạt động của một phương thức nhỏ như vậy có thể là không vì trình tối ưu hóa có thể tối ưu hóa cuộc gọi đi và nội tuyến mã. Mã đơn giản như thế này cho phép trình tối ưu hóa thực hiện công việc tốt nhất của nó.

Mã nên được viết cho rõ ràng và đơn giản. Tôi cố gắng giới hạn một phương pháp ở một trong hai vai trò: đưa ra quyết định; hoặc thực hiện công việc. Điều này có thể tạo ra một phương thức dòng. Tôi càng giỏi trong việc này, tôi càng tìm thấy mã của mình tốt hơn.

Mã như thế này có xu hướng có độ gắn kết cao và khớp nối thấp, đó là thực hành mã hóa tốt.

EDIT: Một lưu ý về tên phương thức. Sử dụng một tên phương thức cho biết phương thức nào không hoạt động. Tôi thấy verb_noun (_modifier) ​​là một lược đồ đặt tên tốt. Điều này đặt tên như Find_Customer_ByName thay vì Chọn_Customer_Using_NameIdx. Trường hợp thứ hai có xu hướng trở thành không chính xác khi phương thức được sửa đổi. Trong trường hợp đầu tiên, bạn có thể trao đổi toàn bộ triển khai cơ sở dữ liệu của Khách hàng.


+1 để đề cập đến nội tuyến, imo xem xét chính trong hiệu suất và các chức năng ngắn.
Garet Claborn

4

Tái cấu trúc một dòng mã thành một hàm có vẻ quá mức. Có thể có những trường hợp đặc biệt, chẳng hạn như ver loooooong / comples dòng hoặc hết hạn, nhưng tôi sẽ không làm điều này trừ khi tôi biết chức năng sẽ phát triển trong tương lai.

và ví dụ đầu tiên của bạn gợi ý về việc sử dụng toàn cầu (có thể nói hoặc không nói về các vấn đề khác trong mã), tôi sẽ cấu trúc lại nó thêm và biến hai biến đó thành tham số:

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

Các conditionMetví dụ có thể có ích nếu tình trạng này kéo dài và lặp đi lặp lại như:

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

1
Ví dụ đầu tiên của ông không gợi ý về toàn cầu. Nếu bất cứ điều gì, đó là một phương thức gắn kết trong một lớp có độ gắn kết cao, trong đó hầu hết các biến nằm trên đối tượng.
Martin Blore

7
conditionMetHàm đó chỉ là một ==toán tử dài dòng . Điều đó có thể không hữu ích.

1
Tôi chắc chắn không sử dụng toàn cầu. @MeshMan, đó chính xác là ví dụ từ ... một phương thức trên một lớp.
Mark Brown

1
@Mark Brown: @MeshMan: Ok, tôi đoán ví dụ mã quá mơ hồ để biết chắc chắn ...
Thất vọngWithFormsDesigner

Tôi đang ngửi thấy conditionMet (x, relation condition) {ở đây, nơi bạn vượt qua x, '==' và mối quan hệ. Sau đó, bạn không cần lặp lại mã cho '<', '>', '<=', '! =', V.v. Mặt khác - hầu hết các ngôn ngữ đều có các cấu trúc này được xây dựng dưới dạng toán tử (x == condition) thực hiện điều đó. Các chức năng cho các tuyên bố nguyên tử là một bước quá xa.
người dùng không xác định

3

Xem xét điều này:

Một chức năng phát hiện va chạm đơn giản:

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));
}

Nếu bạn đã viết rằng "đơn giản" một lớp lót trong mã của bạn mọi lúc, cuối cùng bạn có thể mắc lỗi. Thêm vào đó, sẽ rất khó khăn khi viết đi viết lại.


Nếu chúng ta giao dịch với C ở đây, chúng ta chỉ có thể lạm dụng #define;)
Cole Johnson

Bạn thậm chí có thể muốn trao đổi điều này cho hypot chậm hơn nhưng chống tràn nếu kích thước hoặc khoảng cách của bạn trở nên rất lớn. Điều này rõ ràng là dễ dàng hơn nhiều để làm một lần.
Matt Krause

2

Không, và đó hiếm khi là một vấn đề. Bây giờ nếu ai đó cảm thấy không có chức năng nào nên dài hơn một dòng mã (nếu chỉ có thể đơn giản như vậy), đó sẽ là một vấn đề và trong một số cách lười biếng vì họ không nghĩ về những gì phù hợp.


Tôi sẽ không đếm nó trong các dòng mã, nhưng trong các biểu thức. "(x == condition)" là nguyên tử, vì vậy tôi sẽ chỉ đưa nó vào một phương thức / hàm, nếu nó được sử dụng nhiều lần VÀ có thể được thay đổi, function isAdult () = { age >= 18; }nhưng chắc chắn là không isAtLeast18.
người dùng không xác định

2

Tôi sẽ nói rằng chúng quá ngắn, nhưng đây là ý kiến ​​chủ quan của tôi.

Bởi vì:

  • Không có lý do để tạo một chức năng nếu nó chỉ được sử dụng một hoặc hai lần. Nhảy để defs hút. Đặc biệt với mã VS và C ++ nhanh đáng kinh ngạc.
  • Tổng quan về lớp học. Khi bạn có hàng ngàn chức năng nhỏ, nó khiến tôi tức giận. Tôi thích thú khi tôi có thể xem các định nghĩa lớp và nhanh chóng xem những gì nó làm, chứ không phải cách SetXToOne, SetYToVector3, MultiplyNumbers, + 100 setters / getters.
  • Trong hầu hết các dự án, những người trợ giúp này trở thành trọng lượng chết sau một giai đoạn hai lần tái cấu trúc và sau đó bạn thực hiện "tìm kiếm tất cả" -> xóa để thoát khỏi mã lỗi thời, thường là ~ 25% +.

Các hàm dài là xấu, nhưng các hàm ngắn hơn 3 dòng và chỉ thực hiện 1 điều là IMHO xấu như nhau.

Vì vậy, tôi muốn nói chỉ viết hàm nhỏ nếu nó:

  • Hơn 3 dòng mã
  • Có những thứ mà các nhà phát triển cơ sở có thể bỏ lỡ (không biết)
  • Có xác nhận thêm không
  • Được sử dụng, hoặc sẽ sử dụng ít nhất 3x
  • Đơn giản hóa giao diện được sử dụng thường xuyên
  • Sẽ không trở thành trọng lượng chết trong lần tái cấu trúc tiếp theo
  • Có một số ý nghĩa đặc biệt, ví dụ, chuyên môn hóa mẫu hoặc một cái gì đó
  • Có một số công việc cô lập - tham chiếu const, ảnh hưởng đến các tham số có thể thay đổi, có truy xuất thành viên riêng không

Tôi đặt cược nhà phát triển tiếp theo (cao cấp) sẽ có nhiều việc phải làm hơn là nhớ tất cả các chức năng SetXToOne của bạn. Vì vậy, họ sẽ sớm biến thành trọng lượng chết.


1

Tôi không thích ví dụ không. 1, vì tên chung thứ i.

conditionMetdường như không phải là chung chung, vì vậy nó là viết tắt của một điều kiện cụ thể? Như

isAdult () = { 
  age >= 18 
}

Điều này sẽ ổn thôi. Đó là một sự khác biệt về ngữ nghĩa, trong khi

isAtLeast18 () { age >= 18; } 

sẽ không tốt cho tôi

Có lẽ nó thường được sử dụng và có thể là đối tượng để thay đổi sau này:

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

cũng tốt Sử dụng nó nhiều lần, bạn chỉ cần thay đổi một địa điểm duy nhất, nếu bạn phải - có thể đánh kem có thể vào ngày mai.

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

không phải là nguyên tử, và sẽ cung cấp cho bạn một cơ hội thử nghiệm tốt đẹp.

Nếu bạn cần vượt qua một chức năng, tất nhiên, vượt qua bất cứ điều gì bạn thích, và viết các chức năng trông ngớ ngẩn khác.

Nhưng nói chung, tôi thấy nhiều chức năng hơn, quá dài, so với các chức năng quá ngắn.

Từ cuối cùng: Một số chức năng chỉ có vẻ phù hợp, vì chúng được viết quá dài dòng:

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

Nếu bạn thấy, nó giống như

return (a < b); 

bạn sẽ không có vấn đề gì với

localLessThan = (a < b); 

thay vì

localLessThan = lessThan (a, b); 

0

Không có mã như không có mã!

Giữ nó đơn giản và đừng quá phức tạp.

Đó không phải là lười biếng, đó là công việc của bạn!


0

Vâng, nó ổn để có một chức năng mã ngắn. Trong trường hợp các phương thức là "getters", "setters", "accesors" là rất phổ biến, như các câu trả lời trước đã đề cập.

Đôi khi, các hàm "accesors" ngắn đó là ảo, bởi vì khi được ghi đè trong các lớp con, các hàm sẽ có nhiều mã hơn.

Nếu bạn muốn bạn hoạt động không quá ngắn, trong nhiều hàm, toàn cầu hoặc phương thức, tôi thường sử dụng biến "kết quả" (kiểu pascal) thay vì trả về trực tiếp, rất hữu ích khi sử dụng trình gỡ lỗi.

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

   // more code, maybe, maybe not

  return Result;
}

0

Quá ngắn không bao giờ là một vấn đề. Một số lý do cho các chức năng ngắn là:

Tái sử dụng

Ví dụ: nếu bạn có một hàm, giống như một phương thức đã đặt, bạn có thể khẳng định nó để đảm bảo các tham số hợp lệ. Việc kiểm tra này phải được thực hiện ở mọi nơi mà biến được đặt.

Bảo trì

Bạn có thể sử dụng một số tuyên bố mà bạn nghĩ trong tương lai có thể thay đổi. Ví dụ, bây giờ bạn hiển thị một biểu tượng trong một cột, nhưng sau đó có thể thay đổi thành một biểu tượng khác (hoặc thậm chí là tiếng bíp).

Đồng nhất

Bạn đang sử dụng ví dụ mẫu mặt tiền và điều duy nhất một hàm thực hiện là chuyển chính xác hàm này sang hàm khác mà không thay đổi đối số.


0

Khi bạn đặt tên cho phần mã, về cơ bản là đặt tên cho nó . Điều này có thể vì bất kỳ lý do nào, nhưng điểm quan trọng là nếu bạn có thể đặt cho nó một cái tên có ý nghĩa bổ sung cho chương trình của bạn. Những cái tên như "addOneToCorer" sẽ không thêm bất cứ thứ gì, nhưng conditionMet()sẽ.

Nếu bạn cần một quy tắc để tìm hiểu xem đoạn trích quá ngắn hay quá dài, thì hãy xem xét bạn mất bao lâu để tìm một tên có ý nghĩa cho đoạn trích. Nếu bạn không thể trong một khoảng thời gian hợp lý, thì đoạn trích không phải là kích thước phù hợp.


0

Không, nhưng nó có thể quá ngắn gọn.

Hãy nhớ rằng: Mã được viết một lần, nhưng đọc nhiều lần.

Đừng viết mã cho trình biên dịch. Viết nó cho các nhà phát triển trong tương lai, những người sẽ phải duy trì mã của bạn.


-1

Vâng, chức năng có thể nhỏ hơn và nhỏ hơn và nó tốt hay xấu tùy thuộc vào Ngôn ngữ / Khung bạn đang sử dụng.

Theo tôi, tôi chủ yếu làm việc trên Front End Technologies, Chức năng nhỏ chủ yếu được sử dụng làm chức năng của người trợ giúp, bạn sẽ bị ràng buộc sử dụng chúng rất nhiều khi làm việc với các bộ lọc nhỏ và sử dụng cùng logic trên ứng dụng của bạn. Nếu ứng dụng của bạn có quá nhiều logic thông thường thì sẽ có hàng tấn các hàm nhỏ.

Nhưng trong một ứng dụng mà bạn không có logic thông thường, bạn sẽ không bị ràng buộc để tạo các hàm nhỏ nhưng bạn có thể chia mã của mình thành các phân đoạn để bạn dễ dàng quản lý và hiểu được.

Nói chung, phá vỡ mã lớn của bạn thành chức năng nhỏ là một cách tiếp cận rất tốt. Trong các khuôn khổ và ngôn ngữ hiện đại, bạn sẽ bị ràng buộc phải làm như vậy, vd

data => initScroll(data)

là một chức năng ẩn danh trong ES 2017 JavaScript và Typecript

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

trong đoạn mã trên, bạn có thể thấy 3 khai báo Hàm và 2 lệnh gọi hàm này là Cuộc gọi dịch vụ đơn giản trong Angular 4 với Bản in. Bạn có thể nghĩ về nó như yêu cầu của bạn

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

Trên đây là 3 chức năng ẩn danh trong ngôn ngữ clojure

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

Trên đây là một tuyên bố chức năng trong clojure

Vì vậy, có CHỨC NĂNG có thể nhỏ hơn nhưng tốt hay xấu nếu bạn có các chức năng như:

incrementNumber(numb) { return ++numb; }

Vâng, đó không phải là một cách thực hành tốt nhưng nếu bạn sử dụng chức năng này trong thẻ HTML như chúng tôi làm trong Angular Framework nếu không có hỗ trợ Tăng hoặc Giảm trong Mẫu HTML Angular thì đây sẽ là giải pháp cho tôi.

Hãy lấy một ví dụ khác

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

Ví dụ trên là bắt buộc khi phát khi các mảng bên trong Mẫu HTML Angular. Vì vậy, đôi khi bạn sẽ phải tạo các chức năng nhỏ


-2

Tôi không đồng ý với câu trả lời gần như được đưa ra tại thời điểm này.

Gần đây tôi tìm thấy một đồng nghiệp viết tất cả các thành viên trong lớp như sau:

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

Đây có thể là một mã tốt trong các trường hợp lẻ tẻ, nhưng chắc chắn là không nếu bạn định nghĩa nhiều lớp có nhiều và nhiều thuộc tính. Tôi không muốn nói, với điều này, các phương pháp như những phương pháp trên sẽ không được viết. Nhưng, nếu bạn kết thúc để viết hầu hết mã là "trình bao bọc" của logic thực, thì có gì đó không đúng.

Có lẽ lập trình viên bỏ lỡ logic tổng thể, sợ hãi về những thay đổi trong tương lai và về việc tái cấu trúc mã.

Định nghĩa của giao diện là bởi vì một nhu cầu thực sự; thực sự nếu bạn cần thiết lập và có được một thuộc tính đơn giản (không có nhiều logic, làm cho thành viên ngắn hơn) thì có thể. Nhưng, nếu nhu cầu thực sự có thể được phân tích theo một cách khác, tại sao không định nghĩa một giao diện trực quan hơn?

Để thực sự trả lời cho câu hỏi, tất nhiên là không, và lý do rất rõ ràng: phương thức / thuộc tính / whatelse sẽ được xác định cho những gì nó cần. Ngay cả một chức năng ảo trống cũng có một lý do để tồn tại.


6
Có một lý do chính đáng để thêm các phương thức accessor / mutator mà bạn gợi ý trong phần "sợ về tương lai ... tái cấu trúc". Nhưng bạn cũng đúng rằng nó không thêm giá trị cho mã. Không bằng cách giảm kích thước (cục bộ hoặc toàn cầu) hoặc tăng khả năng đọc. Trong tâm trí của tôi, điều này nói lên thiết kế ngôn ngữ kém trong cả quy ước Java và JavaBeans. Đây là một lĩnh vực (trong số nhiều) trong đó C # đã cải thiện thành công ngôn ngữ để giải quyết cả hai mối quan tâm với cú pháp thuộc tính tự động . Là một lập trình viên Java, tôi đồng ý với phong cách thô của bạn cho các lớp giống như cấu trúc cơ bản.
Anm

1
Các hàm Getter / setter vẫn tốt ngay cả khi tất cả những gì chúng làm ngay bây giờ là đọc hoặc ghi một biến. Là một vấn đề thực tế, bạn có thể tưởng tượng một kịch bản mà sau này bạn quyết định in một giá trị lên màn hình mỗi khi trường thay đổi hoặc để kiểm tra xem giá trị đó có hợp lệ hay không. (Có thể đó là mẫu số cho một phân số và bạn muốn kiểm tra để chắc chắn rằng nó không phải là số không.)
Rei Miyasaka

2
getters và setters là khủng khiếp, sử dụng hợp lệ của họ mặc dù. Nếu cần sử dụng chúng, tôi coi đó là một sự thất bại của ngôn ngữ.
Carson Myers

@Rei: tại sao một lớp bên ngoài cần kiểm tra giá trị của mẫu số? Điều đó nên được thực hiện bởi hàm split () của lớp Phân số hoặc lớp Phân số sẽ cung cấp một hàm isDivisible () để kiểm tra các mẫu số null. Cần getters / setters thường là một mùi mã mà lớp của bạn có độ khớp cao và / hoặc độ gắn kết thấp (tức là xấu).
Nói dối Ryan

@Lie cái gì? Tôi không bao giờ nói một lớp bên ngoài nên được sử dụng để kiểm tra mẫu số. Tôi đang nói rằng một lớp bên ngoài có thể đặt mẫu số thành 0 một cách tình cờ. Mục đích của việc kiểm tra tính hợp lệ xảy ra tại các setters là để khuyến khích bất kỳ lỗi nào trong mã người tiêu dùng được tìm thấy trước đó. Việc cung cấp một hàm isDivisible () có thể được gọi hoặc có thể không được gọi cũng không hoạt động đến đầu đó. Và chính xác làm thế nào để cần getters / setters chỉ ra rằng có khớp nối cao?
Rei Miyasaka
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.