Функціональне чи об’єктно-орієнтоване програмування: що обрати і чому варто звернути свою увагу на Clojure. Поради для початківців
Серед розробників програмного забезпечення постійно тривають дебати стосовно того, яка парадигма програмування має більше переваг: функціональна чи об’єктно-орієнтована. Маючи на меті розробку гнучких програм, вони відрізняються своїми підходами до вирішення тих чи інших проблем.
Мене звати Андрій Стабрин, я Team Lead в компанії Agiliway. У цій статті розглянемо основні принципи та переваги функціонального програмування, а також поговоримо про те, чому Clojure, як одна із ключових мов цієї парадигми, є альтернативним методом традиційному ООП.
Однією з основних ідіом програмування можна вважати принцип Don’t Repeat Yourself (DRY), коли задля скорочення частотності повторення коду в програмі, а також ефективного оперування сутностями предметної області, використовують абстракції. Якщо на початку за допомогою 0 і 1 оперували напряму з фізичною частиною, то згодом винайшли ассемблер, що уможливив символьне представлення інструкцій (закодованих різними варіантами мов ассемблера) в двійковий код. Саме це можна вважати першим рівнем абстракції, який дозволяє писати програми і оперувати даними з предметної області, не вдаючись в деталі реалізації.
Чому функціональне програмування
Будь-які намагання винайти щось нове у світі програмування відбуваються шляхом численних спроб та маніпуляцій. Часто необхідні десятиліття, аби ці ідеї стали частиною мейнстріму, оскільки сучасні технології просто не можуть їх наздогнати. До прикладу, Java, перш ніж очолити список найпопулярніших мов, критикували за її повільну роботу, а також величезні об’єми пам’яті для забезпечення повноцінної роботи програм. Згодом розвиток потужних електронно-обчислювальних машин змінив ситуацію кардинально.
Схоже відбувалося і з функціональним програмуванням: воно поступово стало проникати у сучасні мови. Втім, основою проблемою став не синтаксис, адже більшість інженерів володіють кількома мовами і використовують наявні знання для вивчення нових. Найскладнішим виявилося змінити спосіб мислення.
Функціональне програмування набуває популярності завдяки своїй ефективності та універсальності у вирішенні сучасних проблем. Програми створюються за допомогою послідовних функцій, кожна з яких приймає вхідне значення і повертає постійне вихідне значення, не змінюючи або не впливаючи на роботу самої програми.
Щодо мов програмування, то до функціональних відносяться Lisp, Hope, Haskell, ML, Erlang, а Java, Python, C++, Ruby, Swift, Objective-C, Vala — об’єктно-орієнтовані.
Імперативний підхід vs. Функціональний підхід
Імперативне програмування описує стиль програмування, що моделюється як послідовність команд (імперативів), які змінюють стан. Традиційний цикл for є чудовим прикладом імперативного стилю програмування, наприклад: встановити початковий стан і виконати серію команд для кожної ітерації циклу.
Скажімо, у вас є список імен, деякі з яких складаються з одного символу, і вам необхідно повернути рядок з іменами, розділеними комами, з вилученими іменами з однієї літери, а також кожним іменем з великими літерами.
На конференції Strange Loop творець Clojure Річард Хікі у своїй доповіді «Simple Made Easy» заново представив термін complect: приєднувати, сплітати разом; переплітати.
В об’єктно-орієнтованому програмуванні доволі часто доводиться сплітати, ускладнювати завдання, аби мати змогу обробити їх всіх у єдиному циклі. В такому випадку необхідно виконати наступні кроки:
- Відфільтрувати (filter) список, щоб виключити окремі символи.
- Перетворити (transform) список, щоб капіталізувати кожне ім’я.
- Конвертувати (convert) список в один рядок.
На імперативній мові необхідно використовувати той самий низькорівневий механізм (ітерація над списком) для всіх трьох типів обробки.
Зі свого боку, функціональне програмування описує програми як вирази та перетворення, моделювання математичних формул, і намагається уникнути зміни стану. Функціональні мови програмування класифікують проблеми інакше, ніж імперативні мови.
Вищевказані категорії (filter, transform і convert) представлені як функції, які реалізують перетворення низького рівня, але покладаються на розробника, щоб налаштувати машину низького рівня з функцією вищого порядку, що передається як один із параметрів.
Замість того, щоб створювати механізми управління змінюваним станом, більшість функціональних мов намагаються видалити цю «рухому частину». Звідси і маємо: якщо мова надає менше потенційно схильних до помилок можливостей, то менш імовірно, щоб розробники зробили помилки.
Мови функціонального програмування віддають перевагу кільком ключовим структурам даних (таких як list, set і map) з високо-оптимізованими операціями на цих структурах даних. Ви передаєте структури даних плюс функції першого класу, щоб «підключити» ці операції і налаштувавши їх для певного використання.
Функціональне програмування |
Об’єктно-орієнтоване програмування |
|
|
Складові функціональної парадигми
Серед основних компонентів функціонального програмування виділяють:
- функції як об’єкт першого класу, сутність, яка може бути побудована в рантаймі (під час виконання програми), передаватись як параметр, повертатись з підпрограми, або присвоюватись змінній;
- функції вищого порядку можуть приймати функції першого класу як параметри або ж повертати їх;
- чисті функції беруть і повертають значення без зміни даних і не мають побічних ефектів (наприклад, дій, які може виконувати функція, які не містяться в самій функції);
- анонімні функції, функції визначення, що не пов’язані з ідентифікаторами;
- рекурсія дозволяє писати лаконічні алгоритми на основі лише вхідних даних до наших функцій;
- стійкі структури даних при зміні поля оновлюють лише це поле, зберігаючи лише посилання на інші поля, не створюючи жодних копій;
- нестрогі обчислення дозволяють мати змінні, які раніше не були обчислен
Clojure як одна із ключових мов функціонального програмування
Розроблена у 2005 році, Clojure належить до мов родини Lisp, яка є однією із найстаріших груп мов програмування. Річ Хікі, творець Clojure, зазначив, що хотів створити сучасний варіант Lisp, що зможе працювати на Java Virtual Machine (JVM) та володітиме функцією паралельного програмування.
Clojure — це функціональна мова програмування, яка підтримує функції як об’єкти першого класу, незмінні і, так звані, ліниві дані. Clojure має доступ до бібліотек, що розробляються для JVM, завдяки своїй сумісності з цією платформою. Така взаємодія дозволяє викликати код і реалізовувати класи, що використовують Java або інші JVM-сумісні мови. Іще однією особливістю взаємодії Clojure з Java є те, що Clojure ефективно працює з масивами Java. Позаяк масиви — це не колекції, то Clojure може створювати масиви, взаємодіяти з їхніми окремими частинами, конвертувати дані, і т.д.
Те, що структури даних на Clojure — незмінні, значно спрощує процес виконання завдання програмою. Якщо говорити про багатопотокове програмування, то використання Clojure теж буде значною перевагою, оскільки ключові структури даних можна з легкістю «шерити» між потоками. Що ж до використання змінних структур, то, при потребі, можемо використовувати Software Transactional Memory (STM).
Серед основних характеристик Clojure, які приваблюють розробників, варто зазначити:
- динамічність — завдяки використанню циклу читання-обчислення-друку (REPL (Read-evaluate-print loop)) Clojure дозволяє відобразити результати обчислень відразу ж після введення виразів.
- генерація байткоду для JVM
- ліниві послідовності
- рекурсія
- паралельне програмування
- мультиметоди, і .т. д.
Які недоліки Clojure
Оскільки Clojure дещо відрізняється від інших поширених мов програмування, то розробнику знадобиться трохи більше часу аби вивчити цю мову і звикнути до специфіки роботи з нею. Також, через великі об’єми пам’яті необхідні для коректної роботи, Clojure може працювати дещо повільніше.
Якщо ви не використовуєте такі платформи як JVM або JS, то ви не зможете використовувати Clojure на своєму проєкті.
Якщо ви не є прихильник прихильником динамічних мов, а, навпаки, віддаєте перевагу статичним змінним, то варто обрати іншу мову.
Для яких проєктів найкраще використовувати Clojure
Завдяки своїй динамічності, багатофункціональності та простоті, Clojure дедалі частіше використовується компаніями, які працюють із великою кількістю даних. Це чудовий інструмент для побудови великих і комплексних систем, що не ламаються. Цільовими проєктами на Clojure є
- маркетплейси;
- стрімінгові платформи;
- FinTech;
- Machine Learning;
- Data Analytics.
Серед іменитих компаній, які вже використовують Clojure, є Adobe, Amazon, Apple, SAP, Oracle, Microsoft, Capital One, Clubhouse, eBay, Facebook, Grammarly, Netflix, paper.li, Salesforce, Spotify, Walmart, та інші. В Україні — маркетплейс Kasta, а також оператор супутникового телебачення Viasat.
Висновки
Попри довготривале протистояння між функціональним та об’єктно-орієнтованим програмуванням, обидві парадигми виконують свої функції на «відмінно». Втім, вибір завжди буде базуватися на типі проєкту, його функціональності та доцільності використання тієї чи іншої мови для виконання поставлених задач.
Серед ключових мов в парадигмі функціональній варто виділити Clojure як сильного опонента Java. Завдяки своїй багатогранності, мова Clojure показала себе як гнучкий та динамічний інструмент у роботі з великими об’ємами даних.
280 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів