Pull to refresh
356
1.1
Alex Efros @powerman

Systems Architect, Team Lead, Lead Go Developer

Send message

Почему? На мой взгляд рут нужен в первую очередь потому, что это единственный способ стать владельцем собственного устройства, а не его арендатором. Во вторую очередь он нужен потому, что без него не будет ни AFWall+, ни AdAway, ни Titanium Backup — а на мой взгляд это довольно критичные инструменты для комфортного использования устройства.

To separate out e.g. logic from presentation prematurely often leads to unnecessary complexity and in retrospect, the wrong abstractions.

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


Likewise, his assertion that “It is hard to imagine an architecture that does not make significant use of [DIP]” says more to me about his imagination than what I consider good software design.

А такое отношение к DIP больше говорит о сложностях автора с тестированием, нежели о хорошей архитектуре.

Все упомянутые проблемы лечит AFWall+ (но для него нужен root).

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

Про форки, включая эти, стоит почитать How to choose a browser for everyday use? — там жёсткий "срыв покровов" по некоторым из них.

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


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


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

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


Например, я заметки очень давно веду в текстовых asciidoc/markdown файлах в ~/doc/, редактирую в vim, ищу чаще всего по имени файла с поддержкой fuzzy search (vim plugin) либо по содержимому через grep/ack/rg (как в командной строке так и через ещё один vim plugin). Что мне даст переход на эту систему?

VPN. Это в любом случае стоит сделать для защиты от перехвата WiFi-трафика.

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


Защита детей — обязанность их родителей. Не надо её перекладывать на чужого дядю в правительстве. Родители могут добровольно и самостоятельно активировать для детских устройств любые фильтры контента. Тот же твиттер вполне можно обязать тегировать контент, чтобы таким фильтрам было проще работать. Но блокирование (и тем более замедление) контента для взрослого населения на государственном уровне — никакого отношения к защите детей не имеет.

за иконки в шрифтах расстреливать надо, нет?

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

В Вашей логике есть несколько просчётов:


Высокая скорость разработки

Да, но только до определённого момента. Писать быстро-грязно и без тестов с какого-то момента (в среднем — через месяца 3-4) становится намного медленнее, чем с тестами (а с тестами уже быстро-грязно писать не получится).


Минимализм (невозможность упростить)

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


Мир и согласие с вашим менеджером

Это ценно, если он вменяемый. А если дурак — то ценнее либо его заставить уйти, либо уйти самому, а не мир с ним строить. (Это безотносительно того, считает ли менеджер необходимым дёшево наговнокодить здесь и сейчас — действительно, есть немало задач, которые стоит писать именно быстро/грязно… просто он должен понимать, что большие проекты так писать всегда дороже, а небольшие дешевле переписать нормально чем поддерживать как есть, поэтому если проект небольшой, но его планируется развивать и поддерживать хотя бы столько же времени, сколько ушло на изначальную быстро-грязно разработку, то его не стоило писать быстро-грязно.)


Не нужно строить из себя оракула и пытаться угадать будущее (все равно облажаетесь)

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


Недостатки:

Тут всё верно написано, чувствуется большой опыт. :)


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


Если уровень качества кода в вашей компании низкий (такаво бизнес требование/модель монетизации) то писать юнит тесты это зло для бизнеса.

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


Если требуется качество на среднем уровне (большинство) то вышеописанное мне кажется идеальный вариант, сложность/функциональность/расширяемость/тестируемость кода должна быть на минималках только чтобы тикет смерджили

Эмм. У меня есть сильное подозрение, что "на минималках" в моём понимании и в Вашем — это очень разные минималки. В моём понимании бизнес под "средним уровнем качества" не подразумевает "код будет дико глючить, уйдёт куча времени на тестирование и пинг-понг между QA и разработчиками, любой кулхацкер сможет ткнуть кавычку в любое поле и получить SQL-инъекцию". Плюс фраза "только чтобы тикет смерджили" звучит очень похоже на "сделал на отъебись".


В моём понимании "только чтобы тикет смерджили" подразумевает отсутствие лишнего (не описанного в тикете) фукнционала. А "на минималках" включает обязательные юнит-тесты изменений в этом PR (с покрытием хотя бы порядка 70%), обязательный процесс ревью кода, обязательное использование линтеров и CI/CD.


Если требуется высокое качество или цена изменений высока (по не связанным с разработкой причинам), то таки да следуйте принципам сразу это рационально — дешевле.

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

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


Замедление работы? На втором прогоне сортировки? Даже не смешно, это место не будет проблемой производительности ни в каком проекте кроме специально написанного для иллюстрации этого замедления синтетического теста. Но допустим, что реальный проект неприемлемо тормозит, и бенчмарки показали, что тормозит он именно на двух проходах сортировки… в этом случае мы просто забиваем на SRP и читабельность этого куска кода, переписываем его так, чтобы он не тормозил, а SRP заменяем детальными комментариями описывающими что, зачем и как делает этот нечитабельный но быстрый код — как всегда делается при необходимости что-то оптимизировать.

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


А весь остальной не-игровой траффик — только через VPN. Причём по возможности — self-hosted. Просто считайте, что ежемесячная стоимость работоспособного интернета выросла примерно на $5 (которые стоит сервер для VPN) — налог на РКН.

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

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


Как вы разнесёте это по модулям? И, главное, даже если это вам удастся, то что вам это даст кроме замедления исполнения и соответствия какому-то там принципу?

Судя по второму вопросу ответ на первый очевиден, так что я могу его опустить и сразу перейти ко второму.


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


  • понимание, что у нас несколько этапов сортировки с разными требованиями
  • как следствие предыдущего пункта — явное определение правил, по которым второй этап может изменять результаты первого
  • возможность менять каждый из этапов в соответствии с требованиями от его "источника изменений" не боясь сломать работу другого этапа и уже реализованные требования другого "источника изменений" (причём не загружая их в голову и даже не видя их — если они в другом файле, например), отдельно их тестировать — в целом всё это как раз ускоряет внесение изменений, а это обычно намного важнее, чем ускорить написание первой версии

На самом деле упомянутое Вами замедление разработки обычно находится в среднем из вышеперечисленных трёх пунктов — необходимость определить как решать конфликты требований. Если мы пишем код без применения SRP, то обычно в этом месте решение принимает разработчик (причём, зачастую, неявно, просто не подумав об этой проблеме и написав код "как пишется"), оно никак не озвучивается, ни с кем не согласовывается, не документируется, а просто неявно вытекает из текущей реализации. В будущем это приводит к тому, что код просто боятся менять и рефакторить, потому что при этом все такие неявные вещи имеют обыкновение ломаться.

Принцип единой ответственности (SRP)

Понят автором неправильно, так что не удивительно, что в результате это привело к:


для меня это несёт не очень много смысла

Подробнее в комментарии выше.


Принцип открытости-закрытости (OCP)

Да, сегодня изменять код дешевле, чем 30 лет назад. Но это "дешевле" всё ещё очень далеко от "бесплатно". Если можно реализовать новый функционал создав новый микросервис или приложение, или добавив новый класс с минимальными изменениями существующего кода — как правило это сильно удешевляет разработку. Если можно изменить логику работы сторонней библиотеки просто передавая ей параметрами свои функции или реализации интерфейсов (как, например, везде делается в Go с интерфейсами io.Reader и io.Writer) — это так же позволит менять её поведение не меняя её код, что опять же сильно удешевляет разработку. Таким образом данный принцип всё ещё актуален.


Весь код для нас — это затраты.

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


Принцип подстановки Лисков (LSP)

язык, который использует LSP ("подтипы") … пытается аппелировать к моделированию сущностей из 1980 года, со всем его "является (is-a)" и "имеет (has-a)" видами наследования.

Это довольно очевидно — он говорит о том, что существовало в те времена когда он был сформулирован. Какой смысл придираться к словам если на суть они не влияют, а суть всё ещё актуальна?


В контексте моделирования, когда мы нож используем в качестве отвертки, а многие объекты наследуются видами: "ведёт-себя-как (act-like-a)", "иногда-используется-как (sometimes-be-used-as)" или "подойдет-если-не-сильно-приглядываться (pass-off-as-a-if-you-squint)"; в этом контексте что мы действительно хотим, так это маленькие, простые типы, которые мы можем композировать в любые насколько угодно сложные структуры, и примириться со всеми нюансами, которые это вызовет.

По сути LSP говорит о поведении разных реализаций одного интерфейса. Их поведение должно быть идентичным, по крайней мере в актуальных сценариях использования, иначе не получится все эти "иногда-используется-как (sometimes-be-used-as)" подсовывать на место других реализаций.


Мой совет, внезапно, "писать более простой код", о котором легко рассуждать.

Вообще-то нет, на самом деле это идущий следующим ISP.


Принцип разделения интерфейсов (ISP)

Всё это имеет смысл, просто дело в том, что это не принцип. Это паттерн.

И снова мимо. Этот принцип о том, чтобы не создавать лишних зависимостей (от неиспользуемого функционала), что вполне уместно считать принципом. God-объект просто пример, который наглядно демонстрирует как такие лишние зависимости образовались.


Принцип инверсии зависимостей (DIP)

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

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


Реальным принципом должна была стать опциональная инверсия. Зависимость интересна нам только тогда, когда есть несколько способов её предоставления, и вам нужно сделать инверсию отношений только если вы считаете, что в будущем это станет необходимо. Это довольно высокая планка, а чаще всего вам просто нужен только метод main.

… но последнее предложение всё испортило. Дело в том, что мы действительно редко меняем одну БД на другую. Но вот код мы тестируем часто. И именно для возможности подставить вместо конкретной реализации тестовый мок и нужна в первую очередь инверсия зависимостей и зависимость от интерфейсов (и именно на этом строится вся "чистая архитектура" дяди Боба). Соответственно, DIP нужно использовать в тех местах, где нужно при тестировании подставлять свои моки (т.е. где по факту у нас действительно есть минимум две реализации одного интерфейса). Тестировать код, который целиком в main и в котором невозможно ничего замокать при тестировании — очень больно.

Да, я с этим полностью согласен. Проблема в том, что у нас уже есть один источник, который сформулировал их корректно (дядя Боб). А желающие решить описанную вами проблему просто добавляют своё описание (чаще всего некорректное в меру их собственного непонимания) к уже имеющимся, и мы получаем N+1 "самых понятных объяснений SOLID". При этом польза от них сомнительна, потому что найти среди них корректные довольно сложно (и на это совершенно точно не способны их читатели, которые набежали читать статью как раз для того, чтобы по-быстрому разобраться с SOLID перед собесом и не хотят тратить время на вникание в первоисточник).

Принцип SRP не требует, чтобы все требования от одного заказчика были реализованы в одном модуле. Он требует чтобы требования от разных заказчиков были реализованы в разных модулях.


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

Но проблема именно в понимании SOLID, а не самих принципах. И вызвана она обычно тем, что при изучении принципа читают только его название или чьё-то уже искажённое понимание (википедию, например). Если читать самого дядю Боба — шанс понять их правильно будет несколько выше.


Например, в книге "Чистая архитектура" русским языком чётко написано (стр.79) про SRP (один из самых неочевидных для понимания по названию/википедии):


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

Иными словами, речь об источниках бизнес-требований к коду — несколько источников могут (и будут) предъявлять несогласованные между собой требования, и это создаст проблему. Поэтому код реализующий требования от разных источников (как дальше в книге приводятся примеры: отделами бухгалтерии, HR, админами БД) должен находиться в разных модулях.


Это — вполне разумно и ни капельки не устарело. И это именно принцип, а не паттерн, он вполне применим во всех случаях. И автор оригинальной статьи, не смотря на упомянутое им изучение "источников", его тоже понял неправильно.

Можно. Из важного — надо обязательно назвать её IFastDB. Ну а что до мелких нюансов реализации — в ней надо сделать сделать методы Get(key), Set(key, value), Del(key). И на этом остановиться. Тогда она и течь не будет, и методы эти будут быстро работать с любой СУБД. :)

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

Information

Rating
1,270-th
Location
Харьков, Харьковская обл., Украина
Date of birth
Registered
Activity