Навіщо знати декілька мов програмування

Я програмую близько 11 років, за цей час перепробував кілька мов, від С++ до JS. Зараз я займаю посаду Senior Developer в ELEKS. Ні, це не сповідь анонімного кодоголіка і не автобіографія. Це всього лише спосіб вкласти в голові свої думки і, можливо, дати поживу для роздумів тим, хто прочитає статтю.

Десь я вже це бачив. Чому мови програмування описують одні й ті самі сутності

Чим взагалі за своєю суттю є мова програмування? Це спосіб сформулювати свій потік свідомості у форму, доступну для розуміння комп’ютера і побратимів за професією, яким доведеться вивчити чимало нових лайливих слів, аналізуючи отриманий продукт. (Рідко трапляється код, під час читання якого плачеш від щастя, якщо таке взагалі буває. Набагато частіше плачеш з інших причин.)

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

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

Так само і з сутностями в програмуванні. Практично будь-яка мова містить ті ж змінні, цикли, функції... Тільки називаються вони по-різному. Все інше — лише надбудови над базовим функціоналом. Понад те, попри різницю в імплементації та принципах роботи, сучасні мови мають приємну тенденцію тирити одна в одної концепції, адаптуючи їх під свої потреби. Подобаються лямбди в C#? Найімовірніше, оціните і стрілкові функції в JS. WriteProcessMemory — твій найкращий друг, милий хакере? Ласкаво просимо в pinvoke C# або Frida.js. Подобається Nest.js? Думка «ух ти, десь я це бачив» не раз наздожене під час вивчення нових версій Angular.

Переваги програміста-поліглота

За весь час, що я програмую, встиг спробувати багато варіантів. Починав із C/C++, експериментував із реверс-інжинірингом (що потребує хоча б базового розуміння асемблеру), потім влаштувався працювати гейм-розробником на Unity3D, де захопився C#. Відтак почав використовувати PHP і JS, добрався до різних видів SQL/NoSQL, трошки колупав ActionScript, AutoHotkey, Lua тощо. Найбільше з того зачепила JavaScript, тож на ній чого тільки не робив: від розширень Chrome до Electron, від сайтів до Frida.js (фреймворк для інжекту коду в нативні аплікації).

Щоб у новому проєкті розібратися із тим, що в ньому робиться хоча б на верхньому рівні (якщо написаний новою для мене мовою), треба від кількох днів до кількох тижнів. Просто сісти та вивчити нову мову не намагався, бо мені зазвичай ближчий метод «вигребе — не вигребе». Є потреба — сів і зробив.

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

Рейтинг мов програмування 2020, DOU

Чому я вивчаю та використовую різні мови

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

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

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

2. Можна підглянути цікаві підходи й за наявності «прямих» рук застосовувати їх і в інших мовах. Наприклад, я намагався використовувати щось схоже до LINQ у JS, поки не з’явилися оті всі filter, map тощо.

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

Загалом на моїх останніх проєктах це є актуальною темою. То проєкт із legacy-кодом на паскалі, то потрібно внести невеликі виправлення у код на Python, то бек на Go. І не завжди легко догукатися до того, хто той код розробляв, щоб зрозуміти, що там взагалі відбувається.

4. Що більше інструментів і що вище уміння їх використання, то простіше підібрати відповідне рішення для кожного конкретного завдання. Це допомагає, наприклад, коли потрібно налаштувати Travis. Наче й більше стосується девопсів, але звичка знаходити аналогії допомагає.

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

6. У срачах з іншими програмістами можна тролити більш аргументовано.

7. Колеги не зможуть пропхати фішки в стилі «це не можна реалізувати в цій мові». Можна.

8. Дуже часто буває таке, що тебе садять або на legacy-проєкт, або на той, що уже в розробці. І так чи інакше потрібно підглядати навіть у той код, що ви в житті не бачили.

Звичайно, не все так ідеально.

Недоліки

1. Найголовніший недолік — вивчаючи кілька мов одночасно, складніше опанувати досконало одну. Це можливо, але часу піде більше (зрештою, що більше ви знаєте, то менше часу піде на вивчення наступного інструменту). Для себе я обрав такий підхід: або приєднуюсь до нового проєкту та пишу код спочатку за зразком, а потім і новий код починаю писати, або вигадую собі ціль і просто експериментую з цим.

2. У якийсь момент можна заплутатися, де конкретна фіча, а де — ні. Документація, IDE та пошук добре допомагають те відловити.

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

4. Якщо немає постійної практики, починаєш забувати, як воно працює. Так, це можна відносно швидко відновити, але все одно поріг входження вищий. Наприклад, я штрикав Angular ще у другій версії, але коли потрібно було зробити на ньому тестове та loopback (про який я мало що чув), це зайняло приблизно 6–7 годин для більшої частини функціоналу.

5. Best practices у різних мовах часто мають специфічні для тієї мови особливості. Їх вивчення теж займає багато часу й іноді конфліктує з попереднім досвідом.

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

Мої принципи вивчення мов програмування

А тепер трошки предметніше. Є кілька принципів, які я можу порекомендувати для формування універсального підходу до вивчення мов.

Алгоритміка та псевдокод

Чудова стартова точка для вивчення. Ще непогано підходять старі мови без зайвих наворотів (у школі, наприклад, нам давали Pascal). Чому це хороша штука? Тому що базові принципи вивчаються без прив’язки до конкретного оточення й мови. Для чого мені знати, як буде поводитись цей шматок коду залежно від архітектури процесора, якщо я тільки почав вивчати програмування? Навіщо мені знати особливості реалізації, якщо вони різняться від платформи до платформи? Правильно, тому що це цікаво, але про це замислюєшся пізніше. Спочатку потрібно подолати цей дикий крик у голові: «Що за змінні? Навіщо ми пишемо перед ними var/int/blah-blah-blah? Що тут взагалі відбувається?».

Вичленовування базових принципів

Власне, логічний пункт, що випливає з попереднього. Це те, що ми намагаємося зрозуміти на попередньому кроці. Не потрібно запам’ятовувати, завжди намагайтеся зрозуміти. Якщо ви збагнули суть явища, то як його описати конкретним способом, майже завжди можна підглянути в найближчому довіднику. Ну або вчіть, якщо пам’яті багато. Але розуміння необхідне завжди.

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

Збереження даних:

  • змінні;
  • масиви;
  • об’єкти;
  • пам’ять (зокрема, при роботі з чимось C++ -подібним додаються посилання, покажчики та інші цікаві штуки. Та й взагалі корисно мати хоча б загальне уявлення про те, як дані зберігаються в пам’яті);
  • бінарні дані у файлах (що це за дивний набір символів/шістнадцятирічного коду і куди котиться світ).

Організація і перевикористання коду:

  • функції;
  • класи;
  • бібліотеки (модулі, фреймворки, платформи тощо);
  • репозиторії.

Базові конструкції:

  • цикл (while, for, вбудовані методи, як-от .filter, .map тощо);
  • умова (if, switch, тернарки).

Оператори:

  • арифметичні (+ - =), включаючи інкремент-декременти;
  • бітові (& | ^);
  • логічні (||, &&).

У типізованих мовах ще додаються типи, але зазвичай є примітиви, які є в більшій частині мов: рядки, числа, булеві змінні.

Знання патернів, архітектури, принципів

Це взагалі універсальна штука, найчастіше без прив’язки до конкретної мови. Всі ці SOLID, MVC, Singleton’и — попри підгонку під конкретну мову, як правило, під капотом несуть ті ж ідеї. Їх не потрібно заучувати, але корисно знати. Втім, як показує практика, часто ви можете не знати навіть назви конкретного патерну, але при цьому чітко розуміти його принципи.

Не вчіть кілька мов одночасно на початку

Поки ви в голові у себе не сформулюєте базові принципи, від цього буде більше шкоди, ніж користі. Пройдіться по курсах, напишіть код для кількох проєктів, попрацюйте з більш досвідченими колегами (в ідеалі з code review), отримайте від них «люлєй» за очевидні, на їхню думку, косяки.

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

Не соромтеся шукати потрібні вам речі й писати на той же Stack Overflow, Toster або Reddit. 50 осіб з вас посміється, та один дасть потрібну пораду. Взагалі не соромтеся визнавати, що чогось не знаєте. Просто не забувайте додавати, що готові й можете це дізнатися.

Цікаве завдання і реалізація різними мовами чи стеком технологій

Це теж дає змогу розвивати асоціативні ланцюжки. А ось різні завдання допоможуть покрити більшу кількість аспектів мови.

Кожна нова мова — це інструмент

Не намагайтеся викруткою зашити рану на руці, для цього є моло... скальпель. Я хотів сказати голка з ниткою. Так і мови. Для математичних операцій широко розрекламований Haskell, для роботи з пам’яттю — C++ або Rust (або що там нині в тренді), для вебу  JS & компані. Правда, іноді ефективніше реалізувати задачу мовою, яка для цього не пристосована, але добре знайома.

Слухати навіть менш досвідчених розробників

Особливо якщо ця людина менш досвідчена тільки у вашому напрямі, а до того була, скажімо, експертом з Haskell або викладачем з математики. Програмування — це не тільки знання мови, а й купа інших навичок. Наприклад, лісоруб може допомогти з обдумуванням цікавого крафту в черговий іграшці, а без хорошого лікаря вкрай важко зробити притомний медичний застосунок.

Пам’ятайте, ваш продукт використовуватимуть не інші програмісти, а звичайні люди. Їм начхати, наскільки ви добре опанували синтаксис і визубрили всі наявні патерни, ще й придумали кілька нових. Їхній біль — неробоча кнопка «зроби мені добре» або черговий косяк в арифметичній операції, який призводить до того, що замість зарплати, призначеної для покупки нового авто, нараховується грошик на шматок хлібця. У кращому випадку.

Чому варто вчити різні мови

Усе просто — життя вкрай різноманітне. Завтра ваша мова може застаріти, й ви різко залишитеся без шматка хліба. Або може прийти проєкт, в якому знадобиться розібратися в Django, закодити щось на ASP або комплексному беку на Go, а ви так звикли працювати на зручному JS. Та й сучасні фреймворки часто виглядають як щось нове й незвичайне. Але ж ми вже вміємо вивчати мови одну за одною, що нам той новий десяток концепцій й особливостей, чи не так? Крім того, це добре прокачує мізки та найчастіше позитивно позначається на швидкості роботи. Вміння виокремлювати асоціації теж допомагає.

Ще корисно звертатися до суміжних галузей. Техліду варто спостерігати за менеджерами та бізнес-аналітиками, для бека — підглядати за девопсами, щоб розуміти, якого дідька ви змінили один рядок, а деплой тю-тю. Верстальнику знадобляться основи дизайнерської майстерності та навички роботи з фотошопом та іншою ... фігмою. Фронтенд-розробнику не буде зайвим розуміти роботу бека, щоб в авральних випадках налагодити той код, який так завзято падає при зверненні до API.

Не цурайтесь нового, якщо є сили та бажання розвиватися. Новий досвід часто дає сил і натхнення.

Все про українське ІТ в телеграмі — підписуйтеся на канал DOU

👍ПодобаєтьсяСподобалось3
До обраногоВ обраному7
LinkedIn



37 коментарів

Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.

Крутотєнюшка!

Как бы каждый проект несколько ЯП использует как правило, при чем я не имею ввиду что фронт-енд это objectiveC Допустим, а бэкенд C#. А то что вот например у меня был проект где было сразу JavaScript, ASP Classic, ASP.NET WinForms, C#, C++ и с этим стеком прихололось работать каждый день, при чем все это встречалось в стеки вызовов за один кол. Про связку С++ и C# на каких то легаси проектах я просто молчу.

Вот мне попадаются проекты, использующие мегасвязку С и С++

Драйвери під Linux на C. Юзерспейс на C++. На STM32, як не дивно, також С++.

В нас була зв’язка C++, C# і Python. Ну і CUDA.

Python використовувався аналітиками, які робили моделі. C#... отут вже не пам’ятаю, чому не обрали Qt, а пішли шляхом C#+WPF.

Аналіз страхових ризиків.

Трейдинг також там був, але вже пізніше.

Я б, власне, сказав, що не так важливо знати багато мов, як бути знайомим з мовами, які фундаментально відрізняються одна від одної.
Думаю, багато хто має приклади, як досвід в мові з одного сімейства допоміг в роботі з іншою того ж сімейства. Мені досвід з C-подібними мовами, типу C/C++/JS/PHP, допоміг написати адаптер для вебсокетів на Swift замість айосника. Він тупо не відстрілював і мені довелося замість нього то зробити, не читаючи документацію про мову — просто дивлячись на наявну кодову базу. Знання Haskell дозволили ознайомитись з Elm, PureScript і ReasonML за 2 вечори — концепти всі давно знайомі.
Рекомендую книги «Seven Languages in Seven Weeks» та «Seven More Languages in Seven Weeks». У них розглядаються досить різноманітні мови. У першій Clojure, Haskell, Io, Prolog, Scala, Erlang і Ruby, а в другій Lua, Factor, Elixir, Elm, Julia, MiniKanren та Idris.

«Seven Languages in Seven Weeks» та «Seven More Languages in Seven Weeks»

О! Дякую за підказку, треба погортати. Ідея видається дуже правильною

А ще було б цікаво до переліку додати LISP, FORTH, APL і, наприклад, Brainfuck.

фундаментально разных и при этом не совсем уж эзотерических не так уже и много получится
я навскидку вижу всего три области:
— что-то со статической системой типов (и чтобы были genetics и ООП)
— что-то с динамической системой типов
— что-то по честному функциональное а-ля Haskell

Дивно не бачити в цьому переліку асемблера

Кому він зараз треба і що з нього можна цікавого навчитись?

ну например таки узнать что «временный объект на стеке» не создаётся вообще и соотв. никак не влияет на производительность ))

В нас написаний кусок обробки зображень на ARM NEON. З інтрінзіками копмілятор чомусь не справляється.

Та хз, може я вже динозавр, але в свій час мене перло від швидкості. Ну і писав у всій час дизасемблери і дебагери, і різні кодогенератори.

Допомагає бачити різні баги, типу невирівняних масивів на стеку.

Ну і FPGA зараз в тренді, писати на них не розуміючи цифрової електроніки досить важко.

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

В тому конкретному випадку компілятор генерував неоптимальний код

В загальному випадку — так. Але коли потрібно оптимізувати вузьке місце, людина часто може зробити краще. Ну і не варто забувати, що будь-яка оптимізація починається з вимірювання. Зробив — поміряв — порівняв.

Постійно зупиняє від вивчення наступної мови думка про те, що основною своєю ще не володію в досконалості

Теория так себе, а вот за практические советы плюс)

За исключением того, что может быть хорошо быстро по верхам глянуть языки из разных областей (например, Питон и С++) чтобы потянуть из Питона хороший ООП, а из С++ понимание, как оно под капотом работает.

я чем ООП именно в Python так хорош?

Очень естественный, и все можно перегрузить.
В С++ напротив оно кривое, как и все там) Виртуальные родительские классы, name shadowing.
В Джаве нет множественного наследования.

Очень естественный

С чьей кочки смотрите?

и все можно перегрузить.

Для скорости это минус. Для понимания объёмного кода — тоже — как только начинают использоваться подобные плюшки. (Как я хочу 90% их выкинуть из нашего продукта...)

Виртуальные родительские классы,

А ты полностью множественное наследование в Питоне понимаешь? ;)
если думаешь, что да — у меня для тебя новости.

То, что в C++ ромбовидным наследованием пугают и есть аж один случай в стандартной библиотеке, не значит, что у других его нет.

name shadowing.

В Питоне то же самое.

В Джаве нет множественного наследования.

Это хорошо или плохо? ;)

С чьей кочки смотрите?

Со своей, как химика.

Для скорости это минус. Для понимания объёмного кода — тоже — как только начинают использоваться подобные плюшки.

Для учебы — хорошо: разобраться, как работают метаклассы, инстанциация, супер и прочие плюшки. Которые в С++ только снились. А в Питоне можно навешивать динамически.

А ты полностью множественное наследование в Питоне понимаешь? ;)
если думаешь, что да — у меня для тебя новости.

Пофиг. Оно работает, и интуитивно.

То, что в C++ ромбовидным наследованием пугают и есть аж один случай в стандартной библиотеке, не значит, что у других его нет.

В Джаве нет, вроде. В Питоне очень удобно сделано.

Это хорошо или плохо? ;)

Мне было бы неудобно. Как минимум — неинтуитивно, появляются какие-то непонятные миксины.

Мне было бы неудобно. Как минимум — неинтуитивно, появляются какие-то непонятные миксины.

Хм, в Python удобно, в Java неудобно... непонятная неровность.

Пофиг. Оно работает, и интуитивно.

Ну так и в C++ работает на том же уровне интуитивности :)

Со своей, как химика.

Я не смог раскурить связь с химией...

Ну так и в C++ работает на том же уровне интуитивности :)

В С++ для множественного либо надо делать виртуальное наследование и ручками вызывать конструктор общей базы, либо получишь несколько инстансов базового класса. Такая же лажа с вызовом методов базовых классов — ручками.

Я не смог раскурить связь с химией...

Хинт: несвязь с математикой

В С++ для множественного либо надо делать виртуальное наследование и ручками вызывать конструктор общей базы, либо получишь несколько инстансов базового класса.

Это да. Но поведение тоже понятно.
«Несколько инстансов базового класса» может быть где-то разумно (а учитывая проблемы реализации виртуального базового класса, в языке такого уровня — даже разумнее).

Хинт: несвязь с математикой

Без поаспектной расшифровки — понятнее не стало.

По моему в пайтоне не Ооп, а пародия на ооп.

В С++ и Джаве лучше? Чем?

Чєм в пітонє. Очевидно ж!

Пролог с Лиспом смотрят неодобрительно на эти принципы

Пролог, к счастью, никуда не смотрит — это чудо сдохло кроме полутора кривых ниш и одного потомка в виде Makefile.
LISP хорош как теоретическая база и как универсальный финализатор Гринспуна, но за пределами тонкого управляющего слоя он никому оказался нафиг не нужен. Хотя по сравнению с Прологом он популярнее раз в 1000, наверно.
То, что из обоих понадёргали идей для более современных проектов — честь и хвала. Но не более того.

IBM Watson смотрит на твой комментарий со смехом
www.cs.nmsu.edu/...​in-the-ibm-watson-system

Это и есть одна из тех ниш. «Программа» на Prolog — это всего лишь форма представления данных. Prolog-движки научены выводить цепочки связей для заданного входного предиката. Но это сама по себе на сейчас задача совершенно студенческого уровня — сделать такой движок. Дальше — уже вопрос оптимальности.
Важно не то, как они представляются, а что за этим стоит — какие данные и как их обрабатывать. У Watson 99% успеха это собственно данные, которыми система набита, и всякие твики по оптимизации поиска в этих данных (которые уже за пределами языка).
Тот, кто придумал эту концепцию — был гением. Все повторятели включая Watson — без конкретных данных — не стоят ничего.

IBM Watson
кривых ниш
и есть одна из тех ниш

Ну, если не замечать, что ты выбросил 99% важных деталей, всё так.

Пока есть люди с таким мнением, можно не переживать за конкуренцию :)
Если что, 6 лет назад на одном медицинском 3D CAD проекте использовали пролог. Сперва, конечно 4-5 месяцев боли, но потом в 2-3 раза увеличенная скорость разработки. По сути то что раньше делала команда из 6 человек + research team, стало делать 2-3 человека.

Підписатись на коментарі