Có bất kỳ nhược điểm đáng kể nào phụ thuộc vào sự trừu tượng?


9

Tôi đã đọc wiki này về Nguyên tắc Trừu tượng Ổn định (SAP) .

SAP tuyên bố rằng gói càng ổn định thì càng trừu tượng. Điều này ngụ ý rằng nếu một gói kém ổn định hơn (có nhiều khả năng thay đổi) thì nó sẽ cụ thể hơn. Điều tôi không thực sự hiểu là tại sao điều này nên xảy ra. Chắc chắn trong mọi trường hợp bất kể sự ổn định, chúng ta nên phụ thuộc vào sự trừu tượng và che giấu việc thực hiện cụ thể?


Hãy thử sử dụng một thành phần mà bạn cảm thấy thoải mái, bằng cách không sử dụng các tóm tắt mà nó cung cấp, nhưng thực hiện mọi thứ chi tiết đầy đủ ở một mức thấp hơn mức bạn đã từng sử dụng. Điều đó sẽ cho bạn một ấn tượng khá tốt về những lợi thế và bất lợi của sự trừu tượng.
Kilian Foth

2
Bạn đã đọc bài viết được liên kết và / hoặc cuốn sách mà bài báo dựa trên?
Jörg W Mittag

1
+1 Câu hỏi hay, đặc biệt là vì tôi không nghĩ rằng mối quan hệ giữa sự ổn định và trừu tượng là trực quan ngay lập tức. Trang 11 của bài viết này giúp, ví dụ của nó về trường hợp trừu tượng có ý nghĩa, nhưng có lẽ ai đó có thể viết một ví dụ rõ ràng hơn về trường hợp cụ thể. Yêu cầu cất cánh giữ.
Mike hỗ trợ Monica

Bạn đang xử lý vấn đề gì với những trừu tượng này? Như đã lưu ý trên C2: "Trong việc mô hình hóa các lĩnh vực trong thế giới thực - thế giới của khách hàng, nhân viên, hóa đơn, hóa đơn vật liệu, sản phẩm, SKU, tiền lương, v.v. - có thể khó tìm thấy sự trừu tượng ổn định. thế giới của ngăn xếp, hàng đợi, chức năng, cây, quy trình, chủ đề, vật dụng đồ họa, báo cáo, biểu mẫu, v.v. - có nhiều khả năng ổn định hơn. " và "Trong một số lĩnh vực, sự trừu tượng ổn định rất khó xảy ra." Không biết bạn đang cố gắng giải quyết vấn đề gì với SAP, thật khó để đưa ra câu trả lời hay.

@ JörgWMittag và Mike - Vâng tôi đã đọc bài viết. Tôi chỉ cảm thấy thiếu một lời giải thích về lý do tại sao "các gói không ổn định nên cụ thể". Trên trang 13 của bài báo đã nói, ông cho thấy một biểu đồ nhưng không thực sự tiếp tục giải thích quá chi tiết tại sao (1,1) trên biểu đồ nên tránh? Là ý tưởng về cơ bản không ổn định có nghĩa là phụ thuộc ít liên kết hơn và không có nhu cầu sử dụng trừu tượng? Nếu vậy ... có phải là không nên sử dụng trừu tượng hay không, chỉ trong trường hợp độ ổn định thay đổi theo yêu cầu thay đổi ..
SteveCallender

Câu trả lời:


7

Hãy suy nghĩ về các gói của bạn như là một API, lấy ví dụ từ giấy, hãy định nghĩa về Readervới string Reader.Read()Writervới void Writer.Write(string)như API trừu tượng của bạn.

Sau đó, bạn có thể tạo một lớp Copyvới một phương thức Copier.Copy(Reader, Writer)và việc thực hiện Writer.Write(Reader.Read())và có thể một số kiểm tra độ tỉnh táo.

Bây giờ, bạn thực hiện triển khai cụ thể, ví dụ như FileReader, FileWriter, KeyboardReaderDownloadThingsFromTheInternetReader.

Điều gì nếu bạn muốn thay đổi việc thực hiện của bạn FileReader? Không có vấn đề, chỉ cần thay đổi lớp và biên dịch lại.

Điều gì nếu bạn muốn thay đổi định nghĩa về sự trừu tượng của bạn Reader? Rất tiếc, bạn không thể chỉ thay đổi điều đó, nhưng bạn cũng sẽ phải thay đổi Copier, FileReader, KeyboardReaderDownloadThingsFromTheInternetReader.

Đây là lý do đằng sau Nguyên tắc trừu tượng ổn định: Làm cho việc cụ thể hóa của bạn kém ổn định hơn so với trừu tượng.


1
Tôi đồng ý với tất cả những gì bạn nói, nhưng tôi tin rằng định nghĩa của tác giả về sự ổn định và của bạn khác nhau. Bạn coi sự ổn định là cần phải thay đổi, tác giả nói "sự ổn định không phải là thước đo khả năng mô-đun sẽ thay đổi; thay vào đó là thước đo về khó khăn trong việc thay đổi mô-đun." Vì vậy, câu hỏi của tôi là nhiều hơn tại sao nó có lợi cho các gói dễ dàng thay đổi để cụ thể hơn là trừu tượng?
SteveCallender

1
@SteveCallender Đó là sự khác biệt tinh tế: Định nghĩa "ổn định" của tác giả là cái mà hầu hết mọi người gọi là "cần sự ổn định", càng nhiều mô-đun phụ thuộc vào một mô-đun, mô-đun càng "ổn định".
Residuum 10/11/2015

6

YAGNI .

Nếu bạn hiện chỉ có một cách thực hiện một điều , tại sao phải bận tâm với một lớp bổ sung và vô dụng? Nó sẽ chỉ dẫn đến sự phức tạp không cần thiết. Thậm chí tệ hơn, đôi khi bạn cung cấp một suy nghĩ trừu tượng cho đến ngày việc thực hiện thứ hai sẽ đến ... và ngày này không bao giờ xảy ra. Thật là một sự lãng phí công việc!

Tôi cũng nghĩ rằng câu hỏi thực sự cần đặt ra không phải là "Tôi có cần phải phụ thuộc vào sự trừu tượng không?" mà là "Tôi có cần mô đun hóa không?". Và mô-đun không phải lúc nào cũng cần thiết, xem bên dưới.

Trong công ty tôi đang làm việc, một số phần mềm tôi phát triển gắn chặt với một số thiết bị phần cứng mà nó phải giao tiếp. Các thiết bị này được phát triển để thực hiện các mục tiêu rất cụ thể và là tất cả mọi thứ trừ mô-đun. :-) Khi thiết bị được sản xuất đầu tiên đi ra khỏi nhà máy và được cài đặt ở đâu đó, cả firmware và phần cứng của nó có thể không bao giờ thay đổi, bao giờ hết .

Vì vậy, tôi có thể chắc chắn rằng một số phần của phần mềm sẽ không bao giờ phát triển. Các phần này không cần phụ thuộc vào trừu tượng vì nó chỉ tồn tại một lần thực hiện và phần này sẽ không bao giờ thay đổi. Khai báo trừu tượng trên các phần mã này sẽ chỉ gây nhầm lẫn cho mọi người và mất nhiều thời gian hơn (mà không tạo ra bất kỳ giá trị nào).


1
Tôi có xu hướng đồng ý với YAGNI, nhưng tôi tự hỏi về ví dụ của bạn. Bạn không bao giờ lặp lại bất kỳ mã trong các thiết bị khác nhau? Tôi thấy khó tin rằng không có một số mã phổ biến trên các thiết bị từ cùng một công ty. Ngoài ra, làm thế nào để khách hàng thích khi bạn không sửa lỗi trong phần sụn của họ? Bạn đang nói không bao giờ có lỗi, bao giờ ? Nếu bạn có cùng một mã lỗi trong 4 lần triển khai khác nhau, bạn phải sửa lỗi 4 lần nếu nó không nằm trong một mô-đun chung.
Fuhrmanator

1
Mã chung @Fuhrmanator khác với trừu tượng. Mã thông thường chỉ có thể có nghĩa là một phương thức trợ giúp hoặc thư viện - không cần trừu tượng hóa.
Eilon

@Fuhrmanator Tất nhiên chúng ta có mã chung trong các thư viện, nhưng như Eilon đã nói, không phải mọi thứ đều phụ thuộc vào sự trừu tượng (tuy nhiên một số phần làm). Tôi chưa bao giờ nói không bao giờ có lỗi, tôi nói rằng chúng không thể được vá (vì những lý do nằm ngoài phạm vi câu hỏi của OP).
Phát hiện

@Eilon bình luận của tôi là về tính mô đun không phải lúc nào cũng cần thiết (không trừu tượng).
Fuhrmanator

@ Phát hiện Không có vấn đề về việc không thể vá. Nó chỉ là một ví dụ khá cụ thể và không phải là điển hình của hầu hết các phần mềm.
Fuhrmanator

6

Tôi nghĩ có lẽ bạn đang bối rối bởi từ ổn định được chọn bởi Robert Martin. Đây là nơi tôi nghĩ rằng sự nhầm lẫn bắt đầu:

Điều này ngụ ý rằng nếu một gói kém ổn định hơn (có nhiều khả năng thay đổi) thì nó sẽ cụ thể hơn.

Nếu bạn đọc qua bài viết gốc , bạn sẽ thấy (nhấn mạnh của tôi):

Định nghĩa cổ điển về sự ổn định của từ là: Không dễ dàng di chuyển. Đây là định nghĩa mà chúng tôi sẽ sử dụng trong bài viết này. Đó là, sự ổn định không phải là thước đo khả năng mô-đun sẽ thay đổi; đúng hơn nó là thước đo cho sự khó khăn trong việc thay đổi một mô-đun .

Rõ ràng, các mô-đun khó thay đổi hơn, sẽ ít biến động hơn. Mô-đun càng khó thay đổi, tức là càng ổn định, nó sẽ càng ít biến động.

Tôi luôn phải vật lộn với sự lựa chọn từ ổn định của tác giả , vì tôi (như bạn) có xu hướng nghĩ về khía cạnh "khả năng" của sự ổn định, nghĩa là không có khả năng thay đổi . Khó khăn ngụ ý rằng việc thay đổi mô-đun đó sẽ phá vỡ rất nhiều mô-đun khác và sẽ rất nhiều công việc để sửa mã.

Martin cũng sử dụng các từ độc lập và có trách nhiệm , mà theo tôi truyền đạt nhiều ý nghĩa hơn. Trong hội thảo đào tạo của mình, ông đã sử dụng một phép ẩn dụ về cha mẹ của những đứa trẻ lớn lên và cách chúng nên "có trách nhiệm", vì con cái của chúng phụ thuộc vào chúng. Ly hôn, thất nghiệp, giam giữ, v.v. là những ví dụ thực tế tuyệt vời về tác động tiêu cực mà sự thay đổi của cha mẹ sẽ gây ra cho con cái. Vì vậy, cha mẹ nên "ổn định" vì lợi ích của con cái họ. Nhân tiện, phép ẩn dụ này của trẻ em / cha mẹ không nhất thiết liên quan đến thừa kế trong OOP!

Vì vậy, theo tinh thần "có trách nhiệm", tôi đã đưa ra ý nghĩa thay thế cho việc khó thay đổi (hoặc không nên thay đổi ):

  • Nghĩa vụ - có nghĩa là các lớp khác phụ thuộc vào lớp này vì vậy nó không nên thay đổi.
  • Này - ibid.
  • Ràng buộc - nghĩa vụ của lớp này giới hạn cơ sở của nó trong việc thay đổi.

Vì vậy, cắm các định nghĩa này vào tuyên bố

gói càng ổn định thì càng trừu tượng

  • gói càng bắt buộc thì càng trừu tượng
  • càng chịu ơn một gói các trừu tượng hơn nó phải được
  • gói càng bị ràng buộc thì càng trừu tượng

Hãy trích dẫn Nguyên tắc trừu tượng ổn định (SAP), nhấn mạnh các từ khó hiểu ổn định / không ổn định:

Các gói ổn định tối đa nên trừu tượng tối đa. Gói không ổn định nên được bê tông. Tính trừu tượng của một gói nên tỷ lệ thuận với tính ổn định của nó .

Làm rõ nó mà không có những từ khó hiểu:

Các gói được tối đa hóa đến các phần khác của hệ thống nên được trừu tượng hóa tối đa. Các gói có thể thay đổi mà không gặp khó khăn nên được cụ thể. Tính trừu tượng của một gói nên tỷ lệ thuận với mức độ khó sửa đổi .

TL; DR

Tiêu đề của câu hỏi của bạn hỏi:

Có bất kỳ nhược điểm đáng kể nào phụ thuộc vào sự trừu tượng?

Tôi nghĩ rằng nếu bạn tạo ra sự trừu tượng đúng cách (ví dụ: chúng tồn tại bởi vì rất nhiều mã phụ thuộc vào chúng), thì sẽ không có bất kỳ nhược điểm đáng kể nào.


0

Điều này ngụ ý rằng nếu một gói kém ổn định hơn (có nhiều khả năng thay đổi) thì nó sẽ cụ thể hơn. Những gì tôi không thực sự hiểu là tại sao điều này nên là trường hợp.

Trừu tượng là những thứ khó thay đổi trong phần mềm vì mọi thứ đều phụ thuộc vào chúng. Nếu gói của bạn sẽ thay đổi thường xuyên và nó cung cấp sự trừu tượng, những người phụ thuộc vào nó sẽ bị buộc phải viết lại một bó lớn mã của họ khi bạn thay đổi thứ gì đó. Nhưng nếu gói không ổn định của bạn cung cấp một số triển khai cụ thể, mã ít hơn nhiều sẽ phải được viết lại sau khi thay đổi.

Vì vậy, nếu gói của bạn sẽ thay đổi thường xuyên, tốt hơn nên cung cấp bê tông hóa, không trừu tượng hóa. Nếu không ... ai sẽ sử dụng nó? ;)


0

Hãy ghi nhớ số liệu ổn định của Martin và ý nghĩa của "tính ổn định":

Instability = Ce / (Ca+Ce)

Hoặc là:

Instability = Outgoing / (Incoming+Outgoing)

Đó là, một gói được coi là hoàn toàn không ổn định nếu tất cả các phụ thuộc của nó là đi: nó sử dụng những thứ khác, nhưng không có gì sử dụng nó. Trong trường hợp đó, nó chỉ có ý nghĩa cho điều đó là cụ thể. Đây cũng sẽ là loại mã dễ thay đổi nhất vì không có gì khác sử dụng nó, và do đó không có gì khác có thể phá vỡ nếu mã đó được sửa đổi.

Trong khi đó, khi bạn có kịch bản ngược lại về sự "ổn định" hoàn toàn với một gói được sử dụng bởi một hoặc nhiều thứ nhưng nó không sử dụng bất cứ thứ gì, như gói trung tâm được sử dụng bởi phần mềm, đó là khi Martin nói điều này nên trừu tượng. Điều đó cũng được củng cố bởi phần DIP của SOLI (D), Nguyên tắc đảo ngược phụ thuộc, về cơ bản nói rằng các phụ thuộc phải thống nhất chảy theo hướng trừu tượng cho cả mã cấp thấp và cấp cao.

Đó là, các phụ thuộc phải thống nhất theo hướng "ổn định", và chính xác hơn, các phụ thuộc sẽ chảy vào các gói có nhiều phụ thuộc đến hơn phụ thuộc đi và hơn nữa, các phụ thuộc sẽ chảy theo trừu tượng. Điểm chính của lý do đằng sau đó là sự trừu tượng cung cấp phòng thở để thay thế một kiểu con cho một kiểu con khác, mang lại mức độ linh hoạt cho các bộ phận cụ thể thực hiện giao diện để thay đổi mà không phá vỡ các phụ thuộc đến giao diện trừu tượng đó.

Có bất kỳ nhược điểm đáng kể nào phụ thuộc vào sự trừu tượng?

Chà, tôi thực sự không đồng ý với Martin ở đây cho tên miền của tôi ít nhất, và ở đây tôi cần đưa ra một định nghĩa mới về "sự ổn định" như trong "thiếu lý do để thay đổi". Trong trường hợp đó tôi sẽ nói rằng các phụ thuộc sẽ chuyển sang ổn định, nhưng các giao diện trừu tượng không giúp ích gì nếu các giao diện trừu tượng không ổn định (theo định nghĩa của tôi về "không ổn định", như dễ bị thay đổi nhiều lần, không phải của Martin). Nếu các nhà phát triển không thể sửa lỗi trừu tượng và khách hàng liên tục thay đổi ý định theo cách khiến các nỗ lực trừu tượng mô hình hóa phần mềm không hoàn chỉnh hoặc không hiệu quả, thì chúng tôi không còn được hưởng lợi từ tính linh hoạt nâng cao của giao diện trừu tượng để bảo vệ hệ thống chống lại các thay đổi phá vỡ phụ thuộc theo tầng. . Trong trường hợp cá nhân của tôi, tôi đã tìm thấy các công cụ ECS, chẳng hạn như các công cụ được tìm thấy trong các trò chơi AAA,cụ thể nhất : hướng tới dữ liệu thô, nhưng dữ liệu đó rất ổn định (như trong "không bao giờ cần phải thay đổi"). Tôi thường thấy xác suất của một cái gì đó đòi hỏi những thay đổi trong tương lai là một số liệu hữu ích hơn so với tỷ lệ của hiệu ứng trên tổng số khớp nối trong các quyết định SE hướng dẫn.

Vì vậy, tôi sẽ thay đổi DIP một chút và chỉ nói, "các phụ thuộc sẽ chảy vào các thành phần có xác suất yêu cầu thay đổi thấp nhất", bất kể các thành phần đó là giao diện trừu tượng hay dữ liệu thô. Tất cả những gì quan trọng với tôi là xác suất mà họ có thể yêu cầu thay đổi thiết kế trực tiếp. Trừu tượng chỉ hữu ích trong bối cảnh ổn định này nếu một cái gì đó, bằng cách trừu tượng, làm giảm xác suất đó.

Đối với nhiều bối cảnh có thể là trường hợp với các kỹ sư và khách hàng tử tế, những người dự đoán được nhu cầu của phần mềm trả trước và thiết kế trừu tượng (như không thay đổi), trong khi những tóm tắt đó cung cấp cho họ tất cả các phòng thở mà họ cần để trao đổi các triển khai cụ thể. Nhưng trong một số lĩnh vực, các tóm tắt có thể không ổn định và dễ bị thiếu, trong khi dữ liệu cần thiết của động cơ có thể dễ dàng hơn nhiều để dự đoán và ổn định trước. Vì vậy, trong những trường hợp đó, nó thực sự có thể có lợi hơn từ quan điểm duy trì (dễ dàng thay đổi và mở rộng hệ thống) cho các phụ thuộc để chuyển sang dữ liệu thay vì trừu tượng hóa. Trong ECS, các bộ phận không ổn định nhất (như trong các bộ phận thường xuyên thay đổi nhất) thường là chức năng cư trú trong các hệ thống (PhysicsSystem, ví dụ), trong khi các phần ổn định nhất (ít có khả năng thay đổi nhất) là các thành phần chỉ bao gồm dữ liệu thô ( MotionComponentví dụ) mà tất cả các hệ thống sử dụng.

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.