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

Код — как археологический слой

Иногда открываешь старый проект и ловишь себя на мысли: «Кто вообще писал этот ужас?» А потом смотришь в git blame — и видишь своё имя.
Это странное чувство — когда твой собственный код становится для тебя загадкой. И ведь дело не в памяти. Просто тогда ты думал иначе. Уровень абстракции, спешка, корпоративные дедлайны — всё наложилось, и через год результат кажется чужим.

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

И если честно, долговечность — не про будущее. Это про уважение к тем, кто придёт после нас. Даже если этим «кем-то» окажетесь вы сами через полгода.

Минимализм как стратегия выживания

Когда систему собирают в спешке, она растёт не вверх, а вширь. Слой на слое. Каждый новый разработчик добавляет «ещё немного логики», и в какой-то момент код перестаёт быть предсказуемым.

Минимализм в программировании — не эстетика, а способ выжить. Он требует дисциплины: писать не всё, что можно, а только то, что нужно.

Пример. Вы работаете над API для учёта пользователей. У вас есть соблазн сделать гибкий универсальный слой валидации, который сможет проверять всё. Звучит круто, пока не начинаешь поддерживать это.

Вместо универсального монстра можно написать просто и честно:

# Python 3.12

def validate_user(user: dict) -> bool:
    if not user.get("email") or "@" not in user["email"]:
        return False
    if len(user.get("password", "")) < 8:
        return False
    return True

Просто, читаемо, расширяемо.
Да, кто-то скажет: «Но ведь нет ни логгирования, ни исключений, ни гибкой схемы». И будет прав. Но если система проживёт дольше, чем ваше желание «улучшить всё сразу» — значит, минимализм сработал.

Минимализм — это не отказ от технологий, это отказ от иллюзии, что код должен быть «идеально умным».

Читаемость: чтобы через пять лет не писать себе письмо с расшифровкой

Хороший код читается сверху вниз, как рассказ. Он не заставляет гадать, зачем эта функция существует.

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

// Go 1.23

func HandleEvent(e Event) error {
    if e.Type == "user_deleted" {
        return cleanupUserData(e.ID)
    }

    if e.Type == "user_created" {
        return provisionDefaults(e.ID)
    }

    return fmt.Errorf("unknown event: %s", e.Type)
}

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

Теперь представьте ту же логику, но через три слоя абстракций, DI-контейнер и пачку generic-хелперов. Код вроде «модульный», но если нужно быстро починить — ты тонешь в слоях.

Читаемость — это не когда красиво. Это когда не больно.

Долговечность: код, который не стареет вместе с фреймворком

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

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

Пример из практики — один старый сервис на Python, написанный в 2017-м. Мы решили обновить FastAPI, и всё рухнуло. Причина была банальной: внутренняя зависимость на приватные части библиотеки.

Вместо того чтобы править всё, я тогда выделил слой обёрток:

# Python 3.12

class APIResponse:
    def __init__(self, data: dict, status: int = 200):
        self.data = data
        self.status = status

def json_ok(data: dict) -> APIResponse:
    return APIResponse(data)

def json_error(message: str, code: int = 400) -> APIResponse:
    return APIResponse({"error": message}, code)

Этот слой прожил уже три версии FastAPI. И дело не в гениальности кода, а в том, что он изолирован.
Долговечность — это не когда код не ломается. Это когда его можно чинить, не переписывая всё вокруг.

Код как коллективная собственность

Если вы работаете в команде, код принадлежит не вам. И вот это, пожалуй, самая трудная истина.

Когда мы пишем что-то сложное, хочется оставить «свой стиль». Но чем больше индивидуальности, тем труднее другим. Долговечный код — это не произведение искусства. Это инструкция, которая должна быть понятна каждому, кто её откроет.

Здесь помогает культура комментариев. Не тех, что объясняют очевидное, а тех, что раскрывают замысел:

// Rust 1.81

// Используем atomic swap, чтобы избежать блокировки при обновлении состояния.
// Это критично, потому что операция вызывается из нескольких потоков.
fn update_state(new_state: State) {
    STATE.swap(Arc::new(new_state));
}

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

Пишите комментарии как письма будущим коллегам. Или себе — но более умному.

Финал. О честности перед будущим

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

Парадоксально, но лучший комплимент коду через пять лет — не «вау, гениально», а «ничего не пришлось менять».

Задайте себе вопрос: если завтра вы уйдёте, сможет ли кто-то поддерживать ваш проект без боли? Если ответ «да» — значит, вы написали код, который переживёт вас.

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


  1. 2medic
    20.10.2025 11:53

    Как писать код, который переживёт вас

    Ответ — никак. Когда-то я писал под ДВК-3 офигительно крутые проекты по управлению лабораторными стендами для изучения явления индукции и гистерезиса. В стендах использовался цифровой осциллограф, я управлял им через КОП, строил графики, аппроксимируя результаты и дополняя их недостающими данными, и тогда мне казалось, что я пишу код, который переживёт меня.

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

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

    А в реальном проекте, где железо и фреймворки «умирают», всё превращается в артефакт: код вроде есть, но выполнить его уже нельзя.


    1. rikert
      20.10.2025 11:53

      Ждем смерти x86 и говнокодим?


  1. TimurZhoraev
    20.10.2025 11:53

    Идеальный вариант - не сам код а человеко- и машиночитаемая на него документация с формулами LaTeX (этот язык наравне с Лиспом для систем компьютерной алгебры и Фортраном, переживёт что угодно)


  1. aaveter
    20.10.2025 11:53

    Хорошо, но мало. В реальных проектах кода много. Одну простую функцию, да, легко сделать читаемой. Но что делать с 5000+ строчек кода в файле...


    1. aaveter
      20.10.2025 11:53

      Есть книга "Чистый код" Р. Мартин. Там много практических советов, но даже они не всегда помогают.


      1. 2medic
        20.10.2025 11:53

        Где-то здесь на хабре была критика этой книги. Примеры из книги противоречили тезисам книги.


  1. UserSergeyB
    20.10.2025 11:53

    Как только программист напишет идеальный код, он потеряет работу.