Про ООП сказано багато, бо воно вже має десятиліття практики, аналізу та переосмислення. На сьогодні маємо різні погляди, тезисно для гумору:
-
воно не треба;
-
тільки так і треба;
-
ви не розумієте, це не про інкапсуляцію-наслідування-поліморфізм;
-
та ви просто не вмієте в functional programming;
-
це про структуризацію коду та dependency management;
-
ви забули, це взагалі-то про message passing;
-
gamedev запитує “а як інакше?”;
-
legacy systems жаліються що їх вже тільки EOL змінить;
-
тощо
У будь-якому випадку ми є постійними користувачами ООП. То не є гарна чи погана новина, просто факт. До прикладу можна пригадати file descriptor концепт з Unix. Вийшов достатньо успішний інтерфейс та абстракція, на якому побудовані як рішення минулого, які досі добре працюють, так і нові, хайпові. Хто працював з I/O потоками, їх перенаправленням та суміжними цікавинками такими як pipes, ті мають гарне практичне відчуття вдалості даного концепту.
Якщо дуже коротенько, то кожен process зазвичай працює хоча б з одним I/O stream, що є абстракцією, де по факту це може бути вивід інформації через текстовий термінал, читання з файлу на диску, запис інформації у network socket, що буде запаковано та відправлено пакетами відповідного мережевого протоколу, й тому подібне. Ідея полягає в тому, що програма не потребує специфічного API для кожного типу I/O stream, та може бути запрограмована один раз використовуючи більш абстраговані функції на кшталт read(file-descriptor, receive-buffer) чи write(file-descriptor, src-buffer). Тут відчувається polymorphism концепт, що є звичним явищем у ООП, так? Конкретику та відповідні структури операційна система ховає від нас, а замість того видає нам деяке число у якості file descriptor та просить вказувати його при операціях читання-запису тощо. Для самої ОС це число є індексом у таблиці file descriptors даного process. Це вже наче деталі реалізації, але цей факт “просочився” у інтерфейс ОС, тому буває що його розуміння потрібно у роботі. Ага, тут пішла знайома нам encapsulation та ще leaky abstraction на додачу. Далі вже різні частини та модулі ОС реалізують згаданий інтерфейс: file systems скриплять дисками чи шепочуть до SSD; sockets знають як працювати з network stack, що спонукає відповідні network interfaces мерехтіти своїми світлодіодами; термінали взагалі роблять не дуже зрозумілі для сьогодення pseudo-речі, бо мають багато багажу минулого.
Саме поняття file було ще з часів першої версії Unix, тобто з 70-х. Та то було усе про звичайні файли на диску, тобто напряму працювало з вказівником на відповідний inode файлової системи. А на початку 80-х до діла взялись файні молоді хлопці з палаючими очима — як це зазвичай і буває 🙂. Це легенди Unix світу — Marshall Kirk McKusick та Bill Joy. Kirk є відомим розробником та вчителем BSD й FreeBSD, зокрема є автором UFS/FFS. Про Bill знають у світі більше й менше одночасно, бо він є менш публічною персоною. Це завдяки йому ми жартуємо про “як вийти з Vim”, бо він є автором оригінального редактору vi. Це він в свій час був одним з керівників CSRG групи у “University of California, Berkeley”, що у кінцевому рахунку подарувала світу вільну від зобовʼязань Unix у вигляді BSD, яка є прямим чи концептуальним предком Unix-like систем сьогодення. Також він є співзасновником Sun Microsystems, що створила безліч корисних речей: VFS, NFS, Solaris, Zones, ZFS, JVM/Java, SPARC тощо. Та і взагалі то був епічний приклад open source based компанії, хоча можливо це одна з причин, чому її вже не існує.
Так от, зі слів Kirk, з моїм перефразуванням, підходить якось до нього Bill та каже:
— Коротче, ООП врятує світ — треба робити ООП! (igoro: у 80-х як раз був розпал цієї теми)
— Так в нас же С, це ж наче не вважається ООП мовою, — відповів Kirk.
— Тю, так ООП — це ж просто indirect function calls. С lang дозволяє легко робити indirect function calls через вказівники на функції, тому то є ООП мова, що й треба було довести, — жартівливо видав Bill.
Таким чином сама структура file отримала так званий fileops інтерфейс, де були такі функції як read, write, ioctl, select, close. Але потім автори зрозуміли, що з першого разу не дуже файний вийшов interface, коли треба було якось абстрагуватись від network socket. Тому ми і маємо сьогодні окремі функції для читання-запису у Socket API такі як recv та send, хоча можна використовувати read/write(file-descriptor, buffer) концепт. Оскільки цей інтерфейс, як то кажуть, вже розійшовся по світу, то вже було важко наважитись робити breaking changes, хоча у авторів було бачення як зробити абстракцію достатньою навіть для специфічних network sockets.
Як вам рішення, яке виявилось не настільки вдалим як хотілось, але доводиться “жити” з ним вже ось років 40+? Для прикладу, коли ми розробляємо SaaS, то в нас не дуже тіпає око при дизайні внутрішніх інтерфейсів — якщо шо, то рефакторинг-рефакторинг та у продакшн, так? 🙂 Звісно, у SaaS випадках прикладом може бути server’s public interface, бо клієнт зазвичай не під нашим контролем, але все одно рівень відповідальності трохи не той, бо кінцеві користувачі не є прямим user base самого інтерфейсу. Ось якийсь Google <you-name-it> API — то вже цікаво. Хоча Google вирішують свої питання дуже просто, з комерційної точки зору, — адаптуйся до breaking changes чи до побачення.
Та й таке. IT happens.
Copyright © Igor Ostapenko
(handmade content)
Post a comment