Sếp của tôi yêu cầu tôi ngừng viết các hàm nhỏ và làm mọi thứ trong cùng một vòng lặp


209

Tôi đã đọc một cuốn sách tên là Clean Code của Robert C. Martin. Trong cuốn sách này, tôi đã thấy nhiều phương pháp để làm sạch mã như viết các hàm nhỏ, chọn tên cẩn thận, v.v ... Dường như đây là cuốn sách thú vị nhất về mã sạch tôi đã đọc. Tuy nhiên, hôm nay ông chủ của tôi không thích cách tôi viết mã sau khi đọc cuốn sách này.

Lập luận của ông là

  • Viết các hàm nhỏ là một nỗi đau vì nó buộc bạn phải di chuyển vào từng hàm nhỏ để xem mã đang làm gì.
  • Đặt mọi thứ trong một vòng lặp lớn chính ngay cả khi vòng lặp chính dài hơn 300 dòng, nó sẽ nhanh hơn để đọc.
  • Chỉ viết các hàm nhỏ nếu bạn phải sao chép mã.
  • Đừng viết một hàm với tên của bình luận, đặt dòng mã phức tạp của bạn (3-4 dòng) với một nhận xét ở trên; tương tự như vậy, bạn có thể sửa đổi mã lỗi trực tiếp

Điều này chống lại mọi thứ tôi đã đọc. Làm thế nào để bạn thường viết mã? Một vòng lặp lớn chính, không có chức năng nhỏ?

Ngôn ngữ tôi sử dụng chủ yếu là Javascript. Bây giờ tôi thực sự gặp khó khăn khi đọc vì tôi đã xóa tất cả các hàm nhỏ được đặt tên rõ ràng của mình và đặt mọi thứ vào một vòng lặp lớn. Tuy nhiên, ông chủ của tôi thích nó theo cách này.

Một ví dụ là:

// The way I would write it
if (isApplicationInProduction(headers)) {
  phoneNumber = headers.resourceId;
} else {
  phoneNumber = DEV_PHONE_NUMBER;
}

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

// The way he would write it
// Take the right resourceId if application is in production
phoneNumber = headers.resourceId ? headers.resourceId : DEV_PHONE_NUMBER;

Trong cuốn sách tôi đã đọc ví dụ, các bình luận được coi là không viết được mã sạch vì chúng bị lỗi thời nếu bạn viết các hàm nhỏ và thường dẫn đến các bình luận không được cập nhật (bạn sửa đổi mã của mình chứ không phải bình luận). Tuy nhiên những gì tôi làm là xóa bình luận và viết một chức năng với tên của bình luận.

Vâng, tôi muốn một số lời khuyên, cách nào / thực hành tốt hơn để viết mã sạch?



4
phoneNumber = headers.resourceId ?: DEV_PHONE_NUMBER;
Joshua

10
Xác thực, rằng bạn muốn làm việc tại chỗ, nơi quản lý nói với bạn CÁCH thực hiện công việc của bạn, thay vì những gì cần phải giải quyết.
Konstantin Petrukhnov

8
@rjmunro Trừ khi bạn thực sự thích công việc của mình, hãy nhớ rằng có ít nhà phát triển hơn công việc. Vì vậy, để trích dẫn Martin Fowler: "Nếu bạn không thể thay đổi tổ chức của mình, hãy thay đổi tổ chức của bạn!" và các ông chủ cho tôi biết cách viết mã là điều tôi khuyên bạn nên thay đổi.
Niels van Reijmersdal

10
ĐỪNG BAO GIỜ có một isApplicationInProduction()chức năng! Bạn phải có các bài kiểm tra và các bài kiểm tra là vô ích nếu mã của bạn hoạt động bất cứ điều gì khác với khi nó được sản xuất. Nó giống như cố ý có mã chưa được kiểm tra / chưa được phát hiện trong sản xuất: nó không có ý nghĩa.
Ronan Paixão

Câu trả lời:


215

Lấy ví dụ mã đầu tiên. Bạn ủng hộ:

if (isApplicationInProduction(headers)) {
  phoneNumber = headers.resourceId;
} else {
  phoneNumber = DEV_PHONE_NUMBER;
}

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

Và ông chủ của bạn sẽ viết nó như sau:

// Take the right resourceId if application is in production
phoneNumber = headers.resourceId ? headers.resourceId : DEV_PHONE_NUMBER;

Theo quan điểm của tôi, cả hai đều có vấn đề. Khi tôi đọc mã của bạn, suy nghĩ ngay lập tức của tôi là "bạn có thể thay thế nó ifbằng một biểu thức tạm thời". Sau đó, tôi đọc mã của sếp và nghĩ "tại sao anh ta lại thay thế chức năng của bạn bằng một bình luận?".

Tôi muốn đề xuất mã tối ưu nằm giữa hai:

phoneNumber = isApplicationInProduction(headers) ? headers.resourceId : DEV_PHONE_NUMBER;

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

Điều đó mang lại cho bạn điều tốt nhất của cả hai thế giới: một biểu thức kiểm tra đơn giản hóa và nhận xét được thay thế bằng mã kiểm tra.

Về quan điểm của sếp về thiết kế mã mặc dù:

Viết các hàm nhỏ là một nỗi đau vì nó buộc bạn phải di chuyển vào từng hàm nhỏ để xem mã đang làm gì.

Nếu chức năng được đặt tên tốt, đây không phải là trường hợp. isApplicationInProductionlà hiển nhiên và không cần thiết phải kiểm tra mã để xem nó làm gì. Trong thực tế thì điều ngược lại là đúng: kiểm tra mã tiết lộ ít về ý định hơn tên hàm thực hiện (đó là lý do tại sao sếp của bạn phải dùng đến các bình luận).

Đặt mọi thứ trong một vòng lặp lớn chính ngay cả khi vòng lặp chính dài hơn 300 dòng, đọc nhanh hơn

Có thể nhanh hơn để quét qua, nhưng để thực sự "đọc" mã, bạn cần có khả năng thực thi nó một cách hiệu quả trong đầu. Điều đó thật dễ dàng với các hàm nhỏ và thực sự rất khó với các phương thức dài 100 dòng.

Chỉ viết các hàm nhỏ nếu bạn phải sao chép mã

Tôi không đồng ý. Như ví dụ mã của bạn cho thấy, các hàm nhỏ, được đặt tên tốt sẽ cải thiện khả năng đọc mã và nên được sử dụng bất cứ khi nào, ví dụ: bạn không quan tâm đến "cách", chỉ "cái gì" của một chức năng.

Đừng viết một hàm với tên của bình luận, hãy đặt dòng mã phức tạp của bạn (3-4 dòng) với một nhận xét ở trên. Như thế này bạn có thể sửa đổi mã lỗi trực tiếp

Tôi thực sự không thể hiểu lý do đằng sau điều này, cho rằng nó thực sự nghiêm trọng. Đó là thứ mà tôi mong đợi sẽ được viết bằng cách nhại lại bởi tài khoản twitter của Expert Expert . Nhận xét có một lỗ hổng cơ bản: chúng không được biên dịch / giải thích và do đó không thể được kiểm tra đơn vị. Mã được sửa đổi và bình luận bị bỏ lại một mình và cuối cùng bạn không biết cái nào đúng.

Viết mã tự viết tài liệu là khó, và các tài liệu bổ sung (thậm chí ở dạng bình luận) đôi khi cần thiết. Nhưng quan điểm của "Chú Bob" rằng các bình luận là một lỗi mã hóa luôn luôn đúng.

Yêu cầu sếp của bạn đọc cuốn sách Clean Code và cố gắng chống lại việc làm cho mã của bạn ít đọc hơn chỉ để thỏa mãn anh ta. Cuối cùng, nếu bạn không thể thuyết phục anh ấy thay đổi, bạn phải xếp hàng hoặc tìm một ông chủ mới có thể viết mã tốt hơn.



13
Quoth @ ExpertBeginner1 : Tôi cảm thấy mệt mỏi khi thấy hàng tấn phương thức nhỏ ở khắp nơi trong mã của chúng tôi, vì vậy từ đây trở đi, có tối thiểu 15 LỘC trên tất cả các phương thức.
Nghiêm

34
"Nhận xét có một lỗ hổng cơ bản: chúng không được biên dịch / giải thích và do đó không thể được kiểm tra đơn vị" Chơi người ủng hộ của quỷ ở đây, điều này cũng đúng nếu bạn thay thế "bình luận" bằng "tên hàm".
mattecapu

11
@mattecapu, tôi sẽ ủng hộ bạn và nhân đôi nó ngay cho bạn. Bất kỳ nhà phát triển rác cũ nào cũng có thể vặn vẹo trong một bình luận cố gắng mô tả những gì một đoạn mã làm. Mô tả ngắn gọn đoạn mã đó với một tên hàm tốt cần một người giao tiếp có kỹ năng. Các nhà phát triển tốt nhất là những người giao tiếp có kỹ năng vì viết mã chủ yếu liên quan đến việc giao tiếp với các nhà phát triển khác và với trình biên dịch là mối quan tâm thứ yếu. Ergo, một nhà phát triển tốt sẽ sử dụng các chức năng được đặt tên tốt và không có ý kiến; các nhà phát triển kém che giấu các kỹ năng kém của họ đằng sau các lý do để sử dụng các bình luận.
David Arno

4
@DavidArno Tất cả các chức năng đều có trước và sau điều kiện, câu hỏi là liệu bạn có tài liệu cho chúng hay không. Nếu chức năng của tôi có một tham số, đó là khoảng cách tính theo feet, bạn phải cung cấp nó theo feet, không phải km. Đây là một điều kiện tiên quyết.
Jørgen Fogh

223

Có những vấn đề khác

Cả hai mã đều không tốt, vì về cơ bản cả hai đều làm mờ mã với trường hợp kiểm tra gỡ lỗi . Điều gì nếu bạn muốn kiểm tra nhiều thứ hơn vì lý do gì?

phoneNumber = DEV_PHONE_NUMBER_WHICH_CAUSED_PROBLEMS_FOR_CUSTOMERS;

hoặc là

phoneNumber = DEV_PHONE_NUMBER_FROM_OTHER_COUNTRY;

Bạn có muốn thêm nhiều chi nhánh hơn không?

Vấn đề quan trọng là về cơ bản bạn sao chép một phần mã của mình và do đó bạn không thực sự kiểm tra mã thực. Bạn viết mã gỡ lỗi để kiểm tra mã gỡ lỗi, nhưng không phải mã sản xuất. Nó giống như một phần tạo ra một cơ sở mã song song.

Bạn đang tranh cãi với sếp về cách viết mã xấu một cách khéo léo hơn. Thay vào đó, bạn nên khắc phục vấn đề cố hữu của chính mã.

Phụ thuộc tiêm

Đây là cách mã của bạn sẽ trông như thế nào:

phoneNumber = headers.resourceId;

Không có phân nhánh ở đây, vì logic ở đây không có phân nhánh. Chương trình sẽ kéo số điện thoại từ tiêu đề. Giai đoạn = Stage.

Nếu bạn muốn có DEV_PHONE_NUMBER_FROM_OTHER_COUNTRYkết quả, bạn nên đặt nó vào headers.resourceId. Một cách để làm điều đó là chỉ cần tiêm một headersđối tượng khác cho các trường hợp thử nghiệm (xin lỗi nếu đây không phải là mã phù hợp, các kỹ năng JavaScript của tôi hơi thô lỗ):

function foo(headers){
    phoneNumber = headers.resourceId;
}

// Creating the test case
foo({resourceId: DEV_PHONE_NUMBER_FROM_OTHER_COUNTRY});

Giả sử đó headerslà một phần của phản hồi bạn nhận được từ máy chủ: Lý tưởng nhất là bạn có toàn bộ máy chủ thử nghiệm cung cấp headerscác loại khác nhau cho mục đích thử nghiệm. Bằng cách này, bạn kiểm tra mã sản xuất thực tế và không phải là một nửa mã trùng lặp có thể có hoặc không hoạt động như mã sản xuất.


11
Tôi đã xem xét giải quyết chính chủ đề này trong câu trả lời của riêng tôi, nhưng cảm thấy nó đã đủ dài. Vì vậy, +1 cho bạn để làm như vậy :)
David Arno

5
@DavidArno Tôi định thêm nó vào như một bình luận cho câu trả lời của bạn, bởi vì câu hỏi vẫn bị khóa khi tôi đọc nó lần đầu tiên, tôi ngạc nhiên rằng nó đã được mở lại và vì vậy đã thêm nó như một câu trả lời. Có lẽ nên nói thêm rằng có hàng tá khung / công cụ để thực hiện kiểm tra tự động. Đặc biệt là trong JS dường như có một cái mới xuất hiện mỗi ngày. Có thể khó bán nó cho ông chủ mặc dù.
null

56
@DavidArno Có lẽ bạn nên chia nhỏ câu trả lời của mình thành những câu trả lời nhỏ hơn. ;)
krillgar

2
@ user949300 Sử dụng một Bitwise OR sẽ không khôn ngoan;)
curiousdannii

1
@cquildannii Vâng, nhận thấy rằng quá muộn để chỉnh sửa ...
user949300

59

Không có câu trả lời "đúng" hay "sai" cho vấn đề này. Tuy nhiên, tôi sẽ đưa ra ý kiến ​​của mình dựa trên 36 năm kinh nghiệm chuyên môn thiết kế và phát triển hệ thống phần mềm ...

  1. Không có thứ gọi là "mã tự ghi." Tại sao? Vì yêu sách đó hoàn toàn chủ quan.
  2. Bình luận không bao giờ là thất bại. Có gì một thất bại là mã mà không thể hiểu được tại tất cả mà không ý kiến.
  3. 300 dòng mã không bị gián đoạn trong một khối mã là một cơn ác mộng bảo trì và rất dễ bị lỗi. Một khối như vậy là dấu hiệu mạnh mẽ của thiết kế và kế hoạch xấu.

Nói trực tiếp với ví dụ bạn đã cung cấp ... Đặt isApplicationInProduction()vào thói quen của riêng mình là điều thông minh (er) cần làm. Ngày nay, bài kiểm tra đó chỉ đơn giản là kiểm tra "tiêu đề" và có thể được xử lý trong toán tử ternary ( ?:). Ngày mai, bài kiểm tra có thể phức tạp hơn nhiều. Ngoài ra, "headers.resourceId" không có mối quan hệ rõ ràng với "trong trạng thái sản xuất của ứng dụng;" Tôi sẽ lập luận rằng một bài kiểm tra cho tình trạng như vậy cần phải được tách rời khỏi dữ liệu cơ bản; một chương trình con sẽ làm điều này và một ternary sẽ không. Ngoài ra, một nhận xét hữu ích sẽ giải thích tại sao resourceId là một thử nghiệm cho "trong sản xuất".

Hãy cẩn thận đừng quá nhiệt tình với "các chức năng nhỏ được đặt tên rõ ràng." Một thói quen nên gói gọn một ý tưởng nhiều hơn là "chỉ mã". Tôi ủng hộ đề xuất của amon phoneNumber = getPhoneNumber(headers)và thêm rằng getPhoneNumber()nên thực hiện bài kiểm tra "tình trạng sản xuất" vớiisApplicationInProduction()


25
Có một điều như những bình luận tốt mà không phải là một thất bại. Tuy nhiên, các bình luận gần như nguyên văn mã mà họ cho là giải thích hoặc chỉ là các khối bình luận trống trước một phương thức / lớp / v.v. chắc chắn là một thất bại.
jpmc26

3
Có thể có mã nhỏ hơn và dễ đọc hơn bất kỳ mô tả bằng tiếng Anh nào về những gì nó làm và các trường hợp góc mà nó làm và không xử lý. Hơn nữa, nếu một hàm được kéo ra theo phương thức riêng của nó, một người nào đó đọc hàm sẽ không biết các trường hợp góc là gì hoặc không được xử lý bởi người gọi của nó và trừ khi tên của hàm rất dài, ai đó kiểm tra người gọi có thể không biết góc nào trường hợp được xử lý bởi các chức năng.
supercat

7
Nhận xét không bao giờ là thất bại về bản chất . Nhận xét có thể là thất bại, và là như vậy khi chúng không chính xác. Mã sai có thể được phát hiện ở nhiều cấp độ, bao gồm cả hành vi sai trong chế độ hộp đen. Nhận xét sai chỉ có thể được phát hiện bằng cách hiểu con người ở chế độ hộp trắng, thông qua nhận biết rằng hai mô hình được mô tả và một trong số đó là không chính xác.
Timbo

7
@Timbo Ý bạn là, "... ít nhất một trong số đó là không chính xác." ;)
jpmc26

5
@immibis Nếu bạn không thể hiểu được những gì mã lệnh thực hiện mà không cần ý kiến, sau đó mã có lẽ là không đủ rõ ràng. Mục đích chính cho các bình luận là làm rõ lý do tại sao mã đang làm những gì nó đang làm. Đó là lập trình viên giải thích thiết kế của mình cho các nhà bảo trì trong tương lai. Mã không bao giờ có thể cung cấp loại giải thích đó, vì vậy các bình luận điền vào những khoảng trống đó trong sự hiểu biết.
Graham

47

Các thực thể không được nhân rộng quá mức cần thiết.

- Dao cạo của Occam

Mã phải đơn giản nhất có thể. Lỗi thích ẩn nấp giữa sự phức tạp, bởi vì chúng rất khó phát hiện ở đó. Vậy điều gì làm cho mã đơn giản?

Các đơn vị nhỏ (tệp, chức năng, lớp) là một ý tưởng tốt . Các đơn vị nhỏ rất dễ hiểu vì có ít thứ bạn phải hiểu cùng một lúc. Con người bình thường chỉ có thể tung hứng ~ 7 khái niệm cùng một lúc. Nhưng kích thước không chỉ được đo bằng các dòng mã . Tôi có thể viết càng ít mã càng tốt bằng cách đánh gôn mã số (chọn tên biến ngắn, sử dụng các phím tắt thông minh, sử dụng nhiều mã nhất có thể trên một dòng), nhưng kết quả cuối cùng không đơn giản. Cố gắng hiểu mã như vậy giống như kỹ thuật đảo ngược hơn là đọc.

Một cách để rút ngắn chức năng là trích xuất các hàm trợ giúp khác nhau. Đó có thể là một ý tưởng tốt khi nó trích xuất một phần phức tạp khép kín . Trong sự cô lập, phần phức tạp đó đơn giản hơn nhiều để quản lý (và kiểm tra!) So với khi được nhúng vào một vấn đề không liên quan.

Nhưng mọi lệnh gọi hàm đều có chi phí nhận thức : Tôi không cần phải hiểu mã trong đoạn mã hiện tại của mình, tôi cũng phải hiểu cách nó tương tác với mã ở bên ngoài . Tôi nghĩ thật công bằng khi nói rằng chức năng bạn trích xuất giới thiệu sự phức tạp vào chức năng hơn là chức năng trích xuất . Đó là những gì ông chủ của bạn có nghĩa là bởi các chức năng nhỏ của [một] là một nỗi đau bởi vì nó buộc bạn phải di chuyển vào từng chức năng nhỏ để xem mã đang làm gì. Giáo dục

Đôi khi, các hàm nhàm chán dài có thể cực kỳ dễ hiểu, ngay cả khi chúng dài hàng trăm dòng. Điều này có xu hướng xảy ra trong mã khởi tạo và mã cấu hình, ví dụ: khi tạo GUI bằng tay mà không cần trình chỉnh sửa kéo và thả. Không có phần phức tạp khép kín mà bạn có thể trích xuất một cách hợp lý. Nhưng nếu định dạng có thể đọc được và có một số bình luận, thực sự không khó để theo dõi những gì đang xảy ra.

Có nhiều số liệu phức tạp khác: Số lượng biến trong một phạm vi nên càng nhỏ càng tốt. Điều đó không có nghĩa là chúng ta nên tránh các biến. Điều đó có nghĩa là chúng ta nên hạn chế từng biến trong phạm vi nhỏ nhất có thể khi cần. Các biến cũng trở nên đơn giản hơn nếu chúng ta không bao giờ thay đổi giá trị mà chúng chứa.

Một số liệu rất quan trọng là độ phức tạp chu kỳ ( độ phức tạp McCabe). Nó đo số lượng đường dẫn độc lập thông qua một đoạn mã. Con số này tăng theo cấp số nhân với từng điều kiện. Mỗi điều kiện hoặc vòng lặp nhân đôi số lượng đường dẫn. Có bằng chứng cho thấy điểm hơn 10 điểm là quá phức tạp. Điều này có nghĩa là một hàm rất dài có thể có điểm 5 có lẽ tốt hơn hàm rất ngắn và đậm đặc với điểm 25. Chúng ta có thể giảm độ phức tạp bằng cách trích luồng điều khiển thành các hàm riêng biệt.

Điều kiện của bạn là một ví dụ về một phần phức tạp có thể được trích xuất hoàn toàn:

function bigFatFunction(...) {
  ...
  phoneNumber = getPhoneNumber(headers);
  ...
}

...

function getPhoneNumber(headers) {
  return headers.resourceId ? headers.resourceId : DEV_PHONE_NUMBER;
}

Điều này vẫn còn rất hữu ích. Tôi không chắc liệu điều đó có làm giảm đáng kể sự phức tạp hay không bởi vì điều kiện này không phải là rất có điều kiện . Trong sản xuất, nó sẽ luôn đi theo cùng một con đường.


Sự phức tạp không bao giờ có thể biến mất. Nó chỉ có thể được xáo trộn xung quanh. Có nhiều điều nhỏ đơn giản hơn vài điều lớn? Điều đó phụ thuộc rất nhiều vào hoàn cảnh. Thông thường, có một số kết hợp cảm thấy vừa phải. Tìm kiếm sự thỏa hiệp giữa các yếu tố phức tạp khác nhau cần có trực giác và kinh nghiệm, và một chút may mắn.

Biết cách viết các hàm rất nhỏ và các hàm rất đơn giản là một kỹ năng hữu ích, bởi vì bạn không thể đưa ra lựa chọn mà không biết các phương án. Mù quáng tuân theo các quy tắc hoặc thực tiễn tốt nhất mà không nghĩ về cách chúng áp dụng vào tình huống hiện tại dẫn đến kết quả trung bình ở mức tốt nhất, lập trình sùng bái hàng hóa ở mức tồi tệ nhất .

Đó là nơi tôi không đồng ý với sếp của bạn. Lập luận của ông không phải là không hợp lệ, nhưng cuốn sách Clean Code cũng không sai. Có thể tốt hơn để làm theo hướng dẫn của sếp, nhưng thực tế là bạn đang nghĩ về những vấn đề này, cố gắng tìm một cách tốt hơn, rất hứa hẹn. Khi bạn có được kinh nghiệm, bạn sẽ dễ dàng tìm thấy một bao thanh toán tốt cho mã của mình.

(Lưu ý: câu trả lời này có trụ sở tại bộ phận trên những suy nghĩ từ Mã lý bài đăng blog trên bảng trắng bởi Jimmy Hoffa , cung cấp một cái nhìn cấp cao về những gì làm cho mã đơn giản.)


Tôi là tướng Tôi thích phản hồi của bạn. Tôi làm, tuy nhiên có vấn đề với các biện pháp phức tạp chu kỳ mcabes. Từ những gì tôi đã thấy về nó, nó không thể hiện một thước đo thực sự của sự phức tạp.
Robert Baron

27

Phong cách lập trình của Robert Martin là phân cực. Bạn sẽ tìm thấy nhiều lập trình viên, thậm chí là những người có kinh nghiệm, những người tìm thấy rất nhiều lý do tại sao chia tách "số tiền đó" quá nhiều và tại sao việc giữ các chức năng lớn hơn một chút là "cách tốt hơn". Tuy nhiên, hầu hết các "lý lẽ" này thường là biểu hiện của việc không muốn thay đổi thói quen cũ và học một cái gì đó mới.

Đừng nghe họ nói!

Bất cứ khi nào bạn có thể lưu một nhận xét bằng cách cấu trúc lại một đoạn mã thành một hàm riêng biệt với một tên biểu cảm, hãy thực hiện nó - rất có thể nó sẽ cải thiện mã của bạn. Bạn đã không đi quá xa khi Bob Martin thực hiện nó trong cuốn sách mã sạch của mình, nhưng phần lớn mã tôi đã thấy trong quá khứ gây ra sự cố bảo trì chứa các hàm quá lớn, không quá nhỏ. Vì vậy, cố gắng viết các hàm nhỏ hơn với tên tự mô tả là những gì bạn nên thử.

Các công cụ tái cấu trúc tự động giúp dễ dàng, đơn giản và an toàn để trích xuất các phương thức. Và xin vui lòng, đừng coi những người nghiêm túc khuyên bạn nên viết hàm với> 300 dòng - những người như vậy chắc chắn không đủ điều kiện để cho bạn biết bạn nên viết mã như thế nào.


53
"Đừng nghe họ!" : với thực tế là OP được ông chủ của mình yêu cầu ngừng chia mã, OP có lẽ nên tránh lời khuyên của bạn. Ngay cả khi ông chủ không sẵn lòng thay đổi thói quen cũ. Cũng lưu ý rằng như được đánh dấu bằng các câu trả lời trước đó, cả mã của OP và mã của ông chủ đều được viết xấu và bạn (cố ý hay không) không đề cập đến điều đó trong câu trả lời của bạn.
Arseni Mourzenko

10
@ArseniMourzenko: không phải ai trong chúng ta cũng phải khóa trước ông chủ của mình. Tôi hy vọng OP đủ tuổi để biết khi nào anh ta phải làm điều đúng đắn, hoặc khi nào anh ta phải làm những gì ông chủ của anh ta nói. Và vâng, tôi đã không đi sâu vào chi tiết của ví dụ này, có đủ câu trả lời khác đã thảo luận về những chi tiết đó.
Doc Brown

8
@DocBrown Đồng ý. 300 dòng là nghi vấn cho cả lớp. Hàm 300 dòng là tục tĩu.
JimmyJames

30
Tôi đã thấy nhiều lớp dài hơn 300 dòng là những lớp hoàn toàn tốt. Java dài dòng đến mức bạn gần như không thể làm bất cứ điều gì có ý nghĩa trong một lớp mà không có nhiều mã. Vì vậy, "số dòng mã trong một lớp", bản thân nó không phải là một số liệu có ý nghĩa, hơn nữa chúng ta sẽ coi SLOC là một số liệu có ý nghĩa cho năng suất của lập trình viên.
Robert Harvey

9
Ngoài ra, tôi đã thấy lời khuyên hiền triết của chú Bob bị hiểu sai và lạm dụng đến mức tôi nghi ngờ rằng nó hữu ích cho bất cứ ai trừ những lập trình viên có kinh nghiệm .
Robert Harvey

23

Trong trường hợp của bạn: Bạn muốn một số điện thoại. Rõ ràng là bạn sẽ nhận được một số điện thoại như thế nào, sau đó bạn viết mã rõ ràng. Hoặc không rõ ràng làm thế nào bạn có được một số điện thoại, sau đó bạn viết một phương pháp cho nó.

Trong trường hợp của bạn, không rõ ràng làm thế nào để có được số điện thoại, vì vậy bạn viết một phương pháp cho nó. Việc triển khai không rõ ràng, nhưng đó là lý do tại sao bạn đưa nó vào một phương thức riêng biệt để bạn chỉ phải xử lý một lần. Một nhận xét sẽ hữu ích vì việc thực hiện không rõ ràng.

Phương thức "isApplicationIn Producttion" khá vô nghĩa. Gọi nó từ phương thức getPhonenumber của bạn sẽ không làm cho việc triển khai trở nên rõ ràng hơn và chỉ làm cho việc tìm hiểu những gì đang diễn ra trở nên khó khăn hơn.

Đừng viết các hàm nhỏ. Viết các hàm có mục đích được xác định rõ và đáp ứng mục đích được xác định rõ đó.

Tái bút Tôi không thích việc thực hiện ở tất cả. Nó giả định rằng sự vắng mặt của số điện thoại có nghĩa là nó là một phiên bản dev. Vì vậy, nếu số điện thoại vắng mặt trong sản xuất, bạn không chỉ không xử lý mà còn thay thế một số điện thoại ngẫu nhiên. Hãy tưởng tượng bạn có 10.000 khách hàng và 17 người không có số điện thoại và bạn đang gặp rắc rối trong quá trình sản xuất. Cho dù bạn đang trong quá trình sản xuất hay phát triển nên được kiểm tra trực tiếp, không bắt nguồn từ thứ khác.


1
"Đừng viết các hàm nhỏ. Viết các hàm có mục đích được xác định rõ và đáp ứng mục đích được xác định rõ đó." đó là tiêu chí chính xác để tách mã. nếu một hàm thực hiện quá nhiều (như nhiều hơn một) các hàm khác nhau , thì hãy tách nó ra. Nguyên tắc trách nhiệm duy nhất là nguyên tắc hướng dẫn.
robert bristow-johnson

16

Ngay cả khi bỏ qua thực tế là không thực hiện là tốt như vậy, tôi sẽ lưu ý rằng đây thực chất là một câu hỏi về hương vị ít nhất là ở mức độ trừu tượng hóa các chức năng tầm thường sử dụng một lần.

Số lượng dòng không phải là một số liệu hữu ích trong hầu hết các trường hợp.

300 (hoặc thậm chí 3000) dòng mã tuần tự hoàn toàn tầm thường (Thiết lập, hoặc một cái gì đó tương tự) hiếm khi là một vấn đề (Nhưng có thể được tạo tự động tốt hơn hoặc dưới dạng bảng dữ liệu hoặc một cái gì đó), 100 dòng vòng lặp lồng nhau với rất nhiều phức tạp điều kiện thoát và toán học như bạn có thể tìm thấy trong Loại bỏ Gaussian hoặc đảo ngược ma trận hoặc như vậy có thể là quá nhiều để làm theo một cách dễ dàng.

Đối với tôi, tôi sẽ không viết một hàm sử dụng duy nhất trừ khi số lượng mã cần thiết để khai báo điều đó nhỏ hơn nhiều so với số lượng mã hình thành nên việc thực hiện (Trừ khi tôi có lý do như muốn nói có thể dễ dàng thực hiện việc tiêm lỗi). Một điều kiện hiếm khi phù hợp với dự luật này.

Bây giờ tôi đến từ một thế giới nhúng lõi nhỏ, nơi chúng tôi cũng phải xem xét những thứ như độ sâu ngăn xếp và tổng phí gọi lại (một lần nữa lập luận chống lại các loại chức năng nhỏ dường như được ủng hộ ở đây), và điều này có thể sai lệch thiết kế của tôi quyết định, nhưng nếu tôi thấy chức năng ban đầu đó trong đánh giá mã, nó sẽ nhận được một ngọn lửa usenet kiểu cũ để đáp lại.

Hương vị là thiết kế rất khó dạy và chỉ thực sự có kinh nghiệm, tôi không chắc nó có thể được giảm xuống theo quy tắc về độ dài chức năng và thậm chí độ phức tạp theo chu kỳ cũng có giới hạn của nó như một thước đo (Đôi khi mọi thứ chỉ phức tạp khi bạn xử lý chúng).
Điều này không có nghĩa là mã sạch sẽ không thảo luận về một số nội dung tốt, và những điều này nên được suy nghĩ nhưng tùy chỉnh cục bộ và cơ sở mã hiện tại cũng nên được cân nhắc.

Ví dụ cụ thể này dường như tôi đang chọn chi tiết tầm thường, tôi sẽ quan tâm nhiều hơn bởi những thứ cấp cao hơn nhiều vì nó quan trọng hơn nhiều đến khả năng hiểu và gỡ lỗi hệ thống một cách dễ dàng.


1
Tôi hoàn toàn đồng ý - tôi sẽ mất một lớp lót rất phức tạp để xem xét việc bọc nó trong một hàm ... Tôi chắc chắn sẽ không bao bọc một dòng giá trị mặc định / mặc định. Tôi đã bọc một lớp lót, nhưng thường thì đó là các kịch bản shell trong đó có mười ống để phân tích thứ gì đó và mã không thể hiểu được nếu không chạy nó.
TemporalWolf

15

Đừng đặt mọi thứ vào một vòng lặp lớn, nhưng cũng đừng làm điều này quá thường xuyên:

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

Vấn đề với vòng lặp lớn là rất khó để thấy cấu trúc tổng thể của nó khi nó trải dài trên nhiều màn hình. Vì vậy, hãy cố gắng đưa ra những khối lớn, khối lý tưởng có một trách nhiệm duy nhất và có thể sử dụng lại.

Vấn đề với chức năng nhỏ bé ở trên, là trong khi tính nguyên tử và mô đun nói chung là tốt, có thể được đưa đi quá xa. Nếu bạn không sử dụng lại chức năng trên, nó sẽ làm mất khả năng đọc và bảo trì mã. Để đi sâu vào chi tiết, bạn phải chuyển đến hàm thay vì có thể đọc chi tiết nội tuyến và lệnh gọi hàm chiếm hầu như không ít không gian hơn so với chi tiết.

Rõ ràng có một sự cân bằng được tìm thấy giữa các phương pháp làm quá nhiều và phương pháp làm quá ít . Tôi sẽ không bao giờ thoát ra một chức năng nhỏ bé như trên trừ khi nó sẽ được gọi từ nhiều nơi, và thậm chí sau đó tôi sẽ nghĩ hai lần về nó, bởi vì chức năng này không đáng kể về mặt giới thiệu logic mới và như hầu như không đảm bảo có sự tồn tại của chính nó.


2
Tôi hiểu rằng một boolean một liner rất dễ đọc nhưng một mình nó thực sự chỉ giải thích "Cái gì" đang xảy ra. Tôi vẫn viết các hàm bao gồm các biểu thức ternary đơn giản vì tên của hàm giúp giải thích lý do "Tại sao" tôi đang thực hiện kiểm tra điều kiện này. Điều này đặc biệt hữu ích khi ai đó mới (hoặc chính bạn trong 6 tháng) cần hiểu logic kinh doanh.
AJ X.

14

Có vẻ như những gì bạn thực sự muốn là thế này:

phoneNumber = headers.resourceId || DEV_PHONE_NUMBER

Điều này nên được tự giải thích cho bất cứ ai đọc nó: set phoneNumberđến resourceIdnếu nó có sẵn, hoặc đặt mặc định DEV_PHONE_NUMBERnếu nó không.

Nếu bạn thực sự muốn chỉ đặt biến đó trong sản xuất, bạn nên có một số phương thức tiện ích toàn ứng dụng khác, chuẩn hơn (không yêu cầu tham số) để xác định nơi bạn đang chạy. Đọc các tiêu đề cho thông tin đó không có ý nghĩa.


Nó tự giải thích những gì nó làm (với một chút đoán ngôn ngữ bạn đang sử dụng), nhưng không rõ ràng những gì đang xảy ra. Rõ ràng nhà phát triển giả định rằng phoneNumber được lưu trữ dưới "resourceId" trong phiên bản sản xuất và resourceId không có trong phiên bản phát triển và anh ta muốn sử dụng DEV_PHONE_NUMBER trong phiên bản phát triển. tiêu đề và điều đó có nghĩa là mọi thứ sẽ trở nên tồi tệ nếu thiếu số điện thoại trong phiên bản sản xuất.
gnasher729

14

Hãy để tôi nói thẳng: dường như với tôi rằng môi trường của bạn (ngôn ngữ / khung / thiết kế lớp, v.v.) không thực sự phù hợp với mã "sạch". Bạn đang trộn lẫn tất cả các loại điều có thể lên trong một vài dòng mã không thực sự gần nhau. Một chức năng duy nhất có chức năng kinh doanh gì khi biết điều đó resourceId==undefcó nghĩa là bạn không sản xuất, rằng bạn đang sử dụng số điện thoại mặc định trong các hệ thống không sản xuất, rằng resourceId được lưu trong một số "tiêu đề", v.v. Tôi giả sử headerslà các tiêu đề HTTP, vì vậy bạn thậm chí còn để lại quyết định về môi trường mà bạn đang ở cho người dùng cuối?

Bao gồm các phần đơn lẻ trong các chức năng sẽ không giúp bạn nhiều với vấn đề tiềm ẩn đó.

Một số từ khóa để tìm kiếm:

  • tách rời
  • sự gắn kết
  • tiêm phụ thuộc

Bạn có thể đạt được những gì bạn muốn (trong các bối cảnh khác) với các dòng mã bằng 0, bằng cách thay đổi trách nhiệm của mã xung quanh và sử dụng các khung hiện đại (có thể tồn tại hoặc không tồn tại cho ngôn ngữ lập trình / môi trường của bạn).

Từ mô tả của bạn ("300 dòng mã trong hàm 'chính'), ngay cả từ" hàm "(thay vì phương thức) khiến tôi cho rằng không có điểm nào trong những gì bạn đang cố gắng đạt được. Trong môi trường lập trình trường học cũ đó (tức là lập trình mệnh lệnh cơ bản với ít cấu trúc, chắc chắn không có lớp có ý nghĩa, không có mẫu khung lớp như MVC hay somesuch), thực sự không có nhiều điểm để làm bất cứ điều gì . Bạn sẽ không bao giờ thoát ra khỏi bể chứa mà không có những thay đổi cơ bản. Ít nhất ông chủ của bạn dường như cho phép bạn tạo các chức năng để tránh sao chép mã, đó là bước đầu tiên tốt!

Tôi biết cả loại mã cũng như loại lập trình viên mà bạn đang mô tả khá rõ. Thành thật mà nói, nếu đó là một đồng nghiệp, lời khuyên của tôi sẽ khác. Nhưng vì nó là ông chủ của bạn, việc bạn chiến đấu về việc này là vô ích. Không chỉ là sếp của bạn có thể ghi đè bạn, mà việc bổ sung mã của bạn thực sự sẽ dẫn đến mã tồi tệ hơn nếu chỉ bạn làm "việc của bạn" một phần, và sếp của bạn (và có thể là người khác) tiếp tục như trước. Nó có thể tốt hơn cho kết quả cuối cùng nếu bạn thích nghi với phong cách lập trình của họ (tất nhiên chỉ khi làm việc với cơ sở mã đặc biệt này), và cố gắng, trong bối cảnh này, để tận dụng tốt nhất.


1
Tôi đồng ý 100% rằng có các thành phần ngầm ở đây cần được tách riêng, nhưng không biết thêm về ngôn ngữ / khung, thật khó để biết liệu cách tiếp cận OO có hợp lý hay không. Phân tách và Nguyên tắc Trách nhiệm duy nhất rất quan trọng trong bất kỳ ngôn ngữ nào, từ chức năng thuần túy (ví dụ Haskell) đến mệnh lệnh thuần túy (ví dụ C.) Bước đầu tiên của tôi nếu ông chủ cho phép nó sẽ chuyển đổi chức năng chính thành chức năng điều phối ( như một phác thảo hoặc Mục lục) sẽ đọc theo kiểu khai báo (mô tả chính sách, không phải thuật toán) và đưa công việc sang các chức năng khác.
David Leppik

JavaScript là nguyên mẫu, với các hàm hạng nhất. Nó vốn dĩ là OO, nhưng không phải theo nghĩa cổ điển, vì vậy các giả định của bạn có thể không đúng. Cue giờ xem các video Crockford trên YouTube ...
Kevin_Kinsey

13

"Sạch" là một mục tiêu trong việc viết mã. Đó không phải là mục tiêu duy nhất. Một mục tiêu xứng đáng là colocality . Nói một cách không chính thức, tính phổ biến có nghĩa là mọi người đang cố gắng hiểu mã của bạn không cần phải đi khắp nơi để xem bạn đang làm gì. Sử dụng một chức năng được đặt tên tốt thay vì biểu thức ternary có vẻ như là một điều tốt, nhưng tùy thuộc vào số lượng chức năng như vậy bạn có và vị trí của chúng, thực tế này có thể gây phiền toái. Tôi không thể nói cho bạn biết bạn đã vượt qua ranh giới đó hay chưa, ngoại trừ việc nói rằng nếu mọi người phàn nàn, bạn nên lắng nghe, đặc biệt nếu những người đó có tiếng nói về tình trạng việc làm của bạn.


2
"... Ngoại trừ việc nói rằng nếu mọi người phàn nàn, bạn nên lắng nghe, đặc biệt nếu những người đó có tiếng nói về tình trạng việc làm của bạn". IMO đây là lời khuyên thực sự tồi tệ. Trừ khi bạn là một nhà phát triển kém nghiêm túc, cần đánh giá cao bất kỳ công việc nào bạn có thể nhận được, thì hãy luôn áp dụng nguyên tắc "nếu bạn không thể thay đổi công việc, thay đổi công việc". Không bao giờ cảm thấy được một công ty; họ cần bạn nhiều hơn bạn cần họ, vì vậy hãy đi bộ đến một nơi tốt hơn nếu họ không cung cấp những gì bạn muốn.
David Arno

4
Tôi đã di chuyển một chút trong sự nghiệp của tôi. Tôi không nghĩ rằng tôi đã từng có một công việc mà tôi đã tận mắt nhìn thấy sếp 100% về cách viết mã. Chúng ta là những con người có nền tảng và triết lý riêng. Vì vậy, cá nhân tôi sẽ không rời bỏ công việc chỉ vì có một vài tiêu chuẩn mã hóa mà tôi không thích. (Các nhà quản lý quy ước đặt tên uốn cong bằng ngón tay dường như đặc biệt trái ngược với cách tôi viết mã nếu để lại các thiết bị của riêng tôi.) .
1172763

6

Sử dụng các chức năng nhỏ nói chung là một thực hành tốt. Nhưng lý tưởng là tôi tin rằng việc giới thiệu một hàm nên tách rời các khối logic lớn hoặc giảm kích thước tổng thể của mã bằng cách DRYing nó ra. Ví dụ bạn đưa ra làm cho mã dài hơn và cần nhiều thời gian hơn để nhà phát triển đọc, trong khi phương án ngắn không giải thích rằng "resourceId"giá trị chỉ có trong sản xuất. Một cái gì đó đơn giản như thế vừa dễ quên vừa dễ hiểu khi cố gắng làm việc với nó, đặc biệt nếu bạn vẫn chưa quen với codebase.

Tôi sẽ không nói rằng bạn hoàn toàn nên sử dụng một chú chim nhạn, một số người tôi từng làm việc thích lâu hơn một chút if () {...} else {...}, đó chủ yếu là một lựa chọn cá nhân. Tôi có xu hướng thích "một dòng thực hiện một cách tiếp cận", nhưng về cơ bản tôi vẫn tuân theo bất cứ điều gì mà cơ sở mã hóa thường sử dụng.

Khi sử dụng ternary nếu kiểm tra logic làm cho dòng quá dài hoặc phức tạp thì hãy xem xét việc tạo một biến / s có tên tốt để giữ giá trị.

// NOTE "resourceId" not present in dev build, use test data
let isProduction = 'resourceId' in headers;
let phoneNumber = isProduction ? headers.resourceId : DEV_PHONE_NUMBER;

Tôi cũng muốn nói rằng nếu codebase trải dài tới 300 hàm dòng, thì nó cần một số phân ngành. Nhưng tôi khuyên bạn nên sử dụng các nét rộng hơn một chút.


5

Ví dụ mã bạn đã đưa ra, ông chủ của bạn LÀ ĐÚNG. Một dòng rõ ràng là tốt hơn trong trường hợp đó.

Nói chung, việc phá vỡ logic phức tạp thành các phần nhỏ hơn sẽ tốt hơn cho mức độ dễ đọc, bảo trì mã và khả năng các lớp con sẽ có hành vi khác nhau (ngay cả khi chỉ một chút).

Đừng bỏ qua các nhược điểm: phí chức năng, che khuất (chức năng không thực hiện ý nghĩa và tên hàm), logic spaghetti phức tạp, tiềm năng cho các chức năng chết (tại một thời điểm được tạo ra cho mục đích không còn được gọi nữa).


1
"Hàm trên cao": tùy thuộc vào trình biên dịch. "che khuất": OP đã không cho biết đó là cách duy nhất hay tốt nhất để kiểm tra tài sản đó; bạn cũng không thể biết chắc chắn. "Logic spaghetti phức tạp": ở đâu? "Tiềm năng cho các chức năng chết": loại phân tích mã chết đó là trái cây treo thấp và các công cụ phát triển thiếu nó là chưa trưởng thành.
Rhymoid

Các câu trả lời tập trung hơn vào các ưu điểm, tôi chỉ muốn chỉ ra nhược điểm. Gọi một hàm như sum (a, b) sẽ luôn đắt hơn "a + b" (trừ khi hàm được trình biên dịch nội tuyến). Phần còn lại của những bất lợi chứng minh rằng sự phức tạp quá mức có thể dẫn đến các vấn đề riêng của nó. Mã xấu là mã xấu và chỉ vì mã được chia thành các byte nhỏ hơn (hoặc được giữ trong một vòng lặp 300 dòng) không có nghĩa là nó dễ nuốt hơn.
Phil M

2

Tôi có thể nghĩ về ít nhất hai đối số có lợi cho các hàm dài:

  • Nó có nghĩa là bạn có rất nhiều bối cảnh xung quanh mỗi dòng. Một cách để chính thức hóa điều này: vẽ biểu đồ luồng điều khiển của mã của bạn. Tại một đỉnh (~ = line) giữa chức năng nhập và thoát chức năng, bạn biết tất cả các cạnh đến. Hàm càng dài thì càng có nhiều đỉnh như vậy.

  • Nhiều chức năng nhỏ có nghĩa là có một biểu đồ cuộc gọi lớn hơn và phức tạp hơn. Chọn một dòng ngẫu nhiên trong một hàm ngẫu nhiên và trả lời câu hỏi "dòng này được thực thi trong bối cảnh nào?" Điều này trở nên khó hơn khi biểu đồ cuộc gọi càng lớn và phức tạp hơn, bởi vì bạn phải nhìn vào nhiều đỉnh hơn trong biểu đồ đó.

Ngoài ra còn có các đối số chống lại các chức năng dài Các lò xo có thể kiểm tra đơn vị. Sử dụng th̶e̶ f̶o̶r̶c̶e̶ kinh nghiệm của bạn khi lựa chọn giữa cái này và cái khác.

Lưu ý: Tôi không nói rằng sếp của bạn đúng, chỉ có điều quan điểm của anh ta có thể không hoàn toàn không có giá trị.


Tôi nghĩ rằng quan điểm của tôi là tham số tối ưu hóa tốt không phải là chiều dài chức năng. Tôi nghĩ rằng một desiderata hữu ích hơn để nghĩ theo nghĩa như sau: tất cả những thứ khác đều bằng nhau, tốt hơn là có thể đọc ra mã mô tả cấp cao về cả logic nghiệp vụ và việc triển khai. (Chi tiết triển khai cấp thấp luôn có thể được đọc nếu bạn có thể tìm thấy đoạn mã có liên quan.)


Nhận xét về câu trả lời của David Arno :

Viết các hàm nhỏ là một nỗi đau vì nó buộc bạn phải di chuyển vào từng hàm nhỏ để xem mã đang làm gì.

Nếu chức năng được đặt tên tốt, đây không phải là trường hợp. isApplicationIn Producttion là hiển nhiên và không cần thiết phải kiểm tra mã để xem nó làm gì. Trong thực tế thì điều ngược lại là đúng: kiểm tra mã tiết lộ ít về ý định hơn tên hàm thực hiện (đó là lý do tại sao sếp của bạn phải dùng đến các bình luận).

Tên này cho thấy rõ giá trị trả về nghĩa là gì , nhưng nó không nói gì về tác động của việc thực thi mã (= những gì mã làm ). Tên (chỉ) truyền đạt thông tin về ý định , mã truyền tải thông tin về hành vi (từ đó các phần của ý định đôi khi có thể được suy ra).

Đôi khi bạn muốn cái này, đôi khi cái kia, vì vậy quan sát này không tạo ra quy tắc quyết định hợp lệ một chiều.

Đặt mọi thứ trong một vòng lặp lớn chính ngay cả khi vòng lặp chính dài hơn 300 dòng, đọc nhanh hơn

Có thể nhanh hơn để quét qua, nhưng để thực sự "đọc" mã, bạn cần có khả năng thực thi nó một cách hiệu quả trong đầu. Điều đó thật dễ dàng với các hàm nhỏ và thực sự rất khó với các phương thức dài 100 dòng.

Tôi đồng ý rằng bạn phải thực hiện nó trong đầu của bạn. Nếu bạn có 500 dòng chức năng trong một chức năng lớn so với nhiều chức năng nhỏ, tôi không rõ tại sao việc này trở nên dễ dàng hơn.

Giả sử trường hợp cực đoan của 500 dòng mã hiệu ứng phụ theo đường thẳng và bạn muốn biết hiệu ứng A xảy ra trước hay sau hiệu ứng B. Trong trường hợp chức năng lớn, hãy sử dụng Trang Lên / Xuống để xác định hai dòng rồi so sánh số dòng. Trong trường hợp nhiều hàm nhỏ, bạn phải nhớ các hiệu ứng xảy ra ở đâu trong cây cuộc gọi và nếu bạn quên bạn phải dành một lượng thời gian không đáng kể để khám phá lại cấu trúc của cây này.

Khi đi qua cây cuộc gọi của các chức năng hỗ trợ, bạn cũng phải đối mặt với thách thức xác định khi nào bạn đi từ logic kinh doanh đến các chi tiết triển khai. Tôi khẳng định không có bằng chứng * rằng biểu đồ cuộc gọi càng đơn giản thì càng dễ tạo ra sự khác biệt này.

(*) Ít nhất tôi thành thật về điều đó ;-)

Một lần nữa, tôi nghĩ cả hai cách tiếp cận đều có điểm mạnh và điểm yếu.

Chỉ viết các hàm nhỏ nếu bạn phải sao chép mã

Tôi không đồng ý. Như ví dụ mã của bạn cho thấy, các hàm nhỏ, được đặt tên tốt sẽ cải thiện khả năng đọc mã và nên được sử dụng bất cứ khi nào [ví dụ] bạn không quan tâm đến "làm thế nào", chỉ "cái gì" của một chức năng.

Cho dù bạn quan tâm đến "làm thế nào" hay "cái gì" là một chức năng của mục đích mà bạn đang đọc mã (ví dụ: lấy ý tưởng chung so với theo dõi lỗi). Mục đích mà bạn đang đọc mã không có sẵn trong khi viết chương trình, và rất có thể bạn sẽ đọc mã cho các mục đích khác nhau; quyết định khác nhau sẽ tối ưu hóa cho các mục đích khác nhau.

Điều đó nói rằng, đây là một phần trong quan điểm của ông chủ mà tôi có thể không đồng ý nhất.

Đừng viết một hàm với tên của bình luận, hãy đặt dòng mã phức tạp của bạn (3-4 dòng) với một nhận xét ở trên. Như thế này bạn có thể sửa đổi mã lỗi trực tiếp

Tôi thực sự không thể hiểu lý do đằng sau điều này, cho rằng nó thực sự nghiêm trọng. [...] Nhận xét có một lỗ hổng cơ bản: chúng không được biên dịch / giải thích và do đó không thể được kiểm tra đơn vị. Mã được sửa đổi và bình luận bị bỏ lại một mình và cuối cùng bạn không biết cái nào đúng.

Trình biên dịch chỉ so sánh tên cho sự bình đẳng, chúng không bao giờ cung cấp cho bạn một MisleadNameError. Ngoài ra, vì một số trang web cuộc gọi có thể gọi một chức năng nhất định theo tên, đôi khi việc thay đổi tên trở nên khó khăn và dễ bị lỗi hơn. Bình luận không có vấn đề này. Tuy nhiên, điều này có phần suy đoán; để thực sự giải quyết điều này, có lẽ người ta sẽ cần dữ liệu về việc các lập trình viên có thể cập nhật các bình luận sai lệch so với các tên gây hiểu lầm hay không và tôi không có điều đó.


-1

Theo tôi, mã chính xác cho chức năng bạn yêu cầu là:

phoneNumber = headers.resourceId || DEV_PHONE_NUMBER;

Hoặc nếu bạn muốn tách nó thành một hàm, có thể là một cái gì đó như:

phoneNumber = getPhoneNumber(headers);

function getPhoneNumber(headers) {
  return headers.resourceId || DEV_PHONE_NUMBER
}

Nhưng tôi nghĩ bạn có một vấn đề cơ bản hơn với khái niệm "trong sản xuất". Vấn đề với chức năng của bạn isApplicationInProductionlà có vẻ kỳ lạ vì đây là nơi duy nhất trong hệ thống có vấn đề về "sản xuất" và bạn luôn có thể dựa vào sự hiện diện hay vắng mặt của tiêu đề resourceId để nói với bạn. Cần có một isApplicationInProductionphương pháp chung hoặc getEnvironmentphương pháp kiểm tra môi trường trực tiếp. Mã sẽ giống như:

function isApplicationInProduction() {
  process.env.NODE_ENV === 'production';
}

Sau đó, bạn có thể nhận được số điện thoại với:

phoneNumber = isApplicationInProduction() ? headers.resourceId : DEV_PHONE_NUMBER;

-2

Chỉ cần một nhận xét về hai trong số các gạch đầu dòng

  • Viết các hàm nhỏ là một nỗi đau vì nó buộc bạn phải di chuyển vào từng hàm nhỏ để xem mã đang làm gì.
  • Đặt mọi thứ trong một vòng lặp lớn chính ngay cả khi vòng lặp chính dài hơn 300 dòng, nó sẽ nhanh hơn để đọc.

Nhiều trình soạn thảo (ví dụ IntelliJ) sẽ cho phép bạn chuyển đến một chức năng / lớp chỉ bằng cách Ctrl-Nhấp vào cách sử dụng. Ngoài ra, bạn thường không cần biết chi tiết triển khai của hàm để đọc mã, do đó làm cho việc đọc mã nhanh hơn.

Tôi khuyên bạn nên nói với sếp của bạn; anh ấy sẽ thích sự ủng hộ của bạn và xem đó là sự lãnh đạo. Chỉ cần lịch sự.

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.