Значення негерметичної абстракції?


89

Що означає термін "негерметична абстракція"? (Будь ласка, поясніть на прикладах. Мені часто важко переживати лише теорію.)



14
Можливо, ви захочете прочитати оригінальну статтю Джоеля Спольського «Закон негерметичних абстракцій», яка, наскільки мені відомо, походить від цього терміна.
Даніель Приден

1
Більшість відповідей запропонованого дупу стосуються вільних інтерфейсів.
Девід Торнлі,

@David: Друга публікація, яка отримала найбільше голосів, відповідає, що означає дірява абстракція, і чудовим прикладом.
missingfaktor

4
Коли ви шукаєте Google до цього питання через 4 роки, важко здогадатися, яка публікація раніше була другою з найбільш голосованих.
Джон Рейнольдс,

Відповіді:


106

Ось приклад meatspace :

Автомобілі мають абстракції для водіїв. У чистому вигляді є кермо, прискорювач та гальмо. Ця абстракція приховує багато подробиць про те, що знаходиться під капотом: двигун, кулачки, ремінь ГРМ, свічки запалювання, радіатор тощо.

Акуратне в цій абстракції полягає в тому, що ми можемо замінити частини реалізації поліпшеними, не перекваліфікувавши користувача. Скажімо, ми замінили кришку розподільника на електронне запалювання, а фіксовану кулачку - на змінну. Ці зміни покращують продуктивність, але користувач все одно рухається за кермом і використовує педалі для запуску та зупинки.

Насправді це надзвичайно чудово ... 16-річний або 80-річний може керувати цією складною машиною, не знаючи багато про те, як це працює всередині!

Але є витоки. Коробка передач невелика. В автоматичній коробці передач ви на мить відчуваєте, як автомобіль втрачає потужність, коли він перемикає передачі, тоді як у варіаторі ви відчуваєте плавний крутний момент до кінця.

Також є більші витоки. Якщо ви обертаєте двигун занадто швидко, ви можете йому пошкодити. Якщо блок двигуна занадто холодний, автомобіль може не завестись або він погано працює. І якщо ви одночасно прокрутите радіо, фари та систему змінного струму, ви побачите, як пробіг на бензині зменшиться.


7
Дякую за приклад. Здавалося, ніхто інший не міг дати простих пояснень.
Себастьян Паттен,

7
Це чудова відповідь, тим більше, що вона демонструє точку зору користувача, саме про що йдеться у версії програмного забезпечення.
Чад

1
Що означає м'ясний простір? Пояснення мирянину?
brumScouse

1
@brumScouse "meatspace" означає фізичний, офлайн-світ. Він використовується для протиставлення Інтернету, світу кіберпростору. Я відредагую свою відповідь, включивши посилання на визначення.
Mark E. Haase

1
Мені подобається, як у цій публікації вказується, що "все ще є витоки". Вся справа в їх мінімізації.
alaboudi

51

Це просто означає, що у вашій абстракції висвітлюються деякі деталі реалізації або що ви повинні знати деталі реалізації під час використання абстракції. Цей термін приписується Джоелю Спольському , близько 2002 року. Для отримання додаткової інформації див. Статтю Вікіпедії .

Класичним прикладом є мережеві бібліотеки, які дозволяють розглядати віддалені файли як локальні. Розробник, який використовує цю абстракцію, повинен пам’ятати, що проблеми з мережею можуть спричинити збій таким чином, як це не відбувається у локальних файлах. Потім потрібно розробити код для конкретної обробки помилок поза абстракцією, яку надає мережева бібліотека.


7
@mehaase Я не бачу, як це важливо, чи є ваша абстракція дірявою за дизайном чи через нехтування. Я розширив відповідь прикладом та додатковою інформацією зі статті, на яку посилається, щоб вона могла стояти самостійно. Крім того, я не думаю, що "дірява абстракція" обов'язково повинна бути принизливою. Для мене це просто описує ситуацію, коли вам, як розробнику, потрібно бути обережнішими при роботі з абстракцією. Дизайн може бути хорошим, поганим або байдужим незалежно від "негерметичності".
tvanfosson

13

Вікіпедія має досить хороше визначення для цього

Дірява абстракція означає будь-яку реалізовану абстракцію, призначену зменшити (або приховати) складність, де основні деталі не повністю приховані

Іншими словами, для програмного забезпечення, коли ви можете спостерігати деталі реалізації функції через обмеження або побічні ефекти в програмі.

Швидким прикладом може бути закриття C # / VB.Net та їх нездатність фіксувати параметри виходу / виходу. Причина, по якій їх неможливо захопити, пов’язана з деталлю реалізації того, як відбувається процес підйому. Однак це не означає, що для цього існує кращий спосіб.


13

Ось приклад, знайомий розробникам .NET: Pageклас ASP.NET намагається приховати деталі HTTP-операцій, зокрема управління даними форм, так що розробникам не доведеться мати справу з опублікованими значеннями (оскільки він автоматично відображає значення форми на сервер управління).

Але якщо ви відхиляєтеся від основних сценаріїв використання, Pageабстракція починає просочуватися, і стає важко працювати зі сторінками, якщо ви не зрозуміли деталі реалізації класу.

Одним із поширених прикладів є динамічне додавання елементів керування на сторінку - значення динамічно доданих елементів керування не відображатимуться для вас, якщо ви не додасте їх у потрібний час : перед тим, як основний механізм відображає значення вхідної форми у відповідні елементи керування. Коли вам доведеться цьому навчитися, абстракція просочилася .


Веб-форми мали бо дно у своєму відрі. Гірше те, що тонко завуальовані абстракції дорівнювали роботі з Http, як ви працювали в рукавичці.
brumScouse

9

Ну, певним чином, це суто теоретична річ, хоча і не важлива.

Ми використовуємо абстракції, щоб полегшити сприйняття речей. Я можу оперувати рядковим класом якоюсь мовою, щоб приховати той факт, що я маю справу з упорядкованим набором символів, які є окремими елементами. Я маю справу з упорядкованим набором символів, щоб приховати той факт, що я маю справу з цифрами. Я маю справу з числами, щоб приховати той факт, що я маю справу з 1 і 0.

Дірява абстракція - це та, яка не приховує деталей, які призначається приховувати. Якщо викликати string.Length на 5-символьному рядку в Java або .NET, я міг отримати будь-яку відповідь від 5 до 10, через деталі реалізації, де те, що ці мови називають символами, насправді є точками даних UTF-16, які можуть представляти або 1, або .5 символу. Абстракція просочилася. Якщо його не виточити, це означає, що для пошуку довжини буде потрібно або більше місця для зберігання (для зберігання реальної довжини), або зміниться з значення O (1) на O (n) (для визначення реальної довжини). Якщо я дбаю про реальну відповідь (часто ви насправді цього не робите), вам потрібно попрацювати над знанням того, що насправді відбувається.

Більш суперечливі випадки трапляються у випадках, коли метод чи властивість дозволяють вам увійти у внутрішню роботу, будь то витік абстракції або чітко визначені способи переходу на нижчий рівень абстракції, іноді можуть бути предметом, щодо якого люди не погоджуються.


2
І ви працюєте з
одиницями

7

Я продовжуватиму наводити приклади, використовуючи RPC.

В ідеальному світі RPC виклик віддаленої процедури повинен виглядати як виклик локальної процедури (або так сказано в історії). Це повинно бути повністю прозорим для програміста, щоб, коли вони телефонують, SomeObject.someFunction()вони не уявляли, чи SomeObject(або просто someFunctionз цього приводу) зберігаються та виконуються локально, або віддалено зберігаються та виконуються. Теорія говорить, що це спрощує програмування.

Реальність інша, оскільки існує ВЕЛИЧЕЗНА різниця між здійсненням місцевого виклику функції (навіть якщо ви користуєтеся найповільнішою у світі інтерпретованою мовою) та:

  • виклик через проксі-об'єкт
  • серіалізувати ваші параметри
  • встановлення мережевого підключення (якщо воно ще не встановлене)
  • передача даних на віддалений проксі
  • віддалений проксі відновити дані та викликати віддалену функцію від вашого імені
  • серіалізація повернутих значень
  • передача повернутих значень локальному проксі
  • повторне збирання серіалізованих даних
  • повернення відповіді від віддаленої функції

За один час це приблизно три порядки (або більше!) Різниці величин. Ці три + порядки величини будуть мати значну різницю у продуктивності, що зробить вашу абстракцію виклику процедури досить очевидною, коли ви вперше помилково розглядаєте RPC як реальний виклик функції. Далі реальний виклик функції, за винятком серйозних проблем у вашому коді, матиме дуже мало точок відмови поза помилками реалізації. Виклик RPC має всі перелічені нижче можливі проблеми, які будуть спричинені як випадки відмови понад те, що ви очікуєте від звичайного місцевого дзвінка:

  • можливо, ви не зможете створити екземпляр локального проксі-сервера
  • можливо, ви не зможете створити екземпляр віддаленого проксі-сервера
  • довірені особи не можуть підключитися
  • параметри, які ви надсилаєте, можуть не зробити це цілим або взагалі
  • повернене значення, яке віддає віддалений, може не зробити його цілим або взагалі

Отже, тепер у вашому виклику RPC, який "подібний до виклику локальної функції", є цілий набір додаткових умов відмови, з якими вам не доводиться боротися при виконанні викликів локальних функцій. Абстракція просочилася знову, ще сильніше.

Зрештою, RPC - це погана абстракція, оскільки вона протікає, як решето, на кожному рівні - і тоді, коли вона успішна, і коли не вдається.


<pimp> Мені подобається підхід Erlang до цього тим, що він не намагається приховати різницю між викликом функції та надсиланням повідомлення процесу до того, що ці два використовують дуже різний синтаксис. І віддалене надсилання повідомлення про процес дуже помітно відрізняється від надсилання локального процесу, хоча і використовуючи той самий загальний синтаксис. </pimp>
ТІЛЬКИ МОЯ правильна ДУМКА

2
Ну, це єдина відповідь, яка насправді дає хороший приклад (розуміння читання, люди), тому вона отримує мій +1.
Mark E. Haase

4

Приклад у прикладі ORM django багато-до-багатьох :

Зверніть увагу на зразки використання API, що вам потрібно .save () базовий об’єкт Article a1, перш ніж ви зможете додавати об’єкти публікації до атрибута багато до багатьох. І зауважте, що оновлення атрибута "багато-до-багатьох" негайно зберігається в базовій базі даних, тоді як оновлення атрибута однини не відображається в базі даних, доки не буде викликано .save ().

Абстракція полягає в тому, що ми працюємо з графіком об’єктів, де однозначні атрибути та багатозначні атрибути - це просто атрибути. Але реалізація у вигляді сховища даних, що підтримується реляційною базою даних, витікає ... як система цілісності RDBS з'являється через тонкий шпон об'єктного інтерфейсу.


3

Що таке абстракція?

Абстракція - це спосіб спрощення світу. Це означає, що вам не доведеться турбуватися про те, що насправді відбувається під капотом або за завісою. Це означає, що щось є ідіотським доказом.

Приклад абстракції: Складності польоту літака 737/747 "абстрагуються"

Літаки - це дуже складна техніка. У вас є реактивні двигуни, кисневі системи, електричні системи, системи шасі тощо, але пілоту не потрібно турбуватися про хитросплетіння реактивного двигуна. Це означає, що пілоту потрібно лише турбуватися про керування літаком: ліворуч, щоб їхати ліворуч, а праворуч, щоб рухатися праворуч, підтягуватися, щоб набрати висоту, і натискати вниз, щоб спуститися вниз.

Це досить просто ...... насправді я збрехав: керувати кермом трохи складніше. В ідеальному світі це єдине, про що повинен турбуватися пілот . Але це не так у реальному житті: якщо ви літаєте на літаку, як мавпа, без реального розуміння того, як літак працює, або будь-якої з деталей реалізації, то, швидше за все, ви впадете і вб'єте всіх на борту.

Діряві абстракції у 737 р. Приклад

Насправді пілоту доводиться турбуватися БАГАТО важливих речей - не все було абстраговано: пілоти повинні турбуватися про швидкість вітру, тягу, кути атаки, паливо, висоту, проблеми з погодою, кути спуску та чи пілот йде в правильному напрямку. Комп’ютери можуть допомогти пілоту у виконанні цих завдань, але не все автоматизовано / спрощено.

наприклад, якщо пілот занадто сильно підтягує колону - літак послухається, але тоді пілот ризикує зупинити літак, і після того, як він зупиниться, важко повернути контроль над ним, перш ніж він звалиться назад на землю .

Іншими словами, для пілота недостатньо просто керувати кермом, не знаючи нічого іншого ......... ніоооо ....... він повинен знати про основні ризики та обмеження літака перш ніж він полетить на одному ....... він повинен знати, як працює літак, і як літак літає; він повинен знати деталі реалізації ..... він повинен знати, що занадто сильне підтягування призведе до зриву, або що занадто крута посадка зруйнує літак.

Ці речі не абстраговані. Багато речей абстраговано, але не все. Пілоту потрібно турбуватися лише про рульову колонку, і, можливо, про одну-дві речі. Абстракція "дірява".

Діряві абстракції в коді

...... це те саме у вашому коді. Якщо ви не знаєте основних деталей реалізації, то частіше за все ви самі потрапите в кут.

Ось приклад кодування:

ORM абстрагують багато клопоту при роботі з запитами до бази даних, але якщо ви коли-небудь робили щось на зразок:

User.all.each do |user|
   puts user.name # let's print each user's name
end

Тоді ви зрозумієте, що це приємний спосіб убити вашу програму, якщо у вас більше пари мільйонів користувачів. Не все абстраговано. Ви повинні знати, що дзвінки User.allз 25 мільйонами користувачів збільшать ваше використання пам’яті і спричинять проблеми. Вам потрібно знати деякі основні деталі. Абстракція негерметична.


0

Той факт, що в якийсь момент , який керуватиметься вашим масштабом та виконанням, вам потрібно буде ознайомитись із деталями реалізації вашої системи абстракції, щоб зрозуміти, чому вона поводиться саме так.

Наприклад, розглянемо цей SQLзапит:

SELECT id, first_name, last_name, age, subject FROM student_details;

І його альтернатива:

SELECT * FROM student_details;

Зараз вони виглядають як логічно рівноцінні рішення, але продуктивність першого є кращою завдяки специфікації імен окремих стовпців.

Це тривіальний приклад, але врешті-решт він повертається до цитати Джоеля Спольського:

Усі нетривіальні абстракції певною мірою є дірявими.

У якийсь момент, коли ви досягнете певного масштабу у своїй роботі, ви захочете оптимізувати спосіб роботи вашої БД (SQL). Для цього вам потрібно буде знати, як працюють реляційні бази даних. Спочатку це було для вас абстраговано, але це діряво. Вам потрібно навчитися цього в якийсь момент.


-1

Припустимо, у нас є такий код у бібліотеці:

Object[] fetchDeviceColorAndModel(String serialNumberOfDevice)
{
    //fetch Device Color and Device Model from DB.
    //create new Object[] and set 0th field with color and 1st field with model value. 
}

Коли споживач викликає API, він отримує Object []. Споживач повинен розуміти, що перше поле масиву об'єктів має значення кольору, а друге поле - значення моделі. Тут абстракція просочилася з бібліотеки до споживчого коду.

Одне з рішень - повернути об’єкт, який інкапсулює Модель і Колір Пристрою. Споживач може викликати цей об'єкт, щоб отримати значення моделі та кольору.

DeviceColorAndModel fetchDeviceColorAndModel(String serialNumberOfTheDevice)
{
    //fetch Device Color and Device Model from DB.
    return new DeviceColorAndModel(color, model);
}

-3

Дірява абстракція полягає в інкапсулюючому стані. дуже простий приклад негерметичної абстракції:

$currentTime = new DateTime();

$bankAccount1->setLastRefresh($currentTime);
$bankAccount2->setLastRefresh($currentTime);
$currentTime->setTimestamp($aTimestamp);

class BankAccount {
    // ...

    public function setLastRefresh(DateTimeImmutable $lastRefresh)
    {
        $this->lastRefresh = $lastRefresh;
    } }

і правильний шлях (не дірява абстракція):

class BankAccount
{
    // ...

    public function setLastRefresh(DateTime $lastRefresh)
    {
        $this->lastRefresh = clone $lastRefresh;
    }
}

докладніше опис тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.