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

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

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

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

И я добавлю этот мем на обложку
И я добавлю этот мем на обложку

Хорошему методу - хорошее имя

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

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

Пусть метод будет попроще

Ну, в смысле, пусть метод делает что-то одно, а не всё сразу. А то знаете, есть такой подход, когда метод один, а, в зависимости от параметров, он может так много всего сделать, что можно недоглядеть и случайно грохнуть всю систему или запутать код настолько, что разобрать его уже не выйдет никогда. Это, к слову, тот самый S из SOLID. Принцип единой ответственности.

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

Статическая типизация скажет о многом

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

Комментарии и имена методов, со временем, могут утратить актуальность по разным причинам, а вот статистическая типизация просто завалит сборку проекта в тот момент, когда изначальные правила работы с методом изменятся. А один взгляд на типы легко объяснит: чего же ему нужно.

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

Есть ещё хорошая присказка:

Не говори комментарием ничего, что можно сказать именем метода; не говори именем метода ничего, что можно сказать типом

Разные типы методов

Разработка программного обеспечения множила последние 50 лет различные подходы и аббревиатуры, которые должны были помогать писать код лучше. Среди одного из подходов - явное разделение методов-команд и методов-запросов.

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

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

Добавить немного организации процесса

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

И раз уж мы почти всегда работаем с системой контроля версий - крайне желательно держать свой код актуальным всегда, периодически сливая актуальный код из мастер-ветки в свой. Частота обновления зависит от скорости работы в организации и интервал может быть от 1-2 часов до нескольких дней.

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

Резервирование функциональности

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

Вопрос - как слить в мастер ветку код, который, мягко говоря не работает?

Да очень просто - сделать его незапускаемым. Для этого есть много способов: требовать объявленную директиву компилятора или переменную окружающей среды для запуска своих изменений (это, например, очень актуально для сборщиков типа webpack). Можно, конечно, пойти менее изящным путём и требовать наличия какого-то флага в коде. Но лично мне такой подход не особо нравится: флаг поставил, забыл снять, отправил изменения - и вуаля, у тебя в мастер-ветке нерабочий код.

Эволюция функциональности без революции

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

Большие изменения надо делать не только по чуть-чуть, но и, как бы, параллельно. То есть если надо произвести глубокие изменения - они делаются в соседнем методе/классе/компоненте, а потом объект реконструкции плавненько заменяется на новый. Старое ушло, новое пришло - и без дополнительного стресса. А пока замена не произошла, используется предыдущая версия.

Разумная производительность

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

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

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

Безопасность

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

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

В любом случае, предложение такое: делайте что можете, остальное за вас сделают те, кто получает за это зарплату.

Поведенческий анализ кода

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

Самые "горячие" файлы - меняются чаще всего. Значит именно в них есть нечто, что требует внимания и, возможно, оптимизации. Хотя возможностей, в зависимости от инструмента, может быть и сильно больше.

Подытожим

Очередным пакетом с пакетами нашего профессионально роста будет:

  • Упрощение: один метод отвечает за что-то одно;
  • Имена и типы входных и выходных данных должны уже сообщать информацию о методе, даже если его имя ещё не определено;
  • Процесс работы - ради результата; если процесс сильно мешает достижению результата - от него можно отступить;
  • Планирование и резервирования методов/классов/компонентов под будущий функционал в мастер-ветке, однако выполнение кода до завершения работ - невозможно;
  • Большие изменения делать по чуть-чуть;
  • Заниматься производительностью когда это уместно, а не ради самой идеи;
  • Обеспечивать минимальный уровень безопасности своего кода (прочее потребуют соответствующие специалисты);
  • Выполнять, при возможности, поведенческий анализ кода - как повод для улучшения кодовой базы.