Comments 50
Т.к. из него невозможно ничего убрать.
Когда тебе нужно, к примеру, средство передвижения — вакуум плох, потому что не выполняет этих функций. Велосипед лучше.
Вакуум — это квинтэссенция неопределенности.
В вакууме есть всё.
А материя, напротив, предельно определена, в ней есть только одно.
Действующая и продававшаяся программа длиной в 0 байт.
https://habr.com/post/147075/
Заголовок статьи извольте поправить. Даже в личку писать не хочется...
Можно натянуть сову на глобус и объединить ваши мысли с размышлениями автора, если просто сказать, что минимизировать (непонятно, что, но точно не переменные) надо не в системе в целом, а в том срезе системы, который приходится держать в голове одновременно. В каждом из этих срезов. Т.е., с одной стороны, минимизировать количество уровней абстракции, но с другой — "толщину" каждого слоя. Чтобы можно было разглядывать все слои вместе, не вдаваясь в их детали — и каждый слой в отдельности, не глядя на остальные.
Но вот дальше, когда вы упомянули Javascript и Scala, я уже согласиться не могу. Яваскрипт вообще плохо подходит для больших приложений из-за отсутствия статической типизации (которая есть в скале) и любви к игнорированию ошибок. Я писал большое приложение на JS. Вы в одном месте поделите на ноль, Яваскрипт молчит как партизан, этот NaN расползается по программе и она падает потом где-то в совсем другом месте кода, и ищи, откуда этот NaN появился. Или, например, опечатался в имени поля, никаких сообщений об ошибке, просто где-то будет null вместо значения поля. На этом языке что-то сложное писать — только жизнь себе усложнять. Неужели вы с этим не сталкивались?
Почему же тогда автор придерживается противоположного мнения? Я подозреваю, из-за нехватки опыта. Ему наверно кажется, что скала — это что-то сложное, а яваскрипт можно изучить быстрее. Но это не так. Чтобы разрабатывать сложные приложения, вам нужна и типизация (в JS ее нет, придется добавлять ее через Flow), и знание ООП с паттернами и интерфейсами (которых в JS тоже нет), и dependency injection, модули, системы сборки, автоматические тесты и еще куча вещей. Яваскрипт просто не говорит вам сразу, что это нужно, и потому создается ощущение, что он проще. Хуже того, люди иногда берутся писать сложные приложения, не понимая ООП (то есть они знают, что такое объекты, поля и методы, но не понимают, зачем они нужны и как их правильно использовать, и им это кажется лишним усложнением) и dependency injection, и в итоге выходит плохой для понимания код, который тяжело читать, и тяжело править, не допустив ошибки.
Откройте код JS-редактора вроде Atom, и там вы найдете и ООП, и типизацию, и все, что вам не нравится в Скале.
Потому я не согласен с тем, что относится к Scala и сторонним библиотекам. Они нужны. Но, конечно, важно помнить, что код пишется прежде всего для людей. Надо писать его так, чтобы потом было легко в нем разобраться, и чтобы изменение в одном месте кода не ломало что-то в другом месте.
И повторю еще раз, не используйте классы или интерфейсы, если не разбираетесь в ООП. Не используйте паттерны, если вы их не понимаете, и у вас внутри ощущение, что они не нужны. От этого будет только хуже. Понятность кода важнее.
Хм
Тоже пришел к тому, что на js без типизации сложно
Но…
Во-первых можно писать в безопасном стиле, чтобы падало максимально близко к месту ошибки, можно заранее предугадывать ошибки, и ограждать эти места ловушками, и не падать вовсе, отрабатывая штатно (если логика позволяет)
А во-вторых, мало кто пишет на js, большинство пишут на его диалектах, которые поддерживают статическую типизацию, и которые поддерживают современные браузеры
Так что не всё так страшно
Но писать что-то большое на js не стоит точно, хотя-бы из соображений ресурсов: js всё-таки слишком тяжёлый по памяти и процессору, и применять его надо обдуманно
Он вкусен только двумя вещами:
- перекладывает часть нагрузки с сервера на клиент, пусть и более дорогой ценой, но платим не мы, а клиент
- очень сложно обеспечить интерактивность иначе, кроме как задействуя js — без него интерактивность выливается в сотни лишних запросов на то же действие, и в лишние секунды ожидания прогрузки, вызывающие только негатив у клиента
Очень странно, но везде наблюдаю такую картину интерактивности: вместо того, чтобы написать простенький js-загрузчик для аякса, и обмениваться только данными, почему-то везде генерируют шаблоны изменяемых областей целиком на сервере, и потом просто перезаписывает целые ветви dom этим контентом.
Тут нагрузка на сервер в разы выше, траффик и время ожидания также в разы выше, на пустом месте
Либо лютая день, либо большинство разработчиков просто стараются избегать js
А по поводу отрисовки на сервере — это норм оптимизация (Turbolinks, pjax). То что вы называете «простенький js-загрузчик для аякса» по факту в данной ситуации будет почти полноценным SPA (логика не только для загрузки JSON, но и для того как это всё отрисовать), только без роутинга. А тут уже время первоначальной загрузки страницы…
используя максимально минимальное количество переменныхВот бы ещё научиться статьи об этом так же четко и максимально лаконично, не используя лишних уточняющих прилагательных, совершенно неуместных и даже выглядящих нелепо в данном контексте, писать.
Новички пишут простой код, потому что не умеют писать сложный, средние программисты пишут сложный код, просто потому что могут, профессионалы пишут простой код, потому что не хотят писать сложный.Есть ещё фраза, что мидлы пишут код, который не поймут джуниоры, а сеньор пишет код, который поймут все.
То ли ТС действительно не далекий человек, то ли просто стебется.
Мой опыт программирования не такой внушительный, как у ТС.
Но в легаси системах постоянно сталкиваюсь, со сторонниками методов программирования как у ТС.
Т.е. один контроллер, для «всего».
Один джоб, который делает «все».
и т.д.
Да. «Переменных» мало, но зато внутри >5000 строк кода, которые сплетены в очень запутанный спагетти код.
Который (код) как-то нужно изменять, а его рефакторинг означает — написать заново.
Ох, какая боль в этом
Сам сталкиваюсь, ппц просто
Тут истина посередине: не стоит заводить лишние сущности, если их можно не заводить, но стоит их заводить, если без этого никак.
В данном случае без этого явно никак — было бы проще и понятнее, если быждый модуль выполнял только одну функцию, ту, ради которой его создали.
Но, как это бывает в командах, они пишут несогласованно, и время не бесконечно, так что каждый лепит во что гораздо, и как можно меньшими усилиями: о, зачем мне думать, если вот здесь можно добавить строчку, и моя задача решена?
А потом ещё строчка. И ещё. И так набирается 5000 строк. А рефакторить потом такое тот ещё ад, да и часто времени на это просто не выделяется — основной упор на реализацию функционала
Просто надо сразу продумывать худший сценарий, и закладывать минимальную масштабируемую архитектуру — если видишь, что со временем текущая реализация какой-то функции приведет к проблемам, которые естественно будет дорого решить, когда уже все работает, т.к. потребуется переделать архитектуру и изменить много кода, то… просто сразу закладываешь новый класс с минимально-достаточным функционалом для текущей задачи, который позволит в будущем не наступить на замеченные грабли, и всё. Его потом по мере возникновения потребности расширят и дополнят.
Мало того, что другие члены команды в сердцах помянут добрым словом, обнаружив, что их худшие опасения не сбылись, и необходимая часть архитектуры уже заложена, и их задачи можно решить минимальным количеством кода, так ещё и сами потом будете себя благодарить, что не поленились, и потратили минутку ради этого, потому что такая задача обязательно и вам позже прилетит, вот тут-то и вспомните, что она уже решена на 90% вашей предусмотрительностью.
Нет, особо этим увлекаться не стоит, порождая лишние сущности на каждом шагу. Но иногда есть такие вещи, что прямо кричат: "Эй! Я скоро буду для тебя большой проблемой! Почему бы тебе не решить её сейчас, пока это стоит дешево? Не откладывай! Завтра это обойдется тебе намного дороже"
Вот только их использование, в монолитном приложении, приводит к тому что говорит ТС.
Куча файлов, которые могут делать почти одно и то же (для ООП).
Решение как бы есть — ФП.
Но для ФП порог вхождения выше.
И писать в функциональном стиле «не каждый лишь может».
Лично мне удобнее, когда код хоть как-то разбит, на какие-то логические составляющие.
Чем в виде одного «God Object», где сосредоточена вся логика работы всего приложения.
Но я встречал программистов, которым наоборот удобнее. :-)
Но согласен я только с общей идей, и особенно с заключением статьи.
Но вот примеры — это беда.
Без знания системы в целом, всех средств разработки и т.д. нельзя говорить, что уместно, а что нет. В качестве примера банальное разделение какой-нибудь фабрики или любого другого «глобального» сервиса на интерфейс и его реализацию. В случае если кто-то где-то увидел, что так делают и просто начал лепить это везде, то тут явно нужна минимизация «переменных». Ведь зачем выделять отдельный интерфейс, если большинство DI фреймворков позволяет работать и напрямую с классами (хотя наверное, зависит от конкретных средств опять же). С другой стороны, если есть объективные причины использования такого подхода, как минимум применения юнит-тестирования, то тут минимизация уже начнет мешать, хотя фактические возможность ее и останется, но пользы в ней уже не будет, скорее начнет появляться вред, но который на качестве будет сказываться уже неявно.
Т.е. минимизировать нужно с учетом ограничений и требований уже существующей системы и подходов. С чем я согласен из статьи, так это с идей, что оправдывать большое количество «переменных» заделом на масштабирование, т.к. либо реально это масштабирование не возникает, либо к тому моменту, когда оно требуется, выясняется, что большинство требований и система настолько изменились, что этот самый давно созданный «задел» требуется переписывать заново и уже совсем иначе… (речь конечно о большинстве случаев, но не абсолютно обо всех).
Пример с написанием стилей мне показался еще более неуместным. Во-первых, возникла подмена понятий, «масштабирование» не имеет никакого отношения к вынесению стилей в отдельные файлы, я бы сказал, что тут уместнее понятие «сопровождение», т.к. в первую очередь это упрощает поддержание проекта и внесение изменений. Во-вторых, если взять пример с inline стилями, то это уже перебор, это ведь возможно лишь в некоторых единичных случаях. Ведь если на сайте есть стандартная кнопка, то она должна выглядеть одинаково, откуда появляется сразу 2 проблемы, одна — повторяемость кода, т.е. один и тот же «код» используется в множестве разных мест, вторая — следствие первой, если потребуется глобально что-то изменить, например цвет кнопки, то придется найти все места описания этой самой кнопки.
Как итог, повторюсь еще раз, идея минимизация логична и в общем-то лежит на поверхности. Как правило «проще», значит «лучше» и «надежнее». Но нужно избегать фанатизма и крайностей. И вот частично этот фанатизм и крайности представлены как раз в качестве примеров почему-то…
если функция состоит только из одной строчки — нужно стоит избавиться от этой функции
Слишком спорное утверждение.
Например, функция сложения 2 векторов просто выполняет 2 сложения.
Но, лучше, пусть будет эта функция, чем при копировании кто-нибудь забудет переименовать одну из переменных.
Тем более с этой работой прекрасно справится компилятор.
Если утилитарный класс содержит только одну функцию — нужно избавиться от этого утилитарного класса, если функция состоит только из одной строчки — нужно стоит избавиться от этой функции, если в компоненте находится только 10 строчек кода — нужно удалить этот компонент, если в папке только один файл — нужно избавиться от этой папки, и так далее. И когда несколько тысяч таких, казалось бы незначительных изменений складываются вместе, то в результате получается красивый, лаконичный и минималистичный код, который очень просто читать. Дьявол кроется в деталях как говорится.
Все зависит от того, какая у вас цель, и какой контекст.
Если в проекте вы один, проект конечен, то чем проще, тем лучше.
Если в проекте десятки людей, и проект долгоиграющий, то тонкие слои абстракций и рост их количества начинают себя окупать.
И это не отменяет того факта, что нужно в обоих случаях делать правильно. Легко накосячить и потерять все плюсы (как первого подхода, так и второго), и оставшись с минусами.
Функция-однострочник?
Да, это еще одна абстракция, это минус. Плюс — при правильном именовании функции — самодокументирующийся код.
Утилитный класс с одной функцией?
Да, это еще одна абстракция, это минус. Плюс — легко тестировать, легко управлять зависимостями.
И так по любому аспекту. Нет универсальных подходов. Используем лучший подход в каждом конкретном случае.
Никогда не поверю, что ЭТО поддерживать проще, при том, что реально уникального кода там копейки. Незнакомый с проектом человек в этой каше вообще ориентироваться не в состоянии, да и знакомые, как показывает опыт, несколько путаются.
Я не сказать, чтобы против разумного разделения функциональности, однако большая часть того, что мне доводилось видеть до сих пор видеть написана по принципу «а потом Остапа понесло». Сейчас шутка про эволюцию программиста (про «Hello world») уже не кажется смешной.
Вы ищете золотой молоток. Уходите в экстремум (Последний абзац не в счёт, то одно то другое). "Чтобы писать хороший код вам нужно всего лишь...". Вы для кого код пишете? Для компилятора? Или вы хотите встретить того садиста? Я бы предположил, что вы пишите код для себя, но тогда что мы вообще тут обсуждаем?
Вашим заказчикам до лампочки ваши миллисекунды, паттерны, идеологии. Разве что оно будет безбожно тормозить или это (скорость/память) одно из требований.
Ваш код должен быть читаемым и изменяемым. Если для этого требуются лишние переменные — пусть будут. Если вы хотите дать понять, в каком месте подразумеваете расширение — оставьте лишний интерфейс. Если для решения задачи надо несколько технологий, значит надо несколько технологий.
Если вы не можете рассказать в коде о чём идёт речь — код не будут поддерживать. Если ваш код ужасно рефакторится, он вообще мертворождённый — просто напишут аналог. Профессионалы пишут понятный код, который вы прочтете как книгу.
Введение новых переменных не ведет к масштабируемости архитектуры.
Не нужно ставить телегу впереди лошади.
К масштабируемости ведет такая организация кода и связей, которая позволяет добавлять в систему новые компоненты, не меняя (или минимально меняя) старые.
Для упрощения масштабируемости может потребоваться выделение дополнительных сущностей, отвечающих за взаимодействие систем и организацию правил взаимодействия, что может привести к увеличению переменных и это нормально. Ведь новые сущности добавляются не для того, чтобы их добавить, а для перспективного расширения.
Это всегда сложный вопрос баланса технического долга — когда заложить точки расширения. Подход минимализма может привести к тому, что места для расширения не будут закладываться в архитектуру, либо будут вынужденно добавляться на поздних этапах, приводя к серьезным переделкам, багам и в целом к высокой стоимости работ.
Есть лучше для пользователя, причем он никогда не знает, как ему лучше. Может казаться, что многие элементы сайта лишние и выбиваются из минималистичности, но они призваны обеспечить для пользователя другие цели, помимо собственно функциональности страницы — навигацию, авторизацию для использования доп функций, социальную часть — и не важно, что сейчас пользователь не использует их. Другие пользователи могут использовать их и испытывать благодарность.
Помимо этого, есть «лучше» для других людей.
Для владельцев сайтов — поэтому на страницах есть ссылки на другие материалы, реклама.
Для обеспечения технической части — поэтому есть форма авторизации.
В конце концов для разработчика — можно было бы сделать это очень хорошо, но за 3 года, а нужно взять более общее решение и готовые библиотеки и сделать за месяц.
«Я написал бы короче, но у меня не было времени» (Марк Твен)
К тому же ментальной каши добавляет тот факт, что под переменными в программировании подразумеваются в понимании автора и папки, и файлы, и константы, и классы, и функции, и строки кода — вообще все что угодно, то, что в принципе Окамы названо — сущностями.
фактически вводится в употребление целый новый принцип, по причине того, что автору понятие переменная в понимании сущность зашло больше, чем понятие сущность в понимании сущность.
причем вводится в особо извращенный способ, противоречащий содержанию самого принципа. не доказана его необходимость, учитывая что есть такой же, но не импортозамещенный принцип — от Окамы.
Есть чудесный набор принципов дизайна SOLID, обязательно прочтите про него, если не слышали ранее. Первая же буква акронима означает Single Responsibility, т.е. как раз то, о чем вы говорите, только в пределах одного контекста. Иными словами, минимизировать стоит сущности внутри контекста, но не в проекте в целом. А создавать новые контексты необходимо также с умом, контекст должен быть целостным и в то же время минималистичным. Ваш пример с документацией хорош, потому что страница документации — это как раз один ограниченный и целостный контекст. Он должен быть минималистичным, точным и понятным.
Однострочные функции и временные переменные, против которых вы выступаете, должны в теории сужать текущий контекст, скрывая вычисления за понятным именем. Т.е. видя вызов функции getWidth(), вы сразу понимаете, что это ширина. А если вы видите abs(x2-x1), то вы должны включить в контекст две переменных и функцию и понять что вычисляется. А если таких вычислений и разных много? Вы будете каждый раз пытаться понять, что делает та или иная строчка, раздувая локальный контекст?
Поэтому я не могу согласиться с тем, что простое уменьшение количества сущностей упрощает код и его поддержку. Но могу согласиться, что бездумное создание сущностей действительно сильно усложняет жизнь. Поэтому очень важно уметь правильно ограничивать контексты, их количество и размер, но так же как количество строк кода не является адекватной мерой работы программиста, так же и количество сущностей не может быть мерой сложности кода.
Если утилитарный класс содержит только одну функцию — нужно избавиться от этого утилитарного класса
SOLID (The Interface Segregation Principle)
если функция состоит только из одной строчки — нужно стоит избавиться от этой функции
Это еще почему? А потом исправить ошибку только в одном месте?
если в компоненте находится только 10 строчек кода — нужно удалить этот компонент, если в папке только один файл — нужно избавиться от этой папки, и так далее.
А это почему? Сегодня 1, завтра 100… А компонент у меня еще в 10 местах используется…
И когда несколько тысяч таких, казалось бы незначительных изменений складываются вместе, то в результате получается красивый, лаконичный и минималистичный код, который очень просто читать.
Страшно представить что тогда получится(представил: огромная портянка в которой не видно сути, но зато все детали на виду)…
Дальше не читал… По-моему, Вы отталкиваетесь не от того. Я не против избавления от избыточности, но исходить все-таки надо от другого: будущая поддержка, расширяемость, понятность логики, и др…
Недаром тут столько возражений нашлось — у всякого разработчика с широким опытом есть куча примеров того, как ограничивает и мешает минимизация.
Попытка выделить «главный паттерн программирования вообще» должна была прийти к настолько общей идее, чтобы она оказалась не противоречащей ни сама себе, ни накопленному опыту признанных мастеров. Ведь другие паттерны не на пустом месте возникли…
Если бы я попытался выразить словами такой общий «паттерн», то получилось бы что-то вроде «Главная задача в программировании — это минимизация суммарных затрат на удовлетворение максимальных потребностей, как заказчика, так и исполнителя, включая будущие потребности и затраты».
(можно бы и без явного упоминания будущих, но, как показывает практика, слишком часто про них забывают)
Важно то, что учитывать надо и наши потребности. И не только в зарплате. Технологии поизучать хочется? Пощупать новый фреймворк? Вообще делать что-то нескучное? И время для личной жизни сберечь? И здоровье?
Сама формулировка не сильно новая, примерно так выражается большое число математических задач, в том числе пришедших из чисто практических потребностей. Но есть один огромный нюанс, отличающий программирование. Мы часто имеем деле с неограниченным количеством неопределённых потребностей. Например, задача постройки моста через реку. Там сходу можно накидать сведений по транспортной нагрузке, условиям эксплуатации и даже требований к внешнему виду. Потребностей много, но всё же они перечислимы и большую часть можно точно померять, включая прибыть подрядчика. Задача разработчика — минимизации затрат на строительство и обслуживание. А если мы пишем интернет-магазин, то какие потребности нам учесть? Сколько посетителей/покупателей/товаров/заказов? Да какие вообще планы у бизнеса? магазин-однодневка или будущий алиэкспресс? Код писать будет один разработчик или толпа? а учесть ли финансовый учёт? или заложить меры противодействия взлому/слому со стороны конкурентов? И т.д. и т.п… В реальной жизни хорошо если у заказчика окажется пара готовых ответов. Да и то, он может передумать, когда узнает цену… Поэтому важно умело расставлять рамки, ограничивая поле расчёта, но при этом не оставить за бортом нечто очень важное.
Одна проблема — этот «паттерн» не даёт универсальной рецептуры.
Deleted