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

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

Под термином переменная я подразумеваю не только обычные переменные (которые объявляются через ключевые слова var, let, function), но так же и переменные в более абстрактном смысле этого слова: созданные папки в дереве проекта, подключаемы библиотеки, количество ajax вызовов на сервер, количество компонентов в интерфейсе, количество протоколов которым должен следовать программист при коммите кода (например code review, каждая фича в отдельном бранче) и так далее.

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

Вот список положительных эффектов, которые проявляются когда вы начинаете программировать отталкиваясь от принципа минимизации переменных:

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

Но очень часто происходит обратная ситуация, программисты начинают самоутверждаться за счет введения новых переменных. Вводится 20 различных библиотек, CSS-фреймворков, создается огромное количество многоуровневых абстракций по типу UserFactoryManager (особенно этим грешат Java программисты по какой-то причине), создается слишком большое количество директорий, вводятся более продвинутые методологии разработки, добавляется большее количество протоколов перед коммитом файлов, и так далее. И мотивацию стоящую за такими решениями можно понять, ведь это создает иллюзию профессионализма, дескать посмотрите как много всего я знаю, и какими сложными абстракциями я умею оперировать. Но зачастую это причиняет чудовищный вред проекту.

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

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

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

Огромное количество лишних переменных — это именно та причина по которой я лютой ненавистью ненавижу язык программирования Scala, и та причина по которой я люблю JavaScript. Scala — это просто квинтэссенция переусложненная, очень запутанная система типов, множество концептов которые дублируют друг друга, неявные преобразования, огромное количество способов сделать одно и то же. Когда я использую этот язык программирования, то я думаю не о том что нужно сделать, а о том как это сделать. Я очень часто ловлю себя на том, что просто сейчас моя цель просто заткнуть компилятор. С другой стороны JavaScript — это полная противоположность Scala, он на порядок минималистичнее, используя его я трачу значительно меньшее количество ментальных усилий для того, что бы выразить тот или иной концепт. Безусловно в такой простоте имеются и свои минусы, например в Scala компилятор сообщает об ошибке на этапе компиляции, в то время как в JavaScript об ошибке можно узнать только в рантайме и так же для JavaScript принципиально невозможно написать настолько же функциональную IDE как для строго-типизированных языков, но это те жертвы с которыми я готов смириться.

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

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

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

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

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

Вы можете мне возразить, дескать то же мне, открыл Америку, это уже давным-давно известно и описывается такими принципами как: Бритва Окама, SOLID. Но мне больше нравится называть этот концепт именно «минимизации переменных», просто потому что это такая интерпретация очень лаконично ложится в голову и соответственно ее намного проще придерживаться на практике. Кто из вас может похвастаться тем, что помнит каждый пункт из принципа SOLID?

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

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

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


  1. zuborg
    03.07.2018 20:30
    +3

    Совершенство достигается не тогда, когда больше нечего добавить, а тогда, когда нечего убрать.


    1. mad_nazgul
      04.07.2018 13:22

      Вакуум?!


      1. domix32
        04.07.2018 13:32

        В вакуум можно добавить процентов 75-78 азота, 15-20% кислорода, 2-3 сотые процента углекислого газа, а остальное заполнить какими-нибудь инертными газами. Так что добавлять и добавлять в этот ваш вакуум.


        1. mad_nazgul
          04.07.2018 14:53

          В смысле вакуум это предел совершенства?!
          Т.к. из него невозможно ничего убрать.


          1. domix32
            04.07.2018 15:57

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


          1. SadOcean
            04.07.2018 17:19

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


            1. 0x131315
              04.07.2018 21:55

              Вакуум — это квинтэссенция неопределенности.
              В вакууме есть всё.
              А материя, напротив, предельно определена, в ней есть только одно.


            1. mad_nazgul
              05.07.2018 06:30

              Про то что что-то нужно в исходной цитате ничего нет. ;-)


            1. VolCh
              05.07.2018 08:37

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


      1. remzalp
        05.07.2018 08:15

        Действующая и продававшаяся программа длиной в 0 байт.
        https://habr.com/post/147075/


  1. nafgne
    03.07.2018 21:10

    А вы точно различаете понятия «переменная» и «слой абстракции»?


  1. AntonSazonov
    03.07.2018 22:09
    +1

    Заголовок статьи извольте поправить. Даже в личку писать не хочется...


    1. mnemosha Автор
      03.07.2018 22:13

      Спасибо, такая досадная ошибка :(


      1. AntonSazonov
        03.07.2018 22:18

        Бывает. Errare humanum est.


  1. Neikist
    03.07.2018 22:36
    +1

    Не могу поддержать это мнение. Пока что самый ужасный код который я видел была как раз таки результатом подобного подхода. ИС построенная на одном стеке технологий, тогда как не все потребности заказчика стек удовлетворял (но большинство, и это большинство очень хорошо), и больше бы подошла гетерогенная архитектура. Разросшиеся функции на тысячи строк из за нежелания добавлять новые функции, извращения в запросах, где один запрос может быть 2-3 000 строк, вместо того чтобы добавить новую таблицу в базу. Создание из форм каких нибудь документов прямо god объектов, из за нежелания добавлять новую форму. «Универсальные алгоритмы», которые по факту ни к одному случаю не подходят из желания минимизировать количество случаев. Жестко зашитые зависимости которые даже не то что для тестов, для небольшой доработки не расцепишь и подобное. Это уж не вспоминая о том что лично мой код стало можно читать без особо сильного кровотечения из глаз только после того как я немного научился разбивать его по уровням абстракции. И я скорее предпочту добавить лишний уровень абстракции, вместо того чтобы смешать несколько уровней вместе.


    1. aamonster
      03.07.2018 22:57
      +1

      Можно натянуть сову на глобус и объединить ваши мысли с размышлениями автора, если просто сказать, что минимизировать (непонятно, что, но точно не переменные) надо не в системе в целом, а в том срезе системы, который приходится держать в голове одновременно. В каждом из этих срезов. Т.е., с одной стороны, минимизировать количество уровней абстракции, но с другой — "толщину" каждого слоя. Чтобы можно было разглядывать все слои вместе, не вдаваясь в их детали — и каждый слой в отдельности, не глядя на остальные.


      1. Neikist
        03.07.2018 22:58
        +1

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


  1. Sabubu
    04.07.2018 00:03
    +1

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

    Но вот дальше, когда вы упомянули Javascript и Scala, я уже согласиться не могу. Яваскрипт вообще плохо подходит для больших приложений из-за отсутствия статической типизации (которая есть в скале) и любви к игнорированию ошибок. Я писал большое приложение на JS. Вы в одном месте поделите на ноль, Яваскрипт молчит как партизан, этот NaN расползается по программе и она падает потом где-то в совсем другом месте кода, и ищи, откуда этот NaN появился. Или, например, опечатался в имени поля, никаких сообщений об ошибке, просто где-то будет null вместо значения поля. На этом языке что-то сложное писать — только жизнь себе усложнять. Неужели вы с этим не сталкивались?

    Почему же тогда автор придерживается противоположного мнения? Я подозреваю, из-за нехватки опыта. Ему наверно кажется, что скала — это что-то сложное, а яваскрипт можно изучить быстрее. Но это не так. Чтобы разрабатывать сложные приложения, вам нужна и типизация (в JS ее нет, придется добавлять ее через Flow), и знание ООП с паттернами и интерфейсами (которых в JS тоже нет), и dependency injection, модули, системы сборки, автоматические тесты и еще куча вещей. Яваскрипт просто не говорит вам сразу, что это нужно, и потому создается ощущение, что он проще. Хуже того, люди иногда берутся писать сложные приложения, не понимая ООП (то есть они знают, что такое объекты, поля и методы, но не понимают, зачем они нужны и как их правильно использовать, и им это кажется лишним усложнением) и dependency injection, и в итоге выходит плохой для понимания код, который тяжело читать, и тяжело править, не допустив ошибки.

    Откройте код JS-редактора вроде Atom, и там вы найдете и ООП, и типизацию, и все, что вам не нравится в Скале.

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

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


    1. JSmitty
      04.07.2018 07:31

      То есть по вашему ООП — единственная парадигма, в которой можно создавать сложное ПО? Без ООП жизни нет?


    1. 0x131315
      04.07.2018 22:12
      +1

      Хм
      Тоже пришел к тому, что на js без типизации сложно
      Но…
      Во-первых можно писать в безопасном стиле, чтобы падало максимально близко к месту ошибки, можно заранее предугадывать ошибки, и ограждать эти места ловушками, и не падать вовсе, отрабатывая штатно (если логика позволяет)
      А во-вторых, мало кто пишет на js, большинство пишут на его диалектах, которые поддерживают статическую типизацию, и которые поддерживают современные браузеры
      Так что не всё так страшно


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


      Он вкусен только двумя вещами:


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

      Очень странно, но везде наблюдаю такую картину интерактивности: вместо того, чтобы написать простенький js-загрузчик для аякса, и обмениваться только данными, почему-то везде генерируют шаблоны изменяемых областей целиком на сервере, и потом просто перезаписывает целые ветви dom этим контентом.
      Тут нагрузка на сервер в разы выше, траффик и время ожидания также в разы выше, на пустом месте
      Либо лютая день, либо большинство разработчиков просто стараются избегать js


      1. VolCh
        05.07.2018 08:46

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


      1. Murmurianez
        05.07.2018 19:01

        На диалектах пишет небольшой процент (ES6 я диалектом не считаю).

        А по поводу отрисовки на сервере — это норм оптимизация (Turbolinks, pjax). То что вы называете «простенький js-загрузчик для аякса» по факту в данной ситуации будет почти полноценным SPA (логика не только для загрузки JSON, но и для того как это всё отрисовать), только без роутинга. А тут уже время первоначальной загрузки страницы…


  1. kosmos89
    04.07.2018 00:51

    Я обычно называю некий схожий с «количеством переменных» концепт «энтропией» кода.


  1. dipsy
    04.07.2018 05:20

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


  1. dipsy
    04.07.2018 05:33

    Нужно уменьшать энтропию, проще говоря. Все рефакторинги они примерно об этом.

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


  1. mad_nazgul
    04.07.2018 05:38

    Попытка разжигания флуда засчитана.
    То ли ТС действительно не далекий человек, то ли просто стебется.

    Мой опыт программирования не такой внушительный, как у ТС.
    Но в легаси системах постоянно сталкиваюсь, со сторонниками методов программирования как у ТС.
    Т.е. один контроллер, для «всего».
    Один джоб, который делает «все».
    и т.д.
    Да. «Переменных» мало, но зато внутри >5000 строк кода, которые сплетены в очень запутанный спагетти код.
    Который (код) как-то нужно изменять, а его рефакторинг означает — написать заново.


    1. 0x131315
      04.07.2018 22:31

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


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


      Нет, особо этим увлекаться не стоит, порождая лишние сущности на каждом шагу. Но иногда есть такие вещи, что прямо кричат: "Эй! Я скоро буду для тебя большой проблемой! Почему бы тебе не решить её сейчас, пока это стоит дешево? Не откладывай! Завтра это обойдется тебе намного дороже"


      1. mad_nazgul
        05.07.2018 06:48

        Понятно, что KISS и SOLID «наше всио».
        Вот только их использование, в монолитном приложении, приводит к тому что говорит ТС.
        Куча файлов, которые могут делать почти одно и то же (для ООП).
        Решение как бы есть — ФП.
        Но для ФП порог вхождения выше.
        И писать в функциональном стиле «не каждый лишь может».

        Лично мне удобнее, когда код хоть как-то разбит, на какие-то логические составляющие.
        Чем в виде одного «God Object», где сосредоточена вся логика работы всего приложения.
        Но я встречал программистов, которым наоборот удобнее. :-)


  1. AR1ES
    04.07.2018 08:14
    +1

    Спасибо ТС за статью и очередной повод порефлексировать =)
    Но согласен я только с общей идей, и особенно с заключением статьи.

    Но вот примеры — это беда.
    Без знания системы в целом, всех средств разработки и т.д. нельзя говорить, что уместно, а что нет. В качестве примера банальное разделение какой-нибудь фабрики или любого другого «глобального» сервиса на интерфейс и его реализацию. В случае если кто-то где-то увидел, что так делают и просто начал лепить это везде, то тут явно нужна минимизация «переменных». Ведь зачем выделять отдельный интерфейс, если большинство DI фреймворков позволяет работать и напрямую с классами (хотя наверное, зависит от конкретных средств опять же). С другой стороны, если есть объективные причины использования такого подхода, как минимум применения юнит-тестирования, то тут минимизация уже начнет мешать, хотя фактические возможность ее и останется, но пользы в ней уже не будет, скорее начнет появляться вред, но который на качестве будет сказываться уже неявно.
    Т.е. минимизировать нужно с учетом ограничений и требований уже существующей системы и подходов. С чем я согласен из статьи, так это с идей, что оправдывать большое количество «переменных» заделом на масштабирование, т.к. либо реально это масштабирование не возникает, либо к тому моменту, когда оно требуется, выясняется, что большинство требований и система настолько изменились, что этот самый давно созданный «задел» требуется переписывать заново и уже совсем иначе… (речь конечно о большинстве случаев, но не абсолютно обо всех).

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

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


    1. mnemosha Автор
      04.07.2018 08:26

      Спасибо за развернутый комментарий. Даже поражаюсь тому, насколько на хабре дают адекватные комментарии в сравнении со всем остальным интернетом.


    1. VolCh
      05.07.2018 09:15
      +1

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


      1. AR1ES
        05.07.2018 09:31

        Да, согласен. Но тут есть важный момент. Во-первых, как отмечено, это приводит все равно к созданию очередной «переменной», т.е. минимизация не достигается. Во-вторых, все зависит от конкретного случая, например, когда при здравом подходе без ввода лишнего кода одним компонентом не обойтись, например есть все та же кнопка, а есть выпадающий список, который в состоянии по-умолчанию выглядит как кнопка (только стрелочка справа рисуется), так вот тут уже придется создавать два разных компонента, но при этом «код» (точнее inline-стиль) у них будет заметно пересекаться.


  1. Deosis
    04.07.2018 08:39

    если функция состоит только из одной строчки — нужно стоит избавиться от этой функции

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


    Тем более с этой работой прекрасно справится компилятор.


  1. ggo
    04.07.2018 10:03

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


    Все зависит от того, какая у вас цель, и какой контекст.

    Если в проекте вы один, проект конечен, то чем проще, тем лучше.
    Если в проекте десятки людей, и проект долгоиграющий, то тонкие слои абстракций и рост их количества начинают себя окупать.
    И это не отменяет того факта, что нужно в обоих случаях делать правильно. Легко накосячить и потерять все плюсы (как первого подхода, так и второго), и оставшись с минусами.

    Функция-однострочник?
    Да, это еще одна абстракция, это минус. Плюс — при правильном именовании функции — самодокументирующийся код.

    Утилитный класс с одной функцией?
    Да, это еще одна абстракция, это минус. Плюс — легко тестировать, легко управлять зависимостями.

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


    1. DrZlodberg
      04.07.2018 10:59

      Из личного опыта: контрол, отображающий на клиенте грид (MVC) возвращаемый сервером из БД (суммарно клиент и сервер): ~10 проектов, ~40+ файлов, адовые зависимости между всем этим, куча однострочных функций, который только вызывают другую функцию в другом классе (часто с тем же названием) и т.д. Самый эффективный способ добавления новых контролов — кописпаст всей кучи, правка десятка строчек кода и штук дофига названий классов (чтобы по феншую).

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

      Я не сказать, чтобы против разумного разделения функциональности, однако большая часть того, что мне доводилось видеть до сих пор видеть написана по принципу «а потом Остапа понесло». Сейчас шутка про эволюцию программиста (про «Hello world») уже не кажется смешной.


      1. ggo
        05.07.2018 09:13

        Ваш случай — подтверждение тезиса «нужно в обоих случаях делать правильно».
        Любую самую классную идею можно испоганить бездарным исполнением. Это не делает идею плохой. Как идею «все делать как можно проще», так и идею «нарезаем на тонкие слои абстракций».


  1. avraam_linkoln
    04.07.2018 10:05

    Интересная идея. Разработчикам современных фреймворков нао наверное поучится у автора. Зачем MVC, паттерны и ООП, если можно писать логику, верстку и запросы к базе в одном файле?


    1. DrZlodberg
      04.07.2018 11:00

      Буквально комментарием выше привёл пример. Всё хорошо в меру.


      1. avraam_linkoln
        04.07.2018 16:44

        Помоему лучше уж функции из одной строки чем if ($_GET['action'] == 'edit') {

        }
        и так в каждом файле


  1. Lewik87
    04.07.2018 10:05

    Вы ищете золотой молоток. Уходите в экстремум (Последний абзац не в счёт, то одно то другое). "Чтобы писать хороший код вам нужно всего лишь...". Вы для кого код пишете? Для компилятора? Или вы хотите встретить того садиста? Я бы предположил, что вы пишите код для себя, но тогда что мы вообще тут обсуждаем?


    Вашим заказчикам до лампочки ваши миллисекунды, паттерны, идеологии. Разве что оно будет безбожно тормозить или это (скорость/память) одно из требований.


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


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


  1. SadOcean
    04.07.2018 11:18

    Введение новых переменных не ведет к масштабируемости архитектуры.

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


    1. AlexTOPMAN
      04.07.2018 21:38

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


  1. SadOcean
    04.07.2018 11:26

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

    «Я написал бы короче, но у меня не было времени» (Марк Твен)


  1. Vlad_fox
    04.07.2018 11:52

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

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


  1. domix32
    04.07.2018 13:35

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


  1. dbagaev
    04.07.2018 15:17
    +1

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

    Есть чудесный набор принципов дизайна SOLID, обязательно прочтите про него, если не слышали ранее. Первая же буква акронима означает Single Responsibility, т.е. как раз то, о чем вы говорите, только в пределах одного контекста. Иными словами, минимизировать стоит сущности внутри контекста, но не в проекте в целом. А создавать новые контексты необходимо также с умом, контекст должен быть целостным и в то же время минималистичным. Ваш пример с документацией хорош, потому что страница документации — это как раз один ограниченный и целостный контекст. Он должен быть минималистичным, точным и понятным.

    Однострочные функции и временные переменные, против которых вы выступаете, должны в теории сужать текущий контекст, скрывая вычисления за понятным именем. Т.е. видя вызов функции getWidth(), вы сразу понимаете, что это ширина. А если вы видите abs(x2-x1), то вы должны включить в контекст две переменных и функцию и понять что вычисляется. А если таких вычислений и разных много? Вы будете каждый раз пытаться понять, что делает та или иная строчка, раздувая локальный контекст?

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


  1. BASic_37
    04.07.2018 19:23

    Если утилитарный класс содержит только одну функцию — нужно избавиться от этого утилитарного класса

    SOLID (The Interface Segregation Principle)
    если функция состоит только из одной строчки — нужно стоит избавиться от этой функции

    Это еще почему? А потом исправить ошибку только в одном месте?
    если в компоненте находится только 10 строчек кода — нужно удалить этот компонент, если в папке только один файл — нужно избавиться от этой папки, и так далее.

    А это почему? Сегодня 1, завтра 100… А компонент у меня еще в 10 местах используется…
    И когда несколько тысяч таких, казалось бы незначительных изменений складываются вместе, то в результате получается красивый, лаконичный и минималистичный код, который очень просто читать.

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


  1. staticY
    04.07.2018 19:23
    +2

    Ох уж эти декларативные утверждения «так лучше, а вот так — хуже». Все зависит от того, какой результат нужен на выходе. Если нам нужен рабочий прототип в ограниченное время — то, очевидно, чем быстрее и проще будет написан код — тем лучше. (И то не всегда! Нужно думать головой в первую очередь) Если же проект долгоиграющий, то подход к написанию кода совершенно другой — на первый план выходят расширяемость, поддерживаемость, тестируемость, модульность, «правильность» архитектуры и тп.


  1. Mikluho
    05.07.2018 07:45

    Во всяком «лучше» всегда есть прибавки «где» и «когда». Без них ваше «лучше» ничем не лучше остальных :)
    Недаром тут столько возражений нашлось — у всякого разработчика с широким опытом есть куча примеров того, как ограничивает и мешает минимизация.
    Попытка выделить «главный паттерн программирования вообще» должна была прийти к настолько общей идее, чтобы она оказалась не противоречащей ни сама себе, ни накопленному опыту признанных мастеров. Ведь другие паттерны не на пустом месте возникли…
    Если бы я попытался выразить словами такой общий «паттерн», то получилось бы что-то вроде «Главная задача в программировании — это минимизация суммарных затрат на удовлетворение максимальных потребностей, как заказчика, так и исполнителя, включая будущие потребности и затраты».
    (можно бы и без явного упоминания будущих, но, как показывает практика, слишком часто про них забывают)
    Важно то, что учитывать надо и наши потребности. И не только в зарплате. Технологии поизучать хочется? Пощупать новый фреймворк? Вообще делать что-то нескучное? И время для личной жизни сберечь? И здоровье?
    Сама формулировка не сильно новая, примерно так выражается большое число математических задач, в том числе пришедших из чисто практических потребностей. Но есть один огромный нюанс, отличающий программирование. Мы часто имеем деле с неограниченным количеством неопределённых потребностей. Например, задача постройки моста через реку. Там сходу можно накидать сведений по транспортной нагрузке, условиям эксплуатации и даже требований к внешнему виду. Потребностей много, но всё же они перечислимы и большую часть можно точно померять, включая прибыть подрядчика. Задача разработчика — минимизации затрат на строительство и обслуживание. А если мы пишем интернет-магазин, то какие потребности нам учесть? Сколько посетителей/покупателей/товаров/заказов? Да какие вообще планы у бизнеса? магазин-однодневка или будущий алиэкспресс? Код писать будет один разработчик или толпа? а учесть ли финансовый учёт? или заложить меры противодействия взлому/слому со стороны конкурентов? И т.д. и т.п… В реальной жизни хорошо если у заказчика окажется пара готовых ответов. Да и то, он может передумать, когда узнает цену… Поэтому важно умело расставлять рамки, ограничивая поле расчёта, но при этом не оставить за бортом нечто очень важное.
    Одна проблема — этот «паттерн» не даёт универсальной рецептуры.