Một sự bảo vệ cho nồi hơi?


14

Đối với tôi, mã soạn sẵn rõ ràng là xấu. Tuy nhiên, tôi đã gặp một nhà phát triển hiển thị mức kháng cự trong mọi nỗ lực để giảm nồi hơi. Tôi nhận ra rằng tôi đã không có một cuộc tranh luận dễ dàng hình thành, nghĩ ra quá khứ về sự ghê tởm mà tôi đã phát triển cho nó theo thời gian.

Để tôi có thể hình thành một lập luận thuyết phục cho việc ủng hộ ít nồi hơi hơn, một số phản biện là gì? Nói cách khác, các đối số (nếu có) có lợi cho nồi hơi là gì?

(Ý tôi là những gì tôi nghĩ thường có nghĩa là bằng nồi hơi, nhưng một ví dụ điển hình là getters và setters trong Java.)


7
Đối số chống lại mã trùng lặp (giả sử nồi hơi được sao chép / dán): stackoverflow.com/a/2490897/1583
Oded

1
@Oded: Đúng vậy. Nhưng bạn đã đọc sai câu hỏi. :) Anh ta đang cố gắng xem xét nếu có bất cứ điều gì để nói về mã soạn sẵn. Tôi đoán là anh ấy được thông báo rất tốt về những bất lợi.
Steven Jeuris

3
@StevenJeuris - Tôi đọc câu hỏi một cách hoàn hảo. Đó là lý do tại sao tôi không đăng câu trả lời. Tôi chỉ thêm vào phía bên kia của tranh luận. Chỉ để OP có "một cuộc tranh luận dễ hình thành, đã được cân nhắc kỹ lưỡng về sự ghê tởm mà tôi đã phát triển theo thời gian" cho lần tới;)
Oded

2
Nồi hơi có thể làm hài lòng về mặt thẩm mỹ: en.wikipedia.org/wiki/ This_Is_the_House_That_Jack_Built
SK-logic

Một số câu trả lời tốt và ý kiến ​​bổ sung cho nhau ... khó chọn câu nào để chấp nhận.
tóm tắt

Câu trả lời:


15

Một điều quan trọng cần nhớ là mã thường được làm nhỏ hơn bằng cách loại bỏ bối cảnh không cần thiết. Nếu trình biên dịch có thể tìm ra một cái gì đó, đối số sẽ đi, không cần phải viết nó ra một cách rõ ràng.

Và điều đó sẽ thật tuyệt nếu chỉ có trình biên dịch đã từng có ý định đọc nó. Nhưng hãy nhớ rằng "các chương trình nên được viết cho mọi người đọc, và chỉ tình cờ cho các máy thực thi." (Trớ trêu thay, trích dẫn này xuất phát từ một cuốn sách giáo khoa dành riêng cho một trong những ngôn ngữ khó đọc nhất đối với con người bình thường, do phần lớn là do sự căng thẳng quá mức của nó.)

Những gì có vẻ như nhàm chán, nồi hơi lặp đi lặp lại với bạn khi bạn viết nó có thể là bối cảnh có giá trị với người khác đến sau một năm (hoặc năm) sau đó và phải duy trì mã của bạn.

WRT ví dụ cụ thể về Java, tôi đồng ý rằng đó là một ví dụ tốt về nồi hơi xấu, vì nó có thể được thay thế bằng thứ gì đó vừa ngắn vừa dễ đọc hơn, vừa linh hoạt hơn: Thuộc tính. Nhưng điều đó không có nghĩa là tất cả các yếu tố cú pháp soạn sẵn từ tất cả các ngôn ngữ đều lãng phí như các getters và setters từ Java và C ++.


7
Tất nhiên, lập luận này hoạt động cả hai cách. Một số lượng đáng kể mã soạn sẵn chỉ để xoa dịu trình biên dịch và không giúp con người hiểu được - để ở lại với getters / setters, hàng chục dòng đó phải được đọc hoàn toàn để chắc chắn "đó chỉ là những getters và setters không làm gì cả" , thay vì đọc một dòng ngắn trên mỗi thuộc tính, đơn giản chỉ ra rằng đó là một thuộc tính và loại đó có.

6
Tôi nghĩ cái nồi hơi cũng có hại cho người đọc. Bằng cách bị buộc viết văn bản lặp đi lặp lại, vô nghĩa, chúng tôi đang che khuất các phần có liên quan của mã từ người khác. Nếu một cái gì đó hữu ích, thì theo định nghĩa, nó không phải là nồi hơi.
Andres F.

1
@Giorgio: Ngược lại, đó không chỉ là ý kiến ​​của tôi; đó là ý kiến ​​của đại đa số những người đã từng cố gắng nghiên cứu nó. Và khi "khó đọc" vốn dĩ là vấn đề quan điểm ngay từ đầu, thực tế là ý kiến ​​đó được chia sẻ rộng rãi khá nhiều khiến nó trở thành sự thật.
Mason Wheeler

1
@Mason Wheeler: Cách mọi người nhận thức ngôn ngữ lập trình thường bị ảnh hưởng bởi trải nghiệm trong quá khứ của họ. Những người đã học lập trình trong Scheme thấy C hoặc Pascal vụng về và khó đọc. Mặt khác, đại đa số mọi người đã học lập trình bằng ngôn ngữ chính thống.
Giorgio

2
Tôi cho rằng khi có nhiều bối cảnh bị ẩn khỏi lập trình viên bằng cách loại bỏ bản tóm tắt, điều đó chỉ có nghĩa là Con người phải giữ một bản đồ tinh thần lớn hơn về tất cả những thứ xảy ra đằng sau hậu trườngđó là một bất lợi lớn hơn khi nói đến gỡ lỗi hơn là tiết kiệm một ít không gian trực quan khi tác giả.
Patrick Hughes

7

Một đối số có lợi cho mã soạn sẵn là nếu bạn thay đổi nó ở một nơi, nó chỉ ảnh hưởng đến một luồng mã. Điều này phải được cân bằng với thực tế là thường xuyên hơn không, bạn thực sự muốn một thay đổi ảnh hưởng đến mọi đoạn mã sử dụng nó. Nhưng tôi đã thấy những ví dụ hiếm hoi ủng hộ lập luận.

Giả sử bạn có một đoạn mã nói

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

Điều này được sử dụng ở khoảng 2 nơi trong mã của bạn.

Một ngày nọ có người đi cùng và nói "ok, chỉ trong con đường này, chúng tôi muốn bạn đến quán bar trước khi Fooing nó."

Và bạn nghĩ rằng "điều này thật đơn giản."

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

Sau đó, người dùng của bạn thêm một số chức năng mới và bạn cho rằng nó phù hợp với FooTheBar. Và bạn mạnh dạn hỏi họ xem bạn có nên Grommit thanh đó trước khi bạn Foo không và họ nói "không, không phải lúc này".

Vì vậy, bạn chỉ cần gọi phương pháp trên.

Nhưng sau đó, người dùng của bạn nói "ok, đợi đã, trong trường hợp thứ ba, chúng tôi muốn bạn Doodle Doodle Bar trước khi gọi BeFooed."

Không có vấn đề, bạn nghĩ rằng, tôi có thể làm điều đó.

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

Đột nhiên mã của bạn đang trở nên ít sôi hơn. Có lẽ bạn nên chấp nhận hai dòng mã lặp đi lặp lại. Bây giờ bạn sẽ có ba đoạn mã, mỗi dòng dài 2-3 dòng và trông không lặp lại nữa.

Tất cả điều này đã nói, tôi sẽ phản bác lại rằng "đây không phải là trường hợp phổ biến và khi nó xảy ra, bạn có thể tái cấu trúc".

Một lập luận khác mà tôi đã nghe gần đây là mã soạn sẵn đôi khi có thể giúp bạn điều hướng mã. Ví dụ chúng tôi đã thảo luận là nơi chúng tôi đã loại bỏ hàng tấn mã ánh xạ soạn sẵn và thay thế nó bằng AutoMapper. Bây giờ, nó đã được lập luận, bởi vì mọi thứ đều dựa trên quy ước, bạn không thể nói "Tài sản này được đặt ở đâu" với IDE và mong muốn nó biết.

Tôi đã thấy mọi người tranh luận những điều tương tự về container IoC.

Không nói rằng tôi đồng ý với họ, nhưng dù sao đó cũng là một cuộc tranh luận công bằng.


2
Tôi thích phần thứ hai của câu trả lời của bạn. ; p +1
Steven Jeuris

chỉ cần nhận ra ví dụ của tôi khá giống với bạn ... đoán ngay cả khi nó không phải là lẽ thường thì nó dường như xảy ra khá nhiều :)
kritzikratzi

6

Sự phát triển của hiệu quả

Bạn bắt đầu với điều này:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

sau đó bạn thoát khỏi tất cả cái nồi hơi phiền phức đó và đặt nó vào một chức năng:

  1. createFieldHtml( id, label )

    Điều này là tốt, tôi đang tiết kiệm cho mình rất nhiều dòng!

  2. createFieldHtml( id, label, defaultValue )

    vâng, tôi cũng cần một giá trị mặc định, thật dễ dàng để thêm.

  3. createFieldHtml( id, label, defaultValue, type )

    tuyệt, tôi cũng có thể sử dụng nó cho các hộp kiểm

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    Nhà thiết kế UX cho biết nhãn phải có sau hộp kiểm.

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

    bây giờ nó kết xuất một bộ chọn ngày khi cần thiết. Hừm .. params đang nhận được một chút trong tầm tay

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    có một trường hợp tôi cần thêm các lớp CSS

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

Để bảo vệ nồi hơi

Tôi có một thời gian khó khăn để nói điều này bởi vì nó thực sự là một cái gì đó tôi đã nhận thấy gần đây, vì vậy tôi sẽ lập một danh sách:

  1. Dường như với tôi rằng có một nỗi sợ hãi nhất định về việc có các dòng trùng lặp kéo dài ra một chút. Nếu chỉ là một vài dòng thì có thể không có vấn đề gì cả. một số thứ vốn đã "gần như lặp đi lặp lại" (như ví dụ trên). Tôi thấy ít cơ hội để tối ưu hóa ở đó trong thời gian dài.
  2. Mọi người thích đóng gói chức năng ở đâu đó; nếu bạn nhìn một cách khách quan và có vẻ như đó chỉ là "che giấu mớ hỗn độn" - hãy nghi ngờ! nó có thể là thời gian cho một số nồi hơi cũ tốt
  3. Khi bạn có một chức năng ngày càng trở nên mạnh mẽ hơn; có nhiều đường dẫn thực thi khác nhau tùy thuộc vào đầu vào và cuối cùng thực hiện rất ít - đó có thể là thời gian soạn sẵn!
  4. Khi bạn thêm một lớp trừu tượng lên trên một lớp trừu tượng khác, nhưng chỉ để làm cho mã của bạn ngắn hơn (lớp bên dưới không có nghĩa là phải thay đổi) - thời gian soạn sẵn!
  5. Khi bạn có một hàm có quá nhiều tham số mà bạn thực sự cần phải có các tham số được đặt tên - có thể đó là thời gian soạn sẵn.

Một điều gần đây tôi luôn tự hỏi mình là:
Tôi có thể sao chép và dán vào một dự án khác mà không thay đổi gì không? nếu có, bạn có thể đóng gói hoặc đưa vào thư viện, nếu không: đó là thời gian soạn thảo.

Điều này trái ngược hoàn toàn với nhận thức chung cho rằng soạn thảo là sao chép và dán mã. Đối với tôi, bản tóm tắt là về sao chép và dán, nhưng luôn phải chỉnh nó một chút.


Cập nhật : Tôi vừa bắt gặp một bài viết đưa ra ví dụ của tôi ở trên một tên thực tế: "quá DRY chống mẫu".

Hàm nhận được nhiều tham số hơn và có logic bên trong ngày càng phức tạp để kiểm soát hành vi của nó trong các trường hợp khác nhau. Chức năng quá DRY rất dễ phát hiện. Chúng có rất nhiều logic if-then phức tạp cố gắng giải quyết sự đa dạng trong sử dụng. [...] Ngoài ra, việc lặp lại mã không phải lúc nào cũng là điều tồi tệ nếu mã nhỏ và thực hiện chức năng riêng biệt.

Đây là một bài đọc ngắn và thú vị, bạn có thể tìm thấy bài viết ở đây: Too Dry Anti-Pattern


1
"Khi bạn thêm một lớp trừu tượng lên trên một lớp trừu tượng khác, nhưng chỉ để làm cho mã của bạn ngắn hơn" Đúng, bạn chỉ nên thêm các lớp trừu tượng khi có khả năng sử dụng lại.
Steven Jeuris

4
+1. Đừng lặp lại chính mình, nhưng đừng đi đến độ dài khó xử để tránh gần như lặp lại chính mình.
Julia Hayward

4

Tôi khinh thường mã soạn sẵn, nhưng có thể loại bỏ mã soạn sẵn không có nghĩa là đó là cách tốt nhất để đi.

Khung WPF có các thuộc tính phụ thuộc , bao gồm một số lượng mã soạn sẵn. Trong thời gian rảnh rỗi, tôi đã nghiên cứu một giải pháp giúp giảm đáng kể số lượng mã cần viết. Hơn một năm sau tôi vẫn đang cải thiện giải pháp này và vẫn cần mở rộng về chức năng của nó hoặc sửa lỗi.

Vấn đề là gì? Điều này thật tuyệt vời để tìm hiểu các công cụ mới và khám phá các giải pháp thay thế, nhưng có lẽ đó không phải là quyết định thương mại tốt nhất .

Khung WPF là tài liệu tốt. Nó đúng tài liệu làm thế nào để viết mã soạn sẵn của bạn. Cố gắng loại bỏ mã soạn sẵn này là một bài tập hay, và một điều chắc chắn đáng để khám phá, nhưng để đạt được mức độ "đánh bóng" như những gì mà ms cung cấp mất rất nhiều thời gian, điều mà chúng ta không phải lúc nào cũng có.


Tuy nhiên, tôi vẫn khá hài lòng với kết quả mà tôi có vào lúc này và sẵn sàng sử dụng nó trong các dự án thời gian rảnh rỗi của tôi. :)
Steven Jeuris

3
Mỗi lần tôi chạm vào WPF và các thuộc tính phụ thuộc đó, tôi luôn mong muốn C # có thứ gì đó đơn giản như macro của C ++. Chắc chắn các macro bị lạm dụng trong tay sai, nhưng chúng có thể loại bỏ rất nhiều sự lặp lại ở đây. Tôi sẽ phải xem qua khung AOP của bạn vào lần tới khi tôi bắt đầu muốn có các macro đó :)
DXM

@DXM Nếu bạn làm thế, và nó gặp sự cố một cách thảm hại, đừng quên đổ lỗi cho tôi và đăng các lỗi. ; p
Steven Jeuris

Đoạn mã làm việc cho tôi khá tốt cho các thuộc tính phụ thuộc.
Codism

@Codism: Chà, chúng một giải pháp, nhưng tôi cũng coi thường chúng . :)
Steven Jeuris

1

Vấn đề với nồi hơi là nó vi phạm DRY. Về bản chất, khi bạn viết bản soạn sẵn, bạn đang lặp lại cùng một mã (hoặc mã rất giống nhau) trên một số lớp. Khi mã đó cần được thay đổi, không có gì chắc chắn rằng nhà phát triển sẽ nhớ tất cả các địa điểm mà mã được lặp lại. Điều này dẫn đến các lỗi trong đó các API cũ hoặc các phương thức cũ được sử dụng.

Nếu bạn cấu trúc lại bản soạn sẵn thành một thư viện chung hoặc lớp cha, thì bạn chỉ cần thay đổi mã ở một nơi khi API của bạn thay đổi. Quan trọng hơn, khi những thay đổi bất ngờ xảy ra, mã bị vỡ ở một nơi và cho bạn biết chính xác những gì bạn phải sửa để mọi thứ hoạt động trở lại. Điều này tốt hơn nhiều so với một kịch bản trong đó một thay đổi gây ra thất bại trong hàng chục, hoặc thậm chí hàng trăm lớp.


2
Làm thế nào đây là một đối số có lợi cho nồi hơi ?
Chris Wesseling

0

Tôi sẽ thực hiện một chiến thuật khác. Tính nhất quán trong phát triển là một trong những tính năng quan trọng nhất của thiết kế phần mềm, nó là một công cụ quan trọng trong việc làm cho các ứng dụng có thể mở rộng và duy trì được nhưng có thể khó đạt được khi quản lý một nhóm trên nhiều trang web, ngôn ngữ và múi giờ.

Nếu đạt được, tính nhất quán làm cho mã dễ truy cập hơn "một khi bạn đã nhìn thấy một, bạn đã thấy tất cả", rẻ hơn nhiều để duy trì và tái cấu trúc, nhưng trên hết, dễ dàng mở rộng hơn nhiều. Khi bạn viết một thư viện yêu cầu một số mẫu soạn sẵn, cùng với sức mạnh của thư viện bạn cũng đã trao cho nhà phát triển:

  • Điểm bắt đầu hiểu phần mở đầu (bản tóm tắt) vào chức năng của bạn, hầu hết các lớp chính và điểm truy cập thường sẽ có tính năng như một phần của bản tóm tắt. Điều này cung cấp cho các nhà phát triển một điểm khởi đầu vào tài liệu
  • Kỳ vọng bạn đặt vào các nhà phát triển sẽ trở nên rõ ràng, ví dụ nếu bạn thiết lập một đối tượng theo dõi như một phần của phần mở đầu thì các nhà phát triển sẽ biết nơi để ghi lại các ngoại lệ và thông tin
  • Hiểu ngầm khi bạn buộc nhà phát triển phải trải qua quá trình khởi tạo các lớp của bạn, họ có thể suy ra các kỹ thuật họ sẽ cần để truy cập vào phần còn lại của thư viện của bạn và có cơ hội giới thiệu chúng với bất kỳ quy ước nào bạn đã sử dụng trong thư viện của mình
  • Xác thực dễ dàng khi cần mã nồi hơi của bạn, nó thường có thể dễ dàng xác thực chính nó với các ngoại lệ và các mệnh đề bảo vệ, ngăn người tiêu dùng không bị kẹt nhiều hơn nữa khi bạn đã cam kết với một quy trình bị lỗi
  • Cấu hình của một thư viện yêu cầu mã soạn sẵn rất dễ dàng vì đã có một điểm triển khai rõ ràng để tùy chỉnh chức năng cho một đường thực hiện duy nhất. Điều này đặc biệt hữu ích nếu mã soạn sẵn yêu cầu của bạn được tăng cường với mẫu Factory hoặc Command

Khi người tiêu dùng của thư viện của bạn nắm bắt được việc khởi tạo, họ có thể dễ dàng tạo các phương thức riêng tư / mở rộng, các lớp cha hoặc thậm chí các mẫu để triển khai mã soạn sẵn.


-3

Vấn đề thực sự duy nhất với mã soạn sẵn là khi bạn tìm thấy một lỗi trong đó, bạn phải sửa mọi nơi mà bạn đã sử dụng chứ không phải là nơi bạn sử dụng lại .

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.