Có ổn không khi có mùi mã nếu nó thừa nhận một giải pháp dễ dàng hơn cho vấn đề khác? [đóng cửa]


31

Một nhóm bạn và tôi đã làm việc trong một dự án trong thời gian vừa qua và chúng tôi muốn phát minh ra một cách OOP đẹp để thể hiện một kịch bản cụ thể cho sản phẩm của chúng tôi. Về cơ bản, chúng tôi đang làm việc trong một trò chơi địa ngục đạn kiểu Touhou và chúng tôi muốn tạo ra một hệ thống nơi chúng tôi có thể dễ dàng thể hiện bất kỳ hành vi có thể nào của viên đạn mà chúng tôi có thể mơ thấy.

Vì vậy, đó chính xác là những gì chúng tôi đã làm; chúng tôi đã tạo ra một kiến ​​trúc thực sự tao nhã cho phép chúng tôi phân chia hành vi của viên đạn thành các thành phần khác nhau có thể được gắn vào các trường hợp viên đạn theo ý muốn, giống như hệ thống thành phần của Unity . Nó hoạt động độc đáo, nó dễ dàng mở rộng, nó linh hoạt và bao phủ tất cả các căn cứ của chúng tôi, nhưng có một vấn đề nhỏ.

Ứng dụng của chúng tôi cũng liên quan đến một lượng lớn thế hệ thủ tục, cụ thể là chúng tôi tạo ra các hành vi của viên đạn. Tại sao điều này là một vấn đề? Chà, giải pháp OOP của chúng tôi để thể hiện hành vi viên đạn, trong khi thanh lịch, hơi phức tạp khi làm việc mà không có con người. Con người đủ thông minh để nghĩ ra giải pháp cho các vấn đề vừa logic vừa thông minh. Các thuật toán tạo thủ tục chưa thực sự thông minh và chúng tôi đã gặp khó khăn khi triển khai AI sử dụng kiến ​​trúc OOP của chúng tôi với tiềm năng tối đa của nó. Phải thừa nhận rằng, đó là một lỗ hổng của kiến ​​trúc là nó không trực quan trong mọi tình huống.

Vì vậy, để khắc phục vấn đề này, về cơ bản, chúng tôi đã chuyển tất cả các hành vi được cung cấp bởi các thành phần khác nhau vào lớp đạn, để mọi thứ chúng ta có thể tưởng tượng được cung cấp trực tiếp trong mỗi trường hợp đạn thay vì trong các trường hợp thành phần liên quan khác. Điều này làm cho các thuật toán tạo thủ tục của chúng ta dễ làm việc hơn một chút, nhưng bây giờ lớp đạn của chúng ta là một đối tượng thần khổng lồ . Nó dễ dàng là lớp lớn nhất trong chương trình cho đến nay với mã nhiều hơn năm lần so với bất kỳ thứ gì khác. Đó là một chút đau để duy trì là tốt.

Có ổn không khi một trong các lớp của chúng tôi biến thành một đối tượng thần, chỉ để làm cho nó dễ dàng hơn để làm việc với một vấn đề khác? Nói chung, có ổn không khi mã có mùi trong mã của bạn nếu nó thừa nhận một giải pháp dễ dàng hơn cho một vấn đề khác?


1
Chà ... điều này hơi khó trả lời. Theo tôi KHÔNG. Đặc biệt nếu bạn làm việc cùng với những người khác. Nếu bạn làm việc một mình bạn có thể làm bất cứ điều gì bạn muốn. Nhưng nói chung nó phụ thuộc vào người bạn làm việc với.
Khoai tây Sarcastic

13
"Nếu nó ngu ngốc, và nó hoạt động; nó không ngu ngốc." Điều đó đang được nói, bạn phải cân nhắc rằng ngay cả khi nó hoạt động chính xác như bạn muốn, dù bạn không tạo ra mã hóa trong tương lai trên lớp thần đó gần như không thể vì cách bạn quyết định sửa nó.
Flater

8
Tốt hơn là ngửi và biết bạn bốc mùi, sau đó chỉ ngửi người khác. :)
Phản ứng

1
Âm thanh như bạn cần một lớp bộ điều hợp cung cấp giao diện không OO cho mã thủ tục của bạn, vì vậy bạn có thể giữ phần còn lại của mã sạch (er).
nikie

1
Có vẻ như bạn xây dựng một hệ thống tuyệt vời và quyết định thổi bay tất cả vào địa ngục bây giờ nó không hoạt động như mong đợi trên một tính năng. Đó thực sự là những gì bạn muốn? Hãy tự hào về công việc của bạn!
Cột

Câu trả lời:


74

Khi xây dựng các chương trình trong thế giới thực, thường có sự đánh đổi giữa việc giữ thực dụng một mặt và mặt khác giữ sạch 100%. Nếu việc giữ sạch sẽ cấm bạn vận chuyển sản phẩm của bạn kịp thời, thì tốt hơn hết bạn nên dùng một ít băng keo để lấy đồ vật ra khỏi cửa.

Nói rằng, mô tả của bạn nghe có vẻ khác biệt - có vẻ như bạn sẽ không thêm một chút băng keo, có vẻ như bạn sẽ phá hỏng toàn bộ kiến ​​trúc của mình vì bạn không nhìn lâu và đủ cứng để có giải pháp tốt hơn. Vì vậy, thay vì tìm kiếm ai đó ở đây trên PSE, người ban phước cho bạn về điều này, tốt hơn bạn nên hỏi một câu hỏi khác trong đó bạn mô tả một số chi tiết về các vấn đề bạn gặp phải và xem ai đó có cho bạn ý tưởng tránh thần không cách tiếp cận lớp học.

Có lẽ lớp đạn có thể được thiết kế để mặt tiền cho một loạt các lớp khác, vì vậy lớp đạn trở nên nhỏ hơn. Có lẽ mô hình chiến lược có thể giúp để viên đạn có thể ủy thác các hành vi khác nhau cho các đối tượng chiến lược khác nhau. Có lẽ bạn chỉ cần một bộ chuyển đổi giữa thành phần viên đạn và trình tạo thủ tục của bạn. Nhưng thành thật mà nói, không biết thêm chi tiết về hệ thống của bạn, người ta chỉ có thể đoán xung quanh.


6
Chỉ cần xác nhận lại câu trả lời này, tôi sẽ viết một cái gì đó với hai khuyến nghị rất giống nhau. Về đoạn cuối, những gì OP mô tả dường như là một mùi mã trong chính nó chỉ ra rằng một mức độ gián tiếp khác là cần thiết. Cho dù đó là một lớp nhà máy tốt hơn, mặt tiền hay thậm chí là một DSL hoàn toàn mà AI có thể tạo ra đều thuộc về OP.
Daniel B

2
Đề xuất tốt về Mặt tiền / Chiến lược để chia mã thành các phần nhỏ hơn. Mặc dù không biết thêm chi tiết, thật khó để biết nên gợi ý điều gì.
user949300

25

Câu hỏi thú vị. Tôi hơi thiên vị mặc dù do những kinh nghiệm trước đây của tôi, điều đó khiến tôi phải trả lời bằng số.

Câu trả lời ngắn gọn: Chúng tôi không bao giờ ngừng học hỏi. Khi bạn va vào một bức tường như thế, đó là cơ hội để cải thiện kỹ năng thiết kế / kiến ​​trúc của bạn, không phải là một cái cớ để thêm mùi mã.

Phiên bản dài hơn là tôi đã được hỏi những câu hỏi tương tự rất nhiều lần trong các dự án của tôi tại nơi làm việc, nhưng chắc chắn, cuối cùng chúng tôi đã thảo luận về vấn đề này sâu hơn, sau đó người hỏi ban đầu đã cho nó tín dụng. Bạn muốn bao gồm các tinh thần như phân tích nguyên nhân gốc rễ với điều đó.

Tôi tìm thấy 5 Whys đặc biệt hữu ích. Giải thích của bạn ở đây đọc giống như đầu tiên tại sao:

  • "Chúng ta có lớp thần này ngay bây giờ" Tại sao?
  • "Bởi vì nó đơn giản hóa thuật toán tạo thủ tục"

Chính xác thì nó được đơn giản hóa là gì? Và tại sao lại như vậy? Tiếp tục đi theo hướng đó và điều thường xảy ra là bạn bắt đầu nhận ra cách giải quyết các vấn đề cơ bản hơn, nhưng đồng thời, chúng cũng cho phép bạn giải pháp cơ bản hơn.

Câu chuyện dài, sau khi suy nghĩ sâu hơn về vấn đề hiện tại và đặc biệt là nguyên nhân của nó, theo kinh nghiệm của tôi, câu hỏi ban đầu cuối cùng bị vô hiệu và hoàn toàn không gây hứng thú cho tất cả những người tham gia. Nếu bạn có nghi ngờ, hãy thách thức họ và họ sẽ biến mất, hoặc bạn sẽ biết bạn phải làm gì. Tâm trí bạn, đó là một dấu hiệu tốt trong quan điểm của tôi để có những nghi ngờ về mã / thiết kế. Những người khác gọi đó là cảm giác ruột thịt, nhưng để thách thức những vấn đề này, trước tiên bạn phải nhận ra chúng. Vì bạn đã thực hiện bước đầu tiên đó, xin chúc mừng! Bây giờ đi xuống lỗ thỏ ...


9

Có một lớp thần như thế này là không bao giờ mong muốn, vì điều đó không chỉ có nghĩa là những viên đạn của bạn bây giờ là những vật thể nguyên khối, mà điều tương tự cũng xảy ra với thuật toán tạo thủ tục của bạn.

Bước đầu tiên sẽ là phân tích, tại sao chính xác AI của bạn lại gặp quá nhiều khó khăn khi xử lý sự phức tạp của mô hình của bạn?

Bạn, tình cờ, đã cố gắng biến AI của bạn thành một đối tượng lớp thần, nhận thức đầy đủ về ngữ nghĩa của mọi thuộc tính có thể? Nếu bạn đã làm, đó là nơi vấn đề bắt nguồn.

Giải pháp sau đó sẽ không phải là tích hợp tất cả các chiến lược vào chính lớp đạn, mà thay vào đó, giảm tải gợi ý cho AI từ lõi AI sang chính việc thực hiện chiến lược.

Điều đó sẽ mang lại cho bạn sự linh hoạt mà bạn mong muốn ban đầu, bao gồm tùy chọn mở rộng hệ thống theo các chiến lược mới như bạn muốn mà không sợ gặp phải các tác dụng phụ với các hành vi kế thừa.

Thay vào đó, bây giờ bạn có tất cả các vấn đề liên quan đến các đối tượng của thần: Không chỉ bản thân lớp thần của bạn là một thứ khó hiểu, khó gỡ lỗi, nhưng điều tương tự cũng xảy ra với tất cả các thành phần khác truy cập vào một lớp thần như vậy. Do thiếu tính trừu tượng, AI của bạn hiện đang bị ràng buộc biến thành một sự gớm ghiếc có độ phức tạp tương tự vì nó phải nhận thức được tất cả các thuộc tính riêng lẻ, dư thừa hiện nay.

Ngay cả bây giờ, bạn đã gặp vấn đề với bảo trì. Những vấn đề này đang trở nên tồi tệ hơn, đặc biệt là ngay khi bạn thả lỏng các thành viên trong nhóm, những người vẫn có một mô hình nhận thức về cách thức hoạt động của lớp đó.

Cho đến nay, mọi dự án tôi gặp phải sử dụng các lớp thần hoặc chức năng thần như vậy đều được viết lại hoàn toàn từ đầu hoặc dừng lại, không có ngoại lệ.


Một điều thường bị thiếu trong các cuộc thảo luận về mức độ lớn hay phức tạp của các lớp nên là sự khác biệt giữa "bao nhiêu mã nên chứa tham chiếu của loại X có thể làm được với nó" so với "nhiều logic nên có trong tệp lớp X ". Nếu khách hàng có thể có các bộ sưu tập các đối tượng hỗ trợ nhiều khả năng khác nhau (ví dụ: "fnorble") và thường muốn yêu cầu tất cả các thành viên của bộ sưu tập ví dụ: "fnorble nếu có thể, thì không làm gì cả", sau đó có giao diện kết hợp nhiều phương pháp như vậy có thể hữu ích hơn nhiều so với việc cố gắng phân chia giao diện.
supercat

Với một giao diện như vậy, có thể có mã đóng gói các đối tượng với bất kỳ sự kết hợp các khả năng nào, mà không phải xử lý các kết hợp khác nhau một cách riêng biệt. Việc tách các giao diện sẽ khiến bạn cần phải viết nhiều lớp proxy khác nhau, vì các proxy cho một loại hỗ trợ phương thức X không thể được sử dụng để bọc các đối tượng không thể X và các proxy có thể bao bọc các đối tượng không thể X sẽ ' Không thể hiển thị phương thức X ngay cả khi nó đang bọc một đối tượng có thể hỗ trợ nó.
supercat

8

Tất cả các mã xấu kể từ buổi bình minh của thời gian có một câu chuyện đằng sau sự tiến hóa của nó làm cho nó trông hợp lý từng bước. Bạn cũng không ngoại lệ. Coders học bằng cách mã hóa. Có những khía cạnh của vấn đề của bạn mà bạn không thể lường trước được mà dường như rõ ràng bây giờ. Có những quyết định bạn đưa ra hoàn toàn hợp lý dần dần, nhưng đã khiến kiến ​​trúc của bạn đi sai hướng tổng thể. Bạn cần xác định và xem xét lại những quyết định đó.

Hỏi xung quanh văn phòng của bạn nếu mọi người có bất kỳ ý tưởng nào về cách khắc phục nó. Hầu hết các nơi tôi từng làm việc, khoảng 10-20% lập trình viên có sở trường thực sự cho loại việc đó, và chỉ chờ cơ hội. Tìm ra những người đó là ai. Thông thường, đó là những người thuê mới của bạn, những người không đầu tư lịch sử vào kiến ​​trúc hiện tại, những người có thể dễ dàng nhìn thấy các lựa chọn thay thế nhất. Ghép nối họ với một trong những cựu chiến binh của bạn và bạn có thể ngạc nhiên về những gì họ nghĩ ra cùng nhau.


2

Trong một số trường hợp điều này chắc chắn là chấp nhận được. Tuy nhiên, tôi thấy khó có thể tin rằng không có giải pháp tốt nào bằng cách sử dụng cả việc tạo thủ tục và kiến ​​trúc hành vi dựa trên thành phần / đính kèm đẹp của bạn. Nếu tất cả các hành vi chỉ cần kéo vào lớp đạn, không có sự khác biệt về chức năng giữa đối tượng thần và phiên bản kiến ​​trúc gọn gàng. Điều gì làm cho nó rất khó để các thuật toán tạo thủ tục của bạn sử dụng?

Tôi nghĩ rằng một câu hỏi mới (có thể ở đây, hoặc trên gamedev.stackexchange.com?), Nơi bạn phác thảo những vấn đề bạn gặp phải với kiến ​​trúc của mình kết hợp với Proc. gen., sẽ thực sự thú vị. Hãy cho chúng tôi biết ở đây nếu quá nếu bạn thực hiện một câu hỏi mới!


3
Bạn có thể cung cấp bất kỳ ví dụ nào cho tình huống có lớp thần sẽ vừa được chấp nhận vừa mong muốn trong khi lớp này không chỉ là phần tổng hợp tự động của các nguồn riêng lẻ?
Ext3h

Với sự chấp nhận được, tôi đã đề cập đến "Có ổn không khi có mùi mã nếu nó thừa nhận một giải pháp dễ dàng hơn cho vấn đề khác?" Các lớp học nói chung dễ dàng giải được bằng cách sử dụng thành phần. Nhưng vâng, có một số mùi mã nhất định mà chắc chắn không có giá trị luôn luôn bị loại bỏ 100%. Cuối cùng, một số người thực dụng là cần thiết để hoàn thành công việc :). (Điều này không có nghĩa là tôi nghĩ bạn nên từ bỏ những thực tiễn tốt nhất một cách bất chợt. Tôi tin rằng hầu hết các nhà phần mềm sẽ tốt hơn nếu tuân thủ các thực tiễn tốt nhất một cách nghiêm ngặt hơn).
Roy T.

0

Đối với cảm hứng, bạn có thể muốn có một cái nhìn về lập trình chức năng, hoặc chính xác hơn, các loại được thiết kế chặt chẽ. Ý tưởng là mọi thứ không hoạt động là không thể đại diện trong hệ thống loại bạn có sẵn. Ví dụ: giả sử bạn có một khẩu súng có các thành phần "bắn đạn" và "giữ đạn". Nếu chúng là hai thành phần riêng biệt, có cấu hình không có ý nghĩa - bạn có thể có một khẩu súng bắn đạn nhưng không có trong kho, hoặc súng lưu trữ đạn nhưng không bắn chúng.

Ở mức độ phức tạp này, bạn đang nghĩ "đúng, một con người sẽ nhận ra điều này là vô ích và tránh những sự kết hợp không thể". Một cách tốt hơn có thể là làm cho nó hoàn toàn không thể làm điều này. Ví dụ: thành phần "bắn đạn" có thể yêu cầu tham chiếu đến thành phần "giữ đạn" (hoặc chỉ giữ nó như một phần của chính nó, mặc dù điều đó có vấn đề riêng).

Mặc dù các ví dụ của bạn có thể phức tạp hơn rất nhiều, nhưng khóa vẫn giới hạn các kết hợp có thể, thêm các ràng buộc. Theo một cách nào đó, nếu nó quá phức tạp để tạo ra thủ tục, thì có lẽ nó quá phức tạp. Hãy suy nghĩ về tất cả các cách bạn tự kìm hãm bản thân khi thiết kế vũ khí - bạn có tự nói với mình "đúng không, khẩu súng này đã có súng phun lửa, không có lý do gì để thêm súng phóng lựu"? Đó là một cái gì đó bạn có thể kết hợp trong heuristic của bạn. Bạn có thể muốn sử dụng một cơ chế xác suất phức tạp hơn một chút so với việc chỉ có cơ hội cố định có từng thành phần - bạn có thể có các thành phần có xu hướng loại trừ nhau hoặc các thành phần có xu hướng hoạt động tốt với nhau.

Và cuối cùng, xem xét liệu nó thực sự là một vấn đề đủ lớn. Có phải nó phá hỏng sự thú vị của trò chơi? Là súng kết quả là vô dụng hoặc áp đảo? Bao nhiêu? Là một trong 10 điều vô lý? Các trò chơi như Borderlands (với các hiệu ứng vũ khí được tạo theo thủ tục) thường bỏ qua các kết hợp hiệu ứng vô nghĩa - điểm quan trọng của việc có một khẩu súng ngắn với phạm vi 16x là gì? Nhưng điều đó xảy ra rất thường xuyên ở Borderlands. Nó chỉ chơi để cười, thay vì bị coi là thất bại của các cơ chế thế hệ :)

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.