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

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

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

Забытое чувство предсказуемости

Открывая старые учебники, поражаешься тому, насколько там все прямолинейно. Если речь идет о сортировке — сначала объяснение принципа, потом схема, потом код. И код всегда полностью рабочий. Никаких дополнительных уровней абстракции, никаких расширений, только базовая логика. Возникает мысль: а что если применить этот подход в современных условиях? Допустим, взять тривиальную задачу — сортировка огромного массива данных — и попробовать решить ее так, как учили тогда, на примере языка C.

Вот типичный фрагмент кода из тех времен (язык C):

#include <stdio.h>

void bubble(int arr[], int n) {
    int i, j, tmp;
    for (i = 0; i < n - 1; i++) {
        for (j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }
    }
}

int main() {
    int data[] = {5, 3, 8, 4, 2};
    int size = sizeof(data) / sizeof(data[0]);
    bubble(data, size);
    for (int i = 0; i < size; i++)
        printf("%d ", data[i]);
}

Читая этот код, словно слышишь голос преподавателя: если алгоритм работает медленно — не ной, перепиши руками. И ведь работало. Мы забыли это ощущение предсказуемости: если функция делает одно дело, она делает именно его. Задумывались ли вы, сколько сегодня скрытых слоев между вашим кодом и реальным исполнением?

Инженерия по принципу минимального шума

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

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

def extract_lines(path, keyword):
    result = []
    with open(path, 'r') as f:
        for line in f:
            if keyword in line:
                result.append(line.strip())
    return result

data = extract_lines('system.log', 'ERROR')
for d in data:
    print(d)

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

Принцип прозрачной ответственности

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

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

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello from oldschool style")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

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

Честность низкоуровневых решений

Еще один момент, который редко встречается сегодня: в старых учебниках многое объясняли через низкий уровень. Не только как работает алгоритм, но и что происходит глубже: память, стек, регистры, циклы, сравнения. Сейчас такие объяснения выглядят пугающе, но только пока не попробуешь вернуть их в практику. Я решил повторить упражнение из тех времен — реализовать примитивную строковую операцию на языке Assembly для архитектуры x86.

section .data
    text db "hello", 0

section .text
    global _start

_start:
    mov edx, 5
    mov ecx, text
    mov ebx, 1
    mov eax, 4
    int 0x80

    mov eax, 1
    xor ebx, ebx
    int 0x80

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

Попытка соединить эпохи

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

Большой вопрос к вам, читатели: пробовали ли вы когда-нибудь переписать современную задачу методами, которым вас учили в начале двухтысячных? Попробуйте хотя бы маленький фрагмент. Отключите инструменты, пишите руками. И, возможно, вы почувствуете то же, что почувствовал я — будто вернулся в место, которое давно хотел найти снова.

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


  1. seregina_alya
    26.11.2025 13:37

    Тут нет изящных паттернов, роутеров, middleware

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


  1. s0n0ma
    26.11.2025 13:37

    "Я решил повторить упражнение из тех времен — реализовать примитивную строковую операцию на языке Assembly для архитектуры x86."
    Может быть всё-таки на языке Assembler? ;)


    1. Neusser
      26.11.2025 13:37

      1. s0n0ma
        26.11.2025 13:37

        Всю сознательную жизнь его никто так не называл. Даже по той ссылке, что вы привели, сказано - alternatively assembler language. Писали мы код на языке Assembler'a и сохраняли в файлы с расширением .asm. Да, большинство англоязычных книг называют его именно так Assembly Language (тут я даже спорить не буду - сие есть факт), но в русскоязычной части аудитории его называли, называют и будут называть именно Ассемблером.


        1. mozgoffnet
          26.11.2025 13:37

          пока так же не перепишут прошлое


        1. Neusser
          26.11.2025 13:37

          Так к чему конкретно ваша претензия? Что автор не написал Assembler, как хотелось вам, а написал Assembly?

          Даже по той ссылке, что вы привели, сказано - alternatively assembler language

          Совершенно верно, alternatively.


          1. s0n0ma
            26.11.2025 13:37

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


  1. JBFW
    26.11.2025 13:37

    Потому что теперь слишком много абстракций ради абстракций.

    И не только в программировании - вот хотя бы настройка в Линуксе:
    - раньше у тебя есть 10 скриптов, которые выполняются тупо по порядку, по алфавиту, и в каждом написано что именно он делает. Надо поменять - залез и поменял.
    - сейчас у тебя 100 юнитов для systemd, которые что-то как-то в зависимости от чего-то должны выполнить. Надо поменять - пишешь 101, который должен работать, но если он почему-то не работает - изучаешь 100 юнитов в поисках возможной причины...


  1. pg_expecto
    26.11.2025 13:37

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

    Я пробовал.

    В одном проекте понадобилось реализовать поиск пути в графе . Реализовал алгоритм Дейкстры в виде таблиц и хранимой функции в PostgreSQL. В общем то тривиальная задача . Дел на пару часов.

    На дейлике (скрам аджайл все круто) рассказал - получил удивление и вопрос : а какую библиотеку использовал ?

    Долго понять не мог - о чем вопрос . Поняв, очень загрустил. Это же задача третьего курса института, чему тут удивляться ?

    Пожалуй, главное открытие в этом эксперименте — старые подходы не устарели. Они просто не вписываются в наш ритм.

    да, мир изменился... Хотя с другой стороны, DBA это мало коснулось - реляционная алгебра со времен со времен Эдгара Кодда как была с 70-х годов прошлого века так и осталась .


    1. aloginovpro
      26.11.2025 13:37

      А тестами покрыли?


  1. 2medic
    26.11.2025 13:37

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

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

    В какой-то момент я поймал себя на мысли, что такой код проще поддерживать, чем модные решения.

    До тех пор, пока он помещается на одном экране. А в те времена экраны были 24 строки на 80 символов. И именно из тех времён пришло понятие «листинг». Когда программу печатали на бумаге, лучше рулонной, т.к. на экране уже не так очевидно, где начинается логика, а где заканчивается.

    Скажите честно: неужели мы усложнили даже элементарные вещи ради видимой архитектурности?

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

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

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

    Но для сложных систем использование «архитектурности» не прихоть, а суровая необходимость.

    И, из личного опыта: я много работаю с legacy, и вижу, как быстро императивный процедурный код превращается в неподдерживаемое хрупкое спагетти. С одной стороны я согласен, что понимать его проще. Он перед тобой: линейный, предсказуемый и весь перед глазами. Не нужно прыгать по десятку файлов, чтобы понять, откуда взялись вот эти данные. Не нужно разгадывать ребус из паттернов. Это как инструкция по сборке мебели из прошлого века: «возьми болт А, вставь в отверстие Б, закрути гайкой В». Но всё это ровно до тех пор, пока инструкция помещается на одном листе.


  1. antonb73
    26.11.2025 13:37

    Всё хорошо пока пишешь Hello world, а потом нужно голову включать...


    1. mozgoffnet
      26.11.2025 13:37

      ...и лучше на asm


  1. IgnatF
    26.11.2025 13:37

    Раньше книги писали для людей. А нынче для того, чтобы просто факт написания книги был. Тут еще ИИ подключился ...