Làm thế nào để bạn tránh lặp đi lặp lại vô tận thông qua các thiết kế không tối ưu như nhau?


10

Vì vậy, có lẽ giống như nhiều người, tôi thường thấy đau đầu với các vấn đề thiết kế, ví dụ, có một số mẫu / phương pháp thiết kế có vẻ phù hợp với vấn đề và có lợi ích mong muốn. Rất thường có một số cảnh báo gây khó khăn cho việc thực hiện mô hình / cách tiếp cận mà không có một số loại công việc xung quanh mà sau đó phủ nhận lợi ích của mô hình / cách tiếp cận. Tôi có thể rất dễ dàng kết thúc việc lặp đi lặp lại qua nhiều kiểu / cách tiếp cận vì có thể dự đoán rằng hầu hết tất cả chúng đều có một số cảnh báo rất quan trọng trong các tình huống trong thế giới thực, trong đó đơn giản là không phải là một giải pháp dễ dàng.


Thí dụ:

Tôi sẽ đưa cho bạn một ví dụ giả thuyết dựa trên một ví dụ thực tế mà tôi gặp gần đây. Giả sử tôi muốn sử dụng thành phần trên kế thừa vì hệ thống phân cấp thừa kế đã cản trở khả năng mở rộng của mã trong quá khứ. Tôi có thể cấu trúc lại mã nhưng sau đó thấy rằng có một số bối cảnh trong đó siêu lớp / lớp cơ bản chỉ cần gọi chức năng trên lớp con, mặc dù đã cố gắng tránh nó.

Cách tiếp cận tốt nhất tiếp theo dường như là triển khai một mẫu nửa đại biểu / quan sát viên và một nửa mẫu bố cục để siêu lớp có thể ủy thác hành vi hoặc để lớp con có thể quan sát các sự kiện của siêu lớp. Sau đó, lớp ít có khả năng mở rộng và duy trì được vì không rõ nó nên được mở rộng như thế nào, cũng rất khó để mở rộng người nghe / đại biểu hiện có. Ngoài ra thông tin không được ẩn tốt vì người ta bắt đầu cần biết cách triển khai để xem cách mở rộng siêu lớp (trừ khi bạn sử dụng các bình luận rất rộng rãi).

Vì vậy, sau này tôi có thể chọn chỉ đơn giản là sử dụng các nhà quan sát hoặc đại biểu hoàn toàn để thoát khỏi những nhược điểm đi kèm với việc trộn lẫn các phương pháp tiếp cận nặng nề. Tuy nhiên điều này đi kèm với các vấn đề riêng của nó. Ví dụ, tôi có thể thấy rằng cuối cùng tôi cần người quan sát hoặc đại biểu cho một số lượng hành vi ngày càng tăng cho đến khi tôi cuối cùng cần người quan sát / đại biểu cho thực tế mọi hành vi. Một lựa chọn có thể là chỉ có một người nghe / đại biểu lớn cho tất cả các hành vi nhưng sau đó lớp thực hiện kết thúc với rất nhiều phương thức trống, v.v.

Sau đó, tôi có thể thử một cách tiếp cận khác nhưng cũng có nhiều vấn đề với điều đó. Sau đó, tiếp theo, và sau đó vv


Quá trình lặp này trở nên rất khó khăn khi mỗi cách tiếp cận dường như có nhiều vấn đề như bất kỳ phương pháp nào khác và dẫn đến một loại tê liệt quyết định thiết kế . Cũng khó chấp nhận rằng mã sẽ có vấn đề như nhau bất kể sử dụng mẫu hoặc phương pháp thiết kế nào. Nếu tôi kết thúc trong tình huống này có nghĩa là vấn đề cần phải được xem xét lại? Những người khác làm gì khi gặp phải tình huống này?

Chỉnh sửa: Dường như có một số giải thích cho câu hỏi mà tôi muốn làm rõ:

  • Tôi đã loại bỏ hoàn toàn OOP khỏi câu hỏi vì hóa ra nó không thực sự cụ thể đối với OOP, cộng với việc quá dễ hiểu sai một số ý kiến ​​tôi đưa ra khi chuyển về OOP.
  • Một số người đã tuyên bố tôi nên thực hiện một cách tiếp cận lặp lại và thử các mẫu khác nhau, hoặc tôi nên loại bỏ một mẫu khi nó ngừng hoạt động. Đây là quá trình tôi dự định đề cập đến ở nơi đầu tiên. Tôi nghĩ rằng điều này rõ ràng từ ví dụ nhưng tôi có thể đã làm cho nó rõ ràng hơn, vì vậy tôi đã chỉnh sửa câu hỏi để làm như vậy.

3
Đừng "đăng ký triết lý OO". Đó là một công cụ, không phải là một quyết định lớn trong cuộc sống. Sử dụng nó khi nó giúp và không sử dụng nó khi nó không.
dùng253751

Nếu bạn đang suy nghĩ về các mẫu nhất định, có thể thử viết một số dự án phức tạp vừa phải bằng C, sẽ rất thú vị khi trải nghiệm bạn có thể làm được bao nhiêu nếu không có các mẫu đó.
dùng253751

2
Oh C có hoa văn. Chúng chỉ là những mẫu rất khác nhau. :)
candied_orange

Tôi đã xóa hầu hết các giải thích sai trong bản chỉnh sửa
Jonathan

Có những vấn đề này xuất hiện một lần trong một thời gian tuyệt vời là bình thường. Có chúng xảy ra thường xuyên không nên là trường hợp. Rất có thể, bạn đang sử dụng mô hình lập trình sai cho vấn đề hoặc thiết kế của bạn là một hỗn hợp của các mô hình ở những vị trí sai.
Dunk

Câu trả lời:


8

Khi tôi đi đến một quyết định khó khăn như thế, tôi thường tự hỏi mình ba câu hỏi:

  1. Những ưu và nhược điểm của tất cả các giải pháp có sẵn là gì?

  2. Có một giải pháp, tôi chưa xem xét?

  3. Quan trọng nhất:
    chính xác yêu cầu của tôi là gì? Không phải là yêu cầu trên giấy, những cái cơ bản thực sự?
    Tôi có thể bằng cách nào đó cải tổ vấn đề / điều chỉnh các yêu cầu của nó, để nó cho phép một giải pháp đơn giản, đơn giản không?
    Tôi có thể trình bày dữ liệu của mình theo một số cách khác nhau để nó cho phép một giải pháp đơn giản, đơn giản như vậy không?

    Đây là câu hỏi về các nguyên tắc cơ bản của vấn đề nhận thức. Nó có thể bật ra, rằng bạn thực sự đang cố gắng giải quyết vấn đề sai. Vấn đề của bạn có thể có các yêu cầu cụ thể cho phép giải pháp đơn giản hơn nhiều so với trường hợp chung. Câu hỏi xây dựng vấn đề của bạn!

Tôi thấy rất quan trọng để suy nghĩ về cả ba câu hỏi khó trước khi tiếp tục. Đi dạo, tăng tốc văn phòng của bạn, làm bất cứ điều gì cần thiết để thực sự nghiền ngẫm câu trả lời cho những câu hỏi này. Tuy nhiên, trả lời những câu hỏi này không nên mất nhiều thời gian. Thời gian thích hợp có thể dao động từ 15 phút đến một cái gì đó như một tuần, chúng phụ thuộc vào mức độ xấu của các giải pháp bạn đã tìm thấy và tác động của nó lên toàn bộ.

Giá trị của phương pháp này là, đôi khi bạn sẽ tìm thấy các giải pháp tốt đáng ngạc nhiên. Giải pháp thanh lịch. Giải pháp rất xứng đáng với thời gian bạn đầu tư để trả lời ba câu hỏi này. Và bạn sẽ không tìm thấy giải pháp đó, nếu bạn chỉ cần nhập lần lặp tiếp theo ngay lập tức.

Tất nhiên, đôi khi không có giải pháp tốt dường như tồn tại. Trong trường hợp đó, bạn bị mắc kẹt với câu trả lời của mình cho câu hỏi một, và tốt đơn giản là ít tệ nhất. Trong trường hợp này, giá trị của việc dành thời gian để trả lời những câu hỏi này là bạn có thể tránh các lần lặp bị ràng buộc để thất bại. Chỉ cần chắc chắn rằng bạn quay lại mã hóa trong một khoảng thời gian thích hợp.


Tôi cũng có thể đánh dấu đây là câu trả lời, điều này có ý nghĩa nhất đối với tôi và dường như có một sự đồng thuận về việc đơn giản là đánh giá lại vấn đề.
Jonathan

Ngoài ra tôi thích cách bạn chia nó thành các bước để có một số thủ tục lỏng lẻo để đánh giá tình hình.
Jonathan

OP, tôi thấy bạn bị mắc kẹt trong các cơ chế của giải pháp mã, vì vậy vâng bạn "cũng có thể đánh dấu câu trả lời này." Mã tốt nhất mà chúng tôi đã viết là sau khi phân tích rất cẩn thận các yêu cầu, yêu cầu xuất phát, sơ đồ lớp, tương tác lớp, v.v ... Cảm ơn trời, chúng tôi đã chống lại tất cả những rắc rối từ ghế giá rẻ (đọc quản lý & đồng nghiệp): "Bạn sẽ dành quá nhiều thời gian cho thiết kế "," nhanh lên và nhận mã hóa! "," đó là quá nhiều lớp học! ", v.v. Một khi chúng ta đã đạt được nó, mã hóa là một niềm vui - hơn cả niềm vui. Khách quan đó là mã tốt nhất trong toàn bộ dự án.
radarbob

13

Điều đầu tiên trước tiên - các mẫu là trừu tượng hữu ích không phải là tất cả của thiết kế, chứ đừng nói đến thiết kế OO.

Thứ hai - OO hiện đại đủ thông minh để biết rằng không phải mọi thứ đều là đối tượng. Đôi khi sử dụng các hàm cũ đơn giản, hoặc thậm chí một số tập lệnh kiểu bắt buộc sẽ mang lại giải pháp tốt hơn cho các vấn đề nhất định.

Bây giờ đến thịt của sự vật:

Điều này trở nên rất khó khăn khi mỗi cách tiếp cận dường như có nhiều vấn đề như bất kỳ phương pháp nào khác.

Tại sao? Khi bạn có một loạt các tùy chọn tương tự, quyết định của bạn sẽ dễ dàng hơn! Bạn sẽ không mất nhiều tiền bằng cách chọn tùy chọn "sai". Và thực sự, mã không cố định. Hãy thử một cái gì đó, xem nếu nó là tốt. Lặp đi lặp lại .

Cũng khó chấp nhận rằng mã sẽ kết thúc rất có vấn đề bất kể sử dụng mẫu hoặc phương pháp thiết kế nào.

Các loại hạt cứng. Các vấn đề khó - các vấn đề khó về toán học thực tế chỉ là khó. Chắc chắn là khó. Có nghĩa đen là không có giải pháp tốt cho họ. Và hóa ra, những vấn đề dễ dàng không thực sự có giá trị.

Nhưng hãy cảnh giác. Quá thường xuyên, tôi thấy mọi người thất vọng vì không có lựa chọn tốt vì họ bị mắc kẹt khi nhìn vấn đề theo một cách nhất định hoặc họ đã cắt giảm trách nhiệm của mình theo cách không tự nhiên đối với vấn đề trong tay. "Không có lựa chọn tốt" có thể là một mùi mà có gì đó sai về cơ bản với cách tiếp cận của bạn.

Điều này dẫn đến việc mất động lực vì mã "sạch" đôi khi không còn là một lựa chọn.

Hoàn hảo là kẻ thù của tốt. Nhận một cái gì đó làm việc, sau đó cấu trúc lại nó.

Có cách tiếp cận nào để thiết kế có thể giúp giảm thiểu vấn đề này không? Có một thực hành được chấp nhận cho những gì một người nên làm trong tình huống như thế này?

Như tôi đã đề cập, phát triển lặp thường giảm thiểu vấn đề này. Khi bạn đã làm việc gì đó, bạn sẽ quen thuộc hơn với vấn đề đặt bạn vào vị trí tốt hơn để giải quyết nó. Bạn có mã thực tế để xem xét và đánh giá, không phải một số thiết kế trừu tượng có vẻ không đúng.


Chỉ cần nghĩ rằng tôi nên nói rằng tôi đã xóa một số giải thích sai trong chỉnh sửa. Tôi thường làm phương pháp "làm cho nó hoạt động" và tái cấu trúc. Tuy nhiên, điều này thường dẫn đến nhiều nợ kỹ thuật trong kinh nghiệm của tôi. Ví dụ, nếu tôi chỉ làm cho một thứ hoạt động, nhưng sau đó bản thân tôi hoặc những người khác xây dựng trên nó, một số trong những điều đó có thể không thể tránh khỏi sự phụ thuộc mà sau đó cũng cần một tấn tái cấu trúc. Tất nhiên bạn không thể luôn biết điều này trước. Nhưng nếu bạn đã biết cách tiếp cận còn thiếu sót, liệu người ta có nên làm cho nó hoạt động và sau đó lặp lại cấu trúc lại trước khi xây dựng mã không?
Jonathan

@Jonathan - tất cả các thiết kế là một loạt các sự đánh đổi. Có, bạn nên lặp lại ngay lập tức nếu thiết kế bị lỗi và bạn có một cách rõ ràng để cải thiện nó. Nếu không có cải thiện rõ ràng, hãy dừng việc đó lại.
Telastyn

"họ đã cắt giảm trách nhiệm của mình theo cách không tự nhiên đối với vấn đề hiện tại. Không có lựa chọn tốt nào có thể là mùi mà có gì đó sai về cơ bản với cách tiếp cận của bạn." Tôi đặt cược vào cái này Một số nhà phát triển không bao giờ gặp phải các vấn đề được mô tả của OP và những người khác dường như làm điều đó khá thường xuyên. Thường thì giải pháp không dễ thấy khi được nhà phát triển ban đầu đặt ra vì họ đã thiên vị thiết kế theo cách họ đóng khung vấn đề. Đôi khi cách duy nhất để tìm ra giải pháp khá rõ ràng là bắt đầu lại tất cả các yêu cầu cho thiết kế.
Dunk

8

Tình huống mà bạn mô tả trông giống như một cách tiếp cận từ dưới lên. Bạn lấy một chiếc lá, cố gắng sửa nó và tìm ra nó được kết nối với một nhánh mà chính nó cũng được kết nối với một nhánh khác, v.v.

Nó giống như cố gắng chế tạo một chiếc xe bắt đầu bằng lốp xe.

Những gì bạn cần là lùi lại một bước và nhìn vào bức tranh lớn hơn. Làm thế nào mà chiếc lá ngồi trong thiết kế tổng thể? Điều đó vẫn còn hiện tại và chính xác?

Mô-đun sẽ trông như thế nào nếu bạn thiết kế và thực hiện nó từ đầu? Cách xa "lý tưởng" đó là cách thực hiện hiện tại của bạn.

Bằng cách đó bạn có một bức tranh lớn hơn về những gì để làm việc hướng tới. (Hoặc nếu bạn quyết định nó quá nhiều công việc, vấn đề là gì).


4

Ví dụ của bạn mô tả một tình huống phát sinh điển hình với các đoạn mã kế thừa lớn hơn và khi bạn đang cố gắng thực hiện tái cấu trúc "quá lớn".

Lời khuyên tốt nhất tôi có thể cung cấp cho bạn cho tình huống này là:

  • đừng cố gắng đạt được mục tiêu chính của bạn trong một "vụ nổ lớn" ,

  • tìm hiểu làm thế nào để cải thiện mã của bạn trong các bước nhỏ hơn!

Tất nhiên, điều đó dễ viết hơn thực hiện, vậy làm thế nào để thực hiện điều này trong thực tế? Vâng, bạn cần thực hành và kinh nghiệm, nó phụ thuộc rất nhiều vào trường hợp, và không có quy tắc khó và nhanh nào nói "làm cái này hay cái kia" phù hợp với mọi trường hợp. Nhưng hãy để tôi sử dụng ví dụ giả thuyết của bạn. "Thành phần thừa kế" không phải là một mục tiêu thiết kế toàn diện hoặc không có gì, nó là một ứng cử viên hoàn hảo để đạt được trong một số bước nhỏ.

Hãy nói rằng bạn nhận thấy "thừa kế thành phần" là công cụ phù hợp cho trường hợp. Phải có một số dấu hiệu cho thấy đây là một mục tiêu hợp lý, nếu không bạn sẽ không chọn mục tiêu này. Vì vậy, giả sử có rất nhiều chức năng trong siêu lớp chỉ được "gọi" từ các lớp con, vì vậy chức năng này là một ứng cử viên cho việc không ở trong siêu lớp đó.

Nếu bạn nhận thấy bạn không thể loại bỏ siêu lớp ngay lập tức khỏi các lớp con, trước tiên bạn có thể bắt đầu với việc tái cấu trúc siêu lớp thành các thành phần nhỏ hơn đóng gói chức năng được đề cập ở trên. Bắt đầu với các loại trái cây treo thấp nhất, trước tiên hãy trích xuất một số thành phần đơn giản hơn, điều này sẽ làm cho siêu lớp của bạn bớt phức tạp hơn. Siêu lớp càng nhỏ, phép tái cấu trúc bổ sung sẽ càng dễ dàng hơn. Sử dụng các thành phần này từ các lớp con cũng như từ siêu lớp.

Nếu bạn may mắn, mã còn lại trong siêu lớp sẽ trở nên đơn giản trong suốt quá trình này đến mức bạn có thể loại bỏ siêu lớp khỏi các lớp con mà không gặp vấn đề gì thêm. Hoặc, bạn sẽ nhận thấy rằng việc giữ siêu lớp không còn là vấn đề nữa, vì bạn đã trích xuất đủ mã vào các thành phần bạn muốn sử dụng lại mà không cần kế thừa.

Nếu bạn không chắc bắt đầu từ đâu, vì bạn không biết liệu tái cấu trúc sẽ trở nên đơn giản, đôi khi cách tiếp cận tốt nhất là thực hiện một số tái cấu trúc đầu .

Tất nhiên, tình hình thực tế của bạn có thể phức tạp hơn. Vì vậy, học hỏi, thu thập kinh nghiệm và kiên nhẫn, để có được quyền này phải mất nhiều năm. Có hai cuốn sách tôi có thể giới thiệu ở đây, có thể bạn thấy chúng hữu ích:

  • Tái cấu trúc bởi Fowler: mô tả một danh mục đầy đủ các phép tái cấu trúc rất nhỏ .

  • Làm việc hiệu quả với mã kế thừa của Feathers: đưa ra lời khuyên tuyệt vời về cách xử lý các khối lớn mã được thiết kế xấu và làm cho nó dễ kiểm tra hơn trong các bước nhỏ hơn


1
Điều này cũng rất hữu ích. Tái cấu trúc từng bước nhỏ hoặc tái cấu trúc là một ý tưởng hay vì sau đó nó trở thành thứ có thể hoàn thành dần dần cùng với các công việc khác mà không cản trở nó quá nhiều. Tôi ước tôi có thể phê duyệt nhiều câu trả lời!
Jonathan

1

Đôi khi hai nguyên tắc thiết kế tốt nhất là KISS * và YAGNI **. Đừng cảm thấy cần phải nhồi nhét mọi mẫu thiết kế đã biết vào một chương trình chỉ cần in "Xin chào thế giới!".

 * Keep It Simple, Stupid
 ** You Ain't Gonna Need It

Chỉnh sửa sau khi cập nhật câu hỏi (và phản ánh những gì Pieter B nói ở một mức độ nào đó):

Đôi khi bạn đưa ra một quyết định kiến ​​trúc sớm dẫn đến một thiết kế cụ thể dẫn đến tất cả các loại xấu xí khi bạn cố gắng thực hiện nó. Thật không may, tại thời điểm đó, giải pháp "thích hợp" là lùi lại và tìm ra cách bạn đến vị trí đó. Nếu bạn chưa thể xem câu trả lời, hãy tiếp tục lùi lại cho đến khi bạn làm được.

Nhưng nếu công việc để làm điều đó sẽ vượt quá tỷ lệ, thì cần phải có một quyết định thực tế là chỉ đưa ra cách giải quyết ít xấu xí nhất cho vấn đề.


Tôi đã xóa một số điều này trong bản chỉnh sửa, nhưng nói chung tôi đang đề cập chính xác những vấn đề đó không có giải pháp đơn giản nào có sẵn.
Jonathan

À đúng rồi, dường như có một sự đồng thuận đang nổi lên về việc lùi lại và đánh giá lại vấn đề. Đây là một ý tưởng tốt.
Jonathan

1

Khi tôi ở trong tình huống này, điều đầu tiên tôi làm là dừng lại. Tôi chuyển sang một vấn đề khác và giải quyết nó trong một thời gian. Có thể một giờ, có thể một ngày, có thể nhiều hơn. Đó không phải lúc nào cũng là một lựa chọn, nhưng tiềm thức của tôi sẽ hoạt động trên mọi thứ trong khi bộ não có ý thức của tôi làm việc gì đó hiệu quả hơn. Cuối cùng, tôi trở lại với nó bằng đôi mắt mới và thử lại.

Một điều tôi làm là hỏi ai đó thông minh hơn tôi. Điều này có thể ở dạng hỏi trên Stack Exchange, đọc một bài viết trên web về chủ đề này hoặc hỏi một đồng nghiệp có nhiều kinh nghiệm trong lĩnh vực này. Thông thường phương pháp mà tôi nghĩ là phương pháp đúng hóa ra lại hoàn toàn sai đối với những gì tôi đang cố gắng thực hiện. Tôi đã nhầm lẫn một số khía cạnh của vấn đề và nó không thực sự phù hợp với mô hình mà tôi nghĩ nó xảy ra. Khi điều đó xảy ra, việc người khác nói: "Bạn biết đấy, điều này trông giống như ..." có thể là một trợ giúp lớn.

Liên quan đến những điều trên là thiết kế hoặc gỡ lỗi bằng cách tỏ tình. Bạn đến gặp một đồng nghiệp và nói: "Tôi sẽ kể cho bạn vấn đề tôi đang gặp phải, và sau đó tôi sẽ giải thích cho bạn những giải pháp mà tôi có. Bạn chỉ ra những vấn đề trong mỗi cách tiếp cận và đề xuất những cách tiếp cận khác . " Thông thường trước khi người khác nói, như tôi đang giải thích, tôi bắt đầu nhận ra rằng một con đường có vẻ ngang bằng với người khác thực sự tốt hơn hoặc tồi tệ hơn tôi nghĩ ban đầu. Cuộc trò chuyện kết quả có thể củng cố nhận thức đó hoặc chỉ ra những điều mới mà tôi không nghĩ tới.

Vì vậy, TL; DR: Hãy nghỉ ngơi, đừng ép buộc, hãy yêu cầu giúp đỡ.

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.