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

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

Что же такое фреймворки? Фреймворки — это инструменты разработки ПО, которые обеспечивают базу для реализации проектов определенного типа. Так, если вам нужно написать одностраничное веб-приложение на 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, написав код, реализующий этот интерфейс, если вы оставили для них такую возможность. Существует несколько способов реализации этой возможности и ряд концепций, которые могут в этом помочь (наследование, инъекции, дженерики, даже утиная типизация). Инженер способен писать программное обеспечение, которое может быть расширено сверх того, что он смог предусмотреть.

Заключение

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

Комментарии (35)


  1. shasoftX
    13.06.2023 18:24
    +4

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


    1. breninsul
      13.06.2023 18:24
      +1

      ну просто есть категории людей, которые не разбираются, не хотя


  1. sulqadari
    13.06.2023 18:24

    Интересная статья, спасибо!


  1. 100Rubley
    13.06.2023 18:24
    +1

    Знающие хаброжители, помогите советом. Вот я сейчас (на самом деле немного ранее, но это сути не меняет) осознал себя фреймворкером, нашел пробелы в знаниях и стараюсь над ними работать. Но вот мне не дает покоя то, что я наметил себе изучать технологии, а не само "программирование". Как понять что важно выучить? Как понять, что я учу нужную вещь, а не углубляюсь во "фреймворкерство"? Где найти полезные материалы?


    1. vdshat
      13.06.2023 18:24
      +1

      Г.Буч: Объектно-ориентированное проектирование - пробуйте проектировать с нуля

      Макконел: Совершенный код - много полезного, плюс куча ссылок на другие книги по разным темам по тексту

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


    1. sepetov
      13.06.2023 18:24

      Многие книги "заходят" программисту "А", но не заходят программисту "Б". Поэтому книг придётся читать много и многие из них лично вам не понравятся, но это нормально.

      Купить можно много чего. Извиняюсь за качество фото

      Я бы добавил к предыдущему комментарию "Чистый код" Роберта Мартина. Из всех его книг мой уровень подняла только эта.

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

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


      1. cupraer
        13.06.2023 18:24
        +4

        «Чистый код» Роберта Мартина

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


        1. sepetov
          13.06.2023 18:24

          Наслышан об этом. Уже не удивляет наличие двух прямо противоположных точек зрения об этом авторе.

          А вы в книге "Чистый код" что-то полезное всё-таки нашли, или вообще ни одной полезной мысли? Лично мне зашла глава о функциях.


          1. cupraer
            13.06.2023 18:24

            «Чистый код» читать можно, но с преизряднейшей долей скепсиса и после минимум десяти лет стажа в боевой индустрии (не круд, не джейсон, не фреймворки).

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

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

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


            1. breninsul
              13.06.2023 18:24

              воу-воу, Мартин базован, вы конкретику приведите


        1. sepetov
          13.06.2023 18:24

          Пример всё же будет лучше. Есть некая служба, работающая с неподконтрольным нам API (отдаёт в ответ на запросы документы разной структуры). Работа API зависит от т. н. режима работы. Бывают режим "Цех", "Производственная линия" и "Отдел планирования".

          Для активации режима один джун написал одну такую функцию:

          public function setMode($mode)
          {
            // Тут какой-то switch + case для переменной $mode, емнип.
            // В сумме строчек 20
          }

          Другой наш джун написал три разных функции:

          public function setWorkshopMode() // внутри несколько строк
          public function setManufacturingLineMode() // аналогична предыдущей
          public function setPlanningDepartmentMode() // эта тоже единообразна

          Вам чей код больше по нраву и почему?


          1. cupraer
            13.06.2023 18:24

            Никакой из предложенного, страшно подумать, что с этим кодом станет в многопоточной среде.

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


            1. sepetov
              13.06.2023 18:24

              первый код допускает некоторую моду по умолчанию, а второй — нет.

              Вот с этим нельзя не согласиться. Пожалуй, главный аргумент (не в контексте нашего проекта, правда).

              А вот с первым и вторым пунктом нельзя однозначно согласиться. При добавлении, например, нового режима "Валидация продукции на линии" никакой проблемы нет. Незачем изучать код остальных режимов. Их изучение даст ответ на вопрос: "Как?", но не: "Почему?", а будет именно такой вопрос.

              P. S. А поделитесь опытом, как бы сделали вы? Мне тоже полезно, видимо)


              1. cupraer
                13.06.2023 18:24
                +1

                Я бы выделил управление режимом в отдельный процесс с атомарным доступом (самый простой вариант — редис какой-нибудь), повесил коллбэк на переключение режима и вызывал бы напрямую этот внешний атомарный по чтению-записи синглтон.


                1. sepetov
                  13.06.2023 18:24

                  Отлично! Что-то похожее у нас реализовано при изменении даты, когда без остановки линии печатаем новую дату производства после 23:59:59. Спасибо.


          1. 0xd34df00d
            13.06.2023 18:24
            -1

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


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


            Но Мартин, кстати, это все почти игнорирует. У него треть книги — очевидные советы уровня «давайте имена нормально», а две трети — куча WTF. Я даже читал с маркером, чтобы потом написать ради лулзов статью в духе «Хаскелист читает "Чистый код"», но у меня кончился маркер. Согласен с исходным оратором, отвратительная книга.


          1. breninsul
            13.06.2023 18:24

            первый, который внутри вызывает вторые, конечно


            1. sepetov
              13.06.2023 18:24

              В том-то и дело, что внутри setMode() не вызывается ни одна из функций ниже :-)

              Покажу на абстрактном примере иначе. Допустим, есть форма, которую нужно иногда показывать, иногда скрывать. Для этого у неё есть булевое свойство visible.

              Первый джун придерживается такого стиля:

              public function visible($bool)
              {
                $this->visible = $bool;
              }
              // в разных местах проекта, соответственно, вызывается так:
              visible(true);
              // либо:
              visible(false);

              Второй джун придерживается стиля с говорящими названиями:

              public function show()
              {
                $this->visible = true;
              }
              public function hide()
              {
                $this->visible = false;
              }


        1. Gotcha7770
          13.06.2023 18:24

          Скажите пожалуйста конкретнее, куда не собеседоваться?


      1. 100Rubley
        13.06.2023 18:24
        +1

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


      1. Samael7777
        13.06.2023 18:24
        +1

        Чистый Код Мартина обалденная книга, очень рекомендую!


      1. Gotcha7770
        13.06.2023 18:24

        Здравствуйте! Вижу у Вас вот эти книги
        - Код, который умещается в голове
        - Современная программная инженерия
        издательства Питер, подскажите пожалуйста, Вы уже читали, как впечатление?


    1. gev
      13.06.2023 18:24
      +1

      Дональд Кнут, "Искусство программирования".


    1. gev
      13.06.2023 18:24
      +1

      вот эту еще пососветую -)
      http://learnyouahaskell.com/


    1. sryze
      13.06.2023 18:24

      Так в статье же написано - изучайте всякие принципы и подходы программирования, независящие от технологий/фреймворков. Мне кажется, в этом может помочь создание какого-нибудь приложения или программы с использованием голых API операционной системы или браузера (т.е. без фреймворка) и постепенное внесение улучшений в код/рефакторинг по мере того как вы изучаете новые штуки со временем. Того и глядишь свой фреймворк напишете под себя, а заодно и узнаете принципы работы популярных фреймворков.


    1. down_in_flames
      13.06.2023 18:24

      У Влада Тана было видео как раз на эту тему, про "базовых программистов"

      Вот ресурс из видео


    1. melodictsk
      13.06.2023 18:24

      Получить высшее профильное образование?


  1. Dimon41
    13.06.2023 18:24
    +3

    Надо выдать MVP уже вчера. И срочно пишем функцию load_from_disk(). Инженер это про вдумчиво планировать на начальном этапе. Кто даст время и фидбэк от заказчика? За это время уже 3 фреймворка поменяются.


    1. Gorthauer87
      13.06.2023 18:24

      Многие простые вещи планируются сразу минут за 5, а многое это просто правила хорошего тона.

      И потом, можно для MVP и простой скрипт наговнокодить, а вот если после проверки идеи потом не дают времени на доработку, то менеджер мудак.


  1. TalesFromApocalypse
    13.06.2023 18:24
    +1

    картина намекает что лучше архитектором


  1. serjeant
    13.06.2023 18:24
    +1

    Потрясающая статья! Приятно встретить единомышленника!


  1. odisseylm
    13.06.2023 18:24
    +1

    Сам себя не похвалишь, никто не похвалит.

    PS: жду дизлайков))


  1. penguin_of_linux
    13.06.2023 18:24

    Вот не знаю. Всегда считал себя посредственным кодером (в сравнении со знакомыми из шараги). Но каждый раз читая подобные статьи удивляюсь очевидности написанного.


  1. amarkevich
    13.06.2023 18:24

    это поведение, которое может измениться

    нужно ипользовать принцип бритвы Оккама. случается, что ТЗ "додумывается", и реализуется функционал, который никогда не будет востребован


  1. Lazhu
    13.06.2023 18:24

    Автору зачет. Но сейчас сюда набежит толпа УНасДедлайнеров, клепающих баблишко копипастом джейсонов