В конкурсе на забивание гвоздей и рассматривание мелких предметов, микроскоп с большим отрывом победил бы молоток. Однако это вряд ли бы привело к замене молотков во всех наборах инструментов на микроскопы; скорее, некоторые рукастые лаборанты жили бы с убеждённостью, что у них под рукой всегда есть столь универсальный инструмент.
Если задуматься, то пример весьма бредовый, но он, тем не менее, отвечает сегодняшним реалиям выбора инструментария при разработке любых проектов. Но обо всём по-порядку.
Любимый язык
Скажем, вам поручили разработать некоторое приложение, ну пусть будет под веб, и оставили на ваше усмотрение выбор технологии. Какой именно стек вы выберите? Кто-то, безусловно, проведёт исследование, подбирая наиболее соответствующий, но, готов поспорить, что абсолютное большинство выберет свой любимый, то есть тот, который хорошо знает и часто использует. И в этом, наверное, нет ничего плохого: в конце концов, если человек достаточно хорошо знает инструмент и умеет его применять, то отчего бы ему не использовать его для решения задачи, которая выглядит вполне понятной?
По правде говоря, поводов нет. Однако, история знает немало примеров, когда такой подход приводил не только к издержкам, но и даже фатальным последствиям для компании. Расскажу пару историй, о которых мне поведали участники событий.
История 1
Одному веб-разработчику поручили сделать сайт. Знаете, такой модный, со свистелками, дуделками: сайт прокручиваешь вниз, а там со всех сторон вылезают всякие окошечки, появляются различные тексты и всё в таком духе. Но техзадание было поставлено не очень точно, поэтому разработчик запилил сайтик на реакте и тот поэкранно отрабатывал сценарий. Колёсико крутанул - следующий слайд появился, птички прилетели, счастливые люди из-за границ экрана вылезли - всё по классике.
Реакт был выбран, по признанию того же самого разработчика, по принципу: "А чего бы и нет? Я его знаю, задачка тривиальная, всё подходит".
А дальше началось веселье: дизайнер сайта посмотрел, погрустнел и заявил, мол, дружище, всё не то: нужно чтобы сайт плавно и постепенно изменялся. Мол, пока крутишь колёсико, всё постепенно надвигается, появляется, проявляется.
Теперь уже пришла очередь грустнеть разработчику: сайт-то он запилил, а вот к такому повороту готов не был. Не знаю, в чём там была особенность, но довольно скоро выяснилось, что реакт не особо-то и любит вот такую модель поведения. При помощи бубна, лома и такой-то матери, он-таки довёл поведение до приемлемого, однако потратил на всё это неоправданно много времени, что, в конечном итоге повлияло на его дальнейшее участие в проекте.
История 2
Один мой товарищ работал в ныне уже не существующей, или почти не существующей, компании (что ещё относительно недавно занимала хорошие позиции на рынке и торговала всевозможным электроинструментом). Обойдёмся без имён, кто знает, тот знает.
И вот, на переломном этапе, когда магазинная торговля стала уступать торговле в этих ваших интернетах, было принято судьбоносное решение о развёртывании более мощной системы онлайн-торговли.
Однако, случились аппаратные игры: финдир предложил решить всё это силами... внимание... отдела разработки 1С, а технический директор, вместо того, чтобы демонстративно грохнуться в обморок или, на худой конец, разгрызть ампулу с ядом, вшитую в воротник, согласился с таким предложением.
Что было дальше - не трудно догадаться. Вся система встала колом практически сразу; любые попытки её реанимировать приводили лишь к усугублению. Рассчёт модели на нагрузки никто, разумеется, не проводил.
То ли это стало тем самым последним гвоздём в крышку гроба, то ли это был один из многих, но компания, которая до того момент вполне уверенно чувстсвовала себя на рынке, перестала существовать, не способная даже обслуживать уже имеемые информационные потоки.
Так что...
Разумеется, истории про то, как неверно выбранная технология погубила всё (компанию, карьеру, надежду соблазнить практикантку и пр.) не так часты, однако они случаются. Может быть у вас есть парочка своих? Поделитесь в комментариях! А я продолжу.
Наверное первый тезис, который я хотел бы озвучить, состоит в том, что использовать "любимую технологию" (язык, фреймворк, БД и прочее) не всегда правильный подход и он может привести отнюдь не к тем последствиям, которые хотелось бы видеть в своей компании или в своём послужном списке.
Выбор технологии, простите за банальность, это, всё же, про исследование и аналитику, а не про то, что "я с этим справлюсь и так, тут же всё понятно".
Написание операционной система с нуля, без смс и регистрации
Как считаете, можно ли было бы написать ОС, скажем, на Python? Как по мне - вполне. Да, с этим возникли бы определённые трудности, по крайней мере на начальном этапе - создание и загрузка ядра, но, после того, как интерпретатор заработал бы, дальше всё пошло бы заметно легче. Возможно, какие-то части языка пришлось бы дописывать на языках низкого уровня, а, возможно, хватило бы и того, что уже есть.
Внимание, вопрос: кому бы вообще в голову пришло такое? Ну, то есть кому помимо меня? Ведь это же совершенно неэффективно! Не так давно смотрел какие-то сравнительные тесты (кажется, сортировка), где один и тот же алгоритм прогоняли на разных языках (C, Rust, C++, Java, Python). Быстрее всего алгоритм выполнялся на C и Rust (там сопоставимые были цифры), медленней всего - на Python, причём не просто медленней, а в 20 раз медленней. Можно предположить, что вся операционная система, написанная на нём, работала бы примерно в 10 раз медленней, чем та, на которой сидите вы. Запас вычислительных мощностей сгладил бы падение производительности, однако дальше лучше точно не было бы.
Поэтому...
В очередной раз мы подходим к тому, что правильно выбранный инструмент сильно влияет на конечный результат. Но теперь, когда мы с этим утверждением, возможно, готовы согласиться, давайте оценим ещё один аспект.
Типизировать или не типизировать?
На сегодняшний день существует примерно два основных типа языков высокого уровня: типизированный и нетипизированный.
И это всё, разумеется, ложь, потому что все языки высокого уровня - типизированные, просто в некоторых дозволяется смена типа переменной в любой момент, а в некоторых - нет. Проще говоря, языки бывают с явной и неявной типизацией, но я буду придерживаться выбранных ранее формулировок.
Тот факт, что типизируемые языки, чаще всего, компилируемые, а нетипизируемые - интерпретируемые - оставим за скобками, потому что есть и обратные примеры.
Но что есть типизация? По сути, у неё только одна задача - определить правила, как работать с данными. С точки зрения процессора, умножения строки на число - это просто умножение величины из одного регистра на величину другого регистра. А вот с точки упомянутого ранее Python - это многократный повтор имеющейся строки. И такое поведение описывается в коде управления типами данных.
Однако, помимо соблюдения правил, в компиляторах (или интерпретаторах) присутствует ещё дополнительная проверка - на соответствие типов, чтобы нельзя было в функцию, которая ожидает, скажем, строку передать число. Однако, такая проверка возможна лишь для языков с явной типизацией.
И в этот момент может появиться мысль, что дополнительная точка проверки - это хорошо. И это действительно хорошо, но лишь при условии, что дополнительные издержки на типизацию - оправданы. И вот это, на мой взгляд, ключевой момент. Но вернёмся к этому чуть позже.
Цена ошибки
Давайте ненадолго отвлечёмся от личных предпочтений и попробуем ответить на вопрос: какова цена ошибки в приложении, которое я сейчас разрабатываю?
Так уж получилось, что мне удалось поучаствовать в различных проектах: это были и терминалы, написанные на Delphi (ныне почти не представленном на рынке), и торрент-сети, написанные на C++ и веб приложения с разных сторон и на разном наборе технологий. И везде цена ошибки была своя.
Собственно, есть несколько уровней ошибок, от незначительной до фатальной, которые определяют возможность продолжения использования запущенного приложения и сохранения целостности данных. И тут всё упирается в незамысловатое "какую цену мы заплатим, если потеряем данные"? Риски могут быть разными: репутационными, финансовыми или ...никакими.
Представим себе веб-прижение на стороне клиента. Произошла какая-то ошибка и что-то там не открылось или зависло в вечном ожидании. Пользователь жмёт F5 и приложение перезапускается в том же самом месте, где оно остановилось, но, благодаря перезагрузке, выходит из тупикового состояния. Если при этом данные, хранимые на сервере не повредились, заполненная форма не пропала, то пользователь с высокой долей вероятности даже не обратит внимание на происшествие, мол, ну, бывает. А вот если в результате этой ошибки потерялись деньги, ключевые данные и тому подобное, то ситуация совсем другая. Но это вопрос уже к архитектуру решения.
Типизация и надёжность приложения
В какой-то момент может появиться вопрос: а насколько повышается надёжность приложения, если в него добавить типизацию. В качестве примера предлагаю рассмотреть javascript и typescript в разрезе: какая модель лучше подходит для разработки веб-приложений на стороне клиента. В дискуссиях с адептами TS, а также с нейросетью я смог выявить три его сильных стороны.
Typescript лучше подходит для средних и больших проектов! Но я участвовал в средних и больших проектах (около полумиллиона строк кода), где javascript отлично справлялся и вполне уверенно себя чувствовал. Или как понять, что проект "средний" или "большой" проекты? Сколько строк кода он должен содержать?
Typescript защищает от возможности передать в функцию параметры не того типа! Однако такое случается не то, чтобы очень часто. На моём опыте никто не пытался передать в функцию вычисления логарифма строку, а если бы этот некто и попытался бы такое сделать, то выполнение скрипта сразу же остановилось бы и консоль была бы заполнена ошибками.
Typescript обеспечивает чёткое следование контрактам: если вы заменили библиотеку, а параметр функции поменялись - компилятор выдаст ошибку. Это и вовсе странный аргумент: заменять библиотеку не понимая, как и где она повлияет на работу приложения - довольно рисковый манёвр и можно смело утверждать, что на таком проекте необходимость строгой типизации отнюдь не первая из проблем, которую нужно решать.
С другой сторон, typescript позволяют более эффективно использовать низкоквалифицированную команду, значительное число членов которой не удосужились изучить javascript и особенности его использования, а, вероятней всего, перешли с других языков или технологий в веб. И регулярно допускают все упомянутые выше ошибки. Не все же приходят в индустрию синьорами!
Впрочем, несмотря на все плюшки и бонусы typescript, от ошибок при исполнении программы они не защищают и тут они с javascript полностью равны: пришёл json с числом в виде строки - и всё, ошибка.
Исходя из вышесказанного, можно сделать вывод, что типизация не гарантирует идеального решения, хотя для команд определённого состава повышает производительность засчёт сокращения ошибок. Кстати, а каковы ваши наблюдения на этот счёт? Поделитесь в комментах.
Быстрое прототипирование
Языки высокого уровня можно поделить ещё по возможности быстрой прототипизации, то есть, как скоро можно создать рабочее решение поставленной задачи (новое или изменения в существующем).
Все языки позволяют создавать прототипы, но есть нюанс. Взять, например, Rust: в нём есть решения, которые в документации рекомендуется использовать только при написании прототипов (например, unwrap()).
И, по моим наблюдениям, языки высокого уровня с типизацией хуже подходят для быстрого прототипирования (или быстрого решения задач), нежели языки без типизации: много издержек. Сперва нарисуй структуры данных, потом подружи их с компилятором. Морока сплошная!
Простой пример: каскадное обновление структур данных (когда каждая последующая структура обрабатывает пришедшие данных и передаёт последующей). Добавление одного параметра, который первая структура передаёт последней, потребует изменения интерфейсов всех структур, участвующих в цепочке в случае типизированного языка и довольно легко будет решена для нетипизированного.
Если сложно представить абстрактный пример, то вот более наглядный: попытка установить цвет кнопки на третьем вложенном окне, который передаётся из настроек первого быстрее решить используя javascript, нежели typescript: первый потребует лишь быстрого добавления ещё одного параметра, в то время как второму нужно обновить описания входных данных для каждого из окон.
Вместо выводов
Итак, давайте подытожим.
Самый лучший язык программирования (или технология) - тот, который лучше всего подходит для решения именно этой задачи, хотя тут и необходимо учитывать ещё возможность будущей поддержки.
Типизированные и нетипизированные (то есть с явной и неявной типизацией) языки программирования не могут быть "лучше" или "хуже", они просто разные и позволяют решать разные задачи, однако и подход к решению - разный.
Типизация - ещё один способ попытаться сократить количество ошибок, но за неё приходится платить дополнительным кодом. Иногда это бывает оправдано, иногда нет.
Так, статистика утверждает, что языки программирования со строгой типизацией менее востребованные, нежели языки без оной. Исследование на одном из порталов, посвящённых поиску работы, по количеству упоминаний технологий, показало, что на 423 требования знания javascript всего 247 запросов на typescript, а на 463 запроса на знание java - 677 потребностей на знание Python. Да, статистика не совсем верная, но, в общих чертах, ситуация ясна.
Отсутствие типизации языка не гарантирует плохое исполнение задачи или большое количество ошибок. Более того, линтеры позволяют добавить дополнительный уровень проверки. Хотя подсказки в ваших IDE от этого не появятся.
Задачи бывают разные: иногда требуется высокая надёжность, а иногда - быстрое реагирование. Для клиентских веб приложений быстрота реагирования, на мой взгляд, в приоритете, а цена ошибки, чаще всего, не высока; для серверного веб приложения - быстрота реагирования на изменения уже не так актуальна, а надёжность и безопасность в приоритете.
Но, главное, следует всегда помнить, что инструменты бывают разными, но исполнитель всегда человек и именно от него зависит, как хорошо будет работать то, что он написал. Поэтому учите матчасть, расширяйте свой технический кругозор, стремитесь стать сегодня немного более профессионалом, нежели были вчера, осваивайте новые технологии, закрывайте пробелы в своём образовании. И, может быть, однажды мы придём к тому, что из вакансий пропадут позорные требования знания к какому-то определённому фреймворку или языку, а будет лишь короткая запись: "требуется инженер с веб специализацией" или "требуется инженер, специализирующийся на машинном обучении".