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

Иногда кажется, что старые учебники были каким-то магическим артефактом. Не было модных фреймворков, не было размеченных веток в репозиториях, не было удобных 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

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

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

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

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

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


  1. seregina_alya
    26.11.2025 13:37

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

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


    1. koreychenko
      26.11.2025 13:37

      Ну, в Go так обычно и пишут. Это вам не Java с миллионом абстракций.


      1. talbot
        26.11.2025 13:37

        Ну вот Java с миллионом абстракций (нет):

        package com.example;
        
        import com.sun.net.httpserver.HttpServer;
        
        import java.io.IOException;
        import java.net.InetSocketAddress;
        import java.nio.charset.StandardCharsets;
        
        public class HttpServerExample {
        
            public static void main(String[] args) {
                try {
                    var server = HttpServer.create(new InetSocketAddress(8080), 0, "/", exchange -> {
                        try (var out = exchange.getResponseBody()) {
                            var response = "Hello from oldschool style".getBytes(StandardCharsets.UTF_8);
                            exchange.sendResponseHeaders(200, response.length);
                            out.write(response);
                        }
                        exchange.close();
                    });
                    server.start();
                } catch (IOException e) {
                    System.out.println("Could not start HTTP server: " + e.getMessage());
                }
            }
        }


        1. koreychenko
          26.11.2025 13:37

          Это вкусовщина, конечно, но у меня от вызова методов на строке каждый раз кровь из глаз. Что в Java, что в Python.

          Ну и то, что в Java так можно не означает, что в Java так принято.


          1. talbot
            26.11.2025 13:37

            «Как принято» зависит от компании и проекта: где-то может быть netty «кишками наружу», где Future Future погоняет, а где-то (у меня сейчас такой проект) обычные разработчики даже не в курсе, что за фреймворк там под капотом, так как всё спрятано под толстыми слоями абстракций, которыми управляет команда платформы.

            Такая гибкость и является основным преимуществом Java, на мой взгляд.


      1. vlad4kr7
        26.11.2025 13:37

        Есть такая полезная вещь, как zero-cost abstraction.


  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. Neusser
          26.11.2025 13:37

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

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

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


          1. s0n0ma
            26.11.2025 13:37

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


  1. anonymous
    26.11.2025 13:37


  1. anonymous
    26.11.2025 13:37


    1. chnav
      26.11.2025 13:37

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

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

      (добавлено)

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


      1. s0n0ma
        26.11.2025 13:37

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


        1. chnav
          26.11.2025 13:37

          Да тоже решил проверить по своей первой книжке по ассемблеру, Л.Дао "Программирование микропроцессора 8088", нашел английский оригинал 1984 года, в оглавлении действительно термин Assembly. PS: жаль не даёт скачать, забрал бы в коллекцию...



  1. JBFW
    26.11.2025 13:37

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

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


    1. HardlinePeak936
      26.11.2025 13:37

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

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


  1. pg_expecto
    26.11.2025 13:37

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

    Я пробовал.

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

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

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

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

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


    1. aloginovpro
      26.11.2025 13:37

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


      1. Goron_Dekar
        26.11.2025 13:37

        Думаю, не меньше, чем библиотеку ;)


      1. RaptorTV
        26.11.2025 13:37

        А матами? Своих коллег)


    1. ALexKud
      26.11.2025 13:37

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


      1. pg_expecto
        26.11.2025 13:37

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

        Да, был долгий срач на Хабре на эту тему. По личному опыту участия в разработке - причина переноса бизнес логики с уровня СУБД на уровень приложения только одна - нет на рынке разработчиков СУБД.. Или уже нет, или почти нет. Опять таки по лично опыту - искали полгода, а время идет. Кончилось тем , что перешли на ОРМ и я ушел из проекта.

        Впрочем в серверной логике нужен стиль и принцип тоже, иначе будет больно.

        Стиль и принцип это основа нормальной разработки, не важно на уровне сервера или backend или фронтенда. Если бардак и авось, да будет больно - "ой у нас тут что-то все тормозит. А что вы хотели - у вас backend передает на выполнение запрос стоимостью 3 триллиона".


        1. 2medic
          26.11.2025 13:37

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


          1. pg_expecto
            26.11.2025 13:37

            Да. Знакомо, слышал.

            А СУБД для нас это хранилка данных.

            Цитата настоящего разработчика на конфколле по поводу деградации производительности информационной системы и проблем после старта опытно-промышленной эксплуатации .

            -Вы почему эксклюзивную блокировку используете ?

            -Это не мы. Это фреймворк .

            Тоже реальная цитата, на том же конфколле.


            1. RaptorTV
              26.11.2025 13:37

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


              1. bzq
                26.11.2025 13:37

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


              1. brownfox
                26.11.2025 13:37

                Чем лучше? :)


          1. brownfox
            26.11.2025 13:37

            Вообще-то, современные СУБД имеют мощные средства управления доступом к данным, их просто нужно знать . Ну а архитектура - это не только про красоту концепции, но и про производительность.


        1. masterthemac
          26.11.2025 13:37

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


      1. vvbob
        26.11.2025 13:37

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


        1. brownfox
          26.11.2025 13:37

          Это потому, что, во-первых, работа с локальными данными в нативном формате БД быстрее, чем с сетевыми с парой преобразований по дороге. А, во-вторых, потому, что разработчики СУБД уже потратили энное количество человек-часов на то, чтобы оптимизировать работу с информацией, которая не умещается в оперативную память целиком


          1. vvbob
            26.11.2025 13:37

            Да, всё так и есть.

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


            1. alexcohn
              26.11.2025 13:37

              Интересно, не изменилась ли эта ситуация в эпоху LLM? Какому-нибудь Kiro должно быть всё равно, каким кодом манипулировать: Java или диалект PL/SQL.


      1. brownfox
        26.11.2025 13:37

        Меня как, старого архитектора БД, этот модный подход дико раздражает. "Давайте будем использовать СУБД как Excel и гонять гигабайты между базой и микросервисами просто потому, что не умеем в оптимизацию и хранимые процедуры" :)

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


        1. FatherYan
          26.11.2025 13:37

          Понимаю Вашу боль, но это не единственная причина. Размазывание логики между разными слоями это тоже огромная проблема. Представьте, что часть у нас на фронтенде, часть на бэкенде, а часть в СУБД. И через год уже мало кто помнит что где и почему именно так. Такие моменты нужно описывать в документации и в комментариях в коде капсом "ЛОГИКА В БД!".


          1. brownfox
            26.11.2025 13:37

            Размазывание логики в проектах, состоящих не из одного скрипта/бинарника, практически неизбежно. У вас всё равно будет фронт (вебовский или standalone), бэк (возможно, микросервисный) с набором API и БД, не считая промежуточных уровней. В архитектурах с ESB ещё и шина со своей логикой доставки и преобразования данных. Логика на уровне базы данных тут не является чем-то исключительным.

            и в комментариях в коде капсом "ЛОГИКА В БД!"


            Тут кроме качественного документирования мало что поможет. Должно быть не "логика в БД", а ссылка на документ, где описана логика в БД :)

            Ну и живое участие в проекте датабазного разработчика, не совмещённого с должностью DBА экасплуатации (что не редкость).

            Это реально, если проект начинается с проектирования, а не со спринта "куда-то в ту сторону".


  1. 2medic
    26.11.2025 13:37

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

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

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

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

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

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

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

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

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

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


    1. voraa
      26.11.2025 13:37

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


      1. WhiteBehemoth
        26.11.2025 13:37

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


      1. 2medic
        26.11.2025 13:37

        совсем не маленькие и на одном экране не помещаются

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

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

        они работают быстро и правильно

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

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


      1. gres_84
        26.11.2025 13:37

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


    1. aamonster
      26.11.2025 13:37

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

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


    1. BigVal
      26.11.2025 13:37

      Например, для циклов использовалась переменная X. Причём для всех.

      Не, для всех циклов того времени (в качестве счетчика) использовалась переменная i, а для вложенных j :-) ну во всяком случае в книгах которые я читал...


  1. antonb73
    26.11.2025 13:37

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


  1. anonymous
    26.11.2025 13:37


  1. IgnatF
    26.11.2025 13:37

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


  1. jingvar
    26.11.2025 13:37

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


  1. a2a4
    26.11.2025 13:37

    Спасибо автору за статью, я сам собираю старые учебники по программированию, уже 256 книг примерно, люблю 1 книжку ассемблер от Юрова, и приятно читать как что автор написал так и мои комментарии 25 лётной давности на полях, эхх


    1. astenix
      26.11.2025 13:37

      На 256-й можно остановиться


      1. Devastator82
        26.11.2025 13:37

        Да ну, 1024 и ни одной меньше!


      1. 0xff80ff
        26.11.2025 13:37

        Лучше остановиться на 255, чтоб не случилось переполнение.


  1. WatchMaster
    26.11.2025 13:37

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


  1. GBR-613
    26.11.2025 13:37

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


    1. megadrugo2009
      26.11.2025 13:37

      Вы использовали regexp при замене? Если да, то справедливо.


    1. randomsimplenumber
      26.11.2025 13:37

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


      1. GBR-613
        26.11.2025 13:37

        @megadrugo2009 Дажене regexp, а точное совпадение. В двух словах, дело было так: был некий совершенно уникальный ключ, который был в одном единственном месте, и то не всегда. Никто из моих критиков не смог придумать ситуацию, когда он мог появляться больше, чем один раз, или могло появиться что-то с чем его можно было бы спутать. И вот надо было этот ключ найти и его значение перевернуть справа налево. (Действие происходило на Ближнем Востоке.) Этот XML имел только одно предназначение: какой-то пакет делал из него PDF, и все были согласны, что лучше было бы поменять готовый PDF, но идея поменять его папу на XML привела начальство в ужас.


  1. arfedulov
    26.11.2025 13:37

    А сколько уровней абстракции расположено между приведенными в статье примерами сервера на Go и строковой операции на ассемблере?


    1. koreychenko
      26.11.2025 13:37

      Там ещё и рантайм :-)


  1. izibrizi2
    26.11.2025 13:37

    У вас в коде на питоне, вместо формирования списка результатов, можно использоваьь yield, чтобы не тратить память :)


  1. WhiteBehemoth
    26.11.2025 13:37

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

    Вот через недельку начинается Advent of Code 2025 ( adventofcode.com ) вот там - и чему учили вспоминать придется и новому учиться.

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


  1. aamonster
    26.11.2025 13:37

    Так лишние уровни абстракции не от хорошей жизни появляются. И простой код в ваших примерах – потому что вы решаете простую задачу. Но в целом да, принцип KISS (keep it simple, stupid) никто не отменял. И, в принципе, современные языки помогают придерживаться этого принципа. Сравните Swift с Objective C и C++ или Kotlin с Java.


  1. agoncharov
    26.11.2025 13:37

    Пример на Go не низкоуровневый. Попробуйте написать тоже самое используя только tcp соединения. Просто в Go это часть стандартной библиотеки


  1. Dafostr
    26.11.2025 13:37

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


    1. LAutour
      26.11.2025 13:37

      Но ведь кто-то все-равно должен писать эти выверенные и отлаженные библиотеки на явно прописанных алгоритмах внутри.


    1. bear11
      26.11.2025 13:37

      Плюс обработка всевозможных неочевидных (но встреченных и предусмотренных в жизни библиотеки) случаев, типа встреченных случайных символов UNICODE, обработка гигантских строк (что будет, если подать на вход 1GB cтроку?), встроенного протоколирования и уже посчитанной и задокументированной сложности работы этой библиотеки.


  1. dkfbm
    26.11.2025 13:37

    text db "hello", 0

    А если не "hello", а "привет"? И не в 1251, а в UTF-8.


    1. randomsimplenumber
      26.11.2025 13:37

      Ну, будет не hello а привет. Современный транслятор в курсе про utf8 (должен быть)


      1. dkfbm
        26.11.2025 13:37

        Современный транслятор

        А при чём тут транслятор? Там в syscall (aka int 0x80) явно передаётся размер строки 5 байт.


        1. randomsimplenumber
          26.11.2025 13:37

          Ну и? Число 5 транслятор сосчитал? Ну он ненулевые байты utf8 точно так же сосчитает.


          1. dkfbm
            26.11.2025 13:37

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


            1. stephanthe
              26.11.2025 13:37

              text db "hello", 0

              len=$-text

              ...

              mov edx, len

              Что-типа такого. Может не совсем точно, больше 30 лет с asm не имел дело.


              1. randomsimplenumber
                26.11.2025 13:37

                Допустим, программисту нужно передать не hello, а что то из Шекспира. Он что, руками байты считает? 30 лет назад компилятор уже умел сам сосчитать длину текста в байтах. А символы utf8 - тут уже от программиста зависит, как он собирается их обрабатывать. Если, например, сохранять на диск - можно и в байтах.


                1. dkfbm
                  26.11.2025 13:37

                  Он что, руками байты считает?

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

                  mov edx, strlen(text)

                  Такой инструкции просто нет.

                  Тут предлагали вычислять по смещению памяти – уже лучше, но тоже не будет работать. Во-первых, совершенно разные сегменты памяти. Во-вторых, компилятор будет выравнивать адреса данных по границе 16/32/64 бит, и если длина в байтах не кратна 2/4/8, в конце строки будет мусор.

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


                  1. randomsimplenumber
                    26.11.2025 13:37

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


                    1. dkfbm
                      26.11.2025 13:37

                      макрос, который сам считал длину данных.

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


                      1. randomsimplenumber
                        26.11.2025 13:37

                        Бывает strlen, бывает sizeof. Важно не путать ;)


            1. bormant
              26.11.2025 13:37

              Пусть запишет ;-)

              text_l EQU $-text