Как начинающему разработчику избежать безудержной отладки, красных глаз и испорченного настроения
Привет! Я техлид и коуч Binary Studio, поэтому много работаю со студентами и начинающими разработчиками. Все они допускают похожие ошибки, которые замедляют профессиональное развитие. В этом материале я собрал несколько советов, как избежать шишек джуну. Эта статья будет полезна в первую очередь тем, кто уже пробовал писать коммерческие проекты, но еще не имеет достаточно опыта. Я старался концентрироваться исключительно на практических примерах, избегая лишних рассуждений. Весь материал базируется на моем личном опыте, поэтому, если вам есть что дополнить, пишите в комментариях.
Используй готовые инструменты
Если бы я мог вернуться в то время, когда только начинал свою карьеру, одним из самых главных советов самому себе был бы следующий: используй инструменты! Как сейчас помню, писал курсовую работу, задача которой была получить изображение с камеры, обработать его набором алгоритмов, записать некоторые данные в базу и отобразить готовую картинку на экран. И это все в режиме реального времени. Сложнее всего было отлаживать такую программу: нужно было одновременно следить за ошибками в работе с камерой, правильностью алгоритма, обращениями к базе данных и, конечно же, за работой с UI-фреймворком (кто имел дело с WPF-стилизацией, тот меня поймет). Со временем, набив несколько шишек и поучаствовав в создании ряда веб-проектов, я выработал для себя набор принципов, которые могут помочь справиться с этой сложностью.
Как и любой уважающий себя джун, я брался за решение задачи целиком: для того чтобы сверстать страницу, мне приходилось создавать веб-приложение в Visual Studio из темплейта, среди списка существующих файлов находить нужную страницу и писать HTML/CSS наугад, так как результат можно увидеть в браузере только после нажатия F5. Если нужно было отправить запрос на сервер, я добавлял кнопку на страницу, вешал на нее обработчик, добавлял логику построения HTTP-запроса, нажимал F5 и только после клика кнопкой мог посмотреть, правильно ли я описал обработчик запроса на сервере. Visual Studio была моей точкой входа в приложение и точкой выхода. Часто я даже не понимал, что происходит при нажатии на F5, потому что целью было решить ту или иную задачу. Знакомо?
Разделяй и властвуй
Являясь коучем Binary Studio Academy, а также проверяя по несколько десятков домашек за сезон, я каждый раз сталкиваюсь с тем, что начинающие разработчики совершают одну и ту же ошибку: они пытаются охватить сложную задачу целиком вместо того, чтобы разбить ее на мелкие составляющие.
Эта стратегия уменьшения сложности задачи путем ее разделения на более простые подзадачи известна как «разделяй и властвуй». В этом случае есть два предположения, которые обычно верны:
- задача может быть разделена на несколько частей так, что каждая часть может быть решена независимо;
- решение каждой из частей, составляющих задачу, менее сложное, чем решение всей задачи, и таким образом мы можем «победить» ее.
Верстка и фронтенд
Сейчас, если мне нужно написать UI, я не запускаю сервер. Вместо этого открываю онлайн-редактор (например, Codepen) и верстаю нужные мне компоненты. Если мне нужно редактировать уже существующую часть приложения, то Chrome позволяет редактировать HTML/CSS на лету, используя вкладку Elements в Chrome DevTools. После этого останется всего лишь скопировать финальную версию и вставить себе в приложение (это намного проще, чем перезапускать приложение после каждого малейшего изменения). Кроме этого, DevTools позволяет отлаживать JS (не алертами, а с помощью переходов), расставлять точки останова, отслеживать переменные и читать Call stack. Отдельные экстеншены дают возможность упростить работу с JS-фреймворками (Angular, React), отслеживать состояние приложения (Redux) и производительность.
Коммуникация между клиентом и сервером
Если мне нужно отправить запрос, я уже не создаю кнопку Test на форме. Вместо этого есть несколько инструментов, которые позволяют описать HTTP-запросы во всех деталях: cURL, Postman, Fiddler, RESTClient. Последний мне нравится больше всего, так как это экстеншен к VS Code и он позволяет описывать все запросы в виде интерактивного текстового файла, которым легко управлять. Если мне нужно более внимательно анализировать сетевой трафик, то можно обратиться к Fiddler или Wireshark. Таким образом я могу сфокусироваться на разработке конкретного API-метода в какой-то момент времени, не обращая внимания на остальную часть приложения.
Разработка бизнес-логики
Если говорить о бизнес-логике приложения, то в первую очередь в голову приходят юнит-тесты. Вместо того чтобы запускать все приложение целиком, юнит-тесты позволяют сфокусироваться на конкретной функции, которую можно вызвать с теми или иными аргументами. VS предоставляет удобный интерфейс, для того чтобы запускать и отлаживать тесты, а для их написания можно использовать один из следующих фреймворков: xUnit, NUnit, MSTest. Необязательно добиваться стопроцентного покрытия тестами, достаточно уже того, что вы сможете проверить правильную работу своего кода без запуска приложения целиком. Я специально ни слова не сказал о дебаге, потому что, мне кажется, это первое, с чем сталкиваются начинающие программисты. Но, кроме дебага, я советую также разобраться с дизассемблером и научиться читать чужой код (пакеты, библиотеки). Это даст вам более широкую картину того, что происходит за ширмой библиотечных вызовов.
Взаимодействие с базой данных
Не стоит забывать и о данных. ORM всячески стараются скрыть от разработчика работу с SQL. Вы пишете модель, затем пару вызовов библиотечных функций и получаете необходимую выборку. Но чем сложнее система, тем сложнее выглядит эта модель и тем большее у нее число функций. Поэтому заранее вооружитесь инструментами для работы с базой данных: IDE, профилировщиком, анализатором структуры запросов, анализатором логов. Если вы работаете с MS SQL, то большинство инструментов идет из коробки (MS SQL Management Studio, SQL Server Profiler, Execution Plan Analyzer), для других баз данных вам придется гуглить каждый инструмент по ключевым словам.
Очень важно, чтобы вы не просто разбили приложение на отдельные составляющие, а и в тех местах, где определили «швы», описали заглушки: мок-данные, скрипты с HTTP-запросами, SQL-запросы. Это может быть полезно по двум причинам: во-первых, чтобы всегда можно было проверить изолированный компонент, а во-вторых, чтобы при объединении всех частей у вас перед глазами был контракт, которому необходимо следовать.
Перед тем как подвести итог, хотел бы дать пример разработки конкретной фичи (логина пользователя), используя все то, что я перечислил выше:
- В первую очередь я фокусируюсь на UI. Как сказано выше, открываю CodePen и стараюсь нарисовать интерфейс компонента, который соответствует мокапам (два поля для ввода логина и пароля и кнопка Login).
- Когда UI готов, могу перенести весь код в компонент и создать все необходимые обработчики. На этом этапе заменяю все сервисы по работе с данными сервисами с объектами-заглушками, для того чтобы проверить функционирование кнопки без обращений к серверу.
- После того как все операции по работе с формой (клик на кнопку, валидация, сообщения об ошибке или переход на другую страницу приложения) правильно заработают с объектами-заглушками, могу переключиться на бэкенд. Сначала описываю эндпоинт, который принимает модель и возвращает код 200. Используя RESTClient, описываю HTTP-запрос в текстовом файле (адрес, заголовки и тело запроса) и проверяю, чтобы мой сервер отвечал правильно.
- Перед тем как приступить к бизнес-логике, посмотрю в базу данных и проверю, все ли запросы, которые связаны с авторизацией, можно выполнить на существующих данных. Так как обычно я использую ORM, этот шаг является всего лишь подстраховкой, потому что ORM сама построит все запросы, а мне нужно только правильно описать модель.
- Теперь я могу приступить к бизнес-логике. Не буду вдаваться в подробности реализации функционала авторизации, хочу лишь сказать, что на этом этапе правильность вашего алгоритма легче всего проверить с помощью юнит-тестов. Добившись того, чтобы моя функция авторизации работала правильно, я могу подключить ее к базе данных, вызвать посредством API-метода и проверить целую связку, используя все тот же текстовый файл с запросом.
- Когда связка «API + логика + база данных» работает, я могу заменить на клиенте сервисы с заглушками реальными запросами к серверу и, если все контракты были описаны правильно, автоматически получаю рабочий функционал. Стоит отметить, что до последнего шага я каждый раз фокусировался на маленьком участке программы и только в конце запустил все приложение целиком.
Конечно, такой подход неидеален и имеет свои изъяны. Во-первых, здесь очень важна дисциплина. Всегда хочется взяться за все и сразу. Важно научиться делить большую задачу на несколько составляющих и фокусироваться на каждой из них по отдельности, отбрасывая все остальное на потом.
Во-вторых, баги никуда не денутся, однако такой подход дает больше возможностей для контроля на каждом этапе. Если, например, вы видите, что ваш сервер возвращает не те данные (пользуясь вкладкой Network в браузере), можете переключиться на текстовый файл запросов и не использовать браузер до тех пор, пока сервер не будет работать правильно.
В-третьих, вы могли заметить, что в процессе разработки у меня появилось несколько дополнительных артефактов: mock-сервисы с заглушками, текстовый файл с HTTP-запросами, юнит-тесты и запросы к базе данных (которые тоже желательно сохранять в отдельные файлы). В дальнейшем все эти артефакты вам придется поддерживать. Конечно, вы всегда можете избавиться от дополнительных файлов, как только закончите разработку конкретной фичи, но я крайне не рекомендую этого делать. Гораздо лучше постоянно строить себе подобного рода «леса», для того чтобы в любой момент времени было на что опереться.
Наконец, скорее всего, вы будете работать над проектом не один, поэтому желательно, чтобы вся команда следовала подобному подходу. В противном случае кто-то перестанет поддерживать дополнительные артефакты или полностью удалит их за ненадобностью (см. пункт выше).
И все же, запомните главное :)
Когда я начинал свой путь разработчика, то не смог найти подобной статьи, которая подтолкнула бы меня в правильном направлении. Это стоило мне несчетного количества часов безудержной отладки, красных глаз и испорченного настроения. Наблюдая за нынешними студентами, я часто вижу, как они наступают на те же грабли: тратят много времени на уже решенные проблемы, вместо того чтобы сконцентрировать все усилия на предметной области, а второстепенные задачи делегировать инструментам. И даже если описанный выше подход к вашему случаю неприменим, а написание дополнительного кода в тягость, запомните главное: используйте инструменты!