Есть ощущение, что периоды идиократии уже случались в прошлом. Это происходило даже в обществах, где люди умели считать в уме, знали стихи и обладали одним из самых передовых образований в мире. Тем не менее, половина страны заряжала банки с водой перед телевизором, а другая половина несли деньги в финансовые пирамиды вроде МММ. Казалось бы, качественное и фундаментальное образование должно было защитить общество от подобного мракобесия. Но реальность оказалась сложнее.
Подход к образованию действительно нуждается в переосмыслении. Большинство людей до сих пор учатся по шаблонам, разработанным веками назад. То, что происходит сейчас, — это не хорошо и не плохо, это просто перемены, требующие новых подходов. Главное в образовании — развивать у человека достаточное количество нейронных связей и стимулировать активную работу мозга, чтобы к зрелому возрасту он обладал развитым мышлением и был готов к интеграции в профессиональную среду.
Кстати, ещё Сократ говорил: «Нынешняя молодежь привыкла к роскоши, она отличается дурными манерами, презирает авторитеты, не уважает старших, дети спорят со взрослыми, жадно глотают пищу, изводят учителей».
Этот цикл изменений — часть естественного развития общества.
Го не принуждает, к сожалению. Обработку ошибок можно просто скипать. Вот в языках, где есть монады типа Result, тебе уже точно придется распаковать ее и проверить, что внутри — ошибка или результат. И придется обработать все.
Эх, предложили бы сразу монады Result и Maybe. И еще pattern matching с ними сразу бы завезли для их обработки красиво. А там и до Railway oriented programming рукой подать =)
Фактически, все, что десятилетиями изучается широкими массами в программировании, так или иначе создано опытными людьми, как компиляция их пройденного пути с набитыми шишками на поприще программирования.
И не важно, начнете ли вы читать «Совершенный код» Макконелла, «Рефакторинг» Фаулера, «Чистую архитектуру» дяди Боба или «Паттерны» от Банды четырех — все это передача ими эмпирического опыта в предметной области. Это не доказанные истины, не математически стройные и выверенные подходы. По большей части это укладывается в формулу: "я писал много-много лет, даже десятилетий, и кое-что понял, а то, что понял, хочу передать вам".
SOLID, YAGNI, DRY, KISS, DDD, TDD и так далее и тому подобное — все это инструменты, получившие широкую известность в профессии. Инструменты, которые стоит изучить, переняв опыт тех, кто это все собрал вместе и записал в красивые и запоминающиеся аббревиатуры.
А вот применять эти инструменты уже все учатся сами, и разумный баланс в своей работе, в своем проекте всех этих принципов, паттернов и подходов каждый находит исключительно сам.
Собственно, об этом сказано в заключительном слове в статье. Сектантство всегда плохо, догматизм того хуже. Ведь "только ситхи все возводят в абсолют". 😉
Не только в Python, но и в Clojure, которые теперь активно продвигает дядя Боб. Тот же Javascript. Все это уже используется активно в энтерпрайз разработке. Ну и если человек видит, что что-то имеет явное указание по соглашению, что это нельзя трогать (то же нижнее подчеркивание в начале название), но берет и игнорирует это, то вероятно такой разработчик в любом случае набедокурит в другом месте, если не в этом. Обратится к чему-то приватному, что обозначено, как приватное, можно только осознано. Если ты хотя бы базово знаком с конвенцией языка, на котором пишешь.
К тому же есть другие способы сокрытия. Через замыкания внутри тех же функций.
Тут хотелось бы спросить, а какие именно ограничения Java помогают совершать принципиально меньше ошибок? В случае с Haskell я бы мог понять такое утверждение, ведь не зря говорят "if a Haskell program compiles, it probably works". Его компилятор и система типов действительно делают нечто особенное по сравнению с большинством языков. Но Java?
Миллениалы изобрели процедурное программирование со всеми его недостатками.
Если в программе есть и процедурный и другие подходы - оно от этого так сильно хуже? Мы уже видели в виде классической Java через что приходится проходить и какие финты придумывать, чтобы существовать исключительно в чистом ОО мире. Когда нужно сделать какую-то не сложную вещь. К примеру, Go достаточно процедурный язык, что не делает его менее популярным в наше время. И его же за чем-то создали сейчас именно таким? При чем не глупые люди, которые явно знакомы со всеми парадигмами и подходами. Или набирающий популярность Rust, который тоже не является классическим ООП языком. Такие языки, как Питон - мультипарадигменные. Почему нужно боятся где-то написать процедурный код? Или ФП код? Кажется, что причин для этого нет, кроме предубеждений.
Поэтому разработчикам и остаётся писать конструкции c протоколами.
И в этом нет ничего плохого. Протоколы по сути те же интерфейсы. Прекрасно можно ими пользоваться в Питоне. А разговор начат с классов как раз по тому, что именно они в купе с наследованием и есть то самое классическое ООП, о котором идет речь. Есть ООП языки без классов и это не делает их менее ООП. Эталонного ООП просто не существует в настоящий момент. О чем речь тоже идет в статье. Есть разные вариации реализации этой идеи, но подходы могут серьезно отличаться.
И не надо пытаться сделать вид, что такая реализация ООП — это какое-то достоинство Питона.
Вроде ни кто и не пытался, не знаю, где это подается в таком виде. Такой мысли в статье не было.
Чем это будет удобнее? Объяснения нет.
Удобство заключается в том, что отсутствует сама проблема заранее точно определять кому и какое поведение принадлежит и с каким объектом оно должно ходить пришитым. А это частно далеко не самый тривиальный вопрос проектирования. В случае, когда это функция, которая работает с каким-то типом объекта согласно своей сигнатуре, рефакторинг, изменение и ее перемещение становится гораздо проще. Что и было показано в примере в статье. И в целом проще становится конструирование тех самых конвейеров из всех этих функций.
Любой, кто поработал хотя бы немного с ООП в JS, знает, что лучше бы там были обычное ООП и наследование.
Это просто холиварная тема. Как бы нет, не лучше:) И я оставил ссылку на статью, где даже есть подробно описанное мнение почему это так. И привел в пример React, где уже несколько лет никаких классов, наследования и все отлично. React в отличной форме. Можно даже сказать, что в лучшей из тех, что был.
Все аргументы сводятся к «оказывается, код можно как-то написать и без классов» и вырванным из контекста цитатам из авторитетов (причём, если тот же авторитет пишет что-то с чем вы не согласны, нужно обязательно добавить «ну это же было давно и неправда»).
Потому, как речь в целом изначально речь и идет о книгах и подходах, которые эти сами авторитеты и писали. И эти цитаты призваны показать, как менялось с годами их же мнение. Как они не боялись сказать, что в чем-то заблуждались и были где-то не правы. Или что-то переосмыслили. Если вы увидели где-то фразу, которую вырвали из контекста, то можете на нее указать. Когда я подбирал цитаты, то как минимум оставил ссылки на все оригиналы. Где можно прочитать указанные цитаты и мнения с полным контекстом, откуда они были взяты в статью.
Желательно, стараться операции I/O двигать к границам и группировать все в отдельные транзакционные функции. Там уже в ней происходит все необходимое.
Если мы говорим про последовательность шагов в рамках транзакции, то тут встает вопрос, а чего в ней больше - бизнес логики или инфраструктуры? По идее последовательность шагов в транзакции соответствует бизнес процессу. Что за чем сохраняем и как откатываем. Но в то же время мы используем низкоуровневую инфраструктуру для проведения транзакции. Тот же курсор. Так, что вероятнее лучше держать такие вещи на слое persistance, не перетягивая их в слой сервисов. Все-таки, хоть там и есть минимальная логика, но она только про работу с источниками и механизмами их отката. То есть по большей части связана с хранением данных, чем этот слой и занимается. Имя в таком случае лучше подбирать более сфокусировано на общем процессе :) update_post_and_add_comment_and_update_user_and_notify вполне может быть просто названа той причиной, почему эти действия объедены в одну транзакцию. К примеру handle_post_activity или process_post_interaction. Это так, навскидку. Для этого нужно в проекте выработать свою удобную всем конвенцию наименования. Собственно, я не называю этот слой именно репозиторием по двум причинам: во-первых, само определение, как должен быть реализован настоящий репозиторий часто вызывает некоторые холиварные споры, а во-вторых как раз по тому, что там может быть такая транзакционная работа.
В рамках работы нескольких последовательных операций с sql источником на самом деле все не так сложно. Несколько последовательных вызовов к базе группируются и работают с одним и тем же курсором в одной транзакции, если нужно обеспечить механизм rollback. Принимают его в качестве опционального параметра.
Ну, а для работы с другими источниками или серией вызовов для работы с разными источниками тут как и без репозитория приходится прописывать логику rollback уже как-то самому в зависимости от того, как можно откатить действие.
Есть варианты, к примеру, если мы работаем с серией вызовов к источнику sql и нужно сделать какой-то запрос по HTTP и в случае не успеха откатить все. Тогда все операции как раз можно обернуть в контекстный менеджер работы с базой и если HTTP часть завершится с ошибкой, то можно просто исключением прервать транзакцию и выйти из контекста инициировав в ней rollback. Соотвественно, если перед этим была какая-то логика отката по HTTP, то сначала выполняем ее.
Для разных источников sql можно сделать вложенные контекстные менеджеры. В общем большая часть проблем идентична проблемам работы с разнородными источниками и при других подходах.
Опять же, если стараться выдавливать операции I/O к границам, то для бизнес логики это все может оставаться так же абстрагированно.
Как я понял суть этой ветки разговора речь о том, когда пользователю кода не дают делать не хорошие вещи с объектами. И о ситуации, пользователи начинают обращаться к низкоуровневым полям, к которым они не должны обращаться. В общем случае с Питоном это просто решается добавлением нижних подчеркиваний в названия тех вещей, которые трогать не нужно. И это или соблюдается или нет. Добавили ли вы поведение в класс и сделали его методом. Или передали в функцию экземпляр класса, которая должна с ним работать. То, что трогать не желательно по задумке определения этой доменной сущности будет и в том и в том случае обозначатся одинаково в самом названии атрибутов. Соблюдать или игнорировать эту конвенцию можно при любом подходе.
Да, но это больше конвенция, чем реальная преграда. Для класса MyClass атрибут __myattr будет напрямую доступен просто через _MyClass__myattr. Это не говоря о всех тех непотребствах, которые можно натворить прямо в рантайме с помощью того же манки патчинга :)
На самом деле эта картинка намеренно такая "косожопая" вставлена, ведь она в тексте рядом с FizzBuzzEnterpriseEdition. Что как бы намекает, что такой подход порождает что-то подобное на этой картинке :)
С подключением из глобально инициализированного пула внутри get_users в большинстве случаев нет проблем по моему опыту. Инициализировать переменную окружения мы точно не забудем о чем нам скажет завалившийся деплой. Модуль settings просто не найдет инициализированную переменную и старт приложения завершится с ошибкой.
На счет получения сущности из разных источников в рамках одного работающего приложения. В этом случае вариант передать через аргумент коннектор в БД в виде зависимости - да, нормальное решение. Но, как я понимаю, это если в случае, когда данные лежат в одинаковых типах источников. Что само по себе может быть странно, почему сущность юзера лежит в двух разных экземплярах того же Postgres.
Если источники очень разного характера, к примеру SQL и HTTP, то получение данных из них в любом случае лучше разнести по разным функциям. Если одна и та же сущность в одинаковом виде лежит в разных базах для одного и того же приложения, то это скорее повод подумать, все ли в порядке с хранением данных. Обычно данные об одной и той же сущности лежат в разных источниках, если это все же данные разного характера. В случае с Post мы можем получать данные о просмотрах из какого-нибудь кликстрима, вроде Кликхауса. В общем случае работа с разными источниками будет реализована через разные интерфейсы на уровне непосредственного получения данных. Ведь, собственно, за абстрагирование работы с этими разными интерфейсами и отвечает слой persistence. В него мы получаем что-то из слоя infrastructure, вроде коннекта к конкретной базе или HTTP сессию, а уже функция внутри реализует всю работу по извлечению данных через АПИ этого источника и оборачивание в доменную сущность, чтоб вернуть в ее бизнес логику.
Хм, касательно второго думаю, что относительно да, до тех пор, пока в условном классе Users не идет обращение к самому экземпляру внутри методов. :) То есть, пока класс выступает по сути в роли неймспейса для всех этих функций aka методов для из группировки.
Все таки, мне кажется что основная задача наличия класса - это инкапсулирование работы с объектом по изначальной задумке. Найти функцию в модуле и найти метод в классе в целом задачи +- одинаковые по сложности. Сначала нужно найти нужный модуль или класс, потом найти в нем нужное поведение. Ну и доступ к функциям в модуле через IDE можно упростить сделав import functools и потом IDE выдаст через точку все содержимое модуля полностью аналогично с содержимым экземпляра класса. Можно даже написать алиас, если хочется меньше в коде писать символов import functools as ft. Тут главное, чтоб конвенция была для алиасов модулей. Впрочем, как и нужна конвенция для именования переменных и так далее.
выяснится, что функции работы с, например, постами нужны вместе, вместе с необходимыми dataclass, и в неймспейсе вида Post
Тут не очень понял. По идее Post - это доменная сущность и ее объявление, как и правила создания мы кладем в доменный слой нашего приложения. Который не зависит от других слоев. А уже на уровне сервисов мы выстраиваем работу с Post с помощью тех функций, которые реализуют нашу бизнес-логику. Там и встречаются данные и поведение.
Почему такая замена удобна на мой взгляд (группировка функций на уровне модулей, а не методов в классах) - так это обычно менее связанный и проще модифицируемый код. Такой подход к написанию сам тебя подталкивает к тому, чтобы делать меньше не явных преобразований и других сайд-эффектов в поведении. Ведь доступ ко всему поведению внутри метода через self открывает большое окно возможностей делать всякие дополнительные действия не явно внутри методов. С другой стороны функция, которая хочет использовать какое-то поведение явно декларирует это своей зависимостью в сигнатуре. То есть код получается более прозрачный для изучающего, как с ним работать. Опять же, чистые функции. Мы получаем на вход все наши данные и зависимости через аргументы и выдаем данные на выход.
Тут коротко просто отвечу той же мыслью, что высказана в статье. В Питоне нет по настоящему ничего приватного. "Все мы здесь взрослые, отвественые люди". Если кто-то захочет куролесить, изменяя объект так, как этого делать не следует, он всегда сможет это сделать. Такие вещи только код-ревью решаются, так или иначе. Ну и дисциплиной и ответственностью самих разработчиков, опять же так задуман язык его создателем. Тут оно, как есть :)
Отказа от ООП как такового нет, все верно. И об этом даже есть не большая цитата от Роберта Мартина на тему того, что ООП и ФП могут и даже должны хорошо уживаться в современных системах. Отказ от так называемого классического ООП, которое по большей части получило широкое распространение благодаря Java. Это самое ООП может быть очень разным, о чем тоже есть пример в статье - JavaScript.
Никакого объединения данных и методов с помощью неймспейсов не декларируется. Как раз наоборот, данные существуют отдельно. То, что их обрабатывает существует отдельно. И фундаментально проблемы в этом нет, опять же о чем есть пара слов в статье. В ФП языках в принципе не стоит этот вопрос об объединении данных и логики в одну корзину. Что может работать с чем определяется сигнатурами функций и интерфейсами.
Есть ощущение, что периоды идиократии уже случались в прошлом. Это происходило даже в обществах, где люди умели считать в уме, знали стихи и обладали одним из самых передовых образований в мире. Тем не менее, половина страны заряжала банки с водой перед телевизором, а другая половина несли деньги в финансовые пирамиды вроде МММ. Казалось бы, качественное и фундаментальное образование должно было защитить общество от подобного мракобесия. Но реальность оказалась сложнее.
Подход к образованию действительно нуждается в переосмыслении. Большинство людей до сих пор учатся по шаблонам, разработанным веками назад. То, что происходит сейчас, — это не хорошо и не плохо, это просто перемены, требующие новых подходов. Главное в образовании — развивать у человека достаточное количество нейронных связей и стимулировать активную работу мозга, чтобы к зрелому возрасту он обладал развитым мышлением и был готов к интеграции в профессиональную среду.
Кстати, ещё Сократ говорил:
«Нынешняя молодежь привыкла к роскоши, она отличается дурными манерами, презирает авторитеты, не уважает старших, дети спорят со взрослыми, жадно глотают пищу, изводят учителей».
Этот цикл изменений — часть естественного развития общества.
Го не принуждает, к сожалению. Обработку ошибок можно просто скипать. Вот в языках, где есть монады типа Result, тебе уже точно придется распаковать ее и проверить, что внутри — ошибка или результат. И придется обработать все.
Эх, предложили бы сразу монады Result и Maybe. И еще pattern matching с ними сразу бы завезли для их обработки красиво. А там и до Railway oriented programming рукой подать =)
Да, именно так, спасибо. Поправил в тексте.
Да, именно так. В статье это как раз в таком виде и отражено - Принцип инверсии зависимостей (Dependency Inversion Principle). О чём именно речь?
Фактически, все, что десятилетиями изучается широкими массами в программировании, так или иначе создано опытными людьми, как компиляция их пройденного пути с набитыми шишками на поприще программирования.
И не важно, начнете ли вы читать «Совершенный код» Макконелла, «Рефакторинг» Фаулера, «Чистую архитектуру» дяди Боба или «Паттерны» от Банды четырех — все это передача ими эмпирического опыта в предметной области. Это не доказанные истины, не математически стройные и выверенные подходы. По большей части это укладывается в формулу: "я писал много-много лет, даже десятилетий, и кое-что понял, а то, что понял, хочу передать вам".
SOLID, YAGNI, DRY, KISS, DDD, TDD и так далее и тому подобное — все это инструменты, получившие широкую известность в профессии. Инструменты, которые стоит изучить, переняв опыт тех, кто это все собрал вместе и записал в красивые и запоминающиеся аббревиатуры.
А вот применять эти инструменты уже все учатся сами, и разумный баланс в своей работе, в своем проекте всех этих принципов, паттернов и подходов каждый находит исключительно сам.
Собственно, об этом сказано в заключительном слове в статье. Сектантство всегда плохо, догматизм того хуже. Ведь "только ситхи все возводят в абсолют". 😉
Прочитал и сразу вспомнил вот этот отрывок
https://youtube.com/shorts/p5hdkk8LycQ?si=X3fFlKi-DeLsZGsU
Не только в Python, но и в Clojure, которые теперь активно продвигает дядя Боб. Тот же Javascript. Все это уже используется активно в энтерпрайз разработке. Ну и если человек видит, что что-то имеет явное указание по соглашению, что это нельзя трогать (то же нижнее подчеркивание в начале название), но берет и игнорирует это, то вероятно такой разработчик в любом случае набедокурит в другом месте, если не в этом. Обратится к чему-то приватному, что обозначено, как приватное, можно только осознано. Если ты хотя бы базово знаком с конвенцией языка, на котором пишешь.
К тому же есть другие способы сокрытия. Через замыкания внутри тех же функций.
Тут хотелось бы спросить, а какие именно ограничения Java помогают совершать принципиально меньше ошибок? В случае с Haskell я бы мог понять такое утверждение, ведь не зря говорят "if a Haskell program compiles, it probably works". Его компилятор и система типов действительно делают нечто особенное по сравнению с большинством языков. Но Java?
Если в программе есть и процедурный и другие подходы - оно от этого так сильно хуже? Мы уже видели в виде классической Java через что приходится проходить и какие финты придумывать, чтобы существовать исключительно в чистом ОО мире. Когда нужно сделать какую-то не сложную вещь. К примеру, Go достаточно процедурный язык, что не делает его менее популярным в наше время. И его же за чем-то создали сейчас именно таким? При чем не глупые люди, которые явно знакомы со всеми парадигмами и подходами. Или набирающий популярность Rust, который тоже не является классическим ООП языком. Такие языки, как Питон - мультипарадигменные. Почему нужно боятся где-то написать процедурный код? Или ФП код? Кажется, что причин для этого нет, кроме предубеждений.
И в этом нет ничего плохого. Протоколы по сути те же интерфейсы. Прекрасно можно ими пользоваться в Питоне. А разговор начат с классов как раз по тому, что именно они в купе с наследованием и есть то самое классическое ООП, о котором идет речь. Есть ООП языки без классов и это не делает их менее ООП. Эталонного ООП просто не существует в настоящий момент. О чем речь тоже идет в статье. Есть разные вариации реализации этой идеи, но подходы могут серьезно отличаться.
Вроде ни кто и не пытался, не знаю, где это подается в таком виде. Такой мысли в статье не было.
Удобство заключается в том, что отсутствует сама проблема заранее точно определять кому и какое поведение принадлежит и с каким объектом оно должно ходить пришитым. А это частно далеко не самый тривиальный вопрос проектирования. В случае, когда это функция, которая работает с каким-то типом объекта согласно своей сигнатуре, рефакторинг, изменение и ее перемещение становится гораздо проще. Что и было показано в примере в статье. И в целом проще становится конструирование тех самых конвейеров из всех этих функций.
Это просто холиварная тема. Как бы нет, не лучше:) И я оставил ссылку на статью, где даже есть подробно описанное мнение почему это так. И привел в пример React, где уже несколько лет никаких классов, наследования и все отлично. React в отличной форме. Можно даже сказать, что в лучшей из тех, что был.
Потому, как речь в целом изначально речь и идет о книгах и подходах, которые эти сами авторитеты и писали. И эти цитаты призваны показать, как менялось с годами их же мнение. Как они не боялись сказать, что в чем-то заблуждались и были где-то не правы. Или что-то переосмыслили. Если вы увидели где-то фразу, которую вырвали из контекста, то можете на нее указать. Когда я подбирал цитаты, то как минимум оставил ссылки на все оригиналы. Где можно прочитать указанные цитаты и мнения с полным контекстом, откуда они были взяты в статью.
Желательно, стараться операции I/O двигать к границам и группировать все в отдельные транзакционные функции. Там уже в ней происходит все необходимое.
Если мы говорим про последовательность шагов в рамках транзакции, то тут встает вопрос, а чего в ней больше - бизнес логики или инфраструктуры? По идее последовательность шагов в транзакции соответствует бизнес процессу. Что за чем сохраняем и как откатываем. Но в то же время мы используем низкоуровневую инфраструктуру для проведения транзакции. Тот же курсор. Так, что вероятнее лучше держать такие вещи на слое persistance, не перетягивая их в слой сервисов. Все-таки, хоть там и есть минимальная логика, но она только про работу с источниками и механизмами их отката. То есть по большей части связана с хранением данных, чем этот слой и занимается. Имя в таком случае лучше подбирать более сфокусировано на общем процессе :) update_post_and_add_comment_and_update_user_and_notify вполне может быть просто названа той причиной, почему эти действия объедены в одну транзакцию. К примеру handle_post_activity или process_post_interaction. Это так, навскидку. Для этого нужно в проекте выработать свою удобную всем конвенцию наименования. Собственно, я не называю этот слой именно репозиторием по двум причинам: во-первых, само определение, как должен быть реализован настоящий репозиторий часто вызывает некоторые холиварные споры, а во-вторых как раз по тому, что там может быть такая транзакционная работа.
В рамках работы нескольких последовательных операций с sql источником на самом деле все не так сложно. Несколько последовательных вызовов к базе группируются и работают с одним и тем же курсором в одной транзакции, если нужно обеспечить механизм rollback. Принимают его в качестве опционального параметра.
Ну, а для работы с другими источниками или серией вызовов для работы с разными источниками тут как и без репозитория приходится прописывать логику rollback уже как-то самому в зависимости от того, как можно откатить действие.
Есть варианты, к примеру, если мы работаем с серией вызовов к источнику sql и нужно сделать какой-то запрос по HTTP и в случае не успеха откатить все. Тогда все операции как раз можно обернуть в контекстный менеджер работы с базой и если HTTP часть завершится с ошибкой, то можно просто исключением прервать транзакцию и выйти из контекста инициировав в ней rollback. Соотвественно, если перед этим была какая-то логика отката по HTTP, то сначала выполняем ее.
Для разных источников sql можно сделать вложенные контекстные менеджеры. В общем большая часть проблем идентична проблемам работы с разнородными источниками и при других подходах.
Опять же, если стараться выдавливать операции I/O к границам, то для бизнес логики это все может оставаться так же абстрагированно.
Как я понял суть этой ветки разговора речь о том, когда пользователю кода не дают делать не хорошие вещи с объектами. И о ситуации, пользователи начинают обращаться к низкоуровневым полям, к которым они не должны обращаться. В общем случае с Питоном это просто решается добавлением нижних подчеркиваний в названия тех вещей, которые трогать не нужно. И это или соблюдается или нет. Добавили ли вы поведение в класс и сделали его методом. Или передали в функцию экземпляр класса, которая должна с ним работать. То, что трогать не желательно по задумке определения этой доменной сущности будет и в том и в том случае обозначатся одинаково в самом названии атрибутов. Соблюдать или игнорировать эту конвенцию можно при любом подходе.
Да, но это больше конвенция, чем реальная преграда. Для класса MyClass атрибут __myattr будет напрямую доступен просто через _MyClass__myattr. Это не говоря о всех тех непотребствах, которые можно натворить прямо в рантайме с помощью того же манки патчинга :)
На самом деле эта картинка намеренно такая "косожопая" вставлена, ведь она в тексте рядом с FizzBuzzEnterpriseEdition. Что как бы намекает, что такой подход порождает что-то подобное на этой картинке :)
С подключением из глобально инициализированного пула внутри get_users в большинстве случаев нет проблем по моему опыту. Инициализировать переменную окружения мы точно не забудем о чем нам скажет завалившийся деплой. Модуль settings просто не найдет инициализированную переменную и старт приложения завершится с ошибкой.
На счет получения сущности из разных источников в рамках одного работающего приложения. В этом случае вариант передать через аргумент коннектор в БД в виде зависимости - да, нормальное решение. Но, как я понимаю, это если в случае, когда данные лежат в одинаковых типах источников. Что само по себе может быть странно, почему сущность юзера лежит в двух разных экземплярах того же Postgres.
Если источники очень разного характера, к примеру SQL и HTTP, то получение данных из них в любом случае лучше разнести по разным функциям. Если одна и та же сущность в одинаковом виде лежит в разных базах для одного и того же приложения, то это скорее повод подумать, все ли в порядке с хранением данных. Обычно данные об одной и той же сущности лежат в разных источниках, если это все же данные разного характера. В случае с Post мы можем получать данные о просмотрах из какого-нибудь кликстрима, вроде Кликхауса. В общем случае работа с разными источниками будет реализована через разные интерфейсы на уровне непосредственного получения данных. Ведь, собственно, за абстрагирование работы с этими разными интерфейсами и отвечает слой persistence. В него мы получаем что-то из слоя infrastructure, вроде коннекта к конкретной базе или HTTP сессию, а уже функция внутри реализует всю работу по извлечению данных через АПИ этого источника и оборачивание в доменную сущность, чтоб вернуть в ее бизнес логику.
Хм, касательно второго думаю, что относительно да, до тех пор, пока в условном классе Users не идет обращение к самому экземпляру внутри методов. :) То есть, пока класс выступает по сути в роли неймспейса для всех этих функций aka методов для из группировки.
Все таки, мне кажется что основная задача наличия класса - это инкапсулирование работы с объектом по изначальной задумке. Найти функцию в модуле и найти метод в классе в целом задачи +- одинаковые по сложности. Сначала нужно найти нужный модуль или класс, потом найти в нем нужное поведение. Ну и доступ к функциям в модуле через IDE можно упростить сделав import functools и потом IDE выдаст через точку все содержимое модуля полностью аналогично с содержимым экземпляра класса. Можно даже написать алиас, если хочется меньше в коде писать символов import functools as ft. Тут главное, чтоб конвенция была для алиасов модулей. Впрочем, как и нужна конвенция для именования переменных и так далее.
Тут не очень понял. По идее Post - это доменная сущность и ее объявление, как и правила создания мы кладем в доменный слой нашего приложения. Который не зависит от других слоев. А уже на уровне сервисов мы выстраиваем работу с Post с помощью тех функций, которые реализуют нашу бизнес-логику. Там и встречаются данные и поведение.
Почему такая замена удобна на мой взгляд (группировка функций на уровне модулей, а не методов в классах) - так это обычно менее связанный и проще модифицируемый код. Такой подход к написанию сам тебя подталкивает к тому, чтобы делать меньше не явных преобразований и других сайд-эффектов в поведении. Ведь доступ ко всему поведению внутри метода через self открывает большое окно возможностей делать всякие дополнительные действия не явно внутри методов. С другой стороны функция, которая хочет использовать какое-то поведение явно декларирует это своей зависимостью в сигнатуре. То есть код получается более прозрачный для изучающего, как с ним работать. Опять же, чистые функции. Мы получаем на вход все наши данные и зависимости через аргументы и выдаем данные на выход.
Тут коротко просто отвечу той же мыслью, что высказана в статье. В Питоне нет по настоящему ничего приватного. "Все мы здесь взрослые, отвественые люди". Если кто-то захочет куролесить, изменяя объект так, как этого делать не следует, он всегда сможет это сделать. Такие вещи только код-ревью решаются, так или иначе. Ну и дисциплиной и ответственностью самих разработчиков, опять же так задуман язык его создателем. Тут оно, как есть :)
Отказа от ООП как такового нет, все верно. И об этом даже есть не большая цитата от Роберта Мартина на тему того, что ООП и ФП могут и даже должны хорошо уживаться в современных системах. Отказ от так называемого классического ООП, которое по большей части получило широкое распространение благодаря Java. Это самое ООП может быть очень разным, о чем тоже есть пример в статье - JavaScript.
Никакого объединения данных и методов с помощью неймспейсов не декларируется. Как раз наоборот, данные существуют отдельно. То, что их обрабатывает существует отдельно. И фундаментально проблемы в этом нет, опять же о чем есть пара слов в статье. В ФП языках в принципе не стоит этот вопрос об объединении данных и логики в одну корзину. Что может работать с чем определяется сигнатурами функций и интерфейсами.
Так как я не работал с C#, то могу судить только из быстрого ознакомления с предметом по описанию.
Если я все правильно понял, то default interface methods можно примерно похоже реализовать с помощью модуля abc https://docs.python.org/3/library/abc.html
По поводу методов-расширений первое, что приходит на ум - это monkey patching.