Добавить в корзинуПозвонить
Найти в Дзене
Сделай игру

Из программиста в инженера-программиста, часть 2

Итак, мы начали эволюционировать в инженера-программиста, но наш пикачу ещё не стал райчу, так что продолжаем, начатое тут. С чего-то надо начать Знаю, редко кто начинает работу над задачей со всестороннего обдумывания задачи и попытке сформировать приемлемую рабочую модель будущего приложения (хотя лично я таких людей знаю и восхищаюсь ими). Однако, подобно тому, как я писал уже про прокрастинацию через перфекционизм, есть другая сторона, когда требований настолько много, что попытка удовлетворить всем им - задача весьма нетривиальная. Не верите? Попробуйте сконструировать компилятор. Ну так вот, первое что тут надо запомнить: частично рабочее приложение намного лучше чем идеально работающее приложение, которого нет. Это горько и печально, но идеально оптимизированным шедеврам в нашей жизни не остаётся места просто потому, что желание объять необъятное и учесть всевозможные вызовы приводят к тому, что супер-качественное приложение застревает на этапе проектирования. Если "выкатить" ми
Оглавление

Итак, мы начали эволюционировать в инженера-программиста, но наш пикачу ещё не стал райчу, так что продолжаем, начатое тут.

Продолжаем эволюционировать из кабачка в тыкву
Продолжаем эволюционировать из кабачка в тыкву

С чего-то надо начать

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

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

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

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

Документация

Ну да, вы пишите не только код, но и документацию... прямо в коде. Наверное слышали про инструменты вроде @JSDoc, которые позволяют создавать на основании комментариев полноценные инструкции. Хорошее дело, но не исчерпывающее.

Комментарии в коде - важны.

// прибавляем к переменной a единицу
// функция вычисления состояния второго компонента

Но не такие, что написаны выше. Эти - нужны только разработчику, чтобы не сбиться с мысли в момент написания. Код готов? Будь добр, убери этот мусор. От него никакой пользы, лишь отвлечение внимания.

Есть всего 3 причины писать комментарии:

  1. Для автодокументирования (либо есть странная привычка писать такие комментарии, даже если инструмент не работает - хуже не будет);
  2. Пояснить, что тут происходит, когда это не очевидно;
  3. Объяснить своё решение: почему оно было принято.

В принципе, можно, их можно сократить до одной причины - №3: комментарии должны прояснять контекст. И только.

Игнорируй лишнее

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

Лучше всего, если разработка будет идти итеративно: сперва будет сооружён "скелет" функциональности, а потом к нему будут крепиться функции, тесты, ресурсы и прочее. Главное, обходить вниманием то, что находится вне контекста текущей задачи.

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

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

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

Это касается как приложения, так и тестов. Особенно тестов: попытка охватить тестами все варианты событий может легко привести к полной остановке разработки. Минимальное и достаточное - вот наш девиз!

Храните ключевые ресурсы

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

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

Автоматизируйте

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

Пример из тестирования. Функционал условного Postman неплохо дублируется со стороны curl. Порог входа в первый - сильно ниже, чем во второй, однако при автоматизации различных процессов, второе приложение сильно удобней, чем первое. Надо только разобраться; благо, справка имеется и весьма подробная.

Кстати, это, если что, ещё и призыв переходить на консольные утилиты.

Изменение состояния кода

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

Следите за руками: вы преобразуете приложение из "состояние 1" в "состояние 2". И это, чёрт побери, может быть очень рискованно! Что делать? Ответ прост: искусство маленьких шагов. Роберт Мартин даже предлагал набор последовательных изменений. Если просто, то каждое условное нечто в приложении последовательно заменяется на нечто расширенное. Скажем, фиксированное значение на константу, скалярная переменная на массив, массив на контейнер, условный оператор на цикл с предусловием и так далее.

Проще говоря, берём существующий код, и постепенно меняем в нём всё от простого к сложному. Переход из "состояния 1" в "состояние 2" происходит медленно и последовательно. В чётком соответствии с вектором изменения.

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

"Достаточно будет запомнить, что изменение состояние кода (обновление функциональности приложения) лучше делать по чуть-чуть, маленькими шагами", - сказал капитан Очевидность.

Обработка исключений

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

Цикломатическая сложность

Тут я мало что могу рассказать. Если коротко, то это оценка "трудности кода" (для тестирования, поддержки да и для понимания тоже). Одно из определений это "объем логики принятия решений в функции исходного кода".

Проще говоря, код, прошедший оценку и корректировку по показателю цикломатической сложности легче довести до приемлемого вида.

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

Заключение

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

  • Не жди идеальной проработки задачи, начини уже сейчас; потом можно много чего поменяться.
  • Автодокументация и внятные комментарии почему принято такое решение - сильно упрощают процесс поддержки кода.
  • Не надо делать заделы на гипотетическое будущее: игнорируй то, что не актуально сейчас (если есть важные аспекты, которые надо учитывать - учитывай, но по-минимуму).
  • Храни в актуальном состоянии все используемые ресурсы проекта (схемы, скрипты, временные данные итп); можно даже вместе с проектом.
  • Меняй код по чуть-чуть; от простого к сложному, от малого к большому.
  • Обрабатывай исключения. Хотя бы для сбора журнала ошибок с целью последующего исправления.
  • Замерь цикломатическую сложность своего кода. Возможно, её следует снизить.

Окончание тут.