Tại sao mọi người lại phản đối mạnh mẽ các thẻ #region trong các phương thức?


27

Tôi nghe nhiều về việc giữ các phương thức ngắn và tôi đã nghe nhiều lập trình viên nói rằng sử dụng thẻ #region trong một phương thức là một dấu hiệu chắc chắn rằng nó quá dài và nên được tái cấu trúc thành nhiều phương thức. Tuy nhiên, dường như có nhiều trường hợp trong đó tách mã bằng các thẻ #region trong một phương thức là giải pháp ưu việt để tái cấu trúc thành nhiều phương thức.

Giả sử chúng ta có một phương pháp mà tính toán có thể được tách thành ba giai đoạn khá khác biệt. Hơn nữa, mỗi giai đoạn này chỉ liên quan đến tính toán cho phương pháp này và do đó việc trích xuất chúng vào các phương thức mới giúp chúng tôi không sử dụng lại mã. Vậy thì, lợi ích của việc trích xuất từng giai đoạn thành phương pháp riêng của nó là gì? Theo như tôi có thể nói, tất cả những gì chúng ta đạt được là một số khả năng đọc và phạm vi biến riêng biệt cho từng giai đoạn (sẽ giúp ngăn sửa đổi một giai đoạn cụ thể khỏi vô tình phá vỡ một giai đoạn khác).

Tuy nhiên, cả hai điều này có thể đạt được mà không cần trích xuất từng pha thành phương pháp riêng. Thẻ vùng cho phép chúng tôi thu gọn mã thành một dạng có thể đọc được (với lợi ích bổ sung mà chúng tôi không còn phải rời khỏi vị trí của mình trong tệp này nếu chúng tôi quyết định mở rộng và kiểm tra mã), và chỉ cần bọc từng giai đoạn trong {}tạo phạm vi riêng để làm việc với.

Lợi ích của việc thực hiện theo cách này là chúng ta không làm ô nhiễm phạm vi cấp lớp với ba phương thức thực sự chỉ liên quan đến hoạt động bên trong của phương thức thứ tư. Ngay lập tức tái cấu trúc một phương thức dài thành một loạt các phương thức ngắn dường như là việc sử dụng lại mã tương đương với tối ưu hóa sớm; bạn đang giới thiệu thêm sự phức tạp để giải quyết một vấn đề mà trong nhiều trường hợp không bao giờ phát sinh. Bạn luôn có thể trích xuất một trong các giai đoạn thành phương thức riêng của mình sau này nếu có cơ hội tái sử dụng mã.

Suy nghĩ?


4
Tôi hiện đang làm việc với một lớp học khá lớn. Nó tuân theo Nguyên tắc Trách nhiệm duy nhất; tất cả mọi thứ trong lớp là chức năng cần thiết. Nó có rất nhiều phương thức riêng tư, chủ yếu là do tái cấu trúc. Tôi sử dụng #region để phân chia các phương thức này thành các danh mục chức năng, điều này đã giúp ích rất nhiều cho chúng tôi. Có nhiều lớp khác trong dự án này không yêu cầu điều trị như vậy. Công cụ phù hợp cho công việc phù hợp, tôi nói.
Robert Harvey

4
@RobertHarvey, sử dụng chúng trong một lớp khác với sử dụng chúng trong một phương thức.
CaffGeek

18
@Chad: Ah, không nhận thấy điều đó. Sử dụng chúng trong một phương pháp có vẻ hơi cực đoan. Nếu một phương thức quá dài mà nó yêu cầu #regions, tôi sẽ cấu trúc lại nó thành các phương thức riêng biệt.
Robert Harvey

8
Không thực sự là một câu trả lời, nhưng tôi không chỉ ghét tất cả #regioncác thẻ, tôi còn tắt hoàn toàn mã trong Visual Studio. Tôi không thích mã cố gắng giấu tôi.
Daniel Pryden

2
"Hơn nữa, mỗi giai đoạn này chỉ liên quan đến tính toán cho phương pháp này, và vì vậy việc trích xuất chúng vào các phương thức mới giúp chúng tôi không sử dụng lại mã". OTOH, tôi thấy rằng nếu tôi chia một hàm thành 3, tôi thường thấy sau đó các phần riêng lẻ <i> sẽ hữu ích sau này, vd. nếu một số dữ liệu đầu vào chỉ thay đổi một pha, bạn có thể kiểm tra cách ly đó, v.v.
Jack V.

Câu trả lời:


65

Tất cả những gì bạn nên quan tâm là mã của bạn có thể sử dụng được, không sử dụng lại được. Một con khỉ có thể chuyển đổi mã có thể sử dụng thành mã có thể sử dụng lại, nếu có bất kỳ biến đổi nào được thực hiện.

Đối số "Tôi chỉ cần điều này ở đây" là kém, để nói một cách lịch sự. Kỹ thuật mà bạn mô tả thường được gọi là kỹ thuật tiêu đề và thường được tán thành.

  1. Bạn không thể kiểm tra các vùng, nhưng bạn có thể kiểm tra các phương thức thực sự trong sự cô lập.
  2. Khu vực là ý kiến, không phải là yếu tố cú pháp. Trong trường hợp xấu nhất, việc lồng các vùng của bạn và các khối của bạn mâu thuẫn với nhau. Bạn nên luôn luôn cố gắng để đại diện cho ngữ nghĩa của cấu trúc của bạn với các yếu tố cú pháp của ngôn ngữ bạn đang sử dụng.
  3. Sau khi cấu trúc lại các phương thức, người ta không còn cần gấp để đọc văn bản. Người ta có thể đang xem mã nguồn trong bất kỳ công cụ nào không có khả năng gấp, như thiết bị đầu cuối, ứng dụng thư khách, chế độ xem web cho VCS của bạn hoặc trình xem khác.
  4. Sau khi cấu trúc lại các phương thức, phương thức kết quả ít nhất là tốt như với các vùng, cộng với việc di chuyển các phần riêng lẻ xung quanh sẽ đơn giản hơn.
  5. Nguyên tắc trách nhiệm duy nhất cho thấy rằng bất kỳ đơn vị nào cũng chỉ nên có một nhiệm vụ và một nhiệm vụ. Nhiệm vụ của phương thức "chính" là soạn các phương thức "người trợ giúp" để có được kết quả mong muốn. Các phương pháp "người trợ giúp" giải quyết một vấn đề đơn giản, rời rạc. Lớp chứa tất cả các phương thức này cũng chỉ nên thực hiện một nhiệm vụ và chỉ chứa các phương thức liên quan đến nhiệm vụ đó. Vì vậy, các phương thức của trình trợ giúp hoặc thuộc về phạm vi lớp hoặc mã không nên ở trong lớp ngay từ đầu, nhưng ít nhất là trong một số phương thức toàn cầu hoặc tốt hơn là nên được thêm vào .

Cũng liên quan: Suy nghĩ của Jeff Atwoods về việc gấp mã


9
1. Hầu hết các lập trình viên không kiểm tra tất cả các phương pháp riêng tư. 2. Một tên phương thức không thể truyền đạt mọi điều cần biết về phương thức đó; những ngoại lệ nào có thể được ném ra? Là một đầu vào hợp lệ? Đôi khi bạn có thể sử dụng các cấu trúc phi cú pháp để làm cho mã của bạn dễ hiểu hơn. Trong nhiều ngôn ngữ, các tệp là một ví dụ về một yếu tố phi cú pháp được chấp nhận khá rộng rãi như một phương tiện để tổ chức mã. 3. Đi sâu vào hoạt động bên trong của một phương pháp được cố gắng tốt nhất trong một IDE vì nhiều lý do; tình huống trong đó các khu vực có thể cắn bạn trong VCS hoặc ứng dụng thư khách của bạn là khá hiếm.
jjoelson

3
4. Nhưng bạn vừa xuất một số phức tạp nghiêm trọng vào phần còn lại của lớp. Có đáng không? Ngoài ra, các vùng có thể được di chuyển xung quanh dễ dàng như một cuộc gọi phương thức. 5. Bây giờ bạn nói về việc làm ô nhiễm không gian tên của bạn với nhiều lớp hơn sẽ chỉ được sử dụng ở một nơi duy nhất. Tại sao các lớp và phương thức là đơn vị đóng gói duy nhất mà bạn sẽ chấp nhận? Bạn luôn có thể tạo lớp mới đó sau này khi (hoặc nếu) nó trở nên cần thiết để có riêng biệt này.
jjoelson

7
@jjoelson: 1. Vậy thì sao? 2. Chính xác quan điểm của tôi: bạn có thể sử dụng các cấu trúc phi cú pháp nếu chỉ (và chỉ khi) cú pháp là không đủ. 3. "Hiếm?" - Tôi cho rằng bạn có số để thể hiện điều đó. Tôi có thể nói với bạn chắc chắn rằng công cụ diff (hoặc đổ lỗi hoặc bất cứ điều gì cho vấn đề đó) đi kèm với TortoiseSVN không bị gập lại. 4. Làm thế nào là liên quan đến điểm tôi đã thực hiện. 5. Đó là lý do tại sao hầu hết các ngôn ngữ hiện đại có không gian tên lồng nhau. Bạn đang dùng đến nghệ thuật ASCII thay vì sử dụng một bảng rộng các yếu tố ngôn ngữ có sẵn để cấu trúc mã của bạn.
back2dos

4
@jjoelson: 1. Đó là ý kiến ​​của bạn và nằm ngoài phạm vi của câu hỏi này. 2. Bằng cách mở rộng các hàm đối số của tôi, các hàm lồng nhau tốt hơn các vùng, vâng. 3. Bởi vì đôi khi tôi cần duyệt qua một số phiên bản để theo dõi một vấn đề. Dù bằng cách nào, mã nguồn được viết cho con người, không phải IDE. 4. Đối với một đối số không liên quan đến quan điểm của tôi, thứ hai, đó lại chỉ là ý kiến ​​của bạn, thứ ba là nó nằm ngoài phạm vi của câu hỏi này. 5. C # có các phương tiện cấu trúc mã khác ngoài chức năng lồng nhau. Bạn nên sử dụng chúng hoặc ngôn ngữ cho phép các hàm lồng nhau.
back2dos

13
Các bạn nên dùng nó để trò chuyện nếu bạn vẫn muốn tranh luận ... Tôi không còn gì đáng nói với OP, anh ấy là một nhà phát triển cơ sở có quan điểm điển hình đặt trong niềm tin của mình. Không có gì sẽ thay đổi suy nghĩ của anh ấy nhưng trải nghiệm IMO nhiều hơn.
maple_shaft

15

Không phải các khu vực trong các phương thức là vấn đề, mà là trường hợp khi có nhu cầu (hoặc thậm chí sử dụng) để đặt các khu vực trong các phương thức.

Phải gỡ lỗi rất nhiều phương pháp 200-300, tôi có thể nói với bạn rằng tôi sẽ không muốn điều đó với bất kỳ ai. Nếu bạn đang viết và chăm sóc mã của riêng mình thì tốt - hãy làm bất cứ điều gì bạn muốn. Nhưng một khi người khác nhìn vào nó, cần phải rõ ràng ngay lập tức một phương pháp đang làm gì.

"Đầu tiên, nó nhận được các thứ, và sau đó nó đưa chúng ra xung quanh, sau đó nếu chúng cần ù thì nó sẽ kiểm tra xem chúng có màu xanh không và đảo ngược giá trị Copernicus của chúng. Sau đó, nếu điều thứ hai lớn hơn điều thứ nhất, chúng ta cần lấy hộp nước trái cây và nhét nó vào ... "

Không, điều đó không đủ tốt. Chia nó thành các khu vực bạn muốn nhưng tôi vẫn lắc đầu chỉ nghĩ về nó.

Nếu bạn đột nhập vào các phương pháp bạn sẽ nhận được nhiều lợi ích:

  • Hiểu rõ hơn về những gì đang xảy ra ở đâu, ngay cả khi chỉ thông qua tên của phương thức. Và bạn là sai rằng một phương pháp không thể được ghi lại đầy đủ - thêm khối tài liệu (hit ///) và nhập mô tả, thông số, kiểu trả về, và cũng có thể exception, example, remarksnút đến từng chi tiết những kịch bản. Đó là nơi nó đi, đó là những gì nó dành cho!
  • Không có tác dụng phụ hoặc vấn đề phạm vi. Bạn có thể nói rằng bạn khai báo tất cả các biến trong phạm vi phụ {}, nhưng tôi có phải kiểm tra mọi phương thức để đảm bảo bạn không 'gian lận' không? Đây có phải là dodgyObjecttôi đang sử dụng ở đây chỉ vì được sử dụng trong khu vực này, hoặc nó đến từ một nơi khác? Nếu tôi ở trong phương pháp của riêng mình, tôi có thể dễ dàng xem liệu nó được truyền cho tôi hay tôi tự tạo ra nó (hay đúng hơn, cho dù bạn đã tạo ra nó).
  • Nhật ký sự kiện của tôi cho tôi biết phương pháp nào xảy ra ngoại lệ. Có, tôi có thể tìm thấy mã vi phạm với số dòng, nhưng biết tên phương thức (đặc biệt là nếu tôi đã đặt tên cho chúng đúng) cho tôi một dấu hiệu rất tốt về chuyện gì đã xảy ra và chuyện gì đã xảy ra "Ồ, TurnThingsUpsideDownphương pháp thất bại - có lẽ thất bại trong khi biến điều xấu" tốt hơn nhiều so với "Ồ, DoEverythingphương pháp thất bại - có thể là 50 điều khác nhau và tôi sẽ phải tìm kiếm trong một giờ để tìm ra nó" .

Đây là tất cả trước khi bất kỳ mối quan tâm tái sử dụng hoặc khả năng ứng biến. Các phương pháp được phân tách hợp lý rõ ràng tạo điều kiện thuận lợi cho việc tái sử dụng và cũng cho phép bạn dễ dàng thay thế một phương thức không thực hiện (quá chậm, quá lỗi, thay đổi phụ thuộc, v.v.). Bạn đã bao giờ thử tái cấu trúc bất kỳ phương pháp khổng lồ nào chưa? Không có cách nào để biết rằng những gì bạn đang thay đổi sẽ không ảnh hưởng gì khác.

Vui lòng đóng gói logic của bạn vào các phương thức có kích thước hợp lý. Tôi biết rằng họ dễ dàng thoát khỏi tầm tay và cho rằng việc thiết kế lại không đáng một lần vào thời điểm đó là một vấn đề khác. Nhưng bạn phải chấp nhận thực tế rằng không có hại và ít nhất là lợi ích tiềm năng trong việc có các phương pháp được đóng gói đúng cách, được viết sạch sẽ và được thiết kế đơn giản.


Phân tích nhận xét XML của Visual Studio, cùng với các thẻ #region, thuộc danh mục các tính năng của Visual Studio. Toàn bộ quan điểm của tôi là không sai khi dựa vào các tính năng này nếu mọi người trong dự án của bạn đang sử dụng Visual Studio. Đối với các vấn đề về tác dụng phụ và phạm vi, bạn vẫn có thể giải quyết mọi thứ với các lĩnh vực toàn cầu. Trong cả hai trường hợp, bạn phải dựa vào các lập trình viên không làm những điều ngớ ngẩn với tác dụng phụ.
jjoelson

5
@jjoelson Bạn vẫn có thể đọc các nhận xét XML mà không cần studio trực quan, nhưng các thẻ khu vực gần như hoàn toàn vô dụng bên ngoài VS. Phần mở rộng logic của đối số của bạn là một phương thức khổng lồ chạy toàn bộ ứng dụng của bạn là được, miễn là bạn tách nó thành các vùng!
Kirk Broadhurst

2
@jjoelson xin đừng bắt chúng tôi bắt đầu về các lĩnh vực toàn cầu tồi tệ như thế nào. Nói điều gì đó không hữu ích bởi vì bạn có một "cách giải quyết" để làm hỏng nó dù sao chỉ là ngớ ngẩn. Chỉ cần giữ cho bạn các phương thức ngắn và các biến trong phạm vi.
OliverS

@OliverS, Kirk là người đưa ra trạng thái chia sẻ như là một vấn đề với sơ đồ phương pháp theo vùng của tôi. Về cơ bản, tôi đã nói chính xác những gì bạn đang nói: việc một lập trình viên có thể lạm dụng trạng thái bằng cách chia sẻ quá nhiều biến giữa các vùng không phải là bản cáo trạng của toàn bộ lược đồ, giống như khả năng kết nối trạng thái được chia sẻ giữa các phương thức thông qua toàn cầu là không ' một bản cáo trạng của sơ đồ đa phương thức.
jjoelson

7

Nếu phương thức của bạn đủ phức tạp để có thể tách thành ba giai đoạn riêng biệt, thì không chỉ đó là ba phương thức riêng biệt ... mà trên thực tế phương thức của bạn phải là một lớp riêng biệt, dành riêng cho tính toán đó.

"Nhưng sau đó lớp tôi sẽ chỉ có một phương thức công khai!"

Bạn nói đúng, và không có gì sai với điều đó. Ý tưởng của nguyên tắc trách nhiệm duy nhất là lớp học của bạn làm một việc .

Lớp của bạn có thể gọi lần lượt ba phương thức và trả về kết quả. Một điều.

Như một phần thưởng, bây giờ phương pháp của bạn có thể kiểm tra được vì nó không còn là phương thức riêng tư nữa.

Nhưng đừng bận tâm một lớp; trong thực tế, bạn nên có bốn : Một cho mỗi phần trong phương thức của bạn, cộng với một phần lấy ba phần này làm phụ thuộc và gọi chúng theo thứ tự đúng, trả về kết quả.

Điều này làm cho các lớp học của bạn thậm chí còn dễ kiểm tra hơn . Nó cũng giúp bạn dễ dàng thay đổi một trong ba mảnh đó. Chỉ cần viết một lớp mới kế thừa từ lớp cũ và ghi đè hành vi đã thay đổi. Hoặc tạo một giao diện cho hành vi của ba phần của bạn; và sau đó để thay thế một lớp, chỉ cần viết một lớp mới thực hiện giao diện đó và thay thế nó cho lớp cũ trong cấu hình thùng chứa phụ thuộc của bạn.

Gì? Bạn không sử dụng tiêm phụ thuộc? Chà, có lẽ bạn chưa thấy cần, vì bạn không tuân theo nguyên tắc trách nhiệm duy nhất. Khi bạn bắt đầu, bạn sẽ thấy rằng cách dễ nhất để cung cấp cho mỗi lớp phụ thuộc của nó là sử dụng bộ chứa DI.

CHỈNH SỬA :

OK, hãy đặt sang một bên câu hỏi tái cấu trúc. Mục đích của #regionviệc ẩn mã , chủ yếu có nghĩa là mã không cần chỉnh sửa trong bất kỳ trường hợp thông thường nào. được tạo là ví dụ tốt nhất. Nó nên được ẩn trong các khu vực vì thông thường bạn không cần phải chỉnh sửa nó. Nếu bạn cần, thì hành động mở rộng một vùng sẽ cung cấp cho bạn một chút cảnh báo kiểu "Ở đây là rồng" để đảm bảo bạn biết bạn đang làm gì.

Vì vậy, tôi sẽ nói không#region nên được sử dụng ở giữa một phương thức. Nếu tôi mở một phương thức, tôi muốn xem mã. Việc sử dụng #region mang lại cho tôi một mức độ che giấu khác mà tôi không cần và điều đó trở thành một điều khó chịu: Tôi đã mở ra phương pháp ... và vẫn không thể thấy bất kỳ mã nào.

Nếu bạn lo lắng về việc mọi người nhìn thấy cấu trúc của phương thức (và bạn từ chối cấu trúc lại nó), thì hãy thêm các nhận xét biểu ngữ như thế này:

//
// ---------- COMPUTE SOMETHING OR OTHER ----------
//

Những thứ này sẽ giúp ai đó duyệt mã xem các phần riêng lẻ trong phương thức của bạn mà không phải đối phó với việc mở rộng và thu gọn #regioncác thẻ.


2
Tất cả điều này cho một phương pháp được gọi ở một nơi? Ngay cả hầu hết những người khó tính cũng không trừu tượng hóa một hàm bậc cao hơn cho đến khi họ đã xác định được ít nhất hai vị trí có thể sử dụng nó để dễ dàng xác định hàm hơn.
jjoelson

1
@jjoelson Thật khó để tạo một lớp mới? Nó là gì, một dòng, một nẹp mở và một nẹp đóng. Ồ, và bạn phải bấmctrl+n
Kirk Broadhurst

2
Không khó để tạo ra một lớp mới, nhưng có một số chi phí để thêm một lớp học. Đó là một lớp gián tiếp nữa khiến cho người bảo trì mã gặp khó khăn hơn trong việc tìm kiếm những gì cô ấy đang tìm kiếm. Nó không phải một thỏa thuận lớn, nhưng nó cũng không mua cho bạn bất cứ thứ gì trong trường hợp bit mã này khó có thể được gọi từ bất kỳ nơi nào khác. Và, như bạn đã đề cập, nó là khá dễ dàng để làm cho rằng lớp mới và đặt mã đó nếu nó quay ra bạn làm cần phải gọi chút mã này ở nhiều nơi.
jjoelson

2
@jjoelson, đây là một phản ứng khá phổ biến. Đó là của tôi, khi tôi mới biết về những thứ như SRP và DI, và đó là phản ứng của đồng nghiệp của tôi khi chúng tôi bắt đầu thoát ra khỏi sự phụ thuộc. Nếu bạn đang xem xét một trường hợp riêng lẻ , nó có vẻ không đáng. Lợi ích là trong tổng hợp. Khi bạn bắt đầu thực hiện SRP với tất cả các lớp của mình, bạn sẽ thấy việc thay đổi một đoạn mã của mình dễ dàng hơn nhiều mà không cần thay đổi gợn qua một nửa ứng dụng của bạn.
Kyralessa

@Kyralessa, đây là những phương pháp chỉ được sử dụng ở một nơi duy nhất. Thay đổi phương thức như vậy sẽ không gợn qua một nửa ứng dụng của bạn. Nếu mã đó được triển khai như một vùng trong phương thức sử dụng nó, thì bạn đã đóng gói hoàn hảo; chỉ có phương thức chứa là sử dụng mã và vì vậy bạn có thể tự do thay đổi tất cả những gì bạn muốn mà không phải lo lắng về tác dụng của nó ngoại trừ trong phương thức đó.
jjoelson

4

Tôi nghĩ rằng ví dụ bạn đưa ra trong tranh luận của bạn ít hơn về YAGNI (Bạn sẽ không cần nó) và nhiều hơn về cách viết mã chất lượng phù hợp có thể dễ dàng duy trì.

Trong các khóa học lập trình sớm nhất, chúng ta biết rằng nếu một phương thức dài 700 LỘC, thì nó có thể quá lớn và chắc chắn sẽ là một nỗi đau lớn để thử và gỡ lỗi.

Thứ hai, nếu tôi viết các phương thức A, B và C chỉ được sử dụng trong phương thức D, thì tôi có thể dễ dàng kiểm tra đơn vị AB và C độc lập hơn với D, cho phép kiểm tra đơn vị mạnh hơn trong cả 4 phương pháp.


Kiểm thử đơn vị chắc chắn là một điểm công bằng, nhưng tôi không chắc nó chứng minh sự ô nhiễm của phạm vi lớp trong mọi trường hợp. Thực tế mà nói, có ai thực sự đơn vị kiểm tra từng phương pháp riêng tư nhỏ mà họ viết không? Tôi muốn nói rằng mọi người có xu hướng đơn vị kiểm tra các phương thức riêng tư được sử dụng rất nhiều, nghĩa là, các phương thức riêng tư sẽ là ứng cử viên cho việc sử dụng lại mã bằng mọi cách.
jjoelson

@jjoelson Nếu phương thức này có logic có ý nghĩa và không bao bọc một số chức năng khác thì tôi luôn viết một bài kiểm tra đơn vị chống lại nó. Phương pháp kiểm thử đơn vị không liên quan gì đến việc sử dụng lại mã. Bạn nên đơn vị phương pháp kiểm tra để xác minh rằng đối với các đầu vào đã cho mà bạn nhận được đầu ra dự kiến ​​theo cách nhất quán và lặp lại. Nếu bạn nhận thấy rằng phạm vi lớp đang bị ô nhiễm khi bạn gọi nó, thì có lẽ lớp của bạn đang vi phạm Nguyên tắc Trách nhiệm duy nhất.
maple_shaft

2
Hầu hết các lập trình viên mà tôi đã gặp không đồng ý với ý tưởng thử nghiệm đơn vị mọi phương thức riêng tư. Nó chỉ không xứng đáng với thời gian cần thiết để thực hiện và duy trì các thử nghiệm trên tất cả các phương pháp riêng tư.
jjoelson

3

Giả sử chúng ta có một phương pháp mà tính toán có thể được tách thành ba giai đoạn khá khác biệt. Hơn nữa, mỗi giai đoạn này chỉ liên quan đến tính toán cho phương pháp này và do đó việc trích xuất chúng vào các phương thức mới giúp chúng tôi không sử dụng lại mã. Vậy thì, lợi ích của việc trích xuất từng giai đoạn thành phương pháp riêng của nó là gì? Theo như tôi có thể nói, tất cả những gì chúng ta đạt được là một số khả năng đọc và phạm vi biến riêng biệt cho từng giai đoạn (sẽ giúp ngăn sửa đổi một giai đoạn cụ thể khỏi vô tình phá vỡ một giai đoạn khác).

Đó là hai lợi ích. Nhưng điều quan trọng, với tôi dù sao, là gỡ lỗi . Nếu bạn phải theo dõi qua mã đó, việc đơn giản hơn là có thể Bước qua hai trong ba phần và chỉ theo dõi vào phần mà bạn quan tâm. Tái cấu trúc thành các phương thức nhỏ hơn cho phép điều này; thẻ khu vực không.


1
ctrl-f10- chạy đến con trỏ
Steven Jeuris

2

Quy tắc cá nhân của tôi là nếu một phương thức dài hơn một màn hình, giả sử 40 dòng thì quá dài. Nếu một lớp dài hơn 500 dòng, nó quá lớn. Đôi khi tôi phá vỡ các quy tắc này, đôi khi thậm chí bằng một bội số lớn, nhưng tôi thường hối hận trong năm.

Ngay cả một phương pháp dài từ 20 đến 30 dòng cũng hơi lâu trong hầu hết các trường hợp. Vì vậy, tôi sẽ nói rằng sử dụng các vùng trong một phương thức thường là một ý tưởng tồi, đơn giản là vì nó gần như không bao giờ có ý nghĩa để thu gọn một vùng từ 20 đến 30 dòng thành nhiều vùng phụ.

Phân tích các hàm dài theo định nghĩa này có ít nhất hai lợi ích:

  1. Bạn có thể đặt tên cho những chức năng phụ đó đang làm gì, điều này làm rõ suy nghĩ hiện tại của bạn và đơn giản hóa nhiệm vụ của những người bảo trì sau này.

  2. Phân tách thành các hàm nhỏ hơn buộc bạn chỉ truyền các tham số mà các hàm nhỏ hơn cần, do đó phạm vi của dữ liệu họ yêu cầu và sửa đổi là rất rõ ràng. Điều này giả định rằng bạn không truy cập và sửa đổi trạng thái đối tượng trong hàng trăm hàm lá khác nhau, điều mà tôi cũng sẽ không khuyến khích.

Theo kinh nghiệm của tôi, các quy tắc này tạo ra mã dễ viết hơn mà không mắc các lỗi phổ biến và có thể được hiểu và sửa đổi sau đó mà không phá vỡ các hành vi tinh vi. Sẽ không có vấn đề gì nếu người phải hiểu / sửa đổi mã là người khác hoặc chính tôi sau khi tôi đã ngủ và quên mọi thứ.

Vì vậy, tôi sẽ coi các khu vực trong các phương thức là "mùi mã" cho thấy các thực tiễn không bền vững đang được áp dụng. Như mọi khi, có thể có ngoại lệ, nhưng chúng xảy ra không thường xuyên đến mức chúng hầu như không đáng để thảo luận.


2

Ở đây chúng ta lại đi ... Có rất nhiều chủ đề khác ở đây về các lập trình viên đã kết thúc trong cùng một cuộc thảo luận.

Bạn chỉ ra một số đối số rất thú vị liên quan đến các chức năng ngắn. Nó không phải là một tuyên bố phổ biến, nhưng tôi với bạn về điều này . Sau khi thảo luận về nó lần trước, ấn tượng của tôi là cuộc thảo luận thường tập trung vào việc bạn chủ yếu tập trung vào đóng gói thích hợp hay đưa phát triển theo hướng kiểm tra đến mức tối đa. Đây là hai ứng cử viên chính trong những gì dường như sắp xảy ra một cuộc chiến thần thánh khác, và tôi e rằng chúng ta đang ở bên dưới quyền lực.

Tuy nhiên ...

Theo tôi, giải pháp chắc chắn không bao gồm các 'giai đoạn' theo khu vực. Mã gấp được sử dụng để quét mã dưới tấm thảm. Để lại mã ở đó, nó có thể nhắc nhở bạn rằng bạn có thể muốn cấu trúc lại mã đó sau đó! Để liên hệ nó với một đối số trong câu hỏi của bạn: làm thế nào bạn có thể thấy cơ hội tái sử dụng mã nếu bạn không thấy bất kỳ mã nào? Các đoạn mã dài phải chính xác như vậy, một cái gai trong mắt khiến bạn muốn cấu trúc lại nó.

Là một sự thay thế thích hợp cho các vùng, tôi khuyên bạn nên sử dụng các đoạn mã khi Alex Papadimoulis đặt tên cho chúng trong một bình luận . Bạn thực sự có thể đã sử dụng một cách tiếp cận tương tự. Nó chỉ đơn giản là các khối mã với tiêu đề bình luận, giải thích toàn bộ khối này làm gì. Bạn có khả năng đọc các chức năng, nhưng có thể sử dụng các câu tiếng Anh cách đều nhau và bạn không mất bất kỳ đóng gói nào.


Vâng, về cơ bản tôi sử dụng các vùng để phân định các đoạn mã (các vùng có thể có các bình luận có thể nhìn thấy ngay cả khi mã được gấp lại). Tôi thích sử dụng các vùng cho việc này vì nó cho phép người bảo trì lựa chọn xem mã nếu cô ấy muốn kiểm tra việc thực hiện hoặc gấp nó nếu cô ấy chỉ muốn xem "bức tranh lớn".
jjoelson

1

Mặc dù tôi đồng ý rằng thường thì tốt hơn là tái cấu trúc mã hơn là sử dụng #region, nhưng không phải lúc nào cũng có thể.

Để hỗ trợ cho tuyên bố đó, hãy để tôi đưa ra một ví dụ.

class Foo : IComparable
{
  private String name;
  private int foo;
  private Bar bar;

  public int CompareTo(Foo other)
  {
#region Ascending on name
     if (this.name < other.name) return -1;
     if (this.name > other.name) return 1;
#endregion
#region Usual order on bar
     int compBar = bar.compareTo(other.bar);
     if (compBar != 0) return compBar;
#endregion
#region Descending on foo
     if (this.foo > other.foo) return -1;
     if (this.foo < other.foo) return 1;
#endregion
     return 0; // equal
  }

Thật dễ dàng để điều chỉnh các khu vực để thay đổi thứ tự hoặc mở rộng khi các trường bổ sung được thêm vào lớp. Nhận xét được yêu cầu dù sao để nhanh chóng xem cách đặt hàng được cho là hoạt động. Và hầu hết tất cả: Tôi không thấy cách tái cấu trúc sẽ giúp dễ đọc trong trường hợp này.

Tuy nhiên, những ngoại lệ đó là rất hiếm. Thông thường có thể tái cấu trúc, giống như nhiều câu trả lời khác nói.


0

Tôi không nghĩ có một câu trả lời duy nhất cho lý do tại sao một số người hoặc nhóm nhất định quyết định không sử dụng #regionnhưng nếu tôi phải liệt kê một vài điều thì đây sẽ là những lý do hàng đầu mà tôi đã thấy.

  • Tên và thứ tự của các khu vực làm cho rõ ràng hơn việc đặt hàng và tổ chức mã thực thi một phong cách cụ thể có thể trở thành một nguồn tranh chấp và đi xe đạp.
  • Hầu hết các khái niệm không phù hợp với một số khu vực nhỏ. Thông thường, bạn bắt đầu với các vùng bằng các công cụ sửa đổi truy cập công khai , riêng tư , sau đó có thể theo loại thành viên (ví dụ: phương thức, thuộc tính, trường) nhưng sau đó, các hàm tạo bao trùm các bộ sửa đổi đó, các loại tĩnh của tất cả các thành viên được bảo vệ, thành viên nội bộ, nội bộ được bảo vệ các thành viên, các thành viên giao diện ngầm, các sự kiện, v.v ... Cuối cùng, bạn sẽ có các lớp được thiết kế tốt nhất trong đó bạn có một hoặc một phương thức trong mỗi vùng do phân loại dạng hạt.
  • Nếu bạn có thể giữ những thứ thực dụng và chỉ nhóm những thứ thành ba hoặc bốn loại khu vực nhất quán thì điều đó có thể hoạt động nhưng nó thực sự có giá trị gì? Nếu bạn đang thiết kế các lớp tốt, bạn thực sự không cần phải sàng lọc các trang mã.
  • Như các khu vực được gợi ý ở trên có thể ẩn mã xấu, điều này có thể làm cho nó có vẻ ít vấn đề hơn. Giữ nó như một vết loét mắt có thể giúp giải quyết nó.
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.