Chúng ta có nên tránh sử dụng các mẫu thiết kế trong các dự án thay đổi liên tục?


32

Một người bạn của tôi đang làm việc cho một công ty nhỏ trong một dự án mà mọi nhà phát triển đều ghét: anh ta bị áp lực phải phát hành càng nhanh càng tốt, anh ta là người duy nhất quan tâm đến nợ kỹ thuật, khách hàng không có nền tảng kỹ thuật, v.v.

Anh ấy kể cho tôi một câu chuyện khiến tôi suy nghĩ về sự phù hợp của các mẫu thiết kế trong các dự án như thế này. Đây là câu chuyện.

Chúng tôi đã phải hiển thị các sản phẩm tại các địa điểm khác nhau trên trang web. Ví dụ: người quản lý nội dung có thể xem các sản phẩm, nhưng cả người dùng cuối hoặc đối tác thông qua API.

Đôi khi, thông tin bị thiếu trong các sản phẩm: ví dụ, một loạt trong số họ không có bất kỳ giá nào khi sản phẩm vừa được tạo, nhưng giá chưa được chỉ định. Một số không có mô tả (mô tả là một đối tượng phức tạp với lịch sử sửa đổi, nội dung được bản địa hóa, v.v.). Một số thiếu thông tin lô hàng.

Lấy cảm hứng từ các bài đọc gần đây của tôi về các mẫu thiết kế, tôi nghĩ rằng đây là một cơ hội tuyệt vời để sử dụng mẫu Null Object huyền diệu . Vì vậy, tôi đã làm điều đó, và mọi thứ đều trơn tru và sạch sẽ. Người ta chỉ cần gọi product.Price.ToString("c")để hiển thị giá, hoặc product.Description.Currentđể hiển thị mô tả; không có công cụ có điều kiện cần thiết. Cho đến một ngày, các bên liên quan đã yêu cầu hiển thị nó khác nhau trong API, bằng cách có một nullJSON. Và cũng khác nhau đối với người quản lý nội dung bằng cách hiển thị "Giá không xác định [Thay đổi]". Và tôi đã phải giết chết mẫu Null Object yêu quý của mình, bởi vì không cần nó nữa.

Theo cách tương tự, tôi đã phải loại bỏ một vài nhà máy trừu tượng và một vài nhà xây dựng, cuối cùng tôi đã thay thế mẫu Mặt tiền đẹp đẽ của mình bằng các cuộc gọi trực tiếp và xấu xí, bởi vì các giao diện cơ bản đã thay đổi hai lần mỗi ngày trong ba tháng và thậm chí Singleton đã rời bỏ tôi khi các yêu cầu nói rằng đối tượng liên quan phải khác nhau tùy theo ngữ cảnh.

Hơn ba tuần làm việc bao gồm thêm các mẫu thiết kế, sau đó xé chúng ra một tháng sau đó, và mã của tôi cuối cùng đã trở thành spaghetti đủ để không ai có thể duy trì, kể cả bản thân tôi. Sẽ không tốt hơn nếu không bao giờ sử dụng các mẫu đó ở nơi đầu tiên?

Thật vậy, tôi đã phải tự mình làm việc với những loại dự án mà các yêu cầu thay đổi liên tục và bị quyết định bởi những người không thực sự có ý định về sự gắn kết hoặc sự gắn kết của sản phẩm. Trong bối cảnh này, không quan trọng bạn nhanh nhẹn đến mức nào, bạn sẽ đưa ra một giải pháp tao nhã cho một vấn đề và khi cuối cùng bạn thực hiện nó, bạn biết rằng các yêu cầu thay đổi rất lớn, rằng giải pháp thanh lịch của bạn không phù hợp còn nữa

Điều gì sẽ là giải pháp trong trường hợp này?

  • Không sử dụng bất kỳ mẫu thiết kế nào, ngừng suy nghĩ và viết mã trực tiếp?

    Thật thú vị khi thực hiện trải nghiệm khi một nhóm viết mã trực tiếp, trong khi một nhóm khác đang suy nghĩ hai lần trước khi gõ, có nguy cơ phải vứt bỏ thiết kế ban đầu vài ngày sau: ai biết được, có thể cả hai đội sẽ có cùng nợ kỹ thuật. Trong sự vắng mặt của dữ liệu như vậy, tôi sẽ chỉ khẳng định rằng nó không cảm thấy đúng phải gõ mã mà không suy nghĩ trước khi làm việc trên một dự án 20 người đàn ông tháng.

  • Giữ mẫu thiết kế không còn ý nghĩa nữa và cố gắng thêm nhiều mẫu cho tình huống mới được tạo?

    Điều này có vẻ không đúng. Các mẫu được sử dụng để đơn giản hóa sự hiểu biết về mã; đặt quá nhiều mẫu và mã sẽ trở thành một mớ hỗn độn.

  • Bắt đầu nghĩ về một thiết kế mới bao gồm các yêu cầu mới, sau đó từ từ cấu trúc lại thiết kế cũ thành một thiết kế mới?

    Là một nhà lý luận và là người ủng hộ Agile, tôi hoàn toàn thích nó. Trong thực tế, khi bạn biết rằng bạn sẽ phải quay lại bảng trắng mỗi tuần và làm lại phần lớn của thiết kế trước đó và khách hàng sẽ không có đủ tiền để trả cho bạn, cũng không đủ thời gian để chờ đợi , điều này có lẽ sẽ không hoạt động.

Vì vậy, bất kỳ đề nghị?


43
Tôi nghĩ rằng đây là một vấn đề nan giải giả. Bằng cách thừa nhận của chính bạn bè của bạn, mã bây giờ là một đĩa mì spaghetti không thể nhầm lẫn. Đó không phải là lỗi của các mẫu phần mềm; bạn của bạn không thể sử dụng các mẫu đó một cách hợp lý, theo cách tăng khả năng bảo trì, không làm giảm nó. Khi tôi có thể đưa ra các ví dụ cụ thể, tôi sẽ đăng một câu trả lời thích hợp.
Robert Harvey

5
Ngoài ra, FWIW, bất kỳ khách hàng nào không có khả năng chịu chi phí trôi dạt có lẽ không nên thực hiện Agile, trừ khi có các khoản phụ cấp được tích hợp vào chi phí cho các yêu cầu thay đổi.
Robert Harvey

5
Tôi nghi ngờ rằng nếu không có các mẫu thiết kế, mã sẽ đạt đến trạng thái không thể nhận ra sớm hơn nhiều
Steven A. Lowe

28
Câu hỏi này không có ý nghĩa gì. Cách duy nhất để "tránh các mẫu thiết kế" là không viết bất kỳ phần mềm nào cả. Những thứ như "Mẫu XYZ" chỉ là tên được đặt cho các chiến lược mã hóa phổ biến để cho phép các lập trình viên truyền đạt thông tin và lời khuyên về cấu trúc mã và các lựa chọn của chúng tôi cho nhau thuận tiện hơn. Bất kỳ lựa chọn thiết kế nào trong mã của bạn đều có thể được đặt tên và được gọi là "mẫu thiết kế", mặc dù không nhất thiết phải là một mẫu được biết đến rộng rãi (trừ khi, tôi cho rằng, bạn tự hào về thiết kế độc đáo của mình và đủ động lực để đặt tên và blog về nó nó hoặc một cái gì đó).
Jason C

9
Tức là bạn có thể tránh gọi bàn chân của mình là "bàn chân" nhưng bạn vẫn có bàn chân đó, sẽ khó nói chuyện với ai đó hơn nếu bạn không gọi đó là "bàn chân". Bạn có thể nghĩ rằng mình đang "tránh các mẫu thiết kế" nhưng nếu bạn nghĩ ra một thiết kế hợp lý, sau đó quay lại và xem, có lẽ bạn sẽ thấy rằng thiết kế của bạn cuối cùng đã phù hợp với một trong những mẫu được đặt tên phổ biến, cho dù bạn gọi nó hay không.
Jason C

Câu trả lời:


86

Tôi thấy một số giả định sai trong câu hỏi này:

  • mã với các mẫu thiết kế, mặc dù được áp dụng chính xác, cần nhiều thời gian hơn để thực hiện so với mã không có các mẫu đó.

Bản thân các mẫu thiết kế không có kết thúc, chúng nên phục vụ bạn chứ không phải ngược lại. Nếu một mẫu thiết kế không làm cho mã dễ thực hiện hơn, hoặc ít nhất là tốt hơn tiến hóa (điều đó có nghĩa: dễ dàng hơn để được điều chỉnh để thay đổi yêu cầu), sau đó mô hình nhớ mục đích của nó. Đừng áp dụng các mẫu khi họ không làm cho "cuộc sống" dễ dàng hơn cho nhóm. Nếu mẫu đối tượng Null mới phục vụ bạn của bạn trong thời gian anh ta sử dụng nó, thì mọi thứ đều ổn. Nếu nó được loại bỏ sau đó, thì điều này cũng có thể ổn. Nếu mẫu đối tượng Null làm chậm quá trình thực hiện (chính xác), thì việc sử dụng nó đã sai. Lưu ý, từ phần này của câu chuyện, người ta không thể kết luận bất kỳ nguyên nhân nào của "mã spaghetti" cho đến nay.

  • khách hàng phải đổ lỗi vì anh ta không có nền tảng kỹ thuật và không quan tâm đến sự gắn kết hoặc sự gắn kết của sản phẩm

Đó không phải là công việc của anh ấy cũng không phải lỗi của anh ấy! Công việc của bạn là quan tâm đến sự gắn kết và gắn kết. Khi các yêu cầu thay đổi hai lần một ngày, giải pháp của bạn không nên là hy sinh chất lượng mã. Chỉ cần nói với khách hàng mất bao lâu và nếu bạn nghĩ rằng bạn cần thêm thời gian để thiết kế "đúng", thì hãy thêm một mức an toàn đủ lớn vào bất kỳ ước tính nào. Đặc biệt là khi bạn có một khách hàng đang cố gắng gây áp lực cho bạn, hãy sử dụng "Nguyên tắc Scotty" . Và khi tranh luận với một khách hàng phi kỹ thuật về nỗ lực, hãy tránh các thuật ngữ như "tái cấu trúc", "kiểm thử đơn vị", "mẫu thiết kế" hoặc "tài liệu mã" - đó là những điều anh ta không hiểu và có thể coi là "không cần thiết vô nghĩa "bởi vì anh ta thấy không có giá trị trong đó. hoặc ít nhất là dễ hiểu đối với khách hàng (tính năng, tính năng phụ, thay đổi hành vi, tài liệu người dùng, sửa lỗi, tối ưu hóa hiệu suất, v.v.).

  • giải pháp cho các yêu cầu thay đổi nhanh chóng là thay đổi mã nhanh chóng

Thành thật mà nói, nếu "giao diện cơ bản thay đổi hai lần mỗi ngày trong ba tháng", thì giải pháp không nên phản ứng bằng cách thay đổi mã hai lần một ngày. Giải pháp thực sự là hỏi tại sao các yêu cầu thay đổi thường xuyên như vậy và liệu có thể thực hiện thay đổi ở phần đó của quy trình. Có thể một số phân tích trả trước sẽ giúp. Có thể giao diện quá rộng vì ranh giới giữa các thành phần được chọn sai. Đôi khi nó giúp hỏi thêm thông tin về phần nào của các yêu cầu ổn định và phần nào vẫn đang được thảo luận (và thực sự hoãn việc thực hiện cho những điều đang thảo luận). Và đôi khi một số người chỉ cần bị "đá vào mông" vì không thay đổi suy nghĩ hai lần một ngày.


30
+1 - bạn không thể giải quyết vấn đề của mọi người bằng các giải pháp kỹ thuật.
Telastyn

1
+1, nhưng "hoặc ít nhất là có thể tiến hóa tốt hơn (có nghĩa là: dễ thích nghi hơn với các yêu cầu thay đổi)" - Tôi có đủ điều kiện này với các yêu cầu thay đổi hợp lý không?
Fuhrmanator

1
@Fuhrmanator: Tôi nghĩ rằng điều này là khó để thảo luận về các điều khoản chung. IMHO rõ ràng là không có mẫu thiết kế nào có thể giúp bạn khi yêu cầu đầu tiên của bạn là "chúng tôi cần một trình xử lý văn bản" và điều này thay đổi thành "chúng tôi cần một trình mô phỏng bay". Đối với những thay đổi yêu cầu ít quyết liệt hơn, không phải lúc nào cũng dễ dàng quyết định điều gì sẽ giúp bạn giữ cho phần mềm của bạn có thể phát triển được. Điều tốt nhất là IMHO không áp dụng quá nhiều mẫu, nhưng một số nguyên tắc - chủ yếu là các nguyên tắc RẮN và YAGNI. Và tôi đồng ý 100% với Telastyn - khi các yêu cầu thay đổi quá thường xuyên, có lẽ đó không phải là vấn đề kỹ thuật.
Doc Brown

4
+1 - "Thành thật mà nói, nếu 'giao diện cơ bản thay đổi hai lần mỗi ngày trong ba tháng', thì giải pháp không nên phản ứng bằng cách thay đổi mã hai lần một ngày. Giải pháp thực sự là hỏi tại sao các yêu cầu thay đổi thường xuyên như vậy và nếu có thể thực hiện thay đổi ở phần đó của quy trình. "Nếu bạn liên tục được đưa ra những hướng đi mới, tốt nhất là ngồi xuống với tất cả các bên liên quan và xác nhận lại những kỳ vọng là gì. Tìm ra sự khác biệt của bạn và hy vọng không lãng phí thời gian và tiền bạc của mọi người bằng cách cung cấp cho dự án một mục tiêu rõ ràng hơn.
krillgar

1
@Cornelius Doc Brown nói rằng nó khó mà không cụ thể. Các yêu cầu đi từ trình xử lý văn bản đến trình mô phỏng bay sẽ không hợp lý; không có mẫu thiết kế sẽ giúp. Có rất nhiều vùng màu xám ở giữa ví dụ của anh ấy và giả sử thêm định dạng tệp mới vào chức năng Lưu của trình xử lý văn bản (rất hợp lý). Không có chi tiết cụ thể, thật khó để thảo luận. Ngoài ra, không phải là người ta sẽ không muốn thay đổi. Đó là những thay đổi như vậy rất khó, nếu bạn đã sớm đưa ra lựa chọn thiết kế dựa trên yêu cầu. Trình xử lý văn bản so với sim bay là một ví dụ tuyệt vời về sự lựa chọn sớm.
Fuhrmanator

43

Ý kiến ​​khiêm tốn của tôi là bạn không nên tránh hoặc không - tránh sử dụng các mẫu thiết kế.

Các mẫu thiết kế đơn giản là các giải pháp nổi tiếng và đáng tin cậy cho các vấn đề chung, được đặt tên. Chúng không khác biệt về mặt kỹ thuật so với bất kỳ giải pháp hoặc thiết kế nào khác mà bạn có thể nghĩ đến.

Tôi nghĩ rằng gốc rễ của vấn đề có thể là bạn của bạn nghĩ theo cách "áp dụng hoặc không áp dụng một mẫu thiết kế", thay vì suy nghĩ về "giải pháp tốt nhất tôi có thể nghĩ đến, bao gồm nhưng không giới hạn ở các mẫu Tôi biết".

Có lẽ cách tiếp cận này dẫn anh ta sử dụng các mô hình theo cách một phần nhân tạo hoặc bị ép buộc, ở những nơi họ không thuộc về. Và đây là những gì dẫn đến một mớ hỗn độn.


13
+1 "Các mẫu thiết kế đơn giản là các giải pháp nổi tiếng và đáng tin cậy cho các vấn đề chung, được đặt tên. Chúng không khác biệt về mặt kỹ thuật so với bất kỳ giải pháp hoặc thiết kế nào khác mà bạn có thể nghĩ tới." Chính xác. Mọi người bị cuốn vào các mẫu thiết kế được đặt tên đến nỗi họ quên chúng không khác gì những cái tên được đặt cho các chiến lược khác nhau để giúp các lập trình viên dễ dàng giao tiếp với nhau về mã và các lựa chọn thiết kế của chúng tôi. Thái độ này thường rất liên quan đến việc cố gắng ép buộc các "mô hình" không phù hợp đối với các vấn đề không nhất thiết có lợi - sự lộn xộn lớn.
Jason C

14

Trong ví dụ của bạn về việc sử dụng mẫu Null Object, tôi tin rằng cuối cùng nó đã thất bại vì nó đáp ứng nhu cầu của lập trình viên chứ không phải nhu cầu của khách hàng. Khách hàng cần hiển thị giá dưới dạng phù hợp với bối cảnh. Lập trình viên cần đơn giản hóa một số mã hiển thị.

Vì vậy, khi một mẫu thiết kế không đáp ứng các yêu cầu, chúng ta có nói rằng tất cả các mẫu thiết kế đều lãng phí thời gian hay chúng ta nói rằng chúng ta cần một mẫu thiết kế khác?


9

Nó sẽ xuất hiện sai lầm là nhiều hơn để loại bỏ các đối tượng mẫu, hơn là sử dụng chúng. Trong thiết kế ban đầu, Null Object dường như đã cung cấp giải pháp cho một vấn đề. Đây có thể không phải là giải pháp tốt nhất.

Là người duy nhất làm việc trong một dự án cho bạn cơ hội trải nghiệm toàn bộ quá trình phát triển. Nhược điểm lớn là không có ai đó làm cố vấn của bạn. Dành thời gian để tìm hiểu và áp dụng các thực tiễn tốt nhất hoặc tốt hơn có khả năng sẽ được đền đáp nhanh chóng. Bí quyết là xác định thực hành để học khi nào.

Tham chiếu chuỗi trong sản phẩm mẫu.price.toString ('c') vi phạm Luật Demeter . Tôi đã thấy tất cả các loại vấn đề với thực tiễn này, nhiều trong số đó liên quan đến null. Một phương thức như sản phẩm.displayprice ('c') có thể xử lý giá null trong nội bộ. Tương tự như vậy sản phẩm. Mô tả. Hiện tại có thể được xử lý bởi sản phẩm.displayDes mô tả (), sản phẩm.displayCienDes mô tả (). hoặc sản phẩm.diplay ('Hiện tại').

Xử lý yêu cầu mới cho người quản lý và nhà cung cấp nội dung cần được xử lý bằng cách đáp ứng với bối cảnh. Có nhiều cách tiếp cận có thể được sử dụng. Các phương thức xuất xưởng có thể sử dụng các lớp sản phẩm khác nhau tùy thuộc vào lớp người dùng mà chúng sẽ được hiển thị. Một cách tiếp cận khác sẽ là các phương thức hiển thị lớp sản phẩm để xây dựng dữ liệu khác nhau cho những người dùng khác nhau.

Tin tốt là bạn của bạn nhận ra rằng mọi thứ đang vượt ra khỏi tầm tay. Hy vọng, anh ta có mã trong kiểm soát sửa đổi. Điều này sẽ cho phép anh ta rút lại những quyết định tồi tệ, mà anh ta sẽ luôn đưa ra. Một phần của việc học là thử các cách tiếp cận khác nhau, một số trong đó sẽ thất bại. Nếu anh ta có thể xử lý trong vài tháng tới, anh ta có thể tìm ra cách tiếp cận đơn giản hóa cuộc sống của mình và làm sạch mì spaghetti. Anh ấy có thể cố gắng sửa chữa một điều mỗi tuần.


2
Nó cũng có thể chỉ ra thêm, khi thấy rằng bạn "phải" phá vỡ luật của Demeter, rằng mô hình được sử dụng ở bề mặt là không phù hợp. Tại sao "mô hình xem" (được sử dụng theo nghĩa lỏng lẻo) không chỉ có mô tả để hiển thị? (Tức là tại sao có nhiều hơn chỉ là mô tả hiện tại ở cấp độ UI?) Lớp nghiệp vụ có thể chuẩn bị một đối tượng được điền đầy đủ cho lớp UI có nội dung khác nhau tùy thuộc vào đó có phải là người quản lý hay không.
Cornelius

7

Câu hỏi dường như sai ở rất nhiều điểm. Nhưng những người trắng trợn là:

  • Đối với Mẫu đối tượng Null mà bạn đã đề cập, sau khi các yêu cầu thay đổi, bạn thay đổi một chút mã. Điều đó tốt nhưng điều đó không có nghĩa là bạn 'giết' Mô hình đối tượng Null (btw, hãy cẩn thận với từ ngữ của bạn, điều này nghe có vẻ quá cực đoan, một số người quá paranoiac sẽ không thấy điều này là buồn cười cả).

Nhiều người đã nói chính xác, các mẫu thiết kế rất nhiều về ghi nhãn và đặt tên một thông lệ. Vì vậy, hãy nghĩ về một chiếc áo sơ mi, một chiếc áo có cổ áo, vì lý do nào đó bạn loại bỏ cổ áo hoặc một phần của cổ áo. Việc đặt tên và ghi nhãn thay đổi, nhưng về bản chất nó vẫn là một chiếc áo. Đây chính xác là trường hợp ở đây, những thay đổi nhỏ về chi tiết không có nghĩa là bạn đã 'giết chết' mô hình đó. (một lần nữa nhớ từ ngữ cực đoan)

  • Thiết kế mà bạn nói đến là xấu bởi vì khi các yêu cầu thay đổi xuất hiện dưới dạng những điều nhỏ nhặt, bạn thực hiện thay đổi thiết kế chiến lược lớn ở khắp mọi nơi. Trừ khi vấn đề kinh doanh cấp cao thay đổi, bạn không thể biện minh cho việc thay đổi thiết kế lớn.

Từ kinh nghiệm của tôi, khi các yêu cầu nhỏ xuất hiện, bạn chỉ cần thay đổi một phần nhỏ của cơ sở mã. Một số có thể là một chút hack, nhưng không có gì quá nghiêm trọng để ảnh hưởng đáng kể đến khả năng duy trì hoặc khả năng đọc và thường một vài dòng bình luận để giải thích phần hacky sẽ đủ. Đây là một thực tế rất phổ biến là tốt.


7

Chúng ta hãy tạm dừng một lát và xem xét vấn đề cơ bản ở đây - Kiến trúc một hệ thống trong đó mô hình kiến ​​trúc quá gắn liền với các tính năng cấp thấp trong hệ thống, khiến kiến ​​trúc bị phá vỡ thường xuyên trong quá trình phát triển.

Tôi nghĩ rằng chúng ta phải nhớ rằng việc sử dụng các mẫu kiến ​​trúc và thiết kế liên quan đến nó phải được đặt ở một mức độ phù hợp, và việc phân tích mức độ phù hợp là không tầm thường. Một mặt, bạn có thể dễ dàng giữ kiến ​​trúc hệ thống của mình ở mức quá cao chỉ với các ràng buộc rất cơ bản như "MVC" hoặc tương tự, điều này có thể dẫn đến các cơ hội bị bỏ lỡ như trong hướng dẫn rõ ràng và đòn bẩy mã, và nơi mã spaghetti có thể dễ dàng phát triển mạnh trong tất cả không gian trống.

Mặt khác, bạn cũng có thể kiến ​​trúc sư hệ thống của mình quá mức, như khi đặt các ràng buộc ở mức độ chi tiết, trong đó bạn cho rằng bạn có thể dựa vào các ràng buộc mà trong thực tế có nhiều biến động hơn bạn mong đợi, liên tục phá vỡ các ràng buộc của bạn và buộc bạn phải liên tục sửa sang lại và xây dựng lại, cho đến khi bạn bắt đầu tuyệt vọng.

Những thay đổi trong yêu cầu cho một hệ thống sẽ luôn ở đó, ở mức độ thấp hơn hoặc lớn hơn. Và những lợi ích tiềm năng của việc sử dụng các mẫu kiến ​​trúc và thiết kế sẽ luôn tồn tại, vì vậy thực sự không có câu hỏi nào về việc sử dụng các mẫu thiết kế hay không, nhưng ở mức độ nào bạn nên sử dụng chúng.

Điều này đòi hỏi bạn không chỉ hiểu các yêu cầu hiện tại của hệ thống được đề xuất mà còn xác định các khía cạnh nào của hệ thống có thể được xem là thuộc tính cốt lõi ổn định của hệ thống và các thuộc tính nào có thể thay đổi trong quá trình phát triển.

Nếu bạn thấy rằng bạn liên tục phải chiến đấu với mã spaghetti không có tổ chức, có lẽ bạn không làm đủ kiến ​​trúc, hoặc ở mức độ cao. Nếu bạn thấy rằng kiến ​​trúc của bạn thường xuyên bị phá vỡ, có lẽ bạn đang làm kiến ​​trúc quá chi tiết.

Việc sử dụng các mẫu kiến ​​trúc và thiết kế không phải là thứ bạn có thể "phủ" lên một hệ thống, giống như nếu bạn vẽ một cái bàn. Chúng là những kỹ thuật nên được áp dụng một cách chu đáo, ở mức độ mà các ràng buộc bạn cần dựa vào có khả năng ổn định cao và trong đó các kỹ thuật này thực sự đáng để mô hình hóa kiến ​​trúc và thực hiện các ràng buộc / kiến ​​trúc / mẫu thực tế như mã.

Liên quan đến vấn đề kiến ​​trúc quá chi tiết, bạn cũng có thể đặt nhiều nỗ lực vào kiến ​​trúc nơi nó không mang lại nhiều giá trị. Xem kiến ​​trúc hướng rủi ro để tham khảo, tôi thích cuốn sách này - Chỉ cần đủ Kiến trúc phần mềm , có thể bạn cũng sẽ như vậy.

Chỉnh sửa

Làm rõ câu trả lời của tôi kể từ khi tôi nhận ra tôi thường thể hiện mình là "quá nhiều kiến ​​trúc", trong đó tôi thực sự có nghĩa là "kiến trúc quá chi tiết", không hoàn toàn giống nhau. Kiến trúc quá chi tiết có thể thường được xem là kiến ​​trúc "quá nhiều", nhưng ngay cả khi bạn giữ kiến ​​trúc ở mức tốt và tạo ra hệ thống đẹp nhất mà nhân loại từng thấy, điều này vẫn có thể là quá nhiều nỗ lực đối với kiến ​​trúc nếu các ưu tiên là về tính năng và thời gian đưa ra thị trường.


+1 Đây là những suy nghĩ rất tốt về mức độ rất cao Tôi nghĩ bạn phải xem trong một hệ thống nhưng như bạn đã nói, nó đòi hỏi nhiều kinh nghiệm trong thiết kế phần mềm.
Samuel

4

Bạn của bạn dường như đang phải đối mặt với nhiều cơn gió ngược dựa trên giai thoại của anh ấy. Điều đó thật đáng tiếc, và có thể là một môi trường rất khó để làm việc. Mặc dù khó khăn, anh ấy đã đi đúng hướng sử dụng các mô hình để làm cho cuộc sống của mình dễ dàng hơn, và thật xấu hổ khi anh ấy rời khỏi con đường đó. Mã spaghetti là kết quả cuối cùng.

Vì có hai lĩnh vực vấn đề khác nhau, kỹ thuật và liên cá nhân, tôi sẽ giải quyết từng vấn đề riêng biệt.

Liên cá nhân

Cuộc đấu tranh mà bạn của bạn đang gặp phải là với các yêu cầu thay đổi nhanh chóng và điều đó ảnh hưởng đến khả năng viết mã duy trì của anh ấy. Trước tiên tôi sẽ nói rằng các yêu cầu thay đổi hai lần một ngày, mỗi ngày trong một khoảng thời gian dài như vậy là một vấn đề lớn hơn và có một kỳ vọng ngầm không thực tế. Các yêu cầu đang thay đổi nhanh hơn mã có thể thay đổi. Chúng tôi không thể mong đợi mã, hoặc lập trình viên, để theo kịp. Tốc độ thay đổi nhanh chóng này là triệu chứng của một quan niệm không đầy đủ về sản phẩm mong muốn ở mức cao hơn. Đây là một vấn đề. Nếu họ không biết những gì họ thực sự muốn, họ sẽ lãng phí rất nhiều thời gian và tiền bạc để không bao giờ có được nó.

Nó có thể là tốt để thiết lập ranh giới cho những thay đổi. Nhóm cùng nhau thay đổi thành các bộ mỗi hai tuần, sau đó đóng băng chúng trong hai tuần trong khi chúng được thực hiện. Xây dựng một danh sách mới cho giai đoạn hai tuần tới. Tôi có cảm giác một số thay đổi này chồng chéo hoặc mâu thuẫn (ví dụ, vặn vẹo qua lại giữa hai tùy chọn). Khi những thay đổi đến nhanh và nguy hiểm, tất cả đều có ưu tiên hàng đầu. Nếu bạn để họ tích lũy vào một danh sách, bạn có thể làm việc với họ để sắp xếp và ưu tiên những gì quan trọng nhất để tối đa hóa nỗ lực và năng suất. Họ có thể thấy rằng một số thay đổi của họ là ngớ ngẩn hoặc ít quan trọng hơn, mang lại cho bạn của bạn một số phòng thở.

Tuy nhiên, những vấn đề này không thể ngăn bạn viết mã tốt. Mã xấu dẫn đến các vấn đề tồi tệ hơn. Có thể mất thời gian để cấu trúc lại từ giải pháp này sang giải pháp khác, nhưng thực tế là có thể cho thấy lợi ích của việc thực hành mã hóa tốt thông qua các mẫu và nguyên tắc.

Trong một môi trường thay đổi thường xuyên, nợ kỹ thuật sẽ đến hạn vào một lúc nào đó. Nó là tốt hơn nhiều để thực hiện thanh toán cho nó hơn là ném vào khăn và chờ cho đến khi nó trở nên quá lớn để vượt qua. Nếu một mẫu không còn hữu ích, hãy cấu trúc lại nó, nhưng đừng quay lại các cách mã hóa cao bồi.

Kỹ thuật

Bạn của bạn dường như có một nắm bắt tốt về các mẫu thiết kế cơ bản. Đối tượng Null là một cách tiếp cận tốt cho vấn đề mà anh ta đang phải đối mặt. Trong thực tế, nó vẫn là một cách tiếp cận tốt. Nơi mà anh ta dường như có những thách thức là hiểu các nguyên tắc đằng sau các mô hình, lý do tại sao chúng là gì. Nếu không, tôi không tin anh ta sẽ từ bỏ cách tiếp cận của mình.

(Phần tiếp theo là một tập hợp các giải pháp kỹ thuật không được yêu cầu trong câu hỏi ban đầu, nhưng điều đó cho thấy cách chúng ta có thể tuân thủ các mẫu cho mục đích minh họa.)

Nguyên tắc đằng sau đối tượng null là ý tưởng đóng gói những gì khác nhau . Chúng tôi che giấu những thay đổi để chúng tôi không phải đối phó với nó ở mọi nơi khác. Ở đây, đối tượng null được đóng gói phương sai trong product.Pricetrường hợp (tôi sẽ gọi nó là một Priceđối tượng và giá của đối tượng null sẽ là NullPrice). Pricelà một đối tượng miền, một khái niệm kinh doanh. Đôi khi, trong logic kinh doanh của chúng tôi, chúng tôi chưa biết giá. Điều này xảy ra. Trường hợp sử dụng hoàn hảo cho các đối tượng null. Prices có một ToStringphương thức đưa ra giá hoặc chuỗi rỗng nếu không biết (hoặc, NullPrice#ToStringtrả về một chuỗi trống). Đây là một hành vi hợp lý. Sau đó yêu cầu thay đổi.

Chúng tôi phải xuất ra nullchế độ xem API hoặc một chuỗi khác với chế độ xem của người quản lý. Điều này ảnh hưởng đến logic kinh doanh của chúng tôi như thế nào? Vâng, nó không. Trong tuyên bố trên, tôi đã sử dụng từ 'view' hai lần. Từ này có lẽ không được nói rõ ràng, nhưng chúng ta phải tự rèn luyện để nghe những từ ẩn trong yêu cầu. Vậy tại sao 'xem' lại quan trọng đến vậy? Bởi vì nó cho chúng ta biết nơi thay đổi phải thực sự xảy ra: theo quan điểm của chúng tôi.

Ngoài ra : việc chúng ta có sử dụng khung MVC hay không không liên quan ở đây. Mặc dù MVC có ý nghĩa rất cụ thể đối với 'Chế độ xem', nhưng tôi đang sử dụng nó theo nghĩa chung hơn (và có lẽ phù hợp hơn) của một đoạn mã trình bày.

Vì vậy, chúng tôi thực sự cần phải sửa lỗi này trong chế độ xem. Làm thế nào chúng ta có thể làm điều đó? Cách dễ nhất để làm điều này sẽ là một iftuyên bố. Tôi biết đối tượng null được dự định để loại bỏ tất cả các if, nhưng chúng ta phải thực dụng. Chúng ta có thể kiểm tra chuỗi để xem nó có trống không và chuyển đổi:

if(product.Price.ToString("c").Length == 0) { // one way of many
    writer.write("Price unspecified [Change]");
} else {
    writer.write(product.Price.ToString("c"));
}

Điều này ảnh hưởng đến việc đóng gói như thế nào? Phần quan trọng nhất ở đây là logic xem được gói gọn trong khung nhìn . Chúng ta có thể giữ cho các đối tượng logic / miền kinh doanh của mình tách biệt hoàn toàn khỏi các thay đổi trong logic xem theo cách này. Nó xấu, nhưng nó hoạt động. Đây không phải là lựa chọn duy nhất, mặc dù.

Chúng tôi có thể nói rằng logic kinh doanh của chúng tôi đã thay đổi một chút ở chỗ chúng tôi muốn xuất các chuỗi mặc định nếu không đặt giá. Chúng ta có thể thực hiện một điều chỉnh nhỏ cho Price#ToStringphương thức của mình (thực sự tạo ra một phương thức quá tải). Chúng tôi có thể chấp nhận giá trị trả về mặc định và trả về nếu không đặt giá:

class Price {
    ...
    // A new ToString method
    public string ToString(string c, string default) {
        return ToString(c);
    }
    ...
}

class NullPrice {
    ...
    // A new ToString method
    public string ToString(string c, string default) {
        return default;
    }
    ...
}

Và bây giờ mã xem của chúng tôi trở thành:

writer.write(product.Price.ToString("c", "Price unspecified [Change]"));

Các điều kiện đã biến mất. Tuy nhiên, làm điều này quá nhiều có thể sinh sôi nảy nở các phương thức trường hợp đặc biệt vào các đối tượng miền của bạn, vì vậy điều này chỉ có ý nghĩa nếu sẽ chỉ có một vài trường hợp này.

Thay vào đó, chúng ta có thể tạo một IsSetphương thức Pricetrả về boolean:

class Price {
    ...
    public bool IsSet() {
        return return true;
    }
    ...
}

class NullPrice {
    ...
    public bool IsSet() {
        return false;
    }
    ...
}

Xem logic:

if(product.Price.IsSet()) {
    writer.write(product.Price.ToString("c"));
} else {
    writer.write("Price unspecified [Change]");
}

Chúng tôi thấy sự trở lại của điều kiện trong chế độ xem, nhưng trường hợp mạnh hơn cho logic kinh doanh nếu giá được đặt. Chúng tôi có thể sử dụng Price#IsSetở nơi khác mà chúng tôi có sẵn.

Cuối cùng, chúng ta có thể gói gọn ý tưởng trình bày một mức giá hoàn toàn trong một người trợ giúp cho quan điểm. Điều này sẽ ẩn điều kiện, trong khi bảo tồn đối tượng miền nhiều như chúng ta muốn:

class PriceStringHelper {
    public PriceStringHelper() {}

    public string PriceToString(Price price, string default) {
        if(price.IsSet()) { // or use string length to not change the Price class at all
           return price.ToString("c");
        } else {
            return default;
        }
    }
}

Xem logic:

writer.write(new PriceStringHelper().PriceToString(product.Price, "Price unspecified [Change]"));

Có nhiều cách khác để thực hiện các thay đổi (chúng ta có thể khái quát hóa PriceStringHelperthành một đối tượng trả về mặc định nếu một chuỗi trống), nhưng đây là một vài cách nhanh chóng bảo tồn (phần lớn) cả các mẫu nguyên tắc, như cũng như khía cạnh thực dụng của việc tạo ra một sự thay đổi như vậy.


3

Sự phức tạp của một mẫu thiết kế có thể cắn bạn nếu vấn đề cần giải quyết đột nhiên biến mất. Đáng buồn thay, do sự nhiệt tình và phổ biến của các mẫu thiết kế, rủi ro này hiếm khi được làm rõ ràng. Giai thoại của bạn bè giúp bạn rất nhiều để chỉ ra cách các mẫu không được đền đáp. Jeff Atwood có một số từ lựa chọn về chủ đề này.

Điểm biến đổi tài liệu (chúng là rủi ro) trong yêu cầu

Nhiều mẫu thiết kế phức tạp hơn (Null Object không quá nhiều) chứa khái niệm về các biến thể được bảo vệ , đó là "Xác định các điểm của biến thể dự đoán hoặc không ổn định; gán trách nhiệm để tạo giao diện ổn định xung quanh chúng." Bộ điều hợp, Khách truy cập, Mặt tiền, Lớp, Người quan sát, Chiến lược, Trang trí, v.v ... đều khai thác nguyên tắc này. Họ "trả hết" khi phần mềm cần được mở rộng theo chiều biến thiên dự kiến ​​và các giả định "ổn định" vẫn ổn định.

Nếu các yêu cầu của bạn không ổn định đến mức "các biến thể dự đoán" của bạn luôn sai, thì các mẫu bạn áp dụng sẽ khiến bạn đau đớn hoặc phức tạp không cần thiết nhất.

Craig Larman nói về hai cơ hội để áp dụng các biến thể được bảo vệ:

  • điểm biến thể - trong hệ thống hiện tại hoặc yêu cầu hiện tại, chẳng hạn như nhiều giao diện phải được hỗ trợ và
  • điểm tiến hóa - điểm đầu cơ của biến thể không có trong các yêu cầu hiện có.

Cả hai được cho là được ghi lại bởi các nhà phát triển, nhưng có lẽ bạn nên có cam kết của khách hàng đối với các điểm khác nhau.

Để quản lý rủi ro, bạn có thể nói rằng bất kỳ mẫu thiết kế nào áp dụng PV phải được truy tìm đến một điểm khác nhau trong các yêu cầu được ký bởi khách hàng. Nếu khách hàng thay đổi điểm biến thể trong yêu cầu, thiết kế của bạn có thể phải thay đổi hoàn toàn (vì bạn có thể đã đầu tư vào thiết kế [mẫu] để hỗ trợ biến thể đó). Không cần phải giải thích sự gắn kết, khớp nối, vv

Ví dụ: khách hàng của bạn muốn phần mềm hoạt động với ba hệ thống kiểm kê cũ khác nhau. Đó là một điểm khác nhau mà bạn thiết kế xung quanh. Nếu khách hàng bỏ yêu cầu đó, thì tất nhiên bạn có một loạt các cơ sở hạ tầng thiết kế vô dụng. Khách hàng cần biết rằng các điểm khác nhau có giá.

CONSTANTS trong mã nguồn là một hình thức đơn giản của PV

Một tương tự khác cho câu hỏi của bạn sẽ là hỏi xem sử dụng CONSTANTStrong mã nguồn có phải là một ý tưởng tốt hay không. Đề cập đến ví dụ này , giả sử khách hàng bỏ nhu cầu về mật khẩu. Do đó, MAX_PASSWORD_SIZEnhư một sự lây lan liên tục trong toàn bộ mã của bạn sẽ trở nên vô dụng và thậm chí là trở ngại cho việc bảo trì và mức độ dễ đọc. Bạn sẽ đổ lỗi cho việc sử dụng CONSTANTSnhư là lý do?


2

Tôi nghĩ rằng ít nhất một phần phụ thuộc vào bản chất của tình huống của bạn.

Bạn đề cập liên tục thay đổi yêu cầu. Nếu khách hàng nói "Tôi muốn ứng dụng nuôi ong này cũng hoạt động với ong bắp cày" thì đó có vẻ như là tình huống mà thiết kế cẩn thận sẽ giúp tiến bộ, không cản trở nó (đặc biệt là khi bạn nghĩ rằng trong tương lai cô ấy có thể muốn giữ ruồi giấm quá.)

Mặt khác, nếu bản chất của thay đổi giống như "Tôi muốn ứng dụng nuôi ong này quản lý bảng lương của tập đoàn giặt là của tôi", sẽ không có số lượng mã nào đào bạn ra khỏi lỗ hổng của bạn.

Không có gì tốt về các mẫu thiết kế. Chúng là những công cụ như bất kỳ công cụ nào khác - chúng tôi chỉ sử dụng chúng để làm cho công việc của chúng tôi dễ dàng hơn trong thời gian dài đến trung bình. Nếu một công cụ khác (như giao tiếp hoặc nghiên cứu ) hữu ích hơn thì chúng ta sẽ sử dụng 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.