Комментарии 92
Тут нет изящных паттернов, роутеров, middleware
Но ведь рано или поздно приходится пояснять не только базовые вещи, а то, где нужны те самые паттерны и роутеры) И появляется сложный код. А хороший современный учебник или курс и так редко переусложняет базовые примеры, когда без этого можно обойтись
Ну, в Go так обычно и пишут. Это вам не Java с миллионом абстракций.
Ну вот 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());
}
}
}Это вкусовщина, конечно, но у меня от вызова методов на строке каждый раз кровь из глаз. Что в Java, что в Python.
Ну и то, что в Java так можно не означает, что в Java так принято.
«Как принято» зависит от компании и проекта: где-то может быть netty «кишками наружу», где Future Future погоняет, а где-то (у меня сейчас такой проект) обычные разработчики даже не в курсе, что за фреймворк там под капотом, так как всё спрятано под толстыми слоями абстракций, которыми управляет команда платформы.
Такая гибкость и является основным преимуществом Java, на мой взгляд.
Есть такая полезная вещь, как zero-cost abstraction.
"Я решил повторить упражнение из тех времен — реализовать примитивную строковую операцию на языке Assembly для архитектуры x86."
Может быть всё-таки на языке Assembler? ;)
Всю сознательную жизнь его никто так не называл. Даже по той ссылке, что вы привели, сказано - alternatively assembler language. Писали мы код на языке Assembler'a и сохраняли в файлы с расширением .asm. Да, большинство англоязычных книг называют его именно так Assembly Language (тут я даже спорить не буду - сие есть факт), но в русскоязычной части аудитории его называли, называют и будут называть именно Ассемблером.
Так к чему конкретно ваша претензия? Что автор не написал Assembler, как хотелось вам, а написал Assembly?
Даже по той ссылке, что вы привели, сказано - alternatively assembler language.
Совершенно верно, alternatively.
"Я решил повторить упражнение из тех времен — реализовать примитивную строковую операцию на языке Assembly для архитектуры x86."Может быть всё-таки на языке Assembler? ;)
Тоже резануло глаз :) С одной стороны в статье упомянуты старые конспекты 90-х, с другой - абсолютно нетипичный для того времени термин. Википедии тогда не было, а в переводных книгах, как и отечественных, писали "ассемблер" :)
(добавлено)
Это всё придирки :) Спасибо автору, что поднял важную тему. Сегодня приложения пухнут от обилия библиотек, потом концов не найдёшь. Недавно была статья про строковые типы, очень показательно.
И я о том же. Но я (наверное как и автор) тоже стараюсь правильно использовать английский язык и благодаря ему я обратил внимание на тот факт, что действительно assembly language - это устоявшийся термин для языков ассемблера, в английском языке. А вот в русском - это всё-таки ассемблер.
Да тоже решил проверить по своей первой книжке по ассемблеру, Л.Дао "Программирование микропроцессора 8088", нашел английский оригинал 1984 года, в оглавлении действительно термин Assembly. PS: жаль не даёт скачать, забрал бы в коллекцию...
Потому что теперь слишком много абстракций ради абстракций.
И не только в программировании - вот хотя бы настройка в Линуксе:
- раньше у тебя есть 10 скриптов, которые выполняются тупо по порядку, по алфавиту, и в каждом написано что именно он делает. Надо поменять - залез и поменял.
- сейчас у тебя 100 юнитов для systemd, которые что-то как-то в зависимости от чего-то должны выполнить. Надо поменять - пишешь 101, который должен работать, но если он почему-то не работает - изучаешь 100 юнитов в поисках возможной причины...
Не согласен с «абстракциями ради абстракций», пускай местами и иногда даже часто бывает такое. Просто одни умники ограничивают других под разными предлогами, а по итогу получаем какую-нибудь жабу с десятками тысяч библиотек, ещё большим числом классов на каждый чих и постоянно вводимыми улучшениями языка. И нет, это абстрактный пример, который на свой манер относится к большинству языков, а не намёк на Java. А ведь для всего этого хватит и упомянутого в статье ассемблера — пускай и будет слегка громоздко и не слишком легко читаемо (так и решайте эту проблему, а не защищайте меня ;).
P.s. Если кто не понял, я не имею ничего против абстракций и их качества. Просто пытаюсь обратить ваше внимание на замкнутый круг: программиста ограничивают и тем самым вынуждают себя давать взамен абстракции, чтобы тот смог сделать тоже самое, что и раньше, но в соответствии с предлогом изначального ограничения :).
Большой вопрос к вам, читатели: пробовали ли вы когда-нибудь переписать современную задачу методами, которым вас учили в начале двухтысячных?
Я пробовал.
В одном проекте понадобилось реализовать поиск пути в графе . Реализовал алгоритм Дейкстры в виде таблиц и хранимой функции в PostgreSQL. В общем то тривиальная задача . Дел на пару часов.
На дейлике (скрам аджайл все круто) рассказал - получил удивление и вопрос : а какую библиотеку использовал ?
Долго понять не мог - о чем вопрос . Поняв, очень загрустил. Это же задача третьего курса института, чему тут удивляться ?
Пожалуй, главное открытие в этом эксперименте — старые подходы не устарели. Они просто не вписываются в наш ритм.
да, мир изменился... Хотя с другой стороны, DBA это мало коснулось - реляционная алгебра со времен со времен Эдгара Кодда как была с 70-х годов прошлого века так и осталась .
А тестами покрыли?
Многие вещи можно делать намного проще через таблицы и хранимые процедуры. Но это типа антипаттерн сегодня, и логику размазывают по клиенту со всеми левыми билиотеками и фреймворками и прочими прелестями в дальнейшем. Впрочем в серверной логике нужен стиль и принцип тоже, иначе будет больно.
Многие вещи можно делать намного проще через таблицы и хранимые процедуры. Но это типа антипаттерн сегодня
Да, был долгий срач на Хабре на эту тему. По личному опыту участия в разработке - причина переноса бизнес логики с уровня СУБД на уровень приложения только одна - нет на рынке разработчиков СУБД.. Или уже нет, или почти нет. Опять таки по лично опыту - искали полгода, а время идет. Кончилось тем , что перешли на ОРМ и я ушел из проекта.
Впрочем в серверной логике нужен стиль и принцип тоже, иначе будет больно.
Стиль и принцип это основа нормальной разработки, не важно на уровне сервера или backend или фронтенда. Если бардак и авось, да будет больно - "ой у нас тут что-то все тормозит. А что вы хотели - у вас backend передает на выполнение запрос стоимостью 3 триллиона".
СУБД - это инфраструктурный слой. Поэтому если есть необходимость в приложении получить чистый домен, то логика из СУБД просто обязана быть вынесена в домены. Исключения, конечно же, могут быть.
Да. Знакомо, слышал.
А СУБД для нас это хранилка данных.
Цитата настоящего разработчика на конфколле по поводу деградации производительности информационной системы и проблем после старта опытно-промышленной эксплуатации .
-Вы почему эксклюзивную блокировку используете ?
-Это не мы. Это фреймворк .
Тоже реальная цитата, на том же конфколле.
Я спрашивал у многих людей и у нейронки. Все дружно отвечали, что бизнес-логика должна быть на бэкенде. А всякие триггеры и функции в том же PostgreSQL лучше не писать
Триггеры лишний раз конечно же делать не надо, так как потом умаешься искать ту магию, которая в этом триггере работает. Но если надо сделать сложный запрос с аггрегацией данных из нескольких таблиц, то СУБД с этим справится радикально эффективнее, чем бекенд. А вот функции пишите на здоровье, с ними всё хорошо.
Чем лучше? :)
Вообще-то, современные СУБД имеют мощные средства управления доступом к данным, их просто нужно знать . Ну а архитектура - это не только про красоту концепции, но и про производительность.
Еще причиной, на мой взгляд, может являться то, что не всем разработчикам может быть очевидно, что какая-то логика скрывается в БД. В большом проекте, где много команд и где ответственность разделена, а разработчики зачастую и в БД имеют ограниченный доступ, иногда даже и нет возможности легко узнать есть ли какой-то триггер на таблице или нет. Не говоря уж о его коде.
У меня было в практике, перенес довольно мудреную логику в БД, на матвью. Причина - код на яве банально не справлялся с задачей в приемлемое время, Т.е. сам код работал, и довольно хорошо, но на по настоящему больших объемах данных он просто не укладывался в отпущенные лимиты по времени, и никакая оптимизация не помогала, слишком много времени уходило на получение и обработку данных из БД. В итоге перетащили все в матвью, код там тот еще получился.. зато отрабатывало все очень быстро.
Это потому, что, во-первых, работа с локальными данными в нативном формате БД быстрее, чем с сетевыми с парой преобразований по дороге. А, во-вторых, потому, что разработчики СУБД уже потратили энное количество человек-часов на то, чтобы оптимизировать работу с информацией, которая не умещается в оперативную память целиком
Да, всё так и есть.
Единственно что, код в Яве был, конечно, куда как понятнее и лучше поддерживаемый, то что в БД получилось выглядит довольно жутковато, особенно для тех кто с SQL не очень хорошо дружит. Но на это пришлось пойти осознанно, пожертвовали наглядностью и простотой поддержки в пользу производительности.
Меня как, старого архитектора БД, этот модный подход дико раздражает. "Давайте будем использовать СУБД как Excel и гонять гигабайты между базой и микросервисами просто потому, что не умеем в оптимизацию и хранимые процедуры" :)
Причём, такой паттерн не просто широко используется, но и пропагандируется.
Понимаю Вашу боль, но это не единственная причина. Размазывание логики между разными слоями это тоже огромная проблема. Представьте, что часть у нас на фронтенде, часть на бэкенде, а часть в СУБД. И через год уже мало кто помнит что где и почему именно так. Такие моменты нужно описывать в документации и в комментариях в коде капсом "ЛОГИКА В БД!".
Размазывание логики в проектах, состоящих не из одного скрипта/бинарника, практически неизбежно. У вас всё равно будет фронт (вебовский или standalone), бэк (возможно, микросервисный) с набором API и БД, не считая промежуточных уровней. В архитектурах с ESB ещё и шина со своей логикой доставки и преобразования данных. Логика на уровне базы данных тут не является чем-то исключительным.
и в комментариях в коде капсом "ЛОГИКА В БД!"
Тут кроме качественного документирования мало что поможет. Должно быть не "логика в БД", а ссылка на документ, где описана логика в БД :)
Ну и живое участие в проекте датабазного разработчика, не совмещённого с должностью DBА экасплуатации (что не редкость).
Это реально, если проект начинается с проектирования, а не со спринта "куда-то в ту сторону".
Когда читаешь код того времени, сразу видно, где начинается логика, где заканчивается, что хранится в памяти, какие данные меняются и как все связано.
Это потому, что код того времени был процедурным и императивным. Зачастую зажат в рамки того времени. Например, для циклов использовалась переменная X. Причём для всех. Просто потому, что счёт памяти шёл на килобайты, и каждая переменная (область памяти) на счету.
В какой-то момент я поймал себя на мысли, что такой код проще поддерживать, чем модные решения.
До тех пор, пока он помещается на одном экране. А в те времена экраны были 24 строки на 80 символов. И именно из тех времён пришло понятие «листинг». Когда программу печатали на бумаге, лучше рулонной, т.к. на экране уже не так очевидно, где начинается логика, а где заканчивается.
Скажите честно: неужели мы усложнили даже элементарные вещи ради видимой архитектурности?
И да и нет. Раньше программа писалась одним человеком для одного компьютера с одним пользователем, и она работала с десятком-другим килобайт памяти. Сегодняшние приложения это распределённые системы с кучей внешних интеграций. Попробуйте описать эту логику в 24-х строках.
Сегодня над проектом работает работает несколько разработчиков, которые постоянно меняются. Нужны чёткие контракты, интерфейсы и соглашения, чтобы один человек, меняя логику оплаты, не сломал доставку.
Да, если для простейшего CRUD пишут гескагональную архитектуру с CQRS это вредно и избыточно.
Но для сложных систем использование «архитектурности» не прихоть, а суровая необходимость.
И, из личного опыта: я много работаю с legacy, и вижу, как быстро императивный процедурный код превращается в неподдерживаемое хрупкое спагетти. С одной стороны я согласен, что понимать его проще. Он перед тобой: линейный, предсказуемый и весь перед глазами. Не нужно прыгать по десятку файлов, чтобы понять, откуда взялись вот эти данные. Не нужно разгадывать ребус из паттернов. Это как инструкция по сборке мебели из прошлого века: «возьми болт А, вставь в отверстие Б, закрути гайкой В». Но всё это ровно до тех пор, пока инструкция помещается на одном листе.
Программы, которые рассчитывают радиационную защиту ядерного реактора, считают баллистику для запуска ракет, управляют системами пво, совсем не маленькие и на одном экране не помещаются. Но они работают быстро и правильно. Быстро, потому, что них нет всяких уровней абстракций, правильно потому, что они по сути довольно просто и прямолинейно написаны.
главное "потому, что" - это статичность задачи. Рассчитали радиационную защиту, - никто назавтра не придет и не скажет включить в защитный контур наводнения, землетрясения и ураганы. Причем запросы будут не сразу, а постепенно. И потом еще уточнения, типа затопление не водой, а канализацией.
В коммерческой разработке не зря стали популярными всевозможные методологии основанные на цикличности. И управлять проще и сроки прогнозировать.
совсем не маленькие и на одном экране не помещаются
Когда императивный код перестаёт помещаться на экране, программисту приходится постоянно скроллить его туда-сюда. При этом редакторы того времени были достаточно убоги: не было подсветки синтаксиса, автодополнения, закладок. Поэтому программы сначала распечатывали — листинг позволял ставить пометки, видеть логику целиком и планировать изменения. Подсветка синтаксиса была не нужна по причине монохромных дисплеев или вообще их отсутствия, зачастую вывод шёл сразу ну печать.
Но при росте кодовой базы у человека заканчивалось «контекстное окно». Он не мог удержать в голове всю логику. Появилась необходимость делить код на модули, использовать абстракции и структурировать его, чтобы система оставалась понятной и управляемой. Так постепенно формируется архитектура — набор правил и соглашений, позволяющий поддерживать и развивать сложную систему.
они работают быстро и правильно
С этим никто не спорит. Есть масса ситуаций, где прямолинейный код выгоден. Тем более, что программирование это не обязательно написание строчек в редакторе. В своё время, проходя службу в СА, я запрограммировал «контроллер сигнализации». Всё было спаяно на обычных релюшках, иногда не хватало тока удержания, и приходилось в параллель паять конденсатор. Концевики - провода - релюшки - лампочки - сирена. Но вот поддерживать такое решение — такое себе. Всё было припаяно проводами друг к другу, и получилось реальное спагетти. В случае доработки, проще выкинуть и запрограммировать спаять новое. На интегральных схемах, размещённых на плате.
Быстро и прямо работать можно, но чем больше и сложнее система, тем важнее архитектура и структурирование кода.
Вы работали с такими программами? Просто я работал с одной из. Да, программа работала быстро, правильно, но менять ее боялся сам автор, потому что, как указано в комментарии выше "хрупкое спагетти".
Раньше программа писалась одним человеком для одного компьютера с одним пользователем, и она работала с десятком-другим килобайт памяти.
Скучаю по таким задачкам :-). Сейчас такое – совсем редкость, не бывает достаточно мелких прог, которые можно было бы оптимизировать до упора... Пишешь что-то большое, думая в основном о том, как его потом поддерживать.
Например, для циклов использовалась переменная X. Причём для всех.
Не, для всех циклов того времени (в качестве счетчика) использовалась переменная i, а для вложенных j :-) ну во всяком случае в книгах которые я читал...
Всё хорошо пока пишешь Hello world, а потом нужно голову включать...
Раньше книги писали для людей. А нынче для того, чтобы просто факт написания книги был. Тут еще ИИ подключился ...
Что вы хотите если большинство новых модных штук пишут без головы, причем новое Легаси там растёт еще быстрее.
Спасибо автору за статью, я сам собираю старые учебники по программированию, уже 256 книг примерно, люблю 1 книжку ассемблер от Юрова, и приятно читать как что автор написал так и мои комментарии 25 лётной давности на полях, эхх
Вот на первом же примере можно поговорить об усложнении. Считается ли за излишнее усложнение кода введение в сортировку пузырьком счетчика перестановок и проход во втором цикле только неотсортированной части массива? Вот мой препод в универе так не считал и без них лабораторные не принимал, но как только вы добавите их в алгоритм, то легкость и предсказуемость кода этого примера резко снизится. Надо будет понимать зачем это "лишние" действия в коде присутствуют и на что влияют
Попробовал я как-то вместо того, чтобы подгружать XML parser и добавлять зависимость, просто найти в XML файле нужный мне кусок и поменять его на то, что мне было нужно. Ох и скандал получился...
Вы использовали regexp при замене? Если да, то справедливо.
Никто такого не любит. Костыль, который понимает только автор, никто кроме автора нк может с ним ничего сделать, никто (даже автор) не знает, правильно ли он работает и не свалится ли в каких то граничных условиях.
@megadrugo2009 Дажене regexp, а точное совпадение. В двух словах, дело было так: был некий совершенно уникальный ключ, который был в одном единственном месте, и то не всегда. Никто из моих критиков не смог придумать ситуацию, когда он мог появляться больше, чем один раз, или могло появиться что-то с чем его можно было бы спутать. И вот надо было этот ключ найти и его значение перевернуть справа налево. (Действие происходило на Ближнем Востоке.) Этот XML имел только одно предназначение: какой-то пакет делал из него PDF, и все были согласны, что лучше было бы поменять готовый PDF, но идея поменять его папу на XML привела начальство в ужас.
А сколько уровней абстракции расположено между приведенными в статье примерами сервера на Go и строковой операции на ассемблере?
У вас в коде на питоне, вместо формирования списка результатов, можно использоваьь yield, чтобы не тратить память :)
Большой вопрос к вам, читатели: пробовали ли вы когда-нибудь переписать современную задачу методами, которым вас учили в начале двухтысячных?
Вот через недельку начинается Advent of Code 2025 ( adventofcode.com ) вот там - и чему учили вспоминать придется и новому учиться.
А на рабочих проектах (у ремесленников, коих среди программистов большинство нынче) алгоритмы скорее исключение, чем правило. Пару раз сам писал (типа оптимизации распределения ресурсов по куче входных параметров - было очень интересно), пару раз чужие "велосипеды" ремонтировал - куда менее интересно, если помягче сказать. Но обычно - сперва смотришь "стандартные" библиотеки, потом "популярные", а потом принимаешь решение, нужен ли новый велосипед.
Так лишние уровни абстракции не от хорошей жизни появляются. И простой код в ваших примерах – потому что вы решаете простую задачу. Но в целом да, принцип KISS (keep it simple, stupid) никто не отменял. И, в принципе, современные языки помогают придерживаться этого принципа. Сравните Swift с Objective C и C++ или Kotlin с Java.
Пример на Go не низкоуровневый. Попробуйте написать тоже самое используя только tcp соединения. Просто в Go это часть стандартной библиотеки
Именно явно прописанные алгоритмы шумны и многословны. Допустишь малейшую оплошность в написании цифры, скобки или знака - пиши пропало, замучаешься отлаживать, искать. Особенно в случае рекурсии. Поэтому использование выверенных и отлаженных библиотек с простым и ясным интерфейсом убирает весь этот шум и многословие знаков (где всё разложено до мельчайших подробностей) и привносит простую и чёткую идею в код. Идею в чистом виде.
Но ведь кто-то все-равно должен писать эти выверенные и отлаженные библиотеки на явно прописанных алгоритмах внутри.
Плюс обработка всевозможных неочевидных (но встреченных и предусмотренных в жизни библиотеки) случаев, типа встреченных случайных символов UNICODE, обработка гигантских строк (что будет, если подать на вход 1GB cтроку?), встроенного протоколирования и уже посчитанной и задокументированной сложности работы этой библиотеки.
text db "hello", 0А если не "hello", а "привет"? И не в 1251, а в UTF-8.
Ну, будет не hello а привет. Современный транслятор в курсе про utf8 (должен быть)
Современный транслятор
А при чём тут транслятор? Там в syscall (aka int 0x80) явно передаётся размер строки 5 байт.
Ну и? Число 5 транслятор сосчитал? Ну он ненулевые байты utf8 точно так же сосчитает.
Погодите, транслятор ещё не запускался. Пока мы видим код, написанный программистом. И чтобы передать корректное число байт, ему нужно помнить, сколько занимает каждый символ.
text db "hello", 0
len=$-text
...
mov edx, len
Что-типа такого. Может не совсем точно, больше 30 лет с asm не имел дело.
Допустим, программисту нужно передать не hello, а что то из Шекспира. Он что, руками байты считает? 30 лет назад компилятор уже умел сам сосчитать длину текста в байтах. А символы utf8 - тут уже от программиста зависит, как он собирается их обрабатывать. Если, например, сохранять на диск - можно и в байтах.
Он что, руками байты считает?
Вы удивитесь, но в ассемблере именно так: программисты сами, руками считают байты. Нельзя написать
mov edx, strlen(text)Такой инструкции просто нет.
Тут предлагали вычислять по смещению памяти – уже лучше, но тоже не будет работать. Во-первых, совершенно разные сегменты памяти. Во-вторых, компилятор будет выравнивать адреса данных по границе 16/32/64 бит, и если длина в байтах не кратна 2/4/8, в конце строки будет мусор.
Единственный вариант универсального решения тут: добавить в конец строки символ-терминатор (традиционно 0), вычислить в ассемблерном коде её длину (своя реализация strlen) и уже это значение передать в регистр перед вызовом прерывания.
Странно, 30 лет назад на асме я мог сделать макрос, который сам считал длину данных. Ну, разница между 2 адресами в памяти раньше была известна компилятору. Сейчас походу секрет утерян.
макрос, который сам считал длину данных.
Так это то же самое, что кастомный strlen. Я же не утверждаю, что на ассемблере вообще невозможно выводить строки произвольной длины и в разных кодировках. Речь только о том, что данная реализация такого не предусматривает.
Пусть запишет ;-)
text_l EQU $-text
И ни одной отсылки к славной книге по программированию из прошлого?
Не совсем согласен с принципом простых примеров в старых учебниках. С течением времени системы стали масштабные и уже обычным обработчиком запросов не покрыть всю логику. Точнее написать-то можно, но мозг врят ли будет рад такому куску логики, без систематизации архитектуры.
Но про понимание не только языка программирования, а ещё и "языка машин" согласен. Очень не хватает понимая всех слоев абстракции при изучении нового инструмента. Хочется не доверять магии, а управлять её.
А сейчас написание своими руками называют "писать велосипеды". Я, к примеру, разрабатываю в очень ограниченной IDE. И пытаютсь только на random да iterttools написать нейросеть. Да, это велосипед, но он ручной, зато я понимаю, что в нём крутит педали и как работает тормоз, могу удалить колесо и добавить двойной багажник.
Этот пример по современным меркам бесполезный. Но он дает ощущение честности: ты буквально видишь, как данные проходят путь от памяти к выводу.
ХЗ. Я вижу не читаемые каракули и магические константы) Хотя читать ассемблер умею)
Очень хорошая статья. Но, поскольку, я не имею большого опыта в проектах на много человек, мне очень сложно что-то сказать про упоминаемые абстракции.
С одной стороны, мне кажется вопрос остро стоит о проектировании. Чем больше абстракций --
тем сложнее структура -- тем сложнее сообразить "как этим пользоваться?"
И постоянная гонка за "идеальной архитектурой" не всегда приводит к чему-то хорошему.
С другой стороны, полностью приземляться и писать в прикладном духе тоже не всегда хорошо.
Но, то, что старые учебники и книги рецептов учат нас вникать в процесс -- кажется очень похожим на правду.
И это наверное лучшее, что можно вынести.
Цель учебника, который вы приводите в статье - дать базовые знания, с чем он отлично справляется, назовем это первым знакомством с готовкой.
При этом структура в которой он подаёт информацию: задача - пример - улучшение, может как зайти, так и не зайти читателю.
На данном этапе нам нужен результат, вне зависимости от того, как выглядит блюдо.
Если пользователя устраивает результат, он может продолжить также готовить. Но, если продолжать развивать навык готовки, то появляются новые нюансы: внешний вид блюда, посуда, подача и так далее.
Таким образом фокус смещается, уже не достаточно только чтобы покушать(код работал) но и ещё куча других факторов(легко читалось, легко менять, не ломалось и многое другое).
И вот сегодняшнее айти, это блюдо приготовленное людьми, которые учились на таких учебниках. Они придумали много концептов, подходов, правил - все чтобы ресторан был максимально удобен, популярен и полезен как для работников, так и для гостей. Конечно, часть из них, были придуманы чтобы потешить свое самолюбие или доказать другим свои умения. Но принцип думаю понятен.
Но как и в ресторане есть блюда разного ценового сегмента, и рестораны разной доступностю, так и вам никто не мешает писать код так, как вы считаете нужным.
Если надо чтобы работало - готовьте как дома, но не забывайте, что такое блюдо неприлично подавать гостю.
"Я решил проверить, получится ли сделать современный небольшой модуль с тем же принципом. Взял задачу создания простейшего HTTP-обработчика без каких-либо фреймворков. Вот пример на языке Go:"
Ага, простейший обработчик использует методы и типы из двух модулей, один из которых содержит сетевой стек и веб-сервер)
В нулевых только начинала подниматься проблема кроссплатформенной разработки, а теперь - это чуть ли не стандартное решение. Кроссплатформенность - кормовая база для абстракций. Тут без них никак. Декларативные описания UI - тоже самое. Что же касается алгоритмов, то - да, тут очень полезно попробовать написать свою реализацию для объективного восприятия чужих реализаций.
Линейность программирования и его низкоуровневость, в былые времена, напрямую зависела от аппаратного обеспечения той эпохи: коммутаторы, перфокарты, магнитная лента, консоль, интерпретаторы и т.д. Но даже тогда, при переходе с Basic на Pascal, было понятно что последний более гибок, шустр и практичней для поставленных задач. Куски готовых подпрограмм гуляли от продукта к продукту и могли сойти за современные фреймворки. Пальцы и сейчас помнят vc.exe & Shift + F4.

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