Skip to content

Философия работы

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

Короткие определения для повторяющихся здесь терминов собраны на странице Глоссарий.

Практичность важнее декоративности

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

Обычно это означает:

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

Архитектура должна оправдывать свою сложность

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

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

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

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

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

Библиотеки — это полноценная продуктовая работа

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

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

Когда я работаю над библиотеками, мне обычно важно:

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

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

Ограничения — часть проектирования

Бизнес-ограничения не появляются после инженерных решений. Они входят в пространство проектирования с самого начала.

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

Tooling — часть developer experience

Для меня development environment, release pipelines и локальные workflow важны потому, что именно они формируют повседневный опыт разработки.

Сильный рабочий процесс уменьшает hesitation, снижает стоимость изменений и делает качество более воспроизводимым. Tooling не отделен от инженерного качества. Это один из способов сделать качество повторяемым.

Документация — часть реализации

Я не воспринимаю документацию как финальный полировочный этап. Если систему трудно объяснить, это часто сигнал, что сама система еще требует доработки.

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

Clean code — это не лозунг

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

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

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

DRY — это про дублирование знания, а не про внешнее сходство кода

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

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

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

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

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

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

Технический долг должен что-то покупать

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

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

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

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

Legacy — это не автоматически технический долг

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

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

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

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

Это различие важно, потому что оно меняет сам способ рассуждения о дальнейших действиях. Legacy — это контекст. Он требует интерпретации, приоритизации и уважения к ограничениям, которым система все еще служит. Технический долг — это компромисс. Его нужно оценивать через то, что он покупает, сколько стоит и в какой момент перестает быть приемлемым.

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

На что я стараюсь ориентироваться

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

Last updated: