Giá trị trong việc ẩn các chi tiết thông qua trừu tượng là gì? Không có giá trị trong suốt?


30

Lý lịch

Tôi không phải là một fan hâm mộ lớn của sự trừu tượng. Tôi sẽ thừa nhận rằng người ta có thể hưởng lợi từ khả năng thích ứng, tính di động và khả năng sử dụng lại các giao diện, v.v. Có lợi ích thực sự ở đó, và tôi không muốn đặt câu hỏi đó, vì vậy hãy bỏ qua nó.

Có một "lợi ích" lớn khác của sự trừu tượng hóa, đó là che giấu logic thực hiện và chi tiết từ những người sử dụng sự trừu tượng hóa này. Lập luận là bạn không cần phải biết chi tiết và người ta nên tập trung vào logic của riêng họ vào thời điểm này. Làm cho ý nghĩa trong lý thuyết.

Tuy nhiên, bất cứ khi nào tôi duy trì các ứng dụng doanh nghiệp lớn, tôi luôn cần biết thêm chi tiết. Nó trở thành một rắc rối lớn đào sâu và sâu hơn vào sự trừu tượng ở mỗi lượt chỉ để tìm ra chính xác những gì làm gì; tức là phải thực hiện "khai báo mở" khoảng 12 lần trước khi tìm thủ tục lưu trữ được sử dụng.

Điều này 'che giấu tâm lý chi tiết' dường như chỉ cản trở. Tôi luôn mong muốn các giao diện minh bạch hơn và ít trừu tượng hơn. Tôi có thể đọc mã nguồn cấp cao và biết nó làm gì, nhưng tôi sẽ không bao giờ biết nó hoạt động như thế nào, khi nó hoạt động như thế nào, là điều tôi thực sự cần biết.

Những gì đang xảy ra ở đây? Có phải mọi hệ thống tôi từng làm việc chỉ được thiết kế tồi (ít nhất là từ quan điểm này)?

Triết lý của tôi

Khi tôi phát triển phần mềm, tôi cảm thấy như mình cố gắng tuân theo một triết lý mà tôi cảm thấy có liên quan mật thiết đến triết lý ArchLinux :

Arch Linux vẫn giữ được sự phức tạp vốn có của một hệ thống GNU / Linux, trong khi vẫn giữ cho chúng được tổ chức tốt và minh bạch. Các nhà phát triển và người dùng Arch Linux tin rằng việc cố gắng che giấu sự phức tạp của một hệ thống thực sự dẫn đến một hệ thống thậm chí phức tạp hơn, và do đó là điều cần tránh.

Và do đó, tôi không bao giờ cố gắng che giấu sự phức tạp của phần mềm của mình đằng sau các lớp trừu tượng. Tôi cố gắng lạm dụng sự trừu tượng, không trở thành nô lệ cho nó.

Câu hỏi tại tim

  1. Có giá trị thực sự trong việc che giấu các chi tiết?
  2. Không phải chúng ta đang hy sinh tính minh bạch sao?
  3. Sự minh bạch này có giá trị không?

7
Trừu tượng có thể bị lạm dụng ở dạng thiết kế xấu. Nhưng điều đó không có nghĩa là trừu tượng về nguyên tắc là không có giá trị.
Bernard

4
Tôi nghĩ rằng có một câu hỏi hay trong đó, tuy nhiên, nó đọc rất giống như một lời ca ngợi chống lại sự trừu tượng. Bạn có thể không nhấn mạnh điều đó và đưa ra câu hỏi thực tế của bạn nhiều hơn.
PersonalNexus

4
Bạn có chắc là bạn đang sử dụng định nghĩa đúng về "ẩn chi tiết" không? Trong bối cảnh này, đó là về việc giảm khớp nối , không phải là ngăn bạn học các hoạt động bên trong của một cái gì đó.
Andres F.

24
Trừ khi bạn muốn lập trình với một vôn kế và dao động tại bàn của bạn, bạn sẽ lập trình chống lại không có gì ngoài sự trừu tượng trên đầu trừu tượng trên đầu trừu tượng. Có giá trị nào cho bạn trong việc che giấu chi tiết rằng trên thực tế bạn đang thao túng không phải bit mà trên thực tế là điện áp? Làm như vậy hy sinh sự minh bạch? Sự minh bạch đó có giá trị không?
Eric Lippert

8
Tôi nghĩ rằng những gì bạn đang gặp vấn đề không phải là trừu tượng, đó là những lớp không xác định trống rỗng không thực sự trừu tượng. Vâng, những thứ đó thường được tìm thấy trong các hệ thống doanh nghiệp lớn và không, chúng không tốt.
Michael Borgwardt

Câu trả lời:


47

Lý do để ẩn các chi tiết không phải là để giữ các chi tiết ẩn; đó là để có thể sửa đổi việc thực hiện mà không vi phạm mã phụ thuộc.

Hãy tưởng tượng rằng bạn đã có một danh sách các đối tượng và mỗi đối tượng có một thuộc Nametính và dữ liệu khác. Và rất nhiều lần, bạn cần tìm một mục trong danh sách Namephù hợp với một chuỗi nhất định.

Cách rõ ràng là lặp qua từng mục một và kiểm tra xem có Namekhớp với chuỗi không. Nhưng nếu bạn thấy rằng việc đó mất quá nhiều thời gian, (như thể nếu bạn có vài nghìn mục trong danh sách,) bạn có thể muốn thay thế nó bằng tra cứu từ điển đối tượng chuỗi.

Bây giờ nếu tất cả các tra cứu của bạn đã được thực hiện bằng cách truy xuất danh sách và lặp lại nó, bạn đã có một số lượng lớn công việc phải làm để khắc phục điều này. Thậm chí còn khó khăn hơn nếu bạn ở trong thư viện và người dùng bên thứ ba đang sử dụng nó; bạn không thể ra ngoài và sửa mã của họ !

Nhưng nếu bạn có một FindByNamephương pháp để đóng gói quá trình tra cứu tên, bạn chỉ cần thay đổi cách thức triển khai và tất cả mã gọi nó sẽ tiếp tục hoạt động và nhanh hơn rất nhiều. Đó là giá trị thực sự của sự trừu tượng và đóng gói.


Tôi đồng ý với điều này, nhưng đây không phải là điểm của câu hỏi. Tôi hoàn toàn có thể đồng ý rằng một phương pháp để đóng gói chức năng cụ thể là hữu ích, nhưng tôi cảm thấy như đây không phải lúc nào cũng là động lực. Tôi có lầm không?
dùng606723

3
@ User606723: Nên như vậy. Điều đó không có nghĩa là nó luôn luôn . Một số người không hiểu vấn đề và họ chỉ chồng nhiều lớp lên trên nhiều lớp hơn và biến mọi thứ thành một mớ hỗn độn. Đây là lý do tại sao các lập trình viên có kinh nghiệm khuyên các nhà phát triển mới hơn không bao giờ áp dụng công nghệ hoặc kỹ thuật mới cho đến khi họ hiểu nó.
Mason Wheeler

3
@ user606723: Tính minh bạch khuyến khích khớp nối chặt chẽ, vì vậy trong khi có thể không phải lúc nào cũng xấu, nhưng thường là vậy.
Malfist

3
Vấn đề mà Mason mô tả, về việc mọi người chồng chất lên các lớp trong một hình thức lập trình sùng bái hàng hóa, là lý do tại sao tôi nghi ngờ về sự kế thừa quá nhiều và tại sao thành phần nên được ưu tiên hơn kế thừa. Có vẻ đặc biệt là một vấn đề đối với các lập trình viên Java.
jhocking

2
Không, khớp nối chặt chẽ không phải lúc nào cũng xấu. Nó thường rất tệ, nhưng sẽ rất lâu để tránh nó có thể gây ra các vấn đề thậm chí còn tồi tệ hơn, chẳng hạn như mã hóa mềm.
Mason Wheeler

16

Tôi vừa đọc xong phần trong Code Complete về sự trừu tượng, vì vậy đó là nơi hầu hết các nguồn này.

Điểm trừu tượng là loại bỏ nhu cầu hỏi "việc này được thực hiện như thế nào?". Khi bạn gọi user.get_id(), bạn biết rằng đó idlà những gì bạn sẽ nhận lại. Nếu bạn phải hỏi "làm thế nào để có được id người dùng?" sau đó bạn có thể không cần id, hoặc get_id()trả lại một cái gì đó bất ngờ và được thiết kế kém.

Bạn sử dụng sự trừu tượng để cho phép bạn thiết kế:

a house with doors and windows

không thiết kế

a box with four walls,
    with 3 holes,
        two of which fit panes of glass surrounded by wood frames,
        one that fits a large plank of wood with hinges and a metal knob,
etc.

Tôi không nói về những giao diện này. Các giao diện này là tốt. Tôi đang nói về các hệ thống phức tạp lớn được phân chia đằng sau nhiều trừu tượng khác nhau.
dùng606723

9
@ user606723 Sau đó, câu hỏi của bạn là về thiết kế overcomplex, thay vì trừu tượng hóa
Andres F.

3
+1 cho mã hoàn thành. Nó bao gồm cả lý do tại sao sự trừu tượng là cần thiết để thiết kế, và tại sao mức độ trừu tượng sai gây cản trở thiết kế. Để đưa ví dụ của bạn đi xa hơn, nếu tôi làm việc trong văn phòng phân vùng, tôi muốn nghĩ về những ngôi nhà của bạn, mà không cần phải tìm hiểu chi tiết. Nhưng nếu bạn nghĩ về những ngôi nhà theo cách tôi làm, thì bạn không thể xây dựng nó.
Spencer Rathbun

câu hỏi này nên được đóng lại hoặc tiêu đề đã thay đổi
Jake Berger

8

Có giá trị thực sự trong việc che giấu các chi tiết?

Vâng. Bằng cách trình bày trừu tượng, chúng ta có thể suy nghĩ và lập trình ở cấp độ cao hơn.

Tưởng tượng mô hình hệ thống vật lý mà không cần tính toán hoặc đại số ma trận. Nó hoàn toàn không thực tế. Tương tự, nếu chúng ta chỉ có thể lập trình ở cấp vô hướng, chúng ta sẽ không thể giải quyết các vấn đề thú vị. Ngay cả các ứng dụng web tương đối đơn giản cũng có thể hưởng lợi rất nhiều từ sự trừu tượng như libs thẻ. Việc chèn một thẻ có nghĩa là "các trường nhập địa chỉ" sẽ dễ dàng hơn nhiều so với việc liên tục tạo bốn trường văn bản và một hộp chọn. Và nếu bạn quyết định mở rộng ra nước ngoài, bạn chỉ có thể sửa đổi định nghĩa thẻ, thay vì sửa mọi hình thức để xử lý các địa chỉ quốc tế. Sử dụng hiệu quả sự trừu tượng là điều làm cho một số lập trình viên hiệu quả gấp mười lần những người khác.

Con người có một trí nhớ làm việc hạn chế. Trừu tượng cho phép chúng ta suy luận về các hệ thống lớn.

Aren't we sacrificing transparency?

Không. Nếu trừu tượng không được sử dụng, thì mục đích của một thành phần phần mềm sẽ bị chôn vùi trong các chi tiết lặp đi lặp lại. Các nhà phát triển dành cả ngày để lội qua mã như thế này:

for (i = 0; i < pilgrim.wives.size(); ++i) {
  wife = pilgrim.wives[i];
  for (j = 0; j < wife.sacks.size(); ++j) {
     sack = wife.sacks[i];
     for (k = 0; j < sack.cats.size(); ++j) {
        cat = sack.cats[k];
        for (m = 0; m < cat.kits.size(); ++m) {
           ++count;
        }
     }
  }
}

và suy nghĩ "ồ, có một vòng lặp bốn cấp khác trên bộ dụng cụ", thay vì nhìn thấy

pilgrim.kits.each { ++count; }

Sự minh bạch này có giá trị không?

Như bạn đã chỉ ra, có một chi phí cho sự gián tiếp. Không có điểm nào trong việc tạo các lớp "chỉ trong trường hợp". Sử dụng trừu tượng để giảm trùng lặp và làm rõ mã.


7

Khi mọi người nói rằng trừu tượng che giấu các chi tiết triển khai, họ thực sự không có nghĩa là "ẩn" theo nghĩa khó làm cho nó khó tìm. Ý nghĩa của chúng là các chi tiết triển khai riêng biệt từ giao diện công cộng, để giữ cho giao diện đơn giản, ngắn gọn và dễ quản lý. Giống như một chiếc xe "che giấu" hầu hết các bộ phận quan trọng của nó và chỉ cung cấp một bộ điều khiển khá thô sơ để vận hành chúng, một mô-đun phần mềm "ẩn" hầu hết các chức năng của nó nằm sâu trong ruột của nó và chỉ đưa ra một số phương thức truy cập hạn chế lái nó. Hãy tưởng tượng một chiếc xe mà bạn phải tự vận hành tất cả các bộ phận bên trong động cơ (và có rất nhiều thứ kỳ dị), bạn sẽ rất khó để theo dõi giao thông và tìm đường.

Nhưng giữ cho giao diện đơn giản không chỉ đơn thuần là một điều thẩm mỹ; nó có thể tạo ra sự khác biệt giữa một dự án thành công và Death March. Hãy chơi trò bênh vực của quỷ trong một phút; hãy tưởng tượng một dự án phần mềm mà không có bất kỳ trừu tượng nào cả. Nếu bạn cần giữ một giá trị xung quanh, bạn sử dụng biến toàn cục. Nếu bạn cần sử dụng chức năng nhiều lần, bạn sao chép-dán nó. Nếu bạn cần hai phiên bản khác nhau của một phần mã nhất định, bạn sao chép-dán, bọc nó trong một ifcâu lệnh và sửa đổi cả hai nhánh. Về mặt kỹ thuật, nó hoạt động, nhưng vài tháng sau, bạn sẽ chiến đấu với một vài vấn đề thực sự khó chịu:

  • Khi bạn tìm và sửa một lỗi, nó cũng có khả năng tồn tại trong các trường hợp được sao chép khác của mã tương tự, vì vậy, ngoài việc tìm và sửa lỗi, bạn cũng phải tìm kiếm các sự cố khác và cũng sửa chúng.
  • Để tìm lỗi hoặc thực hiện thay đổi, lập trình viên bảo trì phải có khả năng hiểu mã liên quan. Khó khăn trong việc này làm tăng theo kích thước của phần mã có liên quan, nhưng thậm chí nhiều hơn với phạm vi của nó. Giữ một nửa tá biến trong đầu trong khi tinh thần bước qua một số mã là có thể thực hiện được; nhưng nếu bạn có vài trăm trong số đó, năng suất của bạn bị ảnh hưởng nghiêm trọng (tôi muốn so sánh quá trình suy nghĩ với một chương trình hết RAM vật lý và phải nhúng vào hoán đổi: thay vì đọc trôi chảy mã trong một lần , lập trình viên phải nhảy qua nhảy lại để tìm kiếm mọi thứ).
  • Phạm vi của một đoạn mã cũng tác động đến kích thước của cơ sở mã phải tìm kiếm để tìm ra lỗi. Nếu bạn có hàm mười dòng với hai tham số và không có toàn cục và bạn biết các giá trị của đầu vào và dòng mà nó gặp sự cố, việc tìm lỗi thường không quan trọng và thường không yêu cầu gì nhiều hơn là nhìn vào mã. Nếu đó là vài trăm dòng, hai mươi tham số, mười lăm toàn cầu và gọi một vài chức năng khác có tính chất tương tự, bạn sẽ gặp phải một số đau đớn nghiêm trọng.
  • Nếu không có sự trừu tượng hóa thích hợp, bất kỳ thay đổi nào cũng có khả năng ảnh hưởng đến các phần lớn của cơ sở mã, vì thực tế mọi thứ có thể phụ thuộc vào mã được thay đổi. Một triệu chứng điển hình với các cơ sở mã như vậy là bạn thực hiện một thay đổi nhỏ, dường như vô hại và một tính năng hoàn toàn không liên quan đột nhiên bị phá vỡ. Với sự trừu tượng hóa, bạn có thể hạn chế mức độ thiệt hại mà một thay đổi có thể gây ra và bạn làm cho tác động trở nên dễ đoán hơn. Nếu bạn thay đổi tên của một trường riêng, bạn chỉ có một tệp nguồn để kiểm tra; nếu bạn thay đổi tên của một biến toàn cục, bạn cần chạy qua toàn bộ cơ sở mã.

Trong một cơ sở mã bị trừu tượng hóa kém, tác động thường tăng theo cấp số nhân với kích thước của cơ sở mã, nghĩa là thêm một lượng mã không đổi làm tăng nỗ lực bảo trì theo hệ số không đổi. Để làm cho vấn đề tồi tệ hơn, việc thêm nhiều lập trình viên vào một dự án không làm tăng năng suất một cách tuyến tính, nhưng tốt nhất là logarit (vì nhóm của bạn càng lớn, càng cần nhiều chi phí để giao tiếp).


2

Tôi nghĩ bạn nên hiểu làm thế nào nó hoạt động nếu cần thiết. Một khi bạn đã xác định nó làm những gì bạn nghĩ nó sẽ làm, thì bạn yên tâm. Tôi chưa bao giờ nghĩ mục tiêu là che giấu nó mãi mãi.

Khi bạn đặt báo thức trên đồng hồ mà bạn tự tin sẽ hoạt động, bạn có thể ngủ một chút khi biết nó sẽ tắt vào thời gian khắc phục. Thức dậy sớm một giờ chỉ để bạn có thể xem những giây trôi qua thật lãng phí.


1
Chắc chắn, nhưng tôi không thường được yêu cầu thay đổi cách thức hoạt động của đồng hồ báo thức hoặc người khác thay đổi cách đồng hồ báo thức của tôi hoạt động mà không được thông báo đầy đủ về các thay đổi.
dùng606723

1
Bạn có thấy các thay đổi mã cho mọi khung công tác bạn từng sử dụng không?
JeffO

1
không, nhưng tôi không duy trì thay đổi mã cho mọi khung công tác tôi từng sử dụng.
dùng606723

3
Bạn đã chứng minh khá nhiều quan điểm của JeffO: bạn cũng không kinh doanh trong việc duy trì đồng hồ báo thức. Nếu bạn mua một cái và bắt đầu sử dụng nó mà không thực hiện một phân tích đầy đủ và phân tích về cách thức hoạt động của nó, bạn đã chấp nhận rằng phần bên trong sẽ trừu tượng với bạn. Không có gì nói rằng bạn không thể xé nó ra để tìm hiểu làm thế nào nó hoạt động, nhưng bạn có thường xuyên thấy nó cần thiết không?
Blrfl

2

Để trả lời câu hỏi của bạn một cách cụ thể:

Có giá trị thực sự trong việc che giấu các chi tiết?

Vâng. Khi bạn thừa nhận trong dòng đầu tiên của câu hỏi của bạn.

Không phải chúng ta đang hy sinh tính minh bạch sao?

Không hẳn vậy. Một bản tóm tắt được viết tốt sẽ giúp bạn dễ dàng hiểu các chi tiết nếu cần.

Sự minh bạch này có giá trị không?

Vâng. Trừu tượng nên được thiết kế và thực hiện để giúp hiểu chi tiết dễ dàng khi cần / mong muốn.


Cuối cùng một câu trả lời tôi thích.
dùng606723

1

Tôi sẽ nói rằng việc ẩn các chi tiết là tuyệt vời khi những thứ ẩn đó hoạt động.

Chẳng hạn, giả sử chúng tôi phát triển một giao diện xác định các hành vi (ví dụ GetListItems, SendListItem), đó là hai tính năng được người dùng khởi tạo thông qua một số lần nhấp nút hoặc một cái gì đó .. NGAY BÂY GIỜ, mỗi người dùng có thể có "ListItemStore" của riêng họ. một người trên facebook, những người trên myspace .. (ví dụ) .. và nói rằng nó được lưu dưới dạng tài sản người dùng / cài đặt ở đâu đó trong ứng dụng thông qua các khung của người dùng .. và nói rằng các nhà phát triển ứng dụng có thể thêm ListItemStore trong quá trình thời gian (mybook, facespace, v.v.)

bây giờ có rất nhiều chi tiết trong việc kết nối với facebook và nhận chúng các mặt hàng .. và cũng có nhiều chi tiết như nhau khi kết nối với myspace .. v.v.

bây giờ, sau khi mã "truy cập cửa hàng" ban đầu được viết, có thể không cần sửa đổi (trong trường hợp facebook có lẽ chúng ta cần một nhà phát triển toàn thời gian để theo kịp các thay đổi, zing ..),

Vì vậy, khi bạn sử dụng mã, nó giống như:

    new ItemManager(user) //passes in user, allowing class to get all user properties
    ItemManager.GetListItems()

và bây giờ bạn đã có dữ liệu của Người dùng từ bất cứ nơi nào họ lưu trữ và vì tất cả những gì tôi lo lắng là lấy danh sách các mục và làm một cái gì đó với nó, và vì nó chỉ mất 2 dòng sẽ hoạt động cho dù thế nào nhiều cửa hàng khác được thêm vào tôi có thể quay lại trả lời / đăng câu hỏi lên stack ... lol ..

Vì vậy, tất cả các hệ thống ống nước để thực hiện điều đó là "ẩn" và ai thực sự quan tâm làm thế nào miễn là tôi có được danh sách chính xác các mặt hàng .. nếu bạn có bài kiểm tra đơn vị, thì bạn thậm chí có thể nghỉ ngơi dễ dàng hơn vì kết quả sẽ ' đã được định lượng rồi ..


Vâng, nhưng phần cần được duy trì không bao giờ là hai dòng đó. Những cái đó là không thể vít lên. Luôn luôn là cấp 2, 3, 4 mà bạn cần thay đổi. Tôi đồng ý rằng điều này thật tuyệt vời khi bạn có một API mà bạn có thể tin tưởng là ổn định , nhưng nếu nó không thể ổn định chỉ bởi sự phức tạp trong kinh doanh của bạn thì sao?
dùng606723

1
@ user606723 nếu API của bạn không ổn định, thì có khả năng là chưa trưởng thành hoặc nhiều khả năng là sự trừu tượng sai
sdg

@ user606723 - Điều đó đúng và trong các trường hợp đó, chính các quy ước đặt tên nên xác định một số dạng minh bạch ẩn logic / chi tiết lập trình thực tế .. và nếu bạn phải sửa đổi nguồn thực tế, các chi tiết & ý tưởng khác cần được thể hiện thông qua đặt tên thông tin Vì vậy, về bản chất, tính minh bạch có thể được thực hiện bằng cách đặt tên chính xác cho đến hết, tuy nhiên, chúng ta thực sự không cần phải đi xuống hết mức thường xuyên.
hanzolo

@sdg, hoặc vì các yêu cầu của hệ thống luôn thay đổi. Vì luật thay đổi, vì API của người khác thay đổi, nó nằm ngoài tầm kiểm soát của chúng tôi.
dùng606723

1
@ user606723 - Tôi thực sự làm việc trên một hệ thống SaaS tài chính và tôi thấy những cạm bẫy của việc không có đủ sự trừu tượng trong mỗi chu kỳ phát hành. một số trong đó là kết quả của thiết kế kém, nhưng thường thì đó là kết quả của việc đẩy mã ở nơi không được dự định ban đầu. Đi xuống chuỗi có thể đau đớn mà không có những bình luận, tên và đóng gói . nếu tất cả tôi phải làm là Remeasurements.GetRemeasureType (cấp), và sau đó reMeasure.PerformCalc (), đó sẽ là rất nhiều đẹp hơn vì thêm quá tải và đọc thông qua các chi nhánh logic khác nhau để đi đến việc tính toán thích hợp hoặc thêm một cái mới
hanzolo

1

Những gì bạn gọi là "Ẩn", nhiều người coi là một mối quan tâm riêng biệt (ví dụ: Triển khai so với Giao diện).

Theo tôi, một lợi ích chính của sự trừu tượng là làm giảm sự lộn xộn của các chi tiết không cần thiết từ không gian giới hạn của nhà phát triển.

Nếu mã thực thi bị xáo trộn, tôi có thể thấy rằng điều đó cản trở sự minh bạch, nhưng trừu tượng như tôi thấy, đó chỉ là một tổ chức tốt.


1

Trước hết, bất cứ điều gì ngoài một lệnh mã máy đơn về cơ bản là trừu tượng - while...dovòng lặp là một cách tượng trưng nhất quán để biểu diễn các so sánh và các cuộc gọi địa chỉ cần thiết để lặp lại một bộ hướng dẫn cho đến khi đạt được điều kiện. Tương tự, kiểu int là một sự trừu tượng hóa cho số bit X (tùy thuộc vào hệ thống của bạn). Lập trình là tất cả về trừu tượng.

Bạn có thể đồng ý rằng những trừu tượng nguyên thủy đó rất hữu ích. Vâng, như vậy là có thể xây dựng của riêng bạn. OOAD và OOP là tất cả về.

Giả sử bạn có một yêu cầu trong đó người dùng muốn có thể xuất dữ liệu từ màn hình theo nhiều định dạng: văn bản được phân tách, excel và pdf. Thật tiện lợi khi bạn có thể tạo một giao diện gọi là "Trình xuất" với phương thức xuất (dữ liệu), dựa vào đó bạn có thể xây dựng DeliatedTextExporter, ExcelExporter và PDFExporter, mỗi phương thức đều biết cách tạo đầu ra cụ thể của nó? Tất cả các chương trình gọi cần biết là nó có thể gọi phương thức xuất (dữ liệu) và bất kỳ thực hiện nào được sử dụng sẽ làm việc của nó. Hơn nữa, nếu các quy tắc văn bản được phân tách thay đổi, bạn có thể thay đổi DeliatedTextExporter mà không phải gặp rắc rối với ExcelExporter, có thể phá vỡ nó.

Khá nhiều tất cả các mẫu thiết kế nổi tiếng được sử dụng trong lập trình OO phụ thuộc vào sự trừu tượng hóa. Tôi khuyên bạn nên đọc các mẫu thiết kế đầu tiên của Freeman và Freeman để có cảm giác tốt hơn tại sao sự trừu tượng là một điều tốt


1
ngay cả mã máy cũng là một sự trừu tượng, có các quá trình thực tế, vật lý đang diễn ra bên dưới logic, ngay cả các thiết bị điện tử kỹ thuật số cũng là một sự trừu tượng đối với những gì thực sự xảy ra khi bất cứ ai đã tạo ra một con chip ép xung có thể làm chứng cho
jk.

Quá đúng, mặc dù có vẻ cụ thể hơn ở cấp độ chỉ dẫn máy.
Matthew Flynn

1

Tôi nghĩ rằng tôi hiểu cảm giác của bạn về điều này, và tôi nghĩ rằng tôi có một ý kiến ​​tương tự.

Tôi đã làm việc với các nhà phát triển Java, những người biến 50 dòng mã thành 3 lớp và 3 giao diện vì nó dễ hiểu. Và tôi không thể chịu đựng được.

Điều này cực kỳ khó hiểu, gần như không thể gỡ lỗi và không bao giờ cần phải "chuyển đổi việc thực hiện".

Mặt khác, tôi cũng đã thấy mã nơi nhiều đối tượng chia sẻ hành vi tương tự và được sử dụng ở một nơi và thực sự có thể sử dụng các vòng lặp sắp xếp / xử lý chung nếu các phương thức được đưa ra qua giao diện chung.

Vì vậy, IMHO, các đối tượng cốt lõi có khả năng được sử dụng trong các tình huống tương tự thường được hưởng lợi từ hành vi phổ biến có thể truy cập thông qua giao diện. Nhưng đó là khá nhiều, trừu tượng hóa những điều đơn giản bởi vì nó đúng hoặc làm cho nó có thể chuyển đổi các triển khai chỉ là một cách để làm cho mã lộn xộn.

Sau đó, một lần nữa, tôi thích các lớp thông minh hơn trong số các lớp nhỏ bùng nổ với tất cả các vấn đề quản lý trọn đời và khó thấy các mối quan hệ và biểu đồ cuộc gọi spaghetti. Vì vậy, một số người sẽ không đồng ý với tôi.


1

Mục đích hướng dẫn của việc ẩn và trừu tượng nên tách rời người dùng khỏi việc triển khai để họ có thể thay đổi độc lập Nếu người tiêu dùng được kết hợp với các chi tiết triển khai, do sự thay đổi với các phần bên trong của họ được đúc trong đá và việc giới thiệu các tính năng mới trở nên khó khăn hơn hoặc các thuật toán tốt hơn trong tương lai.

Khi viết một mô-đun, các phần ẩn của việc triển khai mang đến cho bạn một suy nghĩ để có thể thay đổi chúng mà không có nguy cơ phá vỡ các mã khác mà bạn không thể nghĩ tới.

Một lợi thế khác để cung cấp các giao diện mờ là chúng làm giảm đáng kể diện tích bề mặt giữa các hệ thống con. Bằng cách giảm số lượng cách họ có thể tương tác, họ có thể trở nên dễ đoán hơn, dễ kiểm tra hơn và có ít lỗi hơn. Tương tác giữa các mô-đun cũng tăng theo phương trình bậc hai với số lượng mô-đun, do đó, có một giá trị trong việc cố gắng kiểm soát sự tăng trưởng phức tạp này.


Điều đó nói rằng, tất nhiên có thể ẩn quá nhiều và giao diện lồng quá sâu. Công việc của lập trình viên, là một con người thông minh, thiết kế hệ thống sao cho nó hữu ích tối đa trong khi cũng giảm thiểu sự phức tạp và tối đa hóa khả năng bảo trì.


0

Trong rất nhiều trường hợp, bạn chỉ đơn giản là không cần biết làm thế nào mọi thứ được thực hiện. Tôi gần như có thể đảm bảo rằng bạn sẽ viết mã như people.Where(p => p.Surname == "Smith")vậy rất nhiều lần một ngày nhưng bạn sẽ khó có thể nghĩ " Where()phương pháp này thực sự hoạt động như thế nào?" Bạn không quan tâm - bạn biết phương pháp này là có và nó sẽ mang lại cho bạn kết quả bạn muốn. Tại sao bạn quan tâm làm thế nào nó hoạt động?

Điều này hoàn toàn giống nhau cho bất kỳ phần mềm nội bộ nào; chỉ vì nó không được viết bởi Oracle, Microsoft, v.v. không có nghĩa là bạn nên đi tìm hiểu cách thức triển khai. Bạn có thể mong đợi một cách hợp lý rằng một phương thức được gọi GetAllPeopleWithSurname(string name)để trả về cho bạn một danh sách những người có họ đó. Nó có thể lặp lại qua một danh sách, nó có thể sử dụng từ điển, nó có thể làm điều gì đó hoàn toàn điên rồ nhưng bạn không nên quan tâm .

Tất nhiên, có một ngoại lệ cho quy tắc này (nó sẽ không phải là quy tắc nếu không có nó!) Và đó là nếu có một lỗi trong phương thức. Vì vậy, trong ví dụ trên, nếu bạn có một danh sách có 3 người trong đó và bạn biết rằng một trong số họ có họ Smith và họ không trở lại trong danh sách thì bạn quan tâm đến việc thực hiện phương pháp đó vì nó bị phá vỡ rõ ràng .

Trừu tượng, khi được thực hiện một cách chính xác, thật tuyệt vời vì nó cho phép bạn lọc ra tất cả những thứ không hữu ích khi bạn phải đọc nó vào một ngày sau đó. Đừng quên rằng dành nhiều thời gian hơn để đọc mã hơn là dành cho việc viết nó, do đó, cần phải nhấn mạnh vào việc thực hiện nhiệm vụ đó dễ dàng nhất có thể. Bạn cũng có thể nghĩ rằng sự trừu tượng có nghĩa là một hệ thống phân cấp các đối tượng miễn là cánh tay của bạn nhưng nó có thể đơn giản như tái cấu trúc một phương thức 100 dòng thành 10 phương thức, mỗi phương thức dài 10 dòng. Vì vậy, những gì đã một lần 10 bước tất cả được gói lại với nhau bây giờ là 10 bước riêng biệt cho phép bạn đi thẳng đến nơi mà con bọ phiền phức này đang ẩn náu.


Ơ, nhưng giả sử bạn là người duy trì việc thực hiện. Ý tôi là, ai đó quan tâm đến việc thực hiện, và người đó là bạn. Bạn cũng là người sử dụng triển khai ... Các yêu cầu nghiệp vụ thay đổi (theo cách bạn không thể dự đoán) gây ra các thay đổi ở nhiều lớp. Tôi đoán quan điểm của tôi là một lỗi không phải là ngoại lệ duy nhất cho quy tắc đó.
dùng606723

Vấn đề làPeopleFactory.People.Strategy.MakePeople.(CoutryLaw.NameRegistry.NameMaker.Make()) as People.Female
Coder

@ user606723 Bạn không cần phải quan tâm đến từng dòng mã trong cơ sở mã của mình mọi lúc. Nếu có lỗi trong quá trình thực hiện đó hoặc nó được gắn cờ là cần phải viết lại (vì nó chậm, viết kém hoặc bất cứ điều gì) và bạn đang viết lại, thì bạn quan tâm đến nó. Nếu không, nó nên được tránh ra. Có thể vấn đề của bạn là bạn đang cố gắng sở hữu tất cả các mã mọi lúc. Theo quan điểm của tôi, bạn chỉ nên tập trung vào mã mà bạn đang làm việc.
Stuart Leyland-Cole

@Coder Rõ ràng đó là một hình thức trừu tượng cực đoan! Lúc đầu, tôi nghĩ đó là điều mà OP chống lại nhưng từ khi đọc phần còn lại của câu trả lời, có vẻ như họ thấy tất cả sự trừu tượng là xấu xấu. Đây là lý do tại sao tôi cố gắng giải thích các mức độ trừu tượng khác nhau trong câu trả lời của tôi.
Stuart Leyland-Cole

0

Trừu tượng dẫn đến ẩn thông tin. Điều này sẽ kết thúc trong khớp nối thấp hơn. Điều này sẽ dẫn đến ít rủi ro hơn trong thay đổi. Điều này sẽ dẫn đến các lập trình viên hạnh phúc, không cảm thấy lo lắng khi chạm vào mã.

Những ý tưởng đó được thể hiện thông qua ba định luật thiết yếu trong kiến ​​trúc phần mềm:

Luật của Simon: "Hệ thống phân cấp làm giảm sự phức tạp." (Phân cấp giới thiệu trừu tượng)

Luật của Parna: "Chỉ những gì bị ẩn mới có thể được thay đổi mà không có rủi ro."

Luật Constantin: Các chương trình mạnh mẽ cần sự liên kết thấp và độ gắn kết cao


"Hệ thống phân cấp giảm độ phức tạp." - không nhất thiết là đúng
Coder

Không có phương pháp thiết kế là xác định. Luật này không xuất phát từ IT / CS, nó được xây dựng theo nghĩa rộng hơn nhiều và cũng được toán học, các nhà vật lý, v.v ... Đó là một hiệu trưởng hợp lệ, nhưng không ai có thể ngăn bạn tạo ra thứ bậc vô nghĩa.
ins0m

0

Tôi cũng đang kinh doanh ứng dụng doanh nghiệp và câu hỏi này đã thu hút sự chú ý của tôi vì bản thân tôi cũng có câu hỏi tương tự. Tôi đã có một số hiểu biết liên quan đến vấn đề trừu tượng trong suốt sự nghiệp của tôi cho đến nay, nhưng cái nhìn sâu sắc của tôi không có nghĩa là câu trả lời phổ quát. Tôi đang tiếp tục học hỏi / lắng nghe những ý tưởng và suy nghĩ mới, vì vậy những gì tôi tin bây giờ có thể thay đổi.

Khi tôi duy trì một ứng dụng chăm sóc sức khỏe lớn và phức tạp, chỉ thích bạn, tôi ghét tất cả những điều trừu tượng ở đó. Hình dung nơi tất cả các mã đi là đau ở cổ. Nhảy quanh các lớp khác nhau làm tôi choáng váng. Vì vậy, tôi đã nói với bản thân mình "sự trừu tượng hút, tôi sẽ giảm thiểu sự trừu tượng khi tôi thiết kế công cụ".

Sau đó, đến lúc tôi phải thiết kế một ứng dụng (thành phần dịch vụ web tương đối nhỏ) từ đầu. Nhớ tất cả nỗi đau, tôi đã có một thiết kế phẳng của thành phần. Vấn đề là, khi các yêu cầu thay đổi, tôi phải thay đổi ở nhiều nơi khác nhau (các yêu cầu khá lỏng lẻo và tôi không thể làm gì về điều đó). Điều đó thật tệ, về cơ bản tôi đã vứt bỏ thiết kế ban đầu của mình và thiết kế lại với sự trừu tượng, và mọi thứ trở nên tốt hơn - tôi không phải thay đổi nhiều nơi khi yêu cầu thay đổi nữa.

Tôi đã gửi đơn, ngồi trong vài tuần và sau đó được bảo bắt đầu duy trì ứng dụng. Tôi đã được một thời gian, tôi đã không nhớ tất cả mọi thứ vì vậy tôi đã đấu tranh một chút để hiểu mã của riêng mình và sự trừu tượng không giúp ích được gì.

Tôi đã được đưa vào nhiều dự án khác nhau sau đó và có cơ hội chơi xung quanh với các mức độ trừu tượng hơn một chút. Những gì tôi thực sự tìm thấy là, và đây chỉ là ý kiến ​​cá nhân của tôi, sự trừu tượng giúp ích rất nhiều cho sự phát triển nhưng có tác động tiêu cực khi bạn không viết mã và đang cố gắng hiểu mọi thứ ở mức độ sâu nhất của ứng dụng; bạn sẽ dành nhiều thời gian hơn để nhảy xung quanh các lớp khác nhau và cố gắng tạo ra các kết nối.

Cảm giác của tôi là sự trừu tượng rất có giá trị trong thời gian phát triển đến nỗi những rắc rối chúng ta gặp phải khi duy trì khi cố gắng hiểu mã là đáng giá. Phần mềm tồn tại để giải quyết các vấn đề kinh doanh, các vấn đề kinh doanh phát triển theo thời gian; do đó, phần mềm phải phát triển theo thời gian. Không có sự trừu tượng, phát triển phần mềm là rất khó. Người ta có thể thiết kế sự trừu tượng theo cách mà người bảo trì có thể điều hướng xung quanh cơ sở mã một cách dễ dàng một khi họ nhìn thấy mô hình của cấu trúc mã, do đó chỉ có đường cong học tập ban đầu là bực bội.


0

Như những người khác đã nói, "ẩn chi tiết" đằng sau một sự trừu tượng cho phép chúng được thay đổi mà không ảnh hưởng đến người dùng. Ý tưởng này xuất phát từ Parnas ' On the Criteria to be used in Decompting Systems Into Modules (1972) , và liên quan đến ý tưởng về các kiểu dữ liệu trừu tượng (ADT) và lập trình hướng đối tượng.

Đồng thời, Mô hình dữ liệu quan hệ cho các ngân hàng dữ liệu chia sẻ lớn (1970) của Codd đã được thúc đẩy (xem phần tóm tắt và giới thiệu) bằng cách muốn thay đổi biểu diễn lưu trữ nội bộ của cơ sở dữ liệu mà không ảnh hưởng đến người dùng cơ sở dữ liệu. Ông đã thấy các lập trình viên thường xuyên mất nhiều ngày, sửa đổi các trang mã, để đối phó với những thay đổi lưu trữ nhỏ.

Điều đó nói rằng, một sự trừu tượng không phải là rất hữu ích nếu bạn phải xem những gì bên trong nó để có thể sử dụng nó. Nó có thể rất khó để thiết kế nó tốt. Một ví dụ về sự trừu tượng tốt là sự bổ sung - lần cuối cùng bạn phải nghĩ về những gì xảy ra bên trong? (nhưng đôi khi bạn làm, ví dụ cho tràn).

Vấn đề thiết yếu (IMHO) là để thiết kế các mô-đun tốt (theo nghĩa của Parnas), bạn cần dự đoán những gì sẽ thay đổi và những gì sẽ không. Dự đoán tương lai là khó khăn - nhưng nếu bạn có nhiều kinh nghiệm với một cái gì đó, và hiểu nó rõ ràng, thì bạn có thể làm một công việc dự đoán khá tốt. Và do đó, bạn có thể thiết kế một mô-đun (trừu tượng) hoạt động tốt.

Tuy nhiên, dường như số phận của tất cả các trừu tượng - thậm chí là tốt nhất - rằng cuối cùng sẽ có những thay đổi không lường trước được (và có thể nói là không lường trước được) đòi hỏi phải phá vỡ sự trừu tượng. Để giải quyết vấn đề này, một số trừu tượng có một lối thoát, nơi bạn có thể truy cập đến mức sâu hơn nếu bạn thực sự cần nó.

Tất cả điều này có vẻ rất tiêu cực. Nhưng tôi nghĩ sự thật là chúng ta bị bao quanh bởi những thứ trừu tượng hoạt động tốt đến mức chúng ta không chú ý đến chúng, hoặc nhận ra những gì chúng đang che giấu. Chúng tôi chỉ nhận thấy sự trừu tượng nghèo nàn, vì vậy chúng tôi có một cái nhìn vàng da về chúng.


0

Trừu tượng chủ yếu là vì lợi ích của người tiêu dùng của họ (ví dụ, lập trình viên ứng dụng). Các lập trình viên hệ thống (nhà thiết kế) có nhiều việc phải làm để làm cho chúng đẹp và hữu ích, đó là lý do tại sao thiết kế tốt thường không được thực hiện bởi người mới bắt đầu.

Có lẽ bạn không thích sự trừu tượng bởi vì chúng luôn thêm phức tạp? Có lẽ các hệ thống bạn đã làm việc bị viêm trừu tượng (sử dụng quá mức trừu tượng)? Chúng không phải là thuốc chữa bách bệnh.

Công việc làm thêm và sự phức tạp của một sự trừu tượng hữu ích sẽ được đền đáp, nhưng thật khó để biết chắc chắn. Nếu bạn nghĩ về sự trừu tượng hóa như một điểm mấu chốt, thì thiết kế phần mềm có thể uốn cong ở hai bên: việc triển khai tính trừu tượng có thể được sửa đổi mà không phá vỡ mã máy khách và / hoặc máy khách mới có thể dễ dàng sử dụng lại sự trừu tượng hóa để tạo ra những điều mới.

Bạn gần như có thể đo lường lợi tức đầu tư của trừu tượng bằng cách cho thấy rằng chúng đã bị "uốn cong" theo thời gian theo một hoặc cả hai hướng sau: thay đổi triển khai tương đối không gây đau đớn và thêm khách hàng mới.

Ví dụ: Sử dụng tính trừu tượng của lớp Socket trong Java, tôi chắc chắn mã ứng dụng của tôi từ Java 1.2 vẫn hoạt động tốt trong Java 7 (mặc dù chúng có thể là một số thay đổi về hiệu năng). Kể từ Java 1.2, chắc chắn cũng có rất nhiều máy khách mới sử dụng tính trừu tượng này.

Đối với sự không hài lòng với sự trừu tượng, nếu tôi nói chuyện với các nhà phát triển đã duy trì mã đằng sau lớp Socket, thì có lẽ cuộc sống của họ không được đào hoa và màu hồng như các khách hàng đã sử dụng Socket để viết các ứng dụng thú vị. Làm việc trên việc thực hiện một sự trừu tượng chắc chắn là công việc nhiều hơn là sử dụng nó. Nhưng điều đó không làm cho nó xấu.

Đối với tính minh bạch, trong chiến lược thiết kế từ trên xuống, tổng độ trong suốt làm cho thiết kế xấu. Các lập trình viên thông minh có xu hướng tận dụng tối đa các thông tin họ có theo ý của họ, và hệ thống sau đó trở nên gắn kết chặt chẽ. Sự thay đổi nhỏ nhất của chi tiết (ví dụ: thay đổi thứ tự byte trong cấu trúc dữ liệu) trong một mô-đun có thể phá vỡ một số mã ở một nơi khác, bởi vì một lập trình viên thông minh đã sử dụng thông tin đó để làm điều gì đó hữu ích. David Parnas đã chỉ ra vấn đề này trong các bài báo cũ như năm 1971 , nơi ông đề xuất giấu thông tin trong các thiết kế.

Việc bạn tham khảo ArchLinux có ý nghĩa với tôi nếu bạn coi "bên trong" của hệ điều hành là việc triển khai phức tạp của bản tóm tắt là HĐH cho các ứng dụng chạy trên nó. Giữ cho nó đơn giản trong ruột của sự trừu tượng.


0

Tôi sẽ trả lời câu hỏi của bạn bằng một câu hỏi; Khi bạn lái xe đi làm sáng nay (thực tế tôi sẽ cho rằng bạn đã làm như vậy), bạn có quan tâm chính xác cách động cơ mở van để cho vào hỗn hợp nhiên liệu không khí, và sau đó đốt cháy chúng không? Không. Bạn không quan tâm làm thế nào động cơ xe của bạn hoạt động khi bạn đang lái xe trên đường. Bạn quan tâm rằng nó không hoạt động.

Giả sử, một ngày, chiếc xe của bạn không hoạt động. Không bắt đầu, ném một cây gậy, phá vỡ một vành đai, không thể giải thích được cày vào hàng rào bê tông đó mà không có lỗi của bạn trong khi bạn đang bận nhắn tin. Bây giờ, bạn cần một chiếc xe mới (ít nhất là tạm thời). Bạn có quan tâm chính xác làm thế nào chiếc xe mới này hoạt động? Không. Điều bạn quan tâm đầu tiên là nó hoạt động và thứ hai là bạn có thể sử dụng cùng kiến ​​thức và kỹ năng mà bạn đã sử dụng để lái chiếc xe cũ của mình để lái chiếc mới. Lý tưởng nhất, nó sẽ xuất hiện với bạn rằng không có thay đổi trong chiếc xe bạn đang lái. Trên thực tế, cách thức hoạt động của chiếc xe mới này sẽ mang đến cho bạn càng ít "bất ngờ" nhất có thể.

Những nguyên lý cơ bản này là nguyên tắc cốt lõi đằng sau sự đóng gói và trừu tượng hóa. Kiến thức về cách một đối tượng làm những gì nó không nên là điều cần thiết để sử dụng nó để làm những gì nó làm. Ngay cả trong lập trình máy tính, các chi tiết về đường dẫn điện trong CPU chạy chương trình của bạn được tóm tắt đằng sau ít nhất nửa tá các hướng dẫn I / O, trình điều khiển, phần mềm hệ điều hành và thời gian chạy. Nhiều kỹ sư phần mềm rất thành công viết mã hoàn toàn tốt mà không một lần lo lắng về kiến ​​trúc phần cứng chính xác, hoặc thậm chí xây dựng hệ điều hành, sẽ chạy nó. Bao gồm cả tôi.

Đóng gói / ẩn thông tin cho phép tâm lý "không quan tâm nó như thế nào, chỉ quan tâm là nó". Đối tượng của bạn nên phơi bày những gì hữu ích cho người tiêu dùng, theo cách mà người tiêu dùng có thể dễ dàng tiêu thụ. Bây giờ, trở lại trong thế giới thực, điều này không có nghĩa là một chiếc xe không nên cung cấp cho người dùng bất kỳ thông tin nào về hoạt động bên trong, hoặc chiếc xe chỉ nên cho phép người dùng những chức năng cơ bản nhất như đánh lửa, vô lăng, và bàn đạp. Tất cả các xe đều có đồng hồ đo tốc độ và đồng hồ đo nhiên liệu, đồng hồ đo tốc độ, đèn ngốc và các phản hồi khác. Hầu như tất cả các xe ô tô cũng có công tắc cho các hệ thống con độc lập khác nhau, như đèn pha, đèn báo rẽ, radio, điều chỉnh chỗ ngồi, v.v. Một số xe cho phép một số đầu vào bí mật của người dùng, như độ nhạy của vi sai trung tâm trượt giới hạn. Trong mọi trường hợp, nếu bạn biết đủ, bạn có thể mở nó ra và thay đổi mọi thứ để làm cho nó hoạt động theo một cách hơi khác. Nhưng, trong hầu hết các trường hợp, có lẽ, chỉ là có thể, người dùng không nên trực tiếp và độc lập điều khiển máy bơm nhiên liệu từ bên trong cabin? Có lẽ, chỉ là có thể, người dùng không nên kích hoạt đèn phanh của họ mà không thực sự nhấn bàn đạp phanh?

Sự trừu tượng cho phép "điều này không giống như vậy, nhưng vì cả hai đều có thể sử dụng chúng như bất kỳ tâm lý X" nào. Nếu đối tượng của bạn kế thừa hoặc thực hiện một sự trừu tượng hóa, người tiêu dùng của bạn sẽ mong đợi việc triển khai của bạn tạo ra kết quả tương tự hoặc tương tự như các triển khai trừu tượng đã biết khác. Một chiếc Toyota Camry và Ford Fusion đều là "xe hơi". Như vậy, chúng có một bộ chức năng chung dự kiến, chẳng hạn như vô lăng. Xoay nó ngược chiều kim đồng hồ, xe đi bên trái. Xoay theo chiều kim đồng hồ, xe đi đúng. Bạn có thể lên bất kỳ chiếc xe nào ở Hoa Kỳ và mong muốn chiếc xe có vô lăng và ít nhất hai bàn đạp, bên phải là bàn đạp "xe đi" và một ở trung tâm là bàn đạp "dừng xe" .

Một hệ quả của sự trừu tượng là "lý thuyết ít ngạc nhiên nhất". Nếu bạn ngồi sau tay lái của một chiếc xe mới để lái thử, xoay vô lăng theo chiều kim đồng hồ và xe rẽ trái, bạn sẽ rất ngạc nhiên khi nói ít nhất. Bạn đã buộc tội đại lý bán lẻ POS và sẽ không thể lắng nghe bất kỳ lý do nào của anh ta tại sao hành vi mới "tốt hơn" so với những gì bạn đã sử dụng, hoặc hành vi này được "ghi lại" như thế nào hoặc " minh bạch "hệ thống kiểm soát là. Mặc dù chiếc xe mới này và tất cả những chiếc khác mà bạn lái vẫn là "xe hơi", nhưng khi lái chiếc xe này, bạn phải thay đổi một số khái niệm cơ bản về cách một chiếc xe được cho là lái để lái chiếc xe mới thành công. Đó thường là một điều xấu, và nó chỉ xảy ra khi có một lợi thế trực quan cho mô hình mới. Có lẽ việc bổ sung dây an toàn là một ví dụ tốt; 50 năm trước bạn vừa mới đi vào, nhưng bây giờ bạn phải khóa lại, lợi thế trực quan là bạn không đi qua kính chắn gió hoặc vào ghế hành khách nếu bạn gặp tai nạn. Ngay cả khi đó, các tài xế đã chống cự; nhiều chủ xe đã cắt dây an toàn ra khỏi xe cho đến khi luật pháp được thông qua bắt buộc 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.