У большинства из нас были отличные оценки по математике в школе и в универе. Помните, как мы решали примеры? Скажем, нужно взять производную от функции:

$f(x) = \frac{\ln{x}}{x^2}$


Мы задумывались на несколько секунд и записывали готовый результат:

$f'(x) = \frac{1-2ln{x}}{x^3}$


Ученики послабее записывали решение по шагам и тратили существенно больше времени:

$f'(x) = \left(\frac{ln{x}}{ x^2}\right)' = \frac{(ln{x})' \cdot x^2 - ln{x} \cdot (x^2)'}{(x^2)^2} =\\ \frac{\frac{1}{x} \cdot x^2 - ln{x} \cdot 2 x}{x^4} = \frac{x - ln{x} \cdot 2 x}{x^4} = \\ \frac{x \cdot (1 - ln{x} \cdot 2)}{x^4} = \frac{1 - 2 ln x}{x^3} $


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

Почему мы так можем, а другие — не могут?

Математика и кратковременная память


Нет, это очевидно, что мы можем выполнить все необходимые операции в уме, и нам нет необходимости записывать промежуточные результаты на бумаге. Но почему это возможно?

В когнитивной психологии ту часть памяти, в которой непосредственно производятся вычисления «в уме», называют кратковременной и рабочей. Там всё сложно и неоднозначно, но как её ни назови, а объём этой памяти сильно ограничен. Разные исследователи называют «магические числа» семь и пять. Это средние значения. Объём «рабочей» памяти зависит от обстоятельств и коррелирует с интеллектуальными способностями.

Получается, способность не записывать промежуточные результаты обусловлена возможностями нашей рабочей (или кратковременной) памяти. У нас, технарей, рабочая память для хранения «технических» элементов объёмнее, чем у гуманитариев. Чем больше памяти, тем больше промежуточных шагов мы можем накапливать в ней, не записывая.

Программирование и кратковременная память


А теперь попробуем представить, как работают наши сверхспособности, когда мы программируем.

Для решения полученной задачи требуется написать определённое количество кода. Но мы торопимся, и мы способны удержать в голове массу деталей. Чувствуете, куда я клоню? Мы не записываем промежуточные шаги. Вместо этого мы пишем такие алгоритмы, которые получают исходные данные и сразу выдают готовый результат. Они длинные, эти алгоритмы, и они делают очень много работы. Столько, сколько мы смогли уместить в нашей собственной рабочей памяти, когда их писали.
Гипотеза. Чем умнее программист (чем более объёмной рабочей памятью он располагает), тем более длинные методы и функции он пишет.

Попробуем подсчитать, насколько большой объём рабочей памяти требуется при программировании. Поскольку мы не знаем, как именно устроено мышление, и какими именно «объектами» оно оперирует, то просто будем подсчитывать независимые объекты, которые встречаются в коде программы.

В качестве подопытного я взял функцию на Ruby длиной 150 строк из проекта BigBlueButton. Сразу признаюсь, что этот код задел меня за живое. Пришлось потратить пару дней и почти полностью переписать несколько методов, чтобы внести косметические изменения в функциональность небольшой части проекта. Ни одну сколько-нибудь длинную последовательность строк не получилось использовать повторно.

Этот код прекрасно иллюстрирует гипотезу. Он был написан так же, как мы привыкли решать примеры. Масса промежуточных шагов удерживалась непосредственно в голове, а «на бумагу» попало лишь окончательное решение. 150 строк, которые решают всю чёртову задачу одним махом. Этот код явно был написан очень талантливым парнем!

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

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

  • 4 аргумента функции, которые упоминаются в общей сложности 15 раз;
  • 42 внутренних переменных, использованных ещё 131 раз;
  • 52 обращения к 24 различным элементам хэшей, переданных функции в качестве аргументов (чтобы работать с кодом, необходимо удерживать в голове внутреннее «устройство» всех этих хэшей);
  • 9 обращений к 8 различным внешним сущностям (константам и методам классов).

Итого, считая по-минимуму, получились 4+42+24+8=78 независимых объектов. И это я ещё не считал операции, которые выполняются над объектами. А ведь операции тоже «занимают» какую-то долю рабочей памяти.

78 объектов против «магических» семи — не многовато ли для одной функции?

Конечно, тут можно бесконечно спорить о том, что раз код написан и работает, значит, 78 объектов — вовсе не проблема. Это ведь не самый длинный метод, так? Значит, объектов может быть ещё больше? К тому же, кто сказал, что все 78 необходимо удерживать строго одновременно?

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

Метрики и кратковременная память


Для оценки качества кода применяются различные метрики. Например, Морис Холстед исследовал численные метрики кода ещё в 70-х (!) годах. Вроде бы понятно, что измерять и оценивать качество кода — дело хорошее. И спору нет, что чем сложнее код, тем больше умственных усилий он требует. Но есть с метриками один вопрос. По выражению EvgeniyRyzhkov, «в метриках не придумано главного — что с ними делать».

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

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

Раз наука, которая изучает свойства интеллекта, называется когнитивной, то и метрику, которая соотносится с ограничениями этого интеллекта, логично тоже назвать когнитивной. Назову её, скажем, когнитивным весом. А то когнитивная сложность уже занята. Кстати, Холстед в своих «Началах науки о программах» описывает метрику, на которую когнитивный вес очень сильно похож. Только Холстед не апеллирует к понятию «когнитивный». (К слову, «Cognitive Psycology» R. Solso была впервые опубликована в 1979-м, а «Elements of Software Science» M. Halstead — в 1977-м).

Так вот, отвечаю на вопрос про метрики.
Практически полезные метрики качества кода следует строить так, чтобы они показывали, с каким кодом мозгу-инструменту будет работать легко, а на каком он «сломается». И не «интуитивно», а опираясь на данные, получаемые от когнитивной науки.

Резюме


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

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

P.S. Один из моих шайтан-методов, до которого никак не доходят руки отрефакторить, имеет длину 120 строк. Когнитивный вес даже считать не хочется. Стыдно.



UPD

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

Школьные оценки для меня никогда не были показателем чего-то существенного. У меня самого по всем предметам, кроме математики, были крайне средние оценки. Своей дочери я всегда старался внушить мысль, что оценки — не главное в жизни. Важно, чтобы что-то было в голове: знания, понимание, интерес к чему-то. Хотя, она меня не слушала и закончила школу с золотой медалью.

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


  1. sondern
    17.02.2018 16:16
    +1

    Этот код прекрасно иллюстрирует гипотезу. Он был написан так же, как мы привыкли решать примеры. Масса промежуточных шагов удерживалась непосредственно в голове, а «на бумагу» попало лишь окончательное решение. 150 строк, которые решают всю чёртову задачу одним махом. Этот код явно был написан очень талантливым парнем!

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


    1. SergeyGalanin Автор
      17.02.2018 16:30

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

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

      Только вот чтобы сначала написать 1500 строк, нужно их всё таки все держать в памяти. А во вторых, рефакторинг 1500 строк до 10 раз по 150 — это не очень хороший рефакторинг. Надо тогда уж хотя бы до 100 раз по 15.


      1. php7
        18.02.2018 15:01
        -1

        На одном месте я видал ваши рефакторинги на 100 функций по 15 строк.


    1. HueyOne
      17.02.2018 17:44

      Логичнее писать псевдокод, его оптимизировать, а потом уже реализовывать (и еще раз оптимизировать). Сам псевдокод можно оставить в комментарии к исходнику.


      1. Bringoff
        18.02.2018 09:18
        +5

        1500 строк псевдокода — хотелось бы посмотреть :)


        1. HueyOne
          18.02.2018 17:26

          Любую книгу по алгоритмам откройте.
          Хотя современным «программистам» зачем оно…


          1. marsermd
            19.02.2018 13:09
            +1

            … И вы там не найдете такого псевдокода:)
            Алгоритмы обычно более короткие.


            1. HueyOne
              19.02.2018 20:49

              Распишите-ка алгоритм, например, работы банкомата с картой.


              1. marsermd
                19.02.2018 21:00

                А такого вы и не увидите в книгах по алгоритмам.
                Вы можете увидеть псевдокод RSA, можете увидеть декартово дерево. Но до 1500 строк там очень далеко:)


      1. AllexIn
        18.02.2018 13:49

        Нельзя на псевдокоде писать алгоритмы. Одна из проблем псевдокода — отсутствие спецификации.
        Простой пример — двойное отрицание над int в С++.
        Двойное отрицание дает нам приведение к строгому bool.
        Но в псевдокоде что даст двойное отрицание? Это будет логическая операция или бинарная? Конкретно в случае двойного отрицания понятно, что оно бессмысленно в случае бинарной операции. Но в любом случае однозначности нет.


        1. VolCh
          18.02.2018 13:54

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


          1. HueyOne
            18.02.2018 17:20
            -2

            Большинство нынешних «разработчиков» это и есть машина для исполнения псевдокода. Причем, очень некачественная.

            PS и да, если вы не можете написать свои сишные уродцы типа «двойного отрицания над int» русским языком, то ваш код сразу можно выкинуть в помойку. Только там место недокументированному коду. Такому коду нельзя доверять, пока его сам не проверишь целиком. А, значит, проще написать заново.


            1. VolCh
              19.02.2018 11:26
              +1

              Математически строгая верификация кода очень трудоемка, если вообще возможна в общем случае. Так или иначе, коду приходится доверять и неважно кто его писал.


              1. HueyOne
                19.02.2018 11:33
                -1

                А потом у нас у всех хартблид или иные факапы сходного масштаба


        1. HueyOne
          18.02.2018 17:17

          то, что тут написано, и есть псевдокод.
          в чем проблема написать «строгий boolean»?


  1. apro
    17.02.2018 17:12
    +2

    А почему "троечник" не может решить пример в три действия?


    (lnx/x^2)' = (lnx)'/x^2 + lnx * (x^-2)' = 1/x / x^2 -2 * lnx / x^3=(1-2*lnx)/x^3

    И не связана ли возможность "отличника" быстро щелкать примеры с тем
    что он в десятки, а возможно и в сотни раз больше задачек решил, чем троечник (
    который например банально не делает домашнее задание) и тем самым просто натренировался как "собака Павлова"?


    1. SergeyGalanin Автор
      17.02.2018 17:25

      Ну, в три действия — это уже «хорошист»!

      Безусловно, бывают такие талантливые троечники, которым просто на математику наплевать, потому что у них есть куда более интересные для них занятия: литература, плавание и КВН, например. На таких ведь так мало…


      1. Kazikus
        17.02.2018 18:36

        А почему мало? У меня один одноклассник троечник — руководитель в строительной компании, второй — бизнесмен в области холодильного оборудования (мерседес новенький купил только только закончив универ). У отличников, тоже все нормально, но троечник это не приговор. Отличники часто чсв свое применить в жизни не могут.


      1. Mr_Rm
        17.02.2018 20:38

        Тут дело не в количестве действий. В решении apro не записано самое важное:
        (lnx/x^2)' = (lnx * x^-2)'
        Это и есть «отличие» — увидеть возможность упростить задачу ещё до применения стандартных правил. А способность в уме выполнять последовательность действий, которую записал «троечник» — тоже, конечно, «отличие», но уже другое.


        1. Juicer507
          18.02.2018 10:11
          -1

          А смысл упрощать её до такого вида, если делением намного проще получается и быстрее?
          Но здесь нет никакого «отличия» — как сказали выше, просто заученный алгоритм и всё


          1. qw1
            18.02.2018 11:44
            +3

            Это примерно как 36*98 можно считать в лоб столбиком, а можно 36*(100-2)=3600-36*2=3600-72=3528. Мне быстрее вторым способом.


        1. Kyushu
          20.02.2018 11:29
          -1

          Формулу (a/b)'=(a'b-ab')/b^2 должны знать и отличник, и троечник. Её использование и стандартно (т.е. более узнаваемо и понятно), и более элегантно. А чтобы её вспомнить, то можно «на полях» вывести её из (a/b)'=(a * b^-1)'=…


          1. mayorovp
            20.02.2018 12:34

            Нет, эта формула ужасна. Применять ее в ситуации деления на x^n — не лучшая идея, слишком много иксов вылазит которые потом сокращать придется.


            1. Kyushu
              20.02.2018 12:40

              Ну, не знаю… некоторые и из левой части уравнения в правую с трудом слагаемые переносят.


            1. Druu
              20.02.2018 13:59

              > Применять ее в ситуации деления на x^n — не лучшая идея, слишком много иксов вылазит которые потом сокращать придется.

              Вылезет — сократим. Вы так говорите, будто вам бумаги жалко.


    1. maxzhurkin
      17.02.2018 19:23

      Вы пытаетесь причесать всех под одну гребёнку, IMHO.
      Два человека, решившие одинаковое количество одинаковых примеров, не будут одинаково выполнять одинаковые примеры


    1. Jon7
      17.02.2018 23:39

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


      1. slovak
        18.02.2018 00:37

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


        1. Bronx
          20.02.2018 10:14

          Такие же оффсеты, как и при сложении. Только мерная лента слегка другая, с логарифмической шкалой :)


          1. khim
            20.02.2018 16:03

            Только вот какой в этом смысл? Как это первокласнику обьяснить?


    1. sondern
      18.02.2018 00:29
      +1

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


  1. crea7or
    17.02.2018 17:33
    +2

    Вы построили такую вот зависимость: отличник -> много запоминает -> пишет длинные функции.
    И первое условие не всегда верное, а уж второе-то…


    1. SergeyGalanin Автор
      17.02.2018 18:03

      успеваемость по таким предметам, как чтение и математика, напрямую связана с рабочей памятью

      Эллоуэй Трейси, глава «Рабочая память и коэффициент интеллекта IQ» из книги «Включите свою рабочую память на полную мощь».

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

      Рабочая память, Википедия.

      Так что первое условие я не придумал. А второе условие — да, это гипотеза, о чём я так прямо и написал. И мне хотелось бы обсудить её. Может быть, следовало обратиться к сообществу психологов? Однако затронутая проблема касается именно программистов, поэтому я предпочёл хабр.

      Я сделал определённые выводы, и мне интересно, что о них думают мои собраться по профессии. Прошу высказываться!


      1. crea7or
        17.02.2018 18:39

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


        1. SamDark
          17.02.2018 22:55

          Умные программисты знают, что:


          1. Есть менее умные, но при этом не менее полезные.
          2. Мозг не всегда одинаково хорошо думает.


          1. SergeyGalanin Автор
            17.02.2018 23:24

            Таких стоит называть «мудрые программисты», чтобы отличать их от просто умных ))


        1. tyomitch
          18.02.2018 00:24

          Что вы скажете про 684-строчную функцию в GCC, внутри которой одно условие if занимает 38 строк? GCC тоже писали «на отвали»?


          1. crea7or
            18.02.2018 01:34

            Не надо ничего вводить в абсолют — мы не на дваче.


          1. khim
            18.02.2018 02:09

            О! Знаменитый reload. Для него даже отдельная статья в Wiki есть.

            По-моему достаточно одной цитаты: Reload is the GCC equivalent of Satan, чтобы понять как к ней относятся разработчики…

            Не думаю, чтобы её писали «на отвали», скорее «так уж вышло»… но да — это не то, чем можно гордится.


            1. tyomitch
              18.02.2018 11:14
              +1

              Я к этому и вёл: что длинные запутанные функции появляются как в случае «писали на отвали», так и в случае «так уж вышло». GCC и его reload — далеко не уникальный случай.


      1. apro
        17.02.2018 18:40

        успеваемость по таким предметам, как чтение и математика, напрямую связана с рабочей памятью

        Есть исследования утверждающие что "общий" интеллект нельзя свести к одному фактору:


        http://www.cell.com/neuron/abstract/S0896-6273(12)00584-3


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


      1. dev96
        17.02.2018 19:49

        Причем тут "рабочая память", когда ПО пишут команды разработчиков. Код должен быть понятным и храниться в памяти компьютера, а не в голове конкретного разработчика. Тем-более код по статистике чаще читается, а не пишется. И читается он не только автором, но и его коллегами и т.д.
        Длина метода в 100+ строк — это уже не есть хорошо. По этому поводу Макконелл еще давно писал. А его книга "Совершенный код" — это классика, к которой все прислушиваются. У него по поводу размера метода отдельный раздел есть, где он пишет, что метод в идеале должен полностью помещаться на экране монитора (50-80 строк).
        Плюс к этому, рекомендуется заменять комментарии, методами с подходящим названием.
        А держать методы в уме (что вылетит из бошки очень быстро) — это не правильно, как по мне.


  1. decomeron
    17.02.2018 18:02

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


    1. SergeyGalanin Автор
      17.02.2018 18:14

      Разумеется. Иначе не быть бы когнитивной психологии отдельной дисциплиной. Вот: «Когнитивная наука. Основы психологии познания» (в двух томах). Суммарно 880 страниц. Можно найти в электронном виде — почитайте содержание ради интереса.


      1. decomeron
        18.02.2018 02:45

        Спасибо, почитаю.


  1. Marui
    17.02.2018 18:04
    +1

    В программировании нет сложных задач. Есть очень-очень-очень много средне-лёгких. Просто их очень много.


    1. Alexsandr_SE
      17.02.2018 18:46

      Просто нужно придумать как из сложной задачи сделать кучу средне-лёгких. Это возможно самый сложный этап.


    1. Yu_Sh
      17.02.2018 19:47

      -


      1. Yu_Sh
        17.02.2018 19:54

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


    1. mickvav
      18.02.2018 23:06
      +1

      Ну прорешайте десяток-другой задач из project euler, что ли.


  1. apapacy
    17.02.2018 18:41

    Вцелом — не очень согласен.
    Если под отличником(-цей) понимать не зубрилу и выскочку (катати как и подлец только мужского рода слова), а способного мальчика или девочку, то точно не согласен что так будет брать производную. Будет расписывать по шагам а не заучивать формулу. У нас в университете даже это просто запрещалось делать. Поэтому решение примера чуть сложднее шекольного например по теме интегралы были на 4-х страницах с двух сторон в каждой клеточке.

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

    По поводу человека проводили опыты с пастухами. Забирали у них из стада численностью 1,2,3 и т.п. голов одну корову и просили сказать все ли коровы на месте не пересчитывая их. Пастухи действтельно начинали ошибаться при стаде из 8 коров.

    Потом сделали тот же оптыс с оленеводами. Дошли ждос стада в 1000 оленей и оленевод всегда точно отвечал типа Сохатого не хватает, однако.

    Тут важен сам подход

    А вот тот код написал троеччник или отличник это еще нужно доказать. С кодом функции в пару тысяч строк например я еще могу разобраться. Но если троечник начинает делать все «по науке» и разбивать 50 строк на модули, но не в стиле «раздляй и властвуй», а в стиле: разложи листики в конвертики, потом конвертики сложи в коробочки, коробчки положи в ящички, потом подойди к ящичкам и найди где лежит заначка. То это гораздо более утомительно. Прошлая Ваша публикация на данную тему кажется мне более инересной.


    1. SergeyGalanin Автор
      17.02.2018 19:28

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

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

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

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

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

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


      1. aamonster
        17.02.2018 20:07

        Вы что — ни разу не видели, как человек дописывает код в процедуру, давно забыв, что было в её начале? Обычное же дело. В итоге длинную глючную процедуру пишет как раз человек, который не смог удержать её в памяти (и благодаря этому почувствовать, что она слишком разрослась).


      1. apapacy
        17.02.2018 21:15

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


  1. vitaliy2
    17.02.2018 18:54

    Некоторые утверждения статьи странные. Константы не нужно держать в голове, что они значат видно прямо из их названия в момент чтения. Насчёт хэшей — точно не уверен, как там в питоне, но в js есть только один вид хэша — получить объект/значение по ключу (и это логично). Причём что это за объект/значение следует прямо из названия хэша. Нужно помнить только сам объект, но и тут его название говорит само за себя: если оно во множественном числе, это массив, если это объект вида user или userObj, то это struct или экземпляр класса, если userId или userCount, то число, если isUser, то boolean и т.?д.

    А функции да, по возможности нужно разбивать на более мелкие — проанализировать 2 независимые функции по 10 строк намного проще, чем одну из 20 строк. Ну и конечно именование функций, параметров, переменных и т.?д. очень важно (а особенно важен API).


  1. SBKarr
    17.02.2018 19:21
    +1

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

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

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

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

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

    Мой коллега после прочтения статьи сразу же предположил, что из гениев, способных перепрыгивать огромные этапы решения, выйдут совсем хреновые программисты. Опровергну. Главная черта гения: умение предсказывать результат своих действий далеко вперёд. Если этот гений ещё и программист, он не будет подкладывать себе же грабли. Он скорее сразу разобьёт код на блоки, которые будут удобны для повторного использования ему самому.

    Из всего вышеописанного следует, что оценки когнитивной психологии в общем смысле здесь применять неверно. Они, несомненно, важны в деле программирования. Но важны в другом месте. Человеку, который может удержать в голове больше объектов, проще построить грамотную архитектуру. Проще разбить задачу на подзадачи наиболее оптимальным образом. В общем смысле, эффективная архитектура не должна оперировать больше, чем пятью объектами на каждом уровне. Это исходит именно из оценки когнитивной психологии. Достичь этого можно кучей методов композиции и уменьшения связности. Чем больше объектов в человек может удержать в голове в один момент времени, тем лучше он выделит наиболее сильные связи и устранит слабые. Самый важный навык — умение быстро переключаться между уровнями архитектуры: между переменными в функции, системными объектами и промежуточными уровнями абстракции. Но это уже тема для статьи, а комментарий как-то подзатянулся.


    1. SBKarr
      17.02.2018 19:35

      Вспомнился такой небольшой постскрипттум. Мой средний балл по математике в районе 3.7 по школе и вузу (матфаку, почему именно матфаку с такой оценкой — отдельная история). Я точно так же, как описано в статье для отличников, прыгал через этапы решения. Просто по рассеянности внимания где-то постоянно терял важные символы. Что характерно, забывал записать, а не применить. Чем больше меня в этом упрекали — тем хуже становилась оценка по математике. Так что, я бы поостерёгся с термином «отличник» в таком контексте.


    1. SergeyGalanin Автор
      17.02.2018 19:45

      Гений — это далеко после «отличника». Кто же их знает, этих гениев? Может, не все умеют предсказывать результаты своих действий далеко вперёд? Я не гений, подтвердить или опровергнуть не могу.

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


      1. SBKarr
        17.02.2018 22:10

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

        Тут возникает другой аспект: какому-нибудь «сеньору», как правило, очевидно, где решение хорошее, а где — плохое, без всяких метрик когнитивной психологии. Эти самые метрики нужны для людей, которые в самой профессии не смыслят. То есть, для внешних управленцев. И мы внезапно оказываемся ну очень далеко от исходной темы.


  1. alek0585
    17.02.2018 19:24

    Да это всем известный факт.
    Кстати, кто-нибудь смотрел исходники, которые выложил ВК? Там ведь сплошь гении и наверняка есть кучи гениальности по всем проектам.
    github.com/vk-com/kphp-kdb/blob/master/queue/queue-engine.c#L1486


    1. smer44
      17.02.2018 19:53

      ёлки, ну и вырвиглаз.
      а дело не только в длинне или непонятности синтаксиса но и в общих правилах структурирования кода


    1. khim
      17.02.2018 21:26
      -1

      Ой, тоже мне нашли беду. Это ж парсер параметров. Сравните с GNU LD'шным.

      Простая функция, пусть и довольно длинная.


      1. vitaliy2
        17.02.2018 22:41

        Наименование переменных :(

        Первая же строчка:

        int r, c;

        Что такое r и что такое c? Это первая строчка функции! Хотя бы коммент оставили.

        Хотя фиг знает, может это общепринятное соглашение, и эти r и c используются 100 раз в коде, но что-то я сомневаюсь, что они писали 100 похожих парсеров.

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


        1. khim
          17.02.2018 23:12

          Что такое r и что такое c? Это первая строчка функции! Хотя бы коммент оставили.
          Зачем? Посмотрите где они инициализируются — и всё станет ясно.

          C99 ещё не везде, так что да, приходится описывать переменные в начале функции, а не там, где они нужны…

          Хотя фиг знает, может это общепринятное соглашение, и эти r и c используются 100 раз в коде, но что-то я сомневаюсь, что они писали 100 похожих парсеров.
          Ноборот — они там 5 строчках используются. И в них легко понять — что это за переменные и что они делают.

          Вы пытаетесь читать программу на C89 опираясь на подходы какого-то другого языка (C++? Python?) — отсюда сложности.

          Глобальные надо менять, когда реально состояние приложения изменилось.
          Опять-таки — это подход современных языков и современных приложений. Которые, типа, могут прочитать конфиг и поменять его «на лету» (ага, три раза). Программки на C обычно читают конфиг один раз и если он неправильный — выдают ошибку. Зачем тут лишние сущности устраивать?


          1. vitaliy2
            17.02.2018 23:16

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


            1. khim
              17.02.2018 23:51

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

              Старые мониторы (80x24), нет IntelliSense… а переменные нужно обьявлять в начале функции в C89 (до первого оператора). Когда-то это имело смысл. А если ты пишешь 10+ лет в таком стиле, то уже как-то и не видишь ничего страшного в одной букве. c(haracter), s(tring), p(ointer) — наиболее частые сокращения. «r»… думаю r(ead result) имелся в виду.

              То есть да — не могу сказать что это прям код — верх изящества, но он вполне в духе «old school» и не сказать чтобы уж прям ужас-ужас…

              P.S. Вообще, конечно же, лучше описывать переменные где используешь… C99 и C++ не зря придумали (и давно), но грехи (Windows и MSVC) не пускают…


              1. vitaliy2
                17.02.2018 23:58

                c — character, s — string, f — function, p — pointer — это всё нормально. Но там попался какой-то «r».

                Но ещё в своём языке я привык объявлять переменные по мере использования. Просто const c — такого не бывает, а вот const c = s[i] — может быть, т.?е. несмотря на короткое имя, назначение очень понятно.

                Но таких коротких переменных можно пересчитать по пальцем, даже a — array — не всегда хороший вариант, потому что если это не совсем временная переменная, лучше назвать users, к примеру. А там все переменные так названы =)


              1. 0xd34df00d
                18.02.2018 21:42

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

                Это было бы «ну так себе нормальненько», если бы этому коду было лет 30, а не 9.


          1. firk
            18.02.2018 03:56

            C99 ещё не везде, так что да, приходится описывать переменные в начале функции, а не там, где они нужны…

            Конкретно в этом коде переменные в середине функции объявляются. (int was_created = -1;) — мне это сразу резануло глаза. Не знаю что в этой "фиче" хорошего, тоже писал так 10 лет назад по глупости, потом перестал.


            1. khim
              18.02.2018 08:35
              +1

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

              А то, что тут у нас смесь C89 и C99 стилей — это как раз плохо. Надо бы выбрать что-нибудь одно, по хорошему-то…


          1. 0xd34df00d
            18.02.2018 21:41

            C99 ещё не везде, так что да, приходится описывать переменные в начале функции, а не там, где они нужны…

            Только мне кажется, что проект, который «consisting of efficient PHP-to-C++ translator called «KPHP» or «KittenPHP», and several auxiliary high-performance «engines» (specialized non-relational databases), needed for its deployment», может позволит себе опираться хоть на С++11, хоть на хаскель.

            Опять-таки — это подход современных языков и современных приложений. Которые, типа, могут прочитать конфиг и поменять его «на лету» (ага, три раза). Программки на C обычно читают конфиг один раз и если он неправильный — выдают ошибку. Зачем тут лишние сущности устраивать?

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

            Чтение много раз — дело десятое.


            1. firk
              19.02.2018 01:35

              Потому что о программах без глобального состояния проще

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


              1. 0xd34df00d
                19.02.2018 09:34

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

                Почему специализированный у нас процесс, а состояние — вся железка?

                Вас же не смущает, когда методы класса меняют состояние класса, а не только свои локальные переменные?

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

                И классы с большим количеством состояния меня тоже смущают.

                например обратиться к this->a всегда сложнее чем к глобальной переменной a

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


                1. firk
                  19.02.2018 12:05

                  Почему специализированный у нас процесс, а состояние — вся железка?

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


                  то бранч индирекшон предиктор быстро обучится.

                  Вам всё равно придётся держать лишний занятый регистр под этот this и тратить несколько лишних байт кода чтобы в него загрузить нужное значение. Может быть это и не особо большой оверхед (хотя насчёт занятого регистра мне всё-таки кажется что заметный) но польза то от этого вообще нулевая в данном случае.


                  1. 0xd34df00d
                    19.02.2018 19:35

                    Потому что там ещё было слово «высоконагруженный». В таких случаях на каждого функционального демона выделяется своя железка, а то и несколько железок (как в вк).

                    И выделяется одна железка под высоконагруженный парсер конфигов?

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

                    Вы правда уверены, что парсинг конфигов — горячая часть этого сервиса?

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

                    И да, индирекшон всё равно есть.


                    1. khim
                      19.02.2018 20:28

                      И да, индирекшон всё равно есть.
                      Где? %rip это ж не регистр, это просто запись такая, адрес в декодере вычисляется…


            1. lastrix
              19.02.2018 08:19

              Потому что о программах без глобального состояния проще

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


              1. 0xd34df00d
                19.02.2018 09:32

                Вы слышали что-нибудь о вещах вроде MonadWriter?


                1. mayorovp
                  19.02.2018 10:01

                  А какое отношение MonadWriter имеет к системам логирования? Существует ли у MonadWriter файл конфигурации, по сложности сравнимый с конфигами семейства log4xxx и их наследников (logback, NLog)?

                  (Это был риторический вопрос, можете не рассказывать мне что такое MonadWriter)


                  1. 0xd34df00d
                    19.02.2018 10:19

                    Это дело десятое. Речь-то о подходе и о возможности избежать глобального состояния даже в этом случае.


                    1. mayorovp
                      19.02.2018 10:21

                      Чем больше конфиг — тем дороже повторное чтение его каждый раз.


                      1. 0xd34df00d
                        19.02.2018 10:24

                        Зачем его читать много раз?

                        В конце концов, говоря на С++-ном, голая глобальная переменная и private static-поле — это ж две сильно разные вещи по возможным последствиям.


                        1. mayorovp
                          19.02.2018 10:27

                          А что делать на Си, где нет приватных полей?


                          1. 0xd34df00d
                            19.02.2018 19:35

                            Задуматься о том, оправдан ли выбор С в данном случае.


                        1. firk
                          19.02.2018 12:11

                          Глобальная static-переменная мало чем отличается, у неё точно так же ограничена область видимости окружающим её кодом (для static-поля окружающий код это класс, для глобальной static-переменой — файл исходника с ней, а есть ещё локальные static-переменные с областью видимости — функией, где она объявлена).


                          1. 0xd34df00d
                            19.02.2018 19:35

                            Только оно там без `static`, я специально смотрел.


                1. lastrix
                  19.02.2018 10:16

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


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


                  1. 0xd34df00d
                    19.02.2018 10:22

                    Это относится к функциональным языкам — у них есть своя специфика, которая и позволяет обходить глобальные состояния… за счет глобальных монад.

                    Я не очень понимаю, что такое глобальная монада.

                    Или идеализм и перфекционизм вездесущи и все строем должны идти учить хаскель?

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

                    Ну и в конце концов, мы же тут об отличниках говорим?


          1. Skler0z
            19.02.2018 11:02
            +2

            «Зачем? Посмотрите где...»
            Ну давайте посмотрим на «с».

            c = *s;

            Ок, пошли смотреть на «s»
            char *ptr, *s;

            Хорошо. Ищем инициализацию «s».
            ptr = s = cfg_cur

            Ура! Всё сразу понятно стало, сэкономленное на оформлении кода время окупилось, разработчику — премию (сарказм!).
            Вот так и ходишь и смотришь большую часть времени, вместо того, чтобы просто читать понятный код.
            Такое оформление, по которому нужно «Посмотрите где...» — это то же самое, что и «идите на...» по отношению к тому, кто в дальнейшем будет работать с кодом.
            Пойдешь вот так, как Вы предлагаете, смотреть, что означает переменная "_suprknadel", а через полчаса обнаруживаешь 15 открытых модулей и еще больше вопросов.
            Поубивал бы.
            Извините за эмоции, но я только что вынырнул из модуля в 17000 строк, с которым работаю :(


        1. 0xd34df00d
          18.02.2018 21:37

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


      1. VioletGiraffe
        18.02.2018 11:49
        -1

        Только у GNU код на два порядка лучше структурирован.


  1. youngmysteriouslight
    17.02.2018 19:44

    В когнитивной психологии ту часть памяти, в которой непосредственно производятся вычисления «в уме», называют кратковременной и рабочей. Там всё сложно и неоднозначно, но как её ни назови, а объём этой памяти сильно ограничен. Разные исследователи называют «магические числа» семь и пять. Это средние значения. Объём «рабочей» памяти зависит от обстоятельств и коррелирует с интеллектуальными способностями.

    — Петька, приборы?
    — 42.
    — Что «42»?!
    — А что «приборы»?

    В каких единицах числа приведены? В битах? Байтах? Вариках?


    1. SergeyGalanin Автор
      17.02.2018 19:54

      Тут всё интересно. Пять и семь — это количество неких «объектов». Если заставить человека запоминать случайную последовательность букв, то такими объектами будут буквы, и человек запомнит в среднем примерно семь букв. А если слова — то примерно семь слов. А букв в этих словах будет существенно больше.


      1. youngmysteriouslight
        17.02.2018 20:12

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

        Это я к тому, что число объяснять надо. Вы говорите, что рассматривается случайная последовательность букв, но в тексте этого нет. Да и код отнюдь не случаен. Да даже для случайной последовательности следует указать размер алфавита «объектов» (7 букв запомнить — не 7 слов, что в свою очередь не 7 иероглифов).

        P.S. я знаю про один эксперимент
        На линейной шкале (оттенки серого, размеров и т.п.) выбирается в определённом смысле равноудалённо n точек и затем предлагается случайная последовательность этих точек человеку, чтобы он идентифицировал каждую точку. Шкалу он видит только единожды, перед началом классификации, число n знает. Оказало, наиболее комфортно человек классифицирует при n<9, причём эта цифра почти не зависит от природы линейной шкалы, лишь бы границы ощущались как диаметрально противоположные (белый-черный, точка-метр).


        1. SergeyGalanin Автор
          17.02.2018 20:37

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

          А вот семь букв или семь слов (знакомых) для нас — это как раз всё равно. Потому что те и другие мы обрабатываем как целостные объекты, гештальты.


          1. youngmysteriouslight
            17.02.2018 21:20

            А Вы знали значение этих иероглифов?
            Разве это существенно? Скажем, иероглифы хираганы я могу запомнить вряд до 15, если при восстановлении будет под рукой таблица, и до 7-10, если не будет. Китайские иероглифы даже в количестве 5 штук я не восстановлю, даже если под рукой будет соответствующая таблица. Значение ни тех, ни иных я не знаю. Просто алфавит меньше.
            А вот семь букв или семь слов (знакомых) для нас — это как раз всё равно. Потому что те и другие мы обрабатываем как целостные объекты, гештальты.
            Опять же. Что проще, запомнить «оывхзку» («о! ы-ы-ы-ы… вот хз… ку» — уже запомнил) и «овации пароходом гештальту пенсне шизофазия велюром седло»? Букв-то всего 33 и многовероятно появление слогов и других знакомых групп. А слов больше и далеко не каждое вызывает устойчивый запоминаемый образ.

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


            1. khim
              17.02.2018 21:35
              +1

              Опять же. Что проще, запомнить «оывхзку» («о! ы-ы-ы-ы… вот хз… ку» — уже запомнил) и «овации пароходом гештальту пенсне шизофазия велюром седло»?
              Во втором случае очень много редких слов, а часть — явно распадается на два (шизофазия) или вообще не воспринимается как слово (гештальту). Если бы там не было таких ужасов — разницы бы не было.

              А слов больше и далеко не каждое вызывает устойчивый запоминаемый образ.
              Это да, некоторые слова будут занимать не один «обьект» в голове, а два или три.

              Или же под объектом в тексте понимается именно образ? Но тогда как сделать однозначное сопоставления объекта и формальных языковых конструкций (букв, слов, словосочетаний)? У каждого же по-разному.
              Именно поэтому мы не можем сказать точно сколько обьектов нужно держать в голове, чтобы осознать как работает функция. Можем только оценить.

              Но можно заметить, что 5-7 обьектов — это столько, сколько мы можем «захватить» не напрягаясь. Если «загружать» в сознание обьекты постепенно и если это — не случайные, никак не связанные друг с другом обьекты, то можно уместить гораздо больше.

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


            1. vitaliy2
              17.02.2018 22:48

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

              Знаки хираганы называются знаками хираганы (или знаками каны, если более обобщённо).


              1. Kobalt_x
                18.02.2018 10:07
                +1

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


              1. tetramino
                19.02.2018 19:10

                Это слоговая азбука.

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


            1. tetramino
              19.02.2018 19:07

              Разве это существенно?

              Да. Значение и происхождение иероглифов помогает их запоминать куда быстрее. Это не моё мнение, это практика моих знакомых японистов из МГУ.


        1. decomeron
          18.02.2018 03:04

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


  1. DonArmaturo
    17.02.2018 19:51

    Резюме понравилось.
    Любая индустриальная технология основана на расчётах, на возможности их проверки. Любой алгоритм должен давать простое понимание границ его применимости. Computing science должна быть доказательной и повторимой, как любая наука.


    1. SBKarr
      17.02.2018 22:16

      Как я написал выше, программирование как разработка программных систем это не только science, но ещё и art. Причём art как раз того порядка, про который мы пока только догадки строим: предсказания на основе непонятных внутренних эвристик. По сути, это как NP-задача, мы можем построить полиномиальные метрики к ней, но придумать полиномиальное решение, подходящее для всех, не можем, и даже не знаем, есть ли оно.


      1. Skerrigan
        19.02.2018 11:04

        даже не знаем, есть ли оно.

        Зато работа есть ;)


    1. tetramino
      19.02.2018 19:18

      Computing science должна быть доказательной и повторимой, как любая наука.

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


      1. 0xd34df00d
        19.02.2018 19:38

        Ну это одно из определений, в общем-то.


        1. tetramino
          19.02.2018 19:57

          Определение того, что именуется ядром науки, а не наукой в целом, если следовать именно принятому в философии делению. Бернал, Прайс, Ильин — почитайте))


  1. Yu_Sh
    17.02.2018 19:55
    +1

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


  1. RUa
    17.02.2018 19:57

    С гипотезой не согласен. С началом изучения действительно, бывало, писал длинные и запутанные портянки. На данный момент главная тенденция — удобочитаемость кода. Функции/процедуры/ и т.п стараюсь вместить на один экран, если допустимо. По длине строк — так же. Даже если объект более 1 раза не используется — ничего страшного. Главное — чтобы эти блоки были логически и мнемонически ясны тебе через месяц/год/и т.п. А если твой код смогут понять без труда другие программисты — то это она самая и есть — гениальность :))). И никакая оперативная мозговая память тут ни при чем.
    А отличники пишут запутанный код 1) из-за спешки 2) Из-за неуважения к себе и другим


    1. SergeyGalanin Автор
      17.02.2018 19:58

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

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


  1. CantaTronic
    17.02.2018 20:02
    +1

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

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

    Звучит примерно как: «Тестировать свой код — это для троечников. Зачем писать столько ненужного лишнего когда, если программа и так будет работать как-нибудь?» Ну… Чем не точка зрения, конечно.
    Я тоже училась на все пятёрки и помню, какой это был понт, когда ты промежуточных вычислений не записываешь. Зачастую это приводило к ошибкам, которые трудно было отследить и исправить (что осложняло работу учителя в разы, как я поняла в дальнейшем, когда сама стала преподавать), но мы велись, и это всё счастье до сих пор живо в наших школах. Но мало ли на что школьники ещё ведутся: что курить — это круто, что если все пойдут с крыши прыгать…
    Называть ли это всё «горем от ума»? Я бы, скорее, говорила о попытке самоутвердиться в своей социальной группе. У разных групп — свои критерии «крутизны», одними и теми же методами стать крутым вообще везде сложно (и это очевидно). А оценки — это просто оценки, они учителе-зависимые. Когда ты ещё ребёнок и не понимаешь, что оценивание твоей контрольной работы на 5 или 4 не имеет ничего общего с оценкой тебя, как человека, ты начинаешь за этой оценкой гоняться. А учителя — разные. Кто-то за многостраничную работу сразу ставит 5, не читая (ибо лень), а кто-то гарантированно снижает на балл-другой (потому что читать было лень, но всё равно пришлось).
    Если ребёнку на уроках информатики начать снижать оценки за нечитабельный код, то через пару месяцев у «завзятого отличника» код станет самым читабельным в классе. Не думаю, что он от этого как-то резко поглупеет.
    Школа она в любом случае и хорошо, что была, и хорошо, что была окончена. Если её выкинуть из головы, хуже не станет.


    1. SergeyGalanin Автор
      17.02.2018 20:03

      Вот бы и правда кто-то стал снижать оценки за нечитабельный код… Мечта…


  1. SbWereWolf
    17.02.2018 20:05

    хотелось бы познакомиться алгоритмом вычисления метрики когнитивный вес, очень очень, или вес это количество объектов?


    1. SergeyGalanin Автор
      17.02.2018 20:32

      Нет пока ещё такого алгоритма. Есть предположение, что, возможно, такая метрика может оказаться полезной. Что в неё следует включать — не до конца ясно. Объекты, которыми оперирует интеллект программиста при написании участка кода. Ясно, что какими объектами он оперирует, те и пишет в код. Но какие именно объекты? Переменные, вызовы методов, операции, константы, элементы структур — что? Какие именно из этих объектов занимают место в рабочей памяти программиста, а какие — нет? Проблема очерчена — есть, над чем поработать.

      Почитайте «Программный код и его метрики», и особенно метрики Холстеда. Там много пищи для размышления.


      1. smer44
        17.02.2018 20:51

        имхо берёшь AST кода, задаёшь каждому узлу ( не только листу, но и ветке включая внутренние узлы) тэг классификации по смыслу, то есть «в этом цикле считается количество домов в городе» а не «в этом цикле переменная и увеличивается от 0 до 1000», определяешь метрики= расстояние между смыслами.
        А всякие количественные метрики это ерунда — ту же самую программу можно переписать в другом виде чтоб весь тот расчёт был другой, то есть он не репрезентативен.


      1. vladob
        18.02.2018 01:11

        Нет пока ещё такого алгоритма

        Думаю, и не будет. По крайней мере — одного для всех.


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


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


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


    1. apro
      19.02.2018 04:20

      Есть Цикломатическая сложность некоторые linter'ы ее умеют считать и выдавать предупреждение, например rust-clippy


  1. Garruz
    17.02.2018 20:39

    Хорошая тема, очень правильная и актуальная.

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

    Мораль сей басни такова – хорош не тот, кто просто зубрит, а тот, кто понимает предмет в целом и суть конкретного вопроса в частности. И на оценки тут уже плевать – они важны только лишь в узких рамках ВУЗа, а дальше жизнь сама расставит всё и всех по своим местам… ;)

    P.S. Хорошо, что хоть по информатике нам достался хоть и «советски»-отсталый, но крайне здравый преподаватель – «неуставные» решения не рубил и не критиковал, а сам приходил от них в восторг. До сих пор вспоминаю его с искренней теплотой… ^_^


    1. JekaMas
      18.02.2018 13:27
      +1

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


      1. Garruz
        18.02.2018 19:41

        увидеть задачу для себя

        Вот именно об этом я и говорил.
        Образ мышления отличника – решить всё «правильно, как учили». Образ мышления программиста – решить всё максимально рационально, пусть даже это будет «не канонично». Иначе говоря, «труъ-программистское решение» – найти путь к тому же (!) результату, но меньшими усилиями и меньшей тратой ресурсов. Оптимизация же, и всё такое (о чём, кстати, вообще и статья)…

        Конечно, идеально, когда оба варианта совпадают. Но если вдруг не совпадают – то, всё же, второй вариант видится как-то намного более предпочтительным.


        1. lastrix
          19.02.2018 08:26

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


          Ваш вариант — это в соревновании бега в мешках пробить в нем дно и бежать.
          Решение не подпадает под заданную цель. Считайте это как ТЗ.


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


          Где же в вашем первоначальном комментарии "правильно, как учили"?


          1. Garruz
            20.02.2018 00:59

            Решение не подпадает под заданную цель. Считайте это как ТЗ.

            ИМХО, для программиста заданная цель – не конкретные методы решения, а решение в целом. Оно и является настоящим ТЗ (если только, конечно, ограничения в методах не вызваны объективными причинами).
            дифуры — это микроскопом гвозди забивать, когда есть более простое и доступное решение.

            Вот, оно самое, о том и речь!
            Это и есть «образ мышления настоящего программиста». Что также во многом зависит и от методов обучения, кстати. Если учили думать – ищи методы оптимизации. Если учили решать «в лоб», «только как положено» – забивай гвозди микроскопом и прочими не предназначенными для этого гаджетами.

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


            1. Druu
              20.02.2018 03:25

              > Настоящая цель – решить оптимально!

              Чтобы решать _оптимально_ надо уметь эффективно использовать широкий спектр методов, понимать как они работают. Если же вместо того, чтобы отрабатывать эти методы, ты занимался «ищи методы оптимизации», то никакого уменя не будет и оптимизировать, соответственно, будет нечего.

              Если человек вечно рисует картинки, вместо того, чтобы формулировать диффур, то он просто и не научится формулировать диффуры (тот самый наук, на развитие которого и дают подобного рода задачи). Это на самом деле _очень_ сложно (в реальных задачах, в учебных задачах для тренировки, конечно, просто).


              1. Garruz
                20.02.2018 14:09

                Если же вместо того, чтобы отрабатывать эти методы, ты занимался «ищи методы оптимизации», то никакого уменя не будет и оптимизировать, соответственно, будет нечего.

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

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

                P.S. Кстати, в том примере также виден явный «подход отличника» – со стороны составителей задачника (не помню уж, кто там был). Те самые «шоры» просто помешали им сразу же понять, что в этой задаче вообще нечего городить диффуры. ))


                1. VolCh
                  20.02.2018 14:13

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


                  1. Garruz
                    20.02.2018 14:37

                    Согласен, порой оптимизация может отнять больше времени, чем «лобовой» вариант. И проще выбрать «в лоб». Но принятие такого решения – тоже есть в своём роде оптимизация. Как минимум, по времени разработки.

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


                    1. VolCh
                      20.02.2018 14:43

                      Так "по умолчанию" означает, что разработчику принимать решение не нужно, оно уже принято за него.


                      1. Garruz
                        20.02.2018 14:58

                        Не вполне понял, почему это адресовано мне. Но отвечу…

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

                        И все мои слова означают как раз то, что спорить с ТЗ порой чертовски нужно – если видите либо его некорректность, либо изъяны в требуемых методах, либо ещё что-то, либо всё вместе.
                        На то вы и специалист, чтобы знать свою работу лучше заказчика. И чтобы при необходимости указать ему на ошибки и/или альтернативные варианты решений.

                        P.S. При этом вновь оговорюсь, что даже в этом благом деле нужен разумный баланс между реальными обоснованными замечаниями к ТЗ и собственными амбициями. Иначе, с другой стороны, получается не профессионал, а просто скандалист-социофоб с манией величия… ))


                        1. VolCh
                          20.02.2018 15:35

                          Потому что:


                          по умолчанию надо выбирать "в лоб"

                          Но принятие такого решения – тоже есть в своём роде оптимизация.

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


                          1. khim
                            20.02.2018 16:11

                            Не очень понятно о чём вы спорите. Для разработчика — во многих случаях «лобовое» решение — правильный выбор. Для ученика — нет.

                            Потому что первому таки-надо решить задачу. Второму-таки нужно научиться определённым приёмам.


                            1. Garruz
                              20.02.2018 17:17

                              Для разработчика — во многих случаях «лобовое» решение — правильный выбор.

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


                          1. Garruz
                            20.02.2018 17:11

                            по умолчанию оптимизировать нужно по скорости разработки

                            Во-первых, речь не только о скорости исполнения, но и о скорости разработки…
                            А) Три дня мудохаться, писать «линейный» код. После каждого исправления переписывать большую часть.
                            Б) Один день подумать, ещё за день написать чётко структурированный код, в котором всё строится всего на паре-тройке ключевых параметров. Исправления делаются за несколько минут.

                            В первом случае – решение «в лоб».
                            Во втором – та самая оптимизация.

                            Недавно как раз был такой веб-проект. Нанятые разрабы писали всё сразу «набело» (то бишь, «в лоб») – в итоге чего каждое исправление/комментарий вылетали минимум в день-два (а то и больше) полного переписывания всех функций, плюс полной отладки заново. Просто вот их так научили – не думать, сразу писать.
                            После всей ругачки и «поучений» (кряхтя, вспомнил все азы) – таки добились того, что теперь в проекте любые исправления обрабатываются максимум за пару-тройку часов. За счёт той самой оптимизации кода, да…

                            И в каком варианте в итоге получилась бОльшая скорость разработки, как вы считаете?


                            1. VolCh
                              20.02.2018 17:15

                              Я не зря упомянул про разносрочные перспективы.


                              1. Garruz
                                20.02.2018 17:29

                                Да здесь даже почти независимо от перспектив…

                                ИМХО – разработчик сразу (!) должен писать так, чтобы быть готовым к любым возможным исправлениям. То есть – сначала продуманная структура, только потом код.
                                Тем более, что ему же самому придётся нереально мудохаться, случись вдруг какие действительно серьёзные исправления. Если даже не «профессионализьму ради» – так хоть ради собственного комфорта…

                                P.S. Не зря ведь есть старинная пословица: «Семь раз отмерь, один отрежь». ;)


                                1. VolCh
                                  20.02.2018 17:42

                                  К любым возможным исправлениям всегда быть готовым невозможно практически. ЧТобы принять решение о подготовке к некоторым изменениям нужно оценить


                                  • стоимость подготовки
                                  • стоимость внесения изменений при условии подготовки
                                  • стоимость внесения изменений при условии отсутствия подготовки
                                  • вероятность появления необходимости внесения изменений


                                  1. Garruz
                                    20.02.2018 17:59

                                    Тут всё проще… )

                                    Чтобы написать действительно хороший проект – прежде всего, вы должны его понять. Это, пожалуй, самая сложная задача. И вот как раз она требует хотя бы 20-25% от общего времени разработки (и это лишь как самый минимум).

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

                                    То есть, как уже писал ранее – сначала чёткая структура, потом код. Это избавит от совершенно большей части указанных вами пунктов…

                                    P.S. Кстати, стоимость как раз проще всего накручивать на «тупо-работах» – вроде переделок и прочего описанного выше. И, в любом случае – вашу зарплату это никак не поднимет, всю пенку снимет работодатель…


                                    1. VolCh
                                      20.02.2018 18:04

                                      Предвидеть, что может измениться — это уровень понимания бизнеса, а не проекта.


            1. lastrix
              20.02.2018 05:00
              -1

              Превосходно. У вас есть GPU (или любой другой специализированный вычислитель) и необходимо решить задачу через матричные вычисления, но у вас же есть "свои" методы, которыми вы успешно решаете на CPU.


              Это провал Карл! Ваше решение не оптимально!


              Дифуры и физика — это всего лишь инструменты, так же как CPU и GPU. И нужно уметь пользоваться ими, а не показать, какой вы молодец. И замечу — способность видеть множество решений — это только плюс вам. Но решение обязано подпадать под ТЗ. Иначе вы подставляете человека.


              Просто подумайте, у вас попросили отмерить 1 метр оптоволокна, но вы решили, что отмерить 2 фута будет проще. Как потом быть заказчику? Смысл именно в инструментах и стандартах.


              1. Garruz
                20.02.2018 14:24

                У вас есть GPU (или любой другой специализированный вычислитель) и необходимо решить задачу через матричные вычисления, но у вас же есть «свои» методы, которыми вы успешно решаете на CPU.

                Если оптимальнее будет на GPU – решаем на GPU. Если оптимальнее на СPU – решаем на СPU. Просто же… ;)
                Но решение обязано подпадать под ТЗ. Иначе вы подставляете человека.

                Какого человека?
                Если того, кто пишет ТЗ – то прежде всего проверяется само ТЗ на предмет компетентности составителя и актуальности поставленных задач. Затем проводится анализ всех методов. Затем, если у вас появляются замечания по ТЗ и если вы считаете, что результата можно и нужно достичь иными способами – проводите переговоры с заказчиком, аргуметированно формулируя ему свою точку зрения.
                Да, это намного больше возни, чем просто «отработать по ТЗ». Но только так и становятся настоящими профессионалами – думая не только об исполнении, но и о результате.
                Просто подумайте, у вас попросили отмерить 1 метр оптоволокна, но вы решили, что отмерить 2 фута будет проще. Как потом быть заказчику?

                Если «вместо» 2 метров заказчик получит 6,5617 фута – он получит именно то, что просил. Но если мне удобнее мерять в футах – он получит свои 2 метра быстрее. Что уже есть оптимизация. Просто же… ;)
                Ну и где тут «подстава человека»? ))


  1. potan
    17.02.2018 20:41

    Можно работать с большим количеством просто устроенных сущностей, а можно с небольшим, но устроенных достаточно сложно. Вычисления «по шагам» относятся к первому варианту, и функции по 150 строк.
    А если работать со сложными сущностями, то IDE, по типам данных, может выдавать полезные советы и помогать анализировать код, в языках со статической типизацией.


  1. leossnet
    17.02.2018 21:28

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

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

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

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

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


  1. sbnur
    17.02.2018 21:58

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


  1. morr
    17.02.2018 23:10

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

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

    Нам лень потому, что это дольше и сложнее.
    Нам плевать потому, что с этим кодом потом будет работать кто-то другой.

    В большинстве случаев диагноз этого такой: человек некомпетентен как разработчик.


  1. fukkit
    17.02.2018 23:16

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


    1. Marui
      17.02.2018 23:38

      сделать, чтобы работало и было понятно среднему индусу

      Вы видели код библиотеки из какого-нибудь Facebook? Для работы, например с распределенными графами? Или что-то иное? Как средний индус будет писать тесты для вот этого:
      github.com/facebook/rocksdb/blob/master/db/compaction_job.cc#L683


      1. fukkit
        18.02.2018 02:37

        Не совсем понял, к какому моему тезису у вас вопрос.
        Код не видел, посмотрел, чудес не заметил. Вероятно, необходимо подтянуть контекст, чтобы понять, что именно там происходит. Комментарии в наличии. Что Вас смущает?


  1. GeMir
    17.02.2018 23:45

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

    Умение (и желание!) быть понятным — такая же профессиональная компетенция, как и умение решать проблемы.


    1. questor
      18.02.2018 11:03
      +1

      Учитель должен давать не только задачу, но и критерии оценки результата.


      1. Druu
        19.02.2018 10:54

        > Учитель должен давать не только задачу, но и критерии оценки результата.

        Задач про бучении бывает всего две:

        1. тренировка навыка
        2. проверка навыка

        Ни ту, ни другую голый ответ не решает.


        1. SergeyGalanin Автор
          19.02.2018 11:19
          +2

          Почему голый ответ не тренирует навык? Я же задачу решал, значит, навык потренировал. А что шаги не записал — ну так это просто лень ручкой по бумаге водить. Голова-то работала…


          1. netch80
            19.02.2018 11:27

            Как проверить, что она работала, и отработала именно нужные навыки?


            1. SergeyGalanin Автор
              19.02.2018 11:37
              +1

              А как проверить, что она работала, когда все шаги записаны? Можно ведь и списать?

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

              А к не очень ответственным и не очень способным — к тем да, возникают вопросы.


              1. netch80
                19.02.2018 11:49

                А как проверить, что она работала, когда все шаги записаны? Можно ведь и списать?

                Против этого наработан ряд стандартных приёмов, начиная с переименования переменных и сдвига коэффициентов :) Если ученик справляется с таким — он достаточно разбирается в теме, даже если отдельные элементы где-то подсмотрел.


                Но для случая голого ответа это не работает в принципе.


                Я думаю, учитель всегда прекрасно знает каждого ученика: его способности и меру ответственности.

                Я вижу, что даже в мелких группах вроде 10-15 человек, как в наших вузах, это не так, погрешность очень велика. Кто-то учит в последнюю ночь, но сдаёт потом с блеском. Кто-то вдруг влюбился и в голове что угодно, кроме дифуров. И так далее. Чтобы это контролировать, надо иметь ежедневное плотное общение с каждым. Такое только в фантастике или при индивидуальном обучении.


                Исключения есть, но чем выше уровень предмета, тем они меньше.


                1. SergeyGalanin Автор
                  19.02.2018 11:51

                  А, если про универ говорить — то да, всё так.


                  1. netch80
                    19.02.2018 11:58

                    Так если речь про дифуры — то сложно предполагать другой контекст. Разве что физ-мат школы высокого уровня, но там уже примерно та же специфика.


            1. VolCh
              19.02.2018 11:39

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


              1. netch80
                19.02.2018 11:57
                +1

                Для начала сообщить обучаемому

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


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


                1. VolCh
                  19.02.2018 12:18

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


                  1. Druu
                    19.02.2018 12:47

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

                    Нет, не достаточно. Доказательством наличия навыка является процесс решения, а не результат.

                    > определенным способом

                    «определенным способом» — это и есть навык. Если у вас задача «есть три мальчика, у каждого по два яблока, сколько вместе» — то это, почти наверняка, задача на умение умножать. И если вы написали «6» путем сложения 2+2+2=6, то вы ни черта не продемонстрировали, кроме того, что до вас медленно доходит.


                    1. VolCh
                      19.02.2018 13:50

                      Доказательством наличия навыка является процесс решения, а не результат.

                      Не согласен. Многократно получены правильные результаты на задачах одного типа — вероятность наличия навыка много выше случайного угадывания.


                      «определенным способом» — это и есть навык.

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


                      то это, почти наверняка, задача на умение умножать.

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


                      1. Druu
                        19.02.2018 14:01

                        > Многократно получены правильные результаты на задачах одного типа — вероятность наличия навыка много выше случайного угадывания.

                        Но наличие навыка это не демонстрирует.

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

                        Необходим и достаточен для чего? Учебные задачи дают не для того, чтобы научиться решать учебные задачи. Их дают для того, чтобы освоить именно тот или иной _способ решения_. Который вы потом будете применять на _других_ задачах. А школьные задачи вы нигде кроме как в школе решать не будете.

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

                        > «Почти» не считается.

                        К счастью, в реальности (а не в модельной ситуации) у ученика есть стопроцентное знание, без почти.


                        1. VolCh
                          19.02.2018 15:25
                          -1

                          Но наличие навыка это не демонстрирует.

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


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

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


                          1. Druu
                            19.02.2018 15:34
                            +1

                            > Ну как не демонстрирует?! Навык решения задач определенного типа как раз и демонстрирует выдача правильного результата на достаточно большой выборке задач этого типа.

                            Навык решения школьных задач никому не нужен. В школе не учат решать школьные задачи. Школа не для этого.

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

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


                            1. VolCh
                              19.02.2018 15:47

                              Навык решения школьных задач никому не нужен. В школе не учат решать школьные задачи. Школа не для этого.

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


                              И проблема в итоге не в непонимании, а в лени.

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


                              1. Druu
                                19.02.2018 15:50

                                > Но речь шла о демонстрации владении навыка решения задач.

                                Нет, не шла. Ученику не требуется демонстрировать навык решения задач. Ему требуется демонстрировать наличие наличие навыков использования определенных методов.

                                > Слишком категорично, чтобы быть правдой. Во-первых, может быть недостаточно быть развит навык использования неполной индукции.

                                Это все замечательные рассуждения, но к реальности они отношения не имеют. В реальности в 99 случаях из ста все ученик прекрасно понимает, но не делает как дОлжно из-за лени и собственного ЧСВ.


                          1. tetramino
                            19.02.2018 19:31

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

                            Оценка по методу черного ящика недостаточна точна и эффективна для задачи обучения людей.

                            Это обычно не сообщается ученикам перед решением задач.

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


              1. Druu
                19.02.2018 12:42

                > Для начала сообщить обучаемому какие навыки должна вводить, закреплять и проверять данная задача.

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


                1. VolCh
                  19.02.2018 15:13

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


                  1. tetramino
                    19.02.2018 19:33

                    задачи данного типа должны сформировать у учеников навык такой-то

                    Для формирования навыка не надо об этом сообщать. Зачастую это даже вредно.


                    1. VolCh
                      19.02.2018 19:37

                      Тогда потом не надо удивляться "улетучившимся" навыкам, которые закреплены были с мотивацией "чтоб учитель "отлично" поставил".


                      1. tetramino
                        19.02.2018 20:00

                        Тогда потом не надо удивляться «улетучившимся» навыкам, которые закреплены были с мотивацией «чтоб учитель „отлично“ поставил».

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


          1. Druu
            19.02.2018 12:37

            > Почему голый ответ не тренирует навык?

            А с чего вы взяли, что не тренирует? Раз речь шла об оценке, то в нашем случае речь не о тренировке навыка (тренировка, очевидно, не может оцениваться), а о его проверке. Записав голый ответ, вы навык не продемонстрировали. Преподаватель ведь должен исходить из фактов, а не из вашего честного «ну я учил»? Вот он и исходит.


            1. VolCh
              19.02.2018 15:16

              Есть задача — даю её ответ. Какая ещё демонстрация навыка решения задач нужна?


              1. tetramino
                19.02.2018 19:43

                Путь поиска ответа важен. Вдруг вы пример 2+2 решаете при помощи порождающих грамматик или вообще просто помните наизусть?


                1. VolCh
                  19.02.2018 20:07

                  Какая разница, если почти всегда я даю верный результат в приемлемое время?


                  1. Druu
                    19.02.2018 20:23

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


                  1. tetramino
                    19.02.2018 23:45

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

                    Я сам сталкивался с аналогичной проблемой, если честно))


      1. bopoh13
        19.02.2018 11:35
        -1

        Критерии всегда одни: либо понять насколько студент понял материал, либо начихать и завалить.


  1. VolCh
    17.02.2018 23:55

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


    1. khim
      18.02.2018 00:02

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

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

      То есть да, я вижу места, где я сделал «некрасиво» и сегодня, наверное, сделал бы «красивее», но понятнее… это же мой код — как он может быть непонятным?


      1. VolCh
        18.02.2018 00:25
        +1

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


        1. khim
          18.02.2018 02:14

          Существует, особенно если напрямую работаешь с неформализованными требованиями бизнеса.
          Ok, будем знать.

          А потом долгое время не используется и выветривается из памяти, пока, как минимум, не возникнет сильная ассоциация.
          Ну не весь же вы код так пишете!

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


    1. VolCh
      18.02.2018 00:20

      Что я хотел сказать в целом: даже при одинаковых когнитивных способностях маловероятно, что код будет одинаково понятным в момент написания и в момент чтения, если контекст сильно поменялся. На только что написанный код надо смотреть пускай не глазами «троечника», но хотя бы своими глазами вне контекста, вычеркнув всё, что не касается локальной области видимости, максимум одной над ней, а лучше даже текущего экрана с размером не более 25 строк максимум. Лучше выделить (разумно) куски текущей подпрограммы в отдельные подпрограммы без всякой надежды на повторное использование, чем через полгода разбираться, что ты имел в виду. Не можешь выделить — напиши себе комментарий, восстанавливающий контекст. Например, ссылку на описание алгоритма типа RSA-шифрования, который ты реализовал, не разбираясь в нём настолько, чтобы логтчески что-то выделять.


  1. vladob
    18.02.2018 00:14
    -1

    Спасибо за статью.
    Исходные положения в статье близки к моим собственным представлениям о предмете.


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


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


    А физик запишет окончательное:
    E=m*c^2


    1. GeMir
      18.02.2018 00:25

      А физик запишет окончательное E=m*c^2
      А физик, знакомый с TeX, аккуратное:
      image

      ;)


      1. vladob
        18.02.2018 00:57

        :) Хотел.


        Не решился. Пробую...

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


        Markdown при этом почему-то не кликнулся.
        А режим редактирования Хабр включает на очень короткое время (на что я напоролся раньше), посему спешил.
        Можно я здесь попробую? :)


        $$display$$E=mc^2$$display$$


        Ну вот же — не сработало… :(


  1. gaploid
    18.02.2018 01:11

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


    1. vladob
      18.02.2018 02:22

      И я не думаю.

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

      Длина/объем кода, сгенерированный в процессе разработки и потом убитый — одна вещь.
      Неструктурированный, с кучей мусора код в продакшене — другое.


  1. ragequit
    18.02.2018 01:24

    >У нас, технарей, рабочая память для хранения «технических» элементов объёмнее, чем у гуманитариев.

    Учился в МРТИ, пропускал целые цепи интегральных вычислений (что было понятно только преподавателю, но не отличникам), в итоге — гуманитарий и филолог.

    Что-то в вашей логике не так.


    1. vladob
      18.02.2018 01:38

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

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

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


      1. ragequit
        18.02.2018 01:46

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

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


        1. vladob
          18.02.2018 02:05

          Привет земляку! :)
          Я же и говорю — границы условны, их, может, четких и вообще нет.


      1. DoctorMoriarty
        18.02.2018 21:39

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

        "Специалист подобен флюсу" (с)


        1. vladob
          19.02.2018 00:12

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


  1. Error1024
    18.02.2018 02:00

    Я бы рад не писать таких огромных функций, с кучей сущностей, однако далеко не всегда вызов функции «бесплатен».

    код
    // BEGIN $RawMaskBlit(WriteByte1, WriteByte2, WriteByte3, WriteByte4)$. Do not change this line!
    void ZXRawMaskBlitCopy(ZXBitmapRef bitmap, int x, int y,
                       ZXBitmapRef src, int srcX, int srcY, int srcWidth, int srcHeight, ZXData maskData)
    {
        /* dest and src */
        ZXData pScan, pSrcScan, pMaskScan, pScanEnd;
        ZXData p, pSrc, pMask;
        unsigned char b, m;
        int scan, srcScan;
        /* offsets, flags, etc */
        int offset, srcOffset, endPixels;
        int fullBytes, endLine;
        int compRealOffset, realOffset;
        int isRegular;
        
        /* calculate the sizes of scan lines */
        scan = BitmapScanSize(bitmap);
        srcScan = BitmapScanSize(src);
        
        /* get pointers to a byte corresponding to a pixel */
        pScan = BitmapPixelPtr(bitmap, x, y);
        pSrcScan = BitmapPixelPtr(src, srcX, srcY);
        pMaskScan = PixelPtrData(maskData, srcScan, srcX, srcY);
        /* calculating end vertical line */
        endLine = y + srcHeight;
        
        /* bitmap offset */
        offset = x % 8;
        /* src offset */
        srcOffset = srcX % 8;
        
        /* get information about how much pixels should be shifted, */
        /* important: when (offset < srcOffset) one byte is completely absorbed when outputting the left byte */
        if(offset >= srcOffset)
            realOffset = offset - srcOffset;
        else
            realOffset = 8 - (srcOffset - offset);
        compRealOffset = 8 - realOffset;
        
        /* count of full-size bytes */
        fullBytes = CalcFullBytes(x, srcWidth);
        /* offset end pixel */
        endPixels = (x + srcWidth) % 8;
        /* regular draw or not */
        /* a) snap to right colum */
        /* b) snap to left colum */
        isRegular = (offset + srcWidth >= 8) || (offset == 0);
        
        /* main loop y */
        for(; y < endLine; y++) {
            p = pScan;
            pSrc = pSrcScan;
            pMask = pMaskScan;
            
            /* take care of left byte */
            /* xxxxxxxx XXXXXXXX xxxxxxxx */
            /* ^ we here */
            if(offset != 0) {
                if (offset >= srcOffset) {
                    b = *pSrc >> realOffset;
                    m = *pMask >> realOffset;
                    
                    /* need next byte if we haven't real offset */
                    if(realOffset == 0) {
                        pSrc++;
                        pMask++;
                    }
                }
                else {
                    b = (*pSrc << compRealOffset) |
                    (*(pSrc + 1) >> realOffset);
                    m = (*pMask << compRealOffset) |
                    (*(pMask + 1) >> realOffset);
                    /* we completely used a byte, take a new */
                    pSrc++;
                    pMask++;
                }
                
                /* combine dest and src */
                if(isRegular) {
                    b = (*p & rByte[offset]) | (b & lByte[offset]);/* $WriteByte1$ */
                    *p = (*p & ~m) | (b & m);
                }
                else {
                    b = (*p & ~(rByte[srcWidth] >> offset)) | (b & (rByte[srcWidth] >> offset));/* $WriteByte2$ */
                    *p = (*p & ~m) | (b & m);
                }
                
                p++;
            }
            
            /* main loop x */
            /* xxxxxxxx XXXXXXXX xxxxxxxx */
            /*          ^ we here */
            pScanEnd = p + fullBytes;
            if(realOffset != 0) {
                for(; p < pScanEnd; p++) {
                    b = (*pSrc << compRealOffset) |
                    (*(pSrc + 1) >> realOffset);
                    m = (*pMask << compRealOffset) |
                    (*(pMask + 1) >> realOffset);
                    
                    /* combine dest and src */
                    b = b; /* $WriteByte3$ */
                    *p = (*p & (~m)) | (b & m);
                    
                    pSrc++;
                    pMask++;
                }
            }
            else {
                for(; p < pScanEnd; p++) {
                    b = *pSrc;
                    m = *pMask;
                    
                    /* combine dest and src */
                    b = b; /* $WriteByte3$ */
                    *p = (*p & (~m)) | (b & m);
                    
                    pSrc++;
                    pMask++;
                }
            }
            
            /* take care of right byte */
            /* xxxxxxxx XXXXXXXX xxxxxxxx */
            /*                   ^ we here */
            if(isRegular && endPixels) {
                if(realOffset != 0) {
                    b = *pSrc << compRealOffset;
                    m = *pMask << compRealOffset;
                    /* .. end pixel is double byte src */
                    if(endPixels > realOffset) {
                        b |= *(pSrc + 1) >> realOffset;
                        m |= *(pMask + 1) >> realOffset;
                    }
                }
                else {
                    b = *pSrc;
                    m = *pMask;
                }
                
                /* combine dest and src */
                b = (*p & lByte[endPixels]) | (b & rByte[endPixels]);  /* $WriteByte4$ */
                *p = (*p & (~m)) | (b & m);
            }
            pScan += scan;
            pSrcScan += srcScan;
            pMaskScan += srcScan;
        }
    }
    // END $RawMaskBlit$. Do not change this line!


    1. firk
      18.02.2018 02:54

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


      1. Error1024
        18.02.2018 03:02

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


    1. charypopper
      18.02.2018 10:25
      +1

      почему бы не использовать inline чтобы выделить какое то поддействие?


      1. Error1024
        18.02.2018 16:04

        По причине того что inline лишь «рекомендует» компилятору заинлайнить функцию, кроме того это код на C89.
        Кроме того, от разделения конкретно этой функции на «действия» станет только непонятнее ее работа.


    1. DistortNeo
      18.02.2018 15:54

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

      Если есть желание, можно переписать то же самое на C++ — будет компактнее.


      1. Error1024
        18.02.2018 16:06

        Данная либа должна компилироваться везде, где только есть более-менее работающий C, поэтому доверить inline компилятору я не могу.


        1. firk
          18.02.2018 19:54

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


          1. Kobalt_x
            18.02.2018 20:54

            а потом очень долго искать ошибку при помощи препроцессора и страдать при отладке этого кода в макросах, т.к. информация о символах как правило генерится по препроцессированному коду


            1. Error1024
              18.02.2018 23:33

              А еще в «функциях»-макросах не создать локальных переменных(про C), что приведет функцию в вид фарша.


              1. netch80
                19.02.2018 11:26

                А еще в «функциях»-макросах не создать локальных переменных(про C)

                Вполне можно. Например,


                #define mamarama(r,x,y)   do {     int z1, z2, z3;     z1 = kumar1(x, y);     z2 = kumar2(x, y, z1);     z3 = kumar3(x, y, z2);     r = z1 + z2 - z3;   } while(0)

                здесь do{}while(0) — стандартный трюк для вложенного блока.


                В GCC/Clang, кроме того, можно за счёт typeof делать такое без завязки на конкретные типы, а за счёт statement expressions — давать им выглядеть как функции с возвращаемыми значениями. Но и без этого уже есть возможность не пачкать внешнее пространство.


                1. Error1024
                  19.02.2018 13:07

                  Так можно делать только с С99 или при наличии у компилятора соответствующего расширения. В C89 так нельзя.


                  1. netch80
                    19.02.2018 15:06

                    Вы с прямым углом перепутали, то есть с определением переменных после первого исполняемого оператора блока.
                    Определять переменные в начале любого блока до первого исполняемого оператора допускается и в C89, и ранее (от ANSI-85 и вплоть до исходного K&R, в той версии, как он попал в книгу), они будут существовать в пределах этого блока.


  1. alexunder
    18.02.2018 02:37

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


    1. apapacy
      18.02.2018 03:00

      Согласен абсолютно. Пока предубеждения касаеются технических вопросов это просто раздражает. Когда касаются людей это немного страшно. Когда руководство это не присекает а поощряет работа прерващается в абсурд. «Саймон сказал ...»


  1. Treg
    18.02.2018 02:55

    Из опыта могу сказать, что программист != математик. Программист — он больше стратег, архитектор, обладающий сильным объемным мышлением. А математик — тактик, который может оптимальнее решать локальные задачи какими-то сложными формулами и алгоритмами, но в больших масштабах его код будет чрезмерно мудреным, что пойдет только во вред.


  1. BOM
    18.02.2018 03:27

    Откуда у автора уверенность в том, что для написания длинных функций необходимо обладать какими-то особыми навыками, отличной памятью и незаурядным интеллектом? Писать длинные лапшеобразные функции как раз таки очень и очень легко и именно такой код и пишут все начинающие программисты, потому что это написание кода в потоке, которое встречает минимальное сопротивление. Сам помню, когда я начинал писать функцию, понятия не имея, что я буду писать дальше, и по ходу написания сотой строки по двадцать раз пробегал глазами по всему написанному, чтобы вспомнить, чего я там нагородил и какой из if-else отвечает за тот результат, который я сейчас использую.
    Следовать DRY, SOLID и какой-то осмысленной архитектуре сложнее на порядок, чем впихивать невпихуемое в один составной оператор. Именно поэтому длинные раздутые контроллеры пишет каждый второй вкатившийся в айти, а до проектирования нормальной архитектуры дорастают единицы.
    Когда я вижу функцию из 300 строк, последнее о чем я могу подумать, так это о том, что этот код писал отличник.
    Писать длинные функции легко и с хорошей памятью это никак не коррелирует. Это, несомненно, очень энергозатратный процесс, но не более.


  1. shybovycha
    18.02.2018 03:38

    Столько умных фраз для описания различия между опытным разработчиком специалистом и малоопытным...


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


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


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


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


    1. BOM
      18.02.2018 03:54

      Мне кажется, что если кто-то не понял твой код, то это необязательно означает, что он менее опытен и меньше разбирается в специфике области и проекта. Джуниоры частенько такой код могут нагородить, в котором сеньор не сразу может что-то понять и со словами «Слышь, что за нафиг» зовут автора строк объяснить, зачем он встроил тернарный оператор с присвоением в тернарный оператор с анонимной функцией, которая по итогу окажется нерабочей и всегда возвращающей пустой массив, когда на самом деле можно было обойтись двумя строками с if.


      1. shybovycha
        19.02.2018 01:44

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


  1. lastrix
    18.02.2018 07:08
    -1

    Второе имя гениальности — краткость, первое — новизна.


  1. BlackSCORPION
    18.02.2018 10:32

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


  1. nefedovgeka
    18.02.2018 10:33
    +2

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


    1. rrrrex
      18.02.2018 15:55

      Так у вас бизнес и в жизни все отлично?


      1. nefedovgeka
        18.02.2018 18:22

        Да!


  1. a4k
    18.02.2018 10:44
    +2

    Ученики послабее записывали решение по шагам и тратили существенно больше времени.
    Нам, отличникам, всё это ни к чему. Зачем писать столько ненужных промежуточных действий, когда можно сразу готовый ответ? Мы же хотим поскорее разделаться с этим примером, чтобы перейти к следующему!

    Гипотеза. Чем умнее программист (чем более объёмной рабочей памятью он располагает), тем более длинные методы и функции он пишет.


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


    1. SergeyGalanin Автор
      18.02.2018 11:16

      Вот критика по существу вопроса. Спасибо!

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

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


      1. anjensan
        18.02.2018 12:35

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


  1. theArhar
    18.02.2018 13:03
    +1

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


    1. SergeyGalanin Автор
      18.02.2018 14:11

      А выводов-то, собственно, ещё и нет. Я же написал: «гипотеза». То, что она не очевидна, не значит, что она не имеет права на существование. Да, она ещё не подтверждена, ну так ведь и не опровергнута. Большинство доводов «против» мне кажутся такими же туманными, как моим оппонентам — мои доводы «за». Хотя никаких особенных доводов я и не стремился приводить — так, высказал идею, предположение.

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

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


  1. urgotto
    18.02.2018 13:07

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


  1. dikkini
    18.02.2018 14:17
    +3

    Вся статья — ЧСВ отличника. Чтобы быть умным — не надо решать примеры в уме. Чтобы писать длинные методы — не надо помнить в голове 78 (!!!) объектов, можно писать метод в умной IDE и получать автокомплит и прочие фишки. А умение решать примеры в голове — еще не говорит, об интеллекте или уме человека. Итого: отличник != ум, длинный метод != автор отличник, оценки в школе/универе не влияют на итоговые умственные способности человека.


  1. Arris
    18.02.2018 15:57

    Лично для меня нет проблемы удержать в памяти длинный, на 120 (или даже 300) строк метод. У меня есть такие ;) Мало, но есть.

    Просто комментарии расставляешь и пишешь попроще, а если где-то применяешь изящную магию — сам себе оставляешь пометку «как это работает» (через несколько месяцев возвращаешься, читаешь, удивляешься и думаешь — да, черт возьми, красиво же).

    Что для меня проблема — так это удержать в сознании несколько (>3 в среднем) уровней абстракции. Особенно если промежуточные слои не несут никакого практического смысла, а сделаны ради «красивого кода», «красивого оформления методов» итп.

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

    P.S. К примеру, разбираясь с библиотекой аутентификации Laravel/Sentinel, я чувстововал реальную боль.


    1. VolCh
      19.02.2018 11:37
      +2

      Абстракции для того и создаются, чтобы не держать в голове уровни под ними. Другое дело, что бывает, что абстракции текут, или задачи ставят сразу на нескольких уровнях, типа "в столбце N отчёта "агрегированные показатели подразделения за отчётный период" должна быть сумма столбца К из таблицы T базы данных D отнесённая к средневзвешенной численности подразделения".


      1. Arris
        19.02.2018 16:07

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

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


        1. VolCh
          19.02.2018 17:25
          +1

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


          1. emacsway
            20.02.2018 02:11

            Если абстракции текут, значит, инкапсуляция не выполняет своей функции по защите абстракций) Так всегда бывает когда нет должного внимания к качеству инкапсуляции.


            1. khim
              20.02.2018 03:06

              К сожалению вашу фразу можно сократить до так всегда бывает. Очень мало абстракций, которые действительно никогда не текут. Как какой-нибудь TCP, который превращает ненадёжное средство доставки в надёжное… но так вещь не бывает! Если я кабель выдернуть — как вы куда-либо что-либо «надёжно» доставите? И как «качество инкапсуляции» вам поможет?


              1. VolCh
                20.02.2018 12:31

                Надёжная доставка — это не доставка всегда и везде, это чёткое понимание доставили или нет.


                1. mayorovp
                  20.02.2018 12:35

                  … и даже это в ситуации с выдернутым кабелем не известно.


  1. Smey
    18.02.2018 16:46

    Гипотеза интересная, но лично мой опыт её не подтверждает.
    Мне кажется, что размер метода в первую очередь связан не с уровнем знания предметной области (назову это так, терминология «отличник — троечник» сомнительна), а с особенностями мышления. Т.е. есть конкретные люди, которые при любой возможности пишут большие методы.


  1. AxisPod
    18.02.2018 19:29

    Умозаключение основанное на 1 человеке, это даже не совпадение и тем более не статистика. Я могу писать крайне непонятный код, но я этого не делаю, потому что мне же придётся его поддерживать, а потом и самому понять сложно. Единственное исключение было в оптимизациях на ZX-Spectrum и борьба за байты и такты. Шаблонную магию в C++ не считаю непонятным кодом и тоже всё же стараюсь делать аккуратно и понятно по максимуму.


    1. SergeyGalanin Автор
      19.02.2018 10:46
      +3

      О боже, спектрум! Какие воспоминания!

      Да, борьбу за байты помню как сейчас. Был у меня тогда самодельный набор хакера. В zeus assembler написал утилитку, которая позволяла делать разнообразные дампы, а потом и дизассемблировать код. Утилитка «жила» в экранной памяти, в средней и нижней трети, чтобы остаток от 48К ОЗУ был свободен для подопытных программ. Когда писал дизассемблер, дозволенные 4 Кб закончились, и пришлось переписывать весь дизассемблер с нуля. Получилось, да ещё несколько сот байт дополнительно освободилось.

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

      Сам zeus я тоже дизассемблировал. Хотел стырить код для парсинга команд, и нашёл внутри команду «What is the meaning of life?», которая всегда выдавала какие-то «42» и ничего больше не делала. Тогда я ещё не читал Дугласа Адамса и не понял прикола.


  1. sand14
    18.02.2018 21:59

    В статье под отличниками понимаются отличники-математики?


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


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


    На примере:
    Пусть у нас есть Web API, реализованное в виде MVC.
    Если кому-то придет идея "а давайте упрощать модель — пусть к слою данных напрямую обращается контроллер, а то этот контроллер сейчас какой пустой", то в этот момент проект "приехал".


  1. netch80
    18.02.2018 22:13

    Функция composite_cut в примере безусловно плоха, но описание того, чем именно она плоха, не ложится на понятия отличников или троечников. Её проблемы не в количестве сущностей — там как раз нормальное структурирование. Сложно не понять, что она делает. Сложно это доказать, хотя бы самому себе. Суть проблемы — она попросту нетестируема. Как бы автор или читатель не был уверен в корректности, тесты для такой задачи необходимы — например, чтобы подтвердить соответствие нижележащего API ожиданиям, воплощённым в коде, или просто отловить банальные опечатки, на которые «глаз замыливается» даже у лучшего отличника. Здесь имеем несколько этапов, результаты которых используются для следующих этапов, но проверить их по выходным данным сложно или просто нельзя. Эту тему хорошо отработал, например, Майкл Физерс, вместе с методами решения, не буду повторяться, кроме того, что её надо было именно для этого разрезать на несколько независимых частей.

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

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


  1. Karpion
    19.02.2018 04:03

    У меня есть чёткое ощущение вида «количество функций примерно соответствует количеству слоёв абстракции». А современный мир как раз страдает избыточностью слоёв абстракции — причём эта избыточность как раз затрудняет понимание системы (не говоря уж о замедлении работы и об увеличении расхода памяти).

    Допустим, программист уложил необходимую работу в 150 строк кода. Что улучшится от того, что он разобьёт этот код на пять функций по тридцать строк? Добавятся имена функций? Ну так можно вписать эти имена в виде комментариев в исходные 150 строк и не париться.
    Т.е. задача сводится к подробному комментированию кода, и всё.

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

    И ещё:
    Похоже, автор полагает, что код надо написать так, чтобы его мог прочесть и понять слабый программист. Причём с малым расходом сил.
    Хм-м-м… А может, надо поднимать планку и не пускать в профессию слабых программистов?


    1. netch80
      19.02.2018 11:11
      +1

      Допустим, программист уложил необходимую работу в 150 строк кода. Что улучшится от того, что он разобьёт этот код на пять функций по тридцать строк?

      Пусть первая часть функции считает, чему равны foo и buka. Вторая — чему равны bar и zuka. Третья использует foo и bar, четвёртая — buka и zuka. Пятая (вы говорили про пять) их как-то обобщает, заодно логгируя.


      Чтобы грок (на всякий случай — осознать во всех деталях) всю 150-строчную функцию, читатель должен, в частности, убедиться, что вторая часть не меняет значения foo и buka, а третья — buka и zuka. А то мало ли, что происходит на 4-м уровне вложенности цикла в этих частях и под каким хитрым условием? Защиты ведь от этого нет, нельзя временно навесить const на переменную, а потом его снять. А в случае раздельных функций это выполняется примитивно и прямолинейно — foo и buka просто принимаются как результат 1-й подфункции (неважно, как часть возвращаемого значения, по указателю, по ссылке, как-то ещё) и не передаются во 2-ю, а в 3-ю и 4-ю передаются только по значению (копируются).


      Вы можете сказать, что можно их назначить const и они будут таковыми до конца жизни функции. Да, но не в Ruby (в нём нет таких констант), и не в чуть-чуть более сложном случае (пусть эти 5 частей выполняются ещё раз в цикле… не принять изменение из отдельной функции — банально, не разрешить менять — уже серьёзные затраты на изучение каждый раз).


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


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

      Но там нет возможности запретить видимость переменных внешнего блока. Ни в одном языке программирования, насколько я видел, такого нет; такой запрет делается уже структурированием на функции/процедуры/назови-как-хочешь. И тем более этого нет в Ruby.
      Вы можете вспомнить про лямбды в C++, но они фактически отдельные вложенные функции.


      Хм-м-м… А может, надо поднимать планку и не пускать в профессию слабых программистов?

      Невыгодно. Если требовать от программистов абсолютно высокого внимания ко всем деталям, то придётся выкинуть 99% тех, кто сейчас успешно работает. Повторюсь — в отрасли останутся аутисты и безумные гениальные счётчики в уме. Вы тоже будете выкинуты на мороз, аутисты не пишут такие комментарии на хабр :)


      1. Karpion
        20.02.2018 01:52

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

        Это я чисто на тему «можно или нельзя» — но не на тему «надо или не надо так делать».

        А в случае раздельных функций это выполняется примитивно и прямолинейно — foo и buka просто принимаются как результат 1-й подфункции (неважно, как часть возвращаемого значения, по указателю, по ссылке, как-то ещё) и не передаются во 2-ю, а в 3-ю и 4-ю передаются только по значению (копируются).
        А вот это уже серьёзный аргумент.

        Второй — обеспечение доверия к качеству реализации через тестирование.
        Тоже хороший аргумент.

        Но там нет возможности запретить видимость переменных внешнего блока.
        Гы! В классическом Pascal даже выделение кода в функцию не спасает от возможности поменять глобальную переменную.

        Если требовать от программистов абсолютно высокого внимания ко всем деталям, то придётся выкинуть 99% тех, кто сейчас успешно работает.
        А может, станут меняться программисты и система образования?


        1. netch80
          20.02.2018 10:42

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

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


          Гы! В классическом Pascal даже выделение кода в функцию не спасает от возможности поменять глобальную переменную.

          Для глобальной — так это точно так же и в C, C++. Это один из недостатков глобальности.
          Но в классическом Pascal можно делать у процедуры несколько блоков var, и если вложенная процедура объявлена после первого, но до второго, она не увидит переменные охватывающей процедуры из второго var. Этим можно активно пользоваться. (Вместо процедуры Pascal тут везде могут быть и функции.)
          Для C аналога такой вложенности не существует, если не смотреть на расширения GCC; для C++ это лямбды с явным заданием используемых переменных.


          А может, станут меняться программисты и система образования?

          На какую? 90% будет занимать дрессировка внимательности к тончайшим мелочам и точного воспроизведения одних и тех же действий? Самим превращаться в компьютеры?
          Я понимаю делать такое там, где людям самим интересна точность и воспроизводимость результата (например, в живой музыке). Но при анализе кода… не буду возражать, но выражу очень плотные сомнения. Если пока что движение в основном было в противоположном направлении — завлечь разнообразием и качеством средств и подходов тех, кто не был готов писать на предыдущих поколениях (например, не хотел мучаться с управлением памятью в unmanaged средах) — наверно, к этому есть не только рыночные причины.


    1. VolCh
      19.02.2018 11:49

      Похоже, автор полагает, что код надо написать так, чтобы его мог прочесть и понять слабый программист. Причём с малым расходом сил.
      Хм-м-м… А может, надо поднимать планку и не пускать в профессию слабых программистов?

      Что, в общем случае, значит "не пускать"? Ввести строгое госурегулирование типа как у врачей? С одной стороны, а кому это надо? С другой, результат всё равно будет далёк от ожидаемого.


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


      1. firk
        19.02.2018 12:24

        Что, в общем случае, значит "не пускать"? Ввести строгое госурегулирование типа как у врачей?

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


        1. VolCh
          19.02.2018 15:27

          Так я рискую обрушить свою профессиональную репутацию до уровня "волшебника", которому лучше ничего не доверять, потому что всё работает на базе непонятной магии.


      1. Karpion
        19.02.2018 20:50

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

        Я не знаю, как именно «не пускать». Это можно обсудить здесь.
        Но как минимум — надо вводить ответственность программистов за косяки. Например, когда BIOS зависает, если размер HDD превышает 32 гигабайта (олдфаги помнят) — то такого программиста совершенно точно надо репрессировать. Ну или репрессировать того, кто допустил их до написания BIOS. Репрессии отпугнут долбоклюев и фуфлогонов. А вот угроза увольнения — не отпугнёт, это вполне очевидно.

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

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

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


        1. netch80
          20.02.2018 11:19
          +2

          А программистов — не контролируют

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


          Например, когда BIOS зависает, если размер HDD превышает 32 гигабайта (олдфаги помнят) — то такого программиста совершенно точно надо репрессировать.

          Плохой, негодный пример. В истории с прохождением размерами дисков цепочки барьеров — косячили все: и производители дисков, и авторы BIOS, и авторы OS, и авторы служебных средств. Но ситуация втыкания нового диска это никак не обычный ход работы критичной системы; это то, что надо было предварительно много раз отработать на стендах.


          Тупой криворукий дебил пишет Windows — и на борьбу с косяками Windows требуется бросить армии прикладных программистов.

          90% проблем Windows это таки не проблемы тупости кодеров, а происходят из дизайна и идеи сохранения наследия. Все непредвзятые источники пишут, что уровень самих людей там очень высокий — но дальше начинают ругать систему, которая приводит их к такому результату, или явные запросы руководства (например недавние 1, 2). Так что не пинайте исполнителей, пинайте Гейтса, Баллмера и тэ дэ.


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

          Уровень специалистов достаточен. Где недостаточен — они способны дообучиться.
          Недостаточны — отражения этой проблемы в других общественных институтах. Заказчики, которые вместо нормального ТЗ способны только сказать "сделайте мне красиво" и потом выдать что-то в духе "7 красных линий зелёным прозрачным цветом". Вендоры, которые обеспечивают vendor lock за откат. Стандартизаторы, которые выбирают не то, что работает, а то, что понравилось 10 старперам, оставшихся мышлением во времена появления COBOL (вспоминаем появление iso-8859-5). А вы просто ищете стрелочника.


          Например, «эту функцию имеет право редактировать только тот, кто освоил предитикативную алгебру» (и хорошо бы указать список литературы).

          Список литературы — да, полезно. Но требование знания предикативной алгебры не нужно, например, для выполнения требования coding style. И что — отвлекать ценного спеца для выравнивания отступов в коде?


  1. emacsway
    19.02.2018 05:45
    +1

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

    По поводу влияния памяти автор сказал совершенно верно, в основе качественного кода лежит магическое число семь.

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

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

    На самом деле, если «умному человеку» дать немного знаний по экономике разработки ПО, а книга Бека является лучшим пособием по этому вопросу, то проблема исчезает.


  1. Druu
    19.02.2018 10:34

    > У нас, технарей, рабочая память для хранения «технических» элементов объёмнее, чем у гуманитариев. Чем больше памяти, тем больше промежуточных шагов мы можем накапливать в ней, не записывая.

    Промежуточные шаги никто не накапливает и не сохраняет, они _пропускаются_. Условный отличник из примера отличается не тем, что выполняет действия в уме, а тем, что он их вообще не выполняет. В принципе. Он сразу знает (из опыта) что в случае Х результат Y, без декомпозиции задачи на подзадачи.

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


    1. SergeyGalanin Автор
      19.02.2018 11:22

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


      1. Druu
        19.02.2018 12:52

        > Иногда приходится решать новые, незнакомые задачи.

        Если задача совершенно новая и незнакомая, то, внезапно, ваша «технарскость» вам ничем и не поможет по сравнению с гуманитарием.