[Перевод] Быть инженером, а не фреймворкером

Эта статья — призыв к самосовершенствованию. У вас все получится. Станьте инженером.

f7139322600a750224165c7dd803513e.png

Как обычно, сначала сделаем несколько пояснений: инженеры безусловно должны пользоваться фреймворками. Они прекрасно подходят для разработки приложений, позволяя выполнять поставленные задачи удобным образом. В этой статье мы не будем рассматривать фреймворки как врагов. Слава фреймворкам. Что ж, хватит об этом.

Что же такое фреймворки? Фреймворки — это инструменты разработки ПО, которые обеспечивают базу для реализации проектов определенного типа. Так, если вам нужно написать одностраничное веб-приложение на TypeScript, необязательно делать это с нуля, ведь есть Angular. Хотите заняться машинным обучением на Python? Позвольте представить вам моих друзей Scikit-Learn и Keras. Хотите построить бэкенд на C#? (О боже, вы чертовски круты.) Уверен, вы уже знакомы с ASP.NET. Можно продолжать эту мысль на протяжении еще 1500 слов, но вы и так все прекрасно поняли.

Зная какой-либо фреймворк, вы сможете получить должность, в названии которой есть слово «инженер» и, возможно, «машинное обучение». Если вы владеете двумя фреймворками, то запросто устроитесь на вакансию, в заголовке которой будет присутствовать словосочетание «full stack». Однако если вы собираетесь добиться успеха на следующей работе — той, на которую вас примут, потому что в вашем резюме указано 3–5 лет «инженерного» опыта, — ваш набор навыков должен быть гораздо глубже, нежели знание парочки фреймворков. Иначе нервы у вас сдадут еще на этапе прохождения испытательного срока.

Это похоже на путешествие. Из фреймворкеров в программисты, из программистов в инженеры. Взглянем на каждую из этих ступеней. Я расскажу о каждой из них и о том, как должен выглядеть профессиональный рост на данной ступени.

Фреймворкер

Если в своей работе вы главным образом пользуетесь каким-то фреймворком (или даже несколькими), это еще не значит, что вы фреймворкер. Но вы вполне можете им являться. 

Фреймворки позволяют делать программные продукты по принципу, похожему на сборку стеллажей из ИКЕА. По окончании работы, получится ли у вас стеллаж? Да. Следует ли после этого называть себя инженером по стеллажам? Пожалуй, не стоит.

Чего не хватает фреймворкеру?  

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

Фреймворкерам недостает и глубокого понимания задач, для решения которых они пользуются фреймворком. Фреймворк представляет собой реализацию концепции конечного программного продукта. Эта низкоуровневая реализация как правило абстрактна, а ее пользователи взаимодействуют с горсткой инструментов внедрения своего кода, таких как базовые классы, декораторы и [автоматически генерируемые] шаблоны.

Такие пользователи могут в рамках родного фреймворка стать искусными специалистами, но при этому не будут ничего знать о самой сути разработки ПО: паттернах проектирования, алгоритмах (CS или ML), асинхронном или распределенном программировании и многом другом. Иногда понимание этих базовых концепций может принести прямую выгоду, предотвратив неправильное использование фреймворка, но зачастую можно адекватно использовать фреймворк, не обладая большой глубиной знаний. Однако все эти «более глубокие» знания очень ценны. С одной стороны, они очень легко переносимы — не только в пределах конкретного программного продукта, но и во всех видах программирования. Более того, без этих знаний специалист по фреймворкам не сможет определить, насколько тот или иной фреймворк может удовлетворить требованиям проекта.

Но так ли это все важно?

Итоги фреймворкерства

Фреймворкинг негативно влияет и на карьеру разработчика, и на компанию, в которой его активно практикуют. Фреймворкеры вечно находятся в подвешенном состоянии: с одной стороны, их код приемлем для работы на проде, с другой — у них не хватает опыта понять, будет ли его легко поддерживать и расширять в будущем. По итогу база проекта пополняется кривым процедурным кодом, незнакомые проблемы решаются с помощью анти-паттернов, и общее качество кодовой базы устремляется в тартарары.

Однако с точки зрения карьеры у фреймворкеров еще более мрачные перспективы. Кодеров с типовым набором легко переносимых навыков (т.е. фреймворкерского опыта) ежедневно массово выпускают десятки «онлайн-академий». И если фреймворкер в конечном итоге получит работу мечты, где ему предложат заняться реальным проектом, его ждет жестокое разочарование: широчайшие пробелы в знаниях станут очевидны всем и каждому.

Примечание: возможно, кому-то из этих людей посчастливится получить позицию менеджера, и в этом случае они добьются невероятного успеха. 

Так что же делать, если специалист по фреймворкам захочет стать настоящим инженером? Я бы предложил начать с того, чтобы стать обычными программистами.

Программист

Я буду использовать термин «программист» в значении специфичном для темы этой статьи. Программист — это тот, кто живет в коде. И под этим расплывчатым определением я подразумеваю две вещи:

Давайте рассмотрим эти аспекты по очереди. 

Вы наверняка слышали, что чтение хорошего кода — один из лучших способов научиться писать хороший код. На начальном этапе это прекрасный способ изучить тонкости синтаксиса. Кроме того, это ключ к освоению идиоматической манеры написания кода на конкретном языке программирования. Вы научитесь разбирать граничные ситуации и профессионально обрабатывать исключения. Но есть и еще более веская причина читать много кода. 

Крайне важно стать хорошим читателем кода. Умение эффективно читать и понимать новый код — это, вероятно, самый важный навык, которым обладают инженеры (а программисту предстоит стать инженером), потому что технологии, языки и библиотеки, составляющие «базовый стек», постоянно меняются. Конечно, потребность в хорошей документации никуда не денется, но ничто не заменит умения понимать код, самостоятельно его читая. И это особенно актуально при переходе на новую работу.

К счастью, на свете существуют тонны кода, который можно прочитать, а познакомиться с ним можно, занимаясь вторым делом. 

Один из способов вырваться из колеи фреймворкера — писать нетипичный для себя код. Это не обязательно означает писать приложения другого назначения. Если вы занимаетесь машинным обучением на Python, у вас может быть параллельный проект, в котором вы сами реализуете алгоритмы ML. (А бонусные очки вы получите, если код написан на C/C++). Этого вполне достаточно, чтобы считать, что вы пишете по-другому. Попробуйте для развлечения разработать графический интерфейс для скриптов, которые вы запускаете каждый день. Разрабатываете веб-интерфейсы? Попробуйте написать текстовую ролевую игру.

Главное, помните, что вы не просто мигрируете с одного фреймворка на другой. Вы пытаетесь учиться. Вы хотите использовать язык программирования на более низком уровне, чем привыкли, а затем создавать свои собственные уровни абстракции поверх него. Изучите такие вещи, как ввод-вывод, сокеты, циклы событий, буферы, генерация хэшей и хвостовая рекурсия. По мере добавления уровней абстракции, необходимо познакомиться с полиморфизмом, наследованием, интерфейсами, машинами состояний и паттернами проектирования. Вам придется пополнить свой словарный запас.

Так когда же мне становиться инженером?

Ограничения профессии программиста

Будучи программистом, вы обнаружите, что с помощью живого кода можно делать штуки, которые недоступны фреймворкерам. Но несмотря на это можно оставаться слабым инженером. 

Представьте, что вы собираете собственный автомобиль из запчастей. По мере работы, каждый раз, когда нужно прикрепить одну неподвижную деталь к другой, вместо того, чтобы использовать гайки и болты, вы свариваете их вместе. В перспективе это не помешает вам собрать автомобиль, даже очень неплохой. На первых километрах. Но вот что-то в нем ломается, и к неисправной детали трудно подобраться — сначала нужно снять несколько других элементов. И тут вы понимаете, что зря вы всё намертво сварили. Если нужно заменить только одну деталь автомобиля — было бы неплохо, если бы ее можно было просто снять и поставить новую.

Я не говорю, что быть Программистом (в указанном выше смысле) означает полностью игнорировать надлежащие инженерные принципы. Но цели фазы становления программистом отличаются от целей фазы становления инженером. Если программирование было более или менее линейным путешествием по приобретению навыков в тех или иных сферах, то превращение в инженера окажется и вовсе крутым поворотом. Можно представить это как развитие речи: будучи программистом, вы обретаете свободное владение языками, с которыми работаете. Став инженером, вы научитесь писать академическую прозу.

Инженер

Так что же представляет собой эта загадочная смена приоритетов, определяющая Инженера? Инженер планирует и пишет программное обеспечение, которое балансирует между стабильностью и изменяемостью. Стабильность — это простая концепция, которую многие программисты реализуют в своем коде. Планирование кода, который может меняться, более затруднительно. Умение балансировать между двумя этими концепциями — вот что делает из вас инженера.

  • Стабильность

Большинство людей понимают основные принципы стабильности: Первый из них заключается в том, что программное обеспечение должно делать то, что оно должно делать. В нем не должно быть ошибок. Оно должно быть надежным. Вторая концепция заключается в том, что способ использования программного обеспечения не должен быстро и часто меняться. Это справедливо в двух отношениях: интерфейс должен быть относительно стабилен с течением времени, и интерфейс должен быть единым для всего программного обеспечения.

Я не собираюсь тратить на это много времени, но подчеркну, что когда я говорю «интерфейс», я имею в виду широкое понятие — он может означать вещь, которую вы явно объявили (а-ля заголовки в C/C++ или интерфейсы в Java/C# и т.д.), он может означать последовательный набор типов данных и имен объектов, он может означать графический интерфейс, с которым сталкиваются ваши пользователи. Разработка стабильного интерфейса невероятно важна не только с точки зрения самой стабильности, но и с точки зрения изменяемости.

  • Изменяемость

Инженер пишет программы таким образом, чтобы они были готовы к изменениям. Если говорить точнее, инженер способен предвидеть, каким образом его программное обеспечение, вероятно, потребуется изменить, и пишет соответствующим образом. Эта способность предвидеть будущее развивается со временем, но есть несколько типов изменений, которые достаточно универсальны, чтобы упомянуть их здесь.

Ошибки. Инженер исходит из того, что в каждой программе, которую он пишет, что-то идет не так. Чтобы можно было изменить (исправить) ошибку, код должен быть упорядочен и хорошо читаем. Не буду вдаваться в подробности. Как минимум, инженер знает, как организовать код в переиспользуемые блоки, будь то функции или классы, и знает, как слабо связать их так, чтобы ошибки были максимально изолированы и требовали ограниченного количества изменений.

Use Cases. Я помню, как разговаривал с руководителем команды, который завершал MVP, предназначенный для одного клиента. Я спросил: «Вы разработали это [программное обеспечение] так, чтобы его можно было использовать для других клиентов, ссылаясь на файл конфигурации, или потребуется дополнительная доработка?». Когда инженер собирает требования для проекта — даже MVP — он постоянно оценивает требуемые модели поведения, чтобы определить, могут ли эти модели поведения измениться таким образом, чтобы их можно было зафиксировать в слое данных. 

Пример. Клиент А присылает вам свои данные в виде файлов Excel, которые сбрасываются на общий диск. У клиента B есть API. Клиент C подключается к ftp и загружает CSV-файлы. Существует три различных варианта поведения. Ваша программа может поддерживать все три, в то время как конфигурационные файлы (по одному для каждого клиента) будут определять, какой вариант поведения использовать. Затем, когда клиент C наконец-то получит API, вам не придется писать ни строчки кода. Вы просто замените информацию о ftp в конфигурационном файле на информацию об API. 

Все это становится возможным, потому что с самого начала вы, Инженер, знали, что импорт файлов Excel с общего диска — это поведение, которое может измениться. Поэтому вы спроектировали программу так, чтобы решать вопросы импорта данных с помощью абстракции, а не жесткого кодирования в функции load_client_a_data_from_u_drive(). (Вы смеетесь, но чего я только не видел…) И вы определили слой данных для обработки конфигурации. 

Расширяемость. В некоторых случаях сценарий использования значительно изменяется по сравнению с тем, что вы ожидали или с тем, что вы готовы поддерживать. Продолжая наш пример, возможно, вам не захочется поддерживать загрузчик данных для хранения блобов от всех облачных провайдеров. Если вы четко определили интерфейс для загрузки данных, вам не придется этого делать. Нижестоящие разработчики все равно могут использовать ваше приложение для импорта данных из S3, написав код, реализующий этот интерфейс, если вы оставили для них такую возможность. Существует несколько способов реализации этой возможности и ряд концепций, которые могут в этом помочь (наследование, инъекции, дженерики, даже утиная типизация). Инженер способен писать программное обеспечение, которое может быть расширено сверх того, что он смог предусмотреть.

Заключение

Итак, на каком этапе своего пути вы сейчас находитесь? Готовы ли вы выйти за рамки начального уровня и придать слову «инженер», которое, возможно, уже есть в названии вашей должности, больше веса? Стать инженером — это не конец пути, а всего лишь воображаемая точка на карте. Вопрос лишь в том, готовы ли вы к ней отправиться.

© Habrahabr.ru