Мы задумывались на несколько секунд и записывали готовый результат:
Ученики послабее записывали решение по шагам и тратили существенно больше времени:
Нам, отличникам, всё это ни к чему. Зачем писать столько ненужных промежуточных действий, когда можно сразу готовый ответ? Мы же хотим поскорее разделаться с этим примером, чтобы перейти к следующему!
Почему мы так можем, а другие — не могут?
Математика и кратковременная память
Нет, это очевидно, что мы можем выполнить все необходимые операции в уме, и нам нет необходимости записывать промежуточные результаты на бумаге. Но почему это возможно?
В когнитивной психологии ту часть памяти, в которой непосредственно производятся вычисления «в уме», называют кратковременной и рабочей. Там всё сложно и неоднозначно, но как её ни назови, а объём этой памяти сильно ограничен. Разные исследователи называют «магические числа» семь и пять. Это средние значения. Объём «рабочей» памяти зависит от обстоятельств и коррелирует с интеллектуальными способностями.
Получается, способность не записывать промежуточные результаты обусловлена возможностями нашей рабочей (или кратковременной) памяти. У нас, технарей, рабочая память для хранения «технических» элементов объёмнее, чем у гуманитариев. Чем больше памяти, тем больше промежуточных шагов мы можем накапливать в ней, не записывая.
Программирование и кратковременная память
А теперь попробуем представить, как работают наши сверхспособности, когда мы программируем.
Для решения полученной задачи требуется написать определённое количество кода. Но мы торопимся, и мы способны удержать в голове массу деталей. Чувствуете, куда я клоню? Мы не записываем промежуточные шаги. Вместо этого мы пишем такие алгоритмы, которые получают исходные данные и сразу выдают готовый результат. Они длинные, эти алгоритмы, и они делают очень много работы. Столько, сколько мы смогли уместить в нашей собственной рабочей памяти, когда их писали.
Гипотеза. Чем умнее программист (чем более объёмной рабочей памятью он располагает), тем более длинные методы и функции он пишет.
Попробуем подсчитать, насколько большой объём рабочей памяти требуется при программировании. Поскольку мы не знаем, как именно устроено мышление, и какими именно «объектами» оно оперирует, то просто будем подсчитывать независимые объекты, которые встречаются в коде программы.
В качестве подопытного я взял функцию на 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)
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
И не связана ли возможность "отличника" быстро щелкать примеры с тем
что он в десятки, а возможно и в сотни раз больше задачек решил, чем троечник (
который например банально не делает домашнее задание) и тем самым просто натренировался как "собака Павлова"?SergeyGalanin Автор
17.02.2018 17:25Ну, в три действия — это уже «хорошист»!
Безусловно, бывают такие талантливые троечники, которым просто на математику наплевать, потому что у них есть куда более интересные для них занятия: литература, плавание и КВН, например. На таких ведь так мало…Kazikus
17.02.2018 18:36А почему мало? У меня один одноклассник троечник — руководитель в строительной компании, второй — бизнесмен в области холодильного оборудования (мерседес новенький купил только только закончив универ). У отличников, тоже все нормально, но троечник это не приговор. Отличники часто чсв свое применить в жизни не могут.
Mr_Rm
17.02.2018 20:38Тут дело не в количестве действий. В решении apro не записано самое важное:
(lnx/x^2)' = (lnx * x^-2)'
Это и есть «отличие» — увидеть возможность упростить задачу ещё до применения стандартных правил. А способность в уме выполнять последовательность действий, которую записал «троечник» — тоже, конечно, «отличие», но уже другое.Juicer507
18.02.2018 10:11-1А смысл упрощать её до такого вида, если делением намного проще получается и быстрее?
Но здесь нет никакого «отличия» — как сказали выше, просто заученный алгоритм и всёqw1
18.02.2018 11:44+3Это примерно как 36*98 можно считать в лоб столбиком, а можно 36*(100-2)=3600-36*2=3600-72=3528. Мне быстрее вторым способом.
Kyushu
20.02.2018 11:29-1Формулу (a/b)'=(a'b-ab')/b^2 должны знать и отличник, и троечник. Её использование и стандартно (т.е. более узнаваемо и понятно), и более элегантно. А чтобы её вспомнить, то можно «на полях» вывести её из (a/b)'=(a * b^-1)'=…
mayorovp
20.02.2018 12:34Нет, эта формула ужасна. Применять ее в ситуации деления на x^n — не лучшая идея, слишком много иксов вылазит которые потом сокращать придется.
Kyushu
20.02.2018 12:40Ну, не знаю… некоторые и из левой части уравнения в правую с трудом слагаемые переносят.
Druu
20.02.2018 13:59> Применять ее в ситуации деления на x^n — не лучшая идея, слишком много иксов вылазит которые потом сокращать придется.
Вылезет — сократим. Вы так говорите, будто вам бумаги жалко.
maxzhurkin
17.02.2018 19:23Вы пытаетесь причесать всех под одну гребёнку, IMHO.
Два человека, решившие одинаковое количество одинаковых примеров, не будут одинаково выполнять одинаковые примеры
Jon7
17.02.2018 23:39Способность отличника быстро щёлкать примеры связана с другой работой мозга. У меня старший ребенок решает примеры и не устаёт. Я старшего спрашивал как ты это делаешь. А он, оказывается числа в голове видит, он работает с зрительной памятью, он их не запоминает а представляет зрительно. Он математику любит. А младший биология и химия, районную олимпиаду выиграл. В биологии как рыба в воде. А считать долго не может, быстро устаёт.
slovak
18.02.2018 00:37Я в детстве числа представлял в виде длинной ленты с метками. Прообразом была мерная лента для шитья, которая висела в гардеробе. Для сложения и вычитания оперировал оффсетами на этой визуальной ленте и довольно быстро. Еще пытался умножение делать. Дальше дело не пошло :-)
sondern
18.02.2018 00:29+1Я думаю что возможность быстро «щёлкать» в первую очередь связана с качеством выстроенной модели в голове. По моему мнению количество решённых примеров влияет только на закреплении этой модели.
Если модели в голове по какой то причине нет, то не важно сколько вы решили задач, это просто форма зубрёжки.
crea7or
17.02.2018 17:33+2Вы построили такую вот зависимость: отличник -> много запоминает -> пишет длинные функции.
И первое условие не всегда верное, а уж второе-то…SergeyGalanin Автор
17.02.2018 18:03успеваемость по таким предметам, как чтение и математика, напрямую связана с рабочей памятью
Эллоуэй Трейси, глава «Рабочая память и коэффициент интеллекта IQ» из книги «Включите свою рабочую память на полную мощь».
Понятие рабочей памяти тесно связывают с понятием подвижного интеллекта. Некоторые учёные находили связь между размером рабочей памяти и уровнем подвижного интеллекта, в связи с чем возникла теория о возможности развития подвижного интеллекта посредством тренировки рабочей памяти при использовании техник вроде n-назад.
Рабочая память, Википедия.
Так что первое условие я не придумал. А второе условие — да, это гипотеза, о чём я так прямо и написал. И мне хотелось бы обсудить её. Может быть, следовало обратиться к сообществу психологов? Однако затронутая проблема касается именно программистов, поэтому я предпочёл хабр.
Я сделал определённые выводы, и мне интересно, что о них думают мои собраться по профессии. Прошу высказываться!crea7or
17.02.2018 18:39Это теория.
Непомерно длинные функции что я видел были написаны или в режиме «на отвали», или фрилансерами(по сути тоже что и первое) или по старой памяти с более низкоуровневых языков. Программисты которые сильно умны, думают не только об уравнениях, но и о качестве кода и его последующей поддержке или они не очень-то и умны как по мне.SamDark
17.02.2018 22:55Умные программисты знают, что:
- Есть менее умные, но при этом не менее полезные.
- Мозг не всегда одинаково хорошо думает.
SergeyGalanin Автор
17.02.2018 23:24Таких стоит называть «мудрые программисты», чтобы отличать их от просто умных ))
tyomitch
18.02.2018 00:24Что вы скажете про 684-строчную функцию в GCC, внутри которой одно условие
if
занимает 38 строк? GCC тоже писали «на отвали»?khim
18.02.2018 02:09О! Знаменитый reload. Для него даже отдельная статья в Wiki есть.
По-моему достаточно одной цитаты: Reload is the GCC equivalent of Satan, чтобы понять как к ней относятся разработчики…
Не думаю, чтобы её писали «на отвали», скорее «так уж вышло»… но да — это не то, чем можно гордится.tyomitch
18.02.2018 11:14+1Я к этому и вёл: что длинные запутанные функции появляются как в случае «писали на отвали», так и в случае «так уж вышло». GCC и его reload — далеко не уникальный случай.
apro
17.02.2018 18:40успеваемость по таким предметам, как чтение и математика, напрямую связана с рабочей памятью
Есть исследования утверждающие что "общий" интеллект нельзя свести к одному фактору:
http://www.cell.com/neuron/abstract/S0896-6273(12)00584-3
и полагаю что такие обширные области как математика или прикладное программирование требуют всех возможностей интеллекта для разных классов задач
и свести все кто одному фактору типа "быстрая память" будет ошибочным упрощением.
dev96
17.02.2018 19:49Причем тут "рабочая память", когда ПО пишут команды разработчиков. Код должен быть понятным и храниться в памяти компьютера, а не в голове конкретного разработчика. Тем-более код по статистике чаще читается, а не пишется. И читается он не только автором, но и его коллегами и т.д.
Длина метода в 100+ строк — это уже не есть хорошо. По этому поводу Макконелл еще давно писал. А его книга "Совершенный код" — это классика, к которой все прислушиваются. У него по поводу размера метода отдельный раздел есть, где он пишет, что метод в идеале должен полностью помещаться на экране монитора (50-80 строк).
Плюс к этому, рекомендуется заменять комментарии, методами с подходящим названием.
А держать методы в уме (что вылетит из бошки очень быстро) — это не правильно, как по мне.
decomeron
17.02.2018 18:02Имхо, память и ум вещи совсем разные. Можно много чего запомнить и держать в голове—это память, но что делать с тем, что у тебя запомнилось? нужно что то еще, например ум, что бы это все вытащить из памяти и скомпоновать все это
SergeyGalanin Автор
17.02.2018 18:14Разумеется. Иначе не быть бы когнитивной психологии отдельной дисциплиной. Вот: «Когнитивная наука. Основы психологии познания» (в двух томах). Суммарно 880 страниц. Можно найти в электронном виде — почитайте содержание ради интереса.
Marui
17.02.2018 18:04+1В программировании нет сложных задач. Есть очень-очень-очень много средне-лёгких. Просто их очень много.
Alexsandr_SE
17.02.2018 18:46Просто нужно придумать как из сложной задачи сделать кучу средне-лёгких. Это возможно самый сложный этап.
apapacy
17.02.2018 18:41Вцелом — не очень согласен.
Если под отличником(-цей) понимать не зубрилу и выскочку (катати как и подлец только мужского рода слова), а способного мальчика или девочку, то точно не согласен что так будет брать производную. Будет расписывать по шагам а не заучивать формулу. У нас в университете даже это просто запрещалось делать. Поэтому решение примера чуть сложднее шекольного например по теме интегралы были на 4-х страницах с двух сторон в каждой клеточке.
Что касается магического числа семь. По этому поводу мне очень хорошо запомнилась байка одного из преподавателей прмышленного дизафна в политехе, где училась моя сестра. Вобщем-то тема была как раз о памяти. По поводу ворон например оказалось что сичтают до трех. Проверяли таким способом. Клали сыр в закрытое помещение куда входили по очереди и потом выходили 1, 2, 3 и 4 человека. Так вот вороны дожидались пока не выйдет 1, 2, 3 человека а на 4-м начали ошибаться.
По поводу человека проводили опыты с пастухами. Забирали у них из стада численностью 1,2,3 и т.п. голов одну корову и просили сказать все ли коровы на месте не пересчитывая их. Пастухи действтельно начинали ошибаться при стаде из 8 коров.
Потом сделали тот же оптыс с оленеводами. Дошли ждос стада в 1000 оленей и оленевод всегда точно отвечал типа Сохатого не хватает, однако.
Тут важен сам подход
А вот тот код написал троеччник или отличник это еще нужно доказать. С кодом функции в пару тысяч строк например я еще могу разобраться. Но если троечник начинает делать все «по науке» и разбивать 50 строк на модули, но не в стиле «раздляй и властвуй», а в стиле: разложи листики в конвертики, потом конвертики сложи в коробочки, коробчки положи в ящички, потом подойди к ящичкам и найди где лежит заначка. То это гораздо более утомительно. Прошлая Ваша публикация на данную тему кажется мне более инересной.SergeyGalanin Автор
17.02.2018 19:28Когда пример лёгкий, как тот, что я привёл в пример в начале поста — такой вполне можно решить в уме и записать сразу готовый ответ. Лично я постоянно так и делал, несмотря на требования расписывать решение по шагам. Ну или хотя бы пропускал половину шагов, потому что влом записывать.
А когда решение на четырёх страницах — его ни один отличник в уме не решит. Более того, каждый отличник (и я в том числе) будет сразу записывать именно по шагам, чтобы потом можно было проверить правильность решения.
Опыт с оленеводом немного к другой теме относится. Пастух — он чужих коров пасёт, и у него они действительно сидят в памяти, близкой к кратковременной. А оленевод своё стадо знает с пелёнок, и кратковременная память тут меньшую роль играет — он здесь на долговременную опирается.
Про код могу так ответить. «Отличник» и «троечник» здесь — условные категории. Надеюсь, их не будут воспринимать слишком буквально. Надо же было их как-то кратко назвать. Не писать же каждый раз «лица с хорошо развитым подвижным интеллектом» и «лица с не так хорошо развитым подвижным интеллектом».
Я просто хотел двинуть идею, что если мы видим длинный код — то написавший его человек обладает хорошо развитой кратковременной памятью. А значит, согласно исследованиям «некоторых учёных», и хорошо развитым подвижным интеллектом. И, скорее всего, — был отличником по математике.
А вот обратное — не всегда верно. Некоторые «отличники» (читай: «талантливые парни с хорошо развитой кратковременной памятью и подвижным интеллектом») — да, всё ещё продолжают писать длинные методы. А некоторые — уже набили достаточно шишек, и перешли к коротким.aamonster
17.02.2018 20:07Вы что — ни разу не видели, как человек дописывает код в процедуру, давно забыв, что было в её начале? Обычное же дело. В итоге длинную глючную процедуру пишет как раз человек, который не смог удержать её в памяти (и благодаря этому почувствовать, что она слишком разрослась).
apapacy
17.02.2018 21:15Да я понимаю о чем Вы хотели сказать. В первой Вашей статье была действительно интересная идея о том что у хорошего программиста-хорошиста код всега очень лаконичный и понятный. В большинстве же своем программисты как и нормальные люди троешники (написал бы троечники но похоже на кучеров троек получается что-то). Мне например сложнее всего вникать в суть не с длинной плохо написанной функици, а предположем 3 функций которые были плохо разбиты на 3 функции. Если Вы дадите троечнику задание разбей свой код на функции он это сделает на ту же самую тройку и будет уже тройка в квадрате.
vitaliy2
17.02.2018 18:54Некоторые утверждения статьи странные. Константы не нужно держать в голове, что они значат видно прямо из их названия в момент чтения. Насчёт хэшей — точно не уверен, как там в питоне, но в js есть только один вид хэша — получить объект/значение по ключу (и это логично). Причём что это за объект/значение следует прямо из названия хэша. Нужно помнить только сам объект, но и тут его название говорит само за себя: если оно во множественном числе, это массив, если это объект вида user или userObj, то это struct или экземпляр класса, если userId или userCount, то число, если isUser, то boolean и т.?д.
А функции да, по возможности нужно разбивать на более мелкие — проанализировать 2 независимые функции по 10 строк намного проще, чем одну из 20 строк. Ну и конечно именование функций, параметров, переменных и т.?д. очень важно (а особенно важен API).
SBKarr
17.02.2018 19:21+1Программирование это навык на границе науки и искусства. Задача программиста: декомпозиция задачи на блоки, каждый из которых должно как можно эффективнее использовать повторно. Наука здесь в декомпозиции и решении задачи. Искусство в эмпирическом предсказании возможности повторного использования каждого отдельного блока решения. Этот тезис был известен даже в СССР. С тех пор не изменился.
Положенная в основу статьи ошибка характерна для всех начинающих программистов и отлично описана. Встречается у программистов любого начального уровня, вне зависимости от их школьных оценок. И лечится активным социальным взаимодействием (в виде старших коллег, неодобрительно взирающих на код, который невозможно использовать повторно).
Беда в том, что из-за низкого порога входа такие вот программисты начинают проектировать свои собственные системы. Которые чуть более, чем полностью состоят из таких вот богоподобных функций с кучей предусловий и неясной механикой работы. В таких системах сложные задачи вполне решаются за 150 строк, если вы достаточно «вкурили» странную логику автора. Только вот это будет навык использования этой конкретной системы, а не навык программирования или решения задач.
Если люди считают, что программирование это решение задач с помощью кода — они «кодеры», программисты низшего уровня. То есть, попросту, или хреновые, или начинающие специалисты. Даже отличники при переходе к реальной работе будут начинающими специалистами. Даже отличники будут совершать типичные ошибки новичков. По опыту могу сказать, что отличники чаще не готовы признать себя начинающими. А значит, склонны дольше оставаться таковыми. Отсюда возникает иллюзия ошибок, характерных именно для отличников. На деле же — обычная ошибка новичка.
Кроме ошибки новичка здесь, несомненно, вина школьного образования в целом. Ибо это образование представляет программирование именно как написание кода. А на деле, написание кода — наименьшая и наиболее простая из задач программиста, вышедшего за пределы начального уровня. Если признать, что отличник это такой ученик, который наилучшим образом встроился в образовательную программу, очевидно, он будет тащить за собой больше всего ошибок этой самой программы.
Мой коллега после прочтения статьи сразу же предположил, что из гениев, способных перепрыгивать огромные этапы решения, выйдут совсем хреновые программисты. Опровергну. Главная черта гения: умение предсказывать результат своих действий далеко вперёд. Если этот гений ещё и программист, он не будет подкладывать себе же грабли. Он скорее сразу разобьёт код на блоки, которые будут удобны для повторного использования ему самому.
Из всего вышеописанного следует, что оценки когнитивной психологии в общем смысле здесь применять неверно. Они, несомненно, важны в деле программирования. Но важны в другом месте. Человеку, который может удержать в голове больше объектов, проще построить грамотную архитектуру. Проще разбить задачу на подзадачи наиболее оптимальным образом. В общем смысле, эффективная архитектура не должна оперировать больше, чем пятью объектами на каждом уровне. Это исходит именно из оценки когнитивной психологии. Достичь этого можно кучей методов композиции и уменьшения связности. Чем больше объектов в человек может удержать в голове в один момент времени, тем лучше он выделит наиболее сильные связи и устранит слабые. Самый важный навык — умение быстро переключаться между уровнями архитектуры: между переменными в функции, системными объектами и промежуточными уровнями абстракции. Но это уже тема для статьи, а комментарий как-то подзатянулся.SBKarr
17.02.2018 19:35Вспомнился такой небольшой постскрипттум. Мой средний балл по математике в районе 3.7 по школе и вузу (матфаку, почему именно матфаку с такой оценкой — отдельная история). Я точно так же, как описано в статье для отличников, прыгал через этапы решения. Просто по рассеянности внимания где-то постоянно терял важные символы. Что характерно, забывал записать, а не применить. Чем больше меня в этом упрекали — тем хуже становилась оценка по математике. Так что, я бы поостерёгся с термином «отличник» в таком контексте.
SergeyGalanin Автор
17.02.2018 19:45Гений — это далеко после «отличника». Кто же их знает, этих гениев? Может, не все умеют предсказывать результаты своих действий далеко вперёд? Я не гений, подтвердить или опровергнуть не могу.
А про когнитивные метрики — так я же как раз об этом. Как сообщить кодеру, что пора завязывать кодить и настало время подумать об архитектуре? Вот тебе метрика: как только вылезет выше семи — начинай грамотно проектировать. И кстати, такая когнитивная метрика сама по себе работать не будет, а только в комплексе со всеми прочими метриками. Потому что про связность и зацепление тоже надо помнить, и прочее, и прочее.SBKarr
17.02.2018 22:10Про кодера скорее идти стоит от обратного. Плох тот солдат, что не мечтает стать генералом. Вот когда в этих попытках стать генералом появляются хорошие метрики — тогда и время повысить его наконец. И мы приходим к обычной для творческой среды проблеме наставничества: а откуда простой кодер возьмёт задачи, в которых сможет показать навыки выше уровня кодера?
Тут возникает другой аспект: какому-нибудь «сеньору», как правило, очевидно, где решение хорошее, а где — плохое, без всяких метрик когнитивной психологии. Эти самые метрики нужны для людей, которые в самой профессии не смыслят. То есть, для внешних управленцев. И мы внезапно оказываемся ну очень далеко от исходной темы.
alek0585
17.02.2018 19:24Да это всем известный факт.
Кстати, кто-нибудь смотрел исходники, которые выложил ВК? Там ведь сплошь гении и наверняка есть кучи гениальности по всем проектам.
github.com/vk-com/kphp-kdb/blob/master/queue/queue-engine.c#L1486smer44
17.02.2018 19:53ёлки, ну и вырвиглаз.
а дело не только в длинне или непонятности синтаксиса но и в общих правилах структурирования кода
khim
17.02.2018 21:26-1Ой, тоже мне нашли беду. Это ж парсер параметров. Сравните с GNU LD'шным.
Простая функция, пусть и довольно длинная.vitaliy2
17.02.2018 22:41Наименование переменных :(
Первая же строчка:
int r, c;
Что такое r и что такое c? Это первая строчка функции! Хотя бы коммент оставили.
Хотя фиг знает, может это общепринятное соглашение, и эти r и c используются 100 раз в коде, но что-то я сомневаюсь, что они писали 100 похожих парсеров.
И почему функция парсера конфига ничего не возвращает? Причём с первой же строчки начинает менять глобальные переменные. Глобальные надо менять, когда реально состояние приложения изменилось. А тут всего лишь парсер конфига.khim
17.02.2018 23:12Что такое r и что такое c? Это первая строчка функции! Хотя бы коммент оставили.
Зачем? Посмотрите где они инициализируются — и всё станет ясно.
C99 ещё не везде, так что да, приходится описывать переменные в начале функции, а не там, где они нужны…
Хотя фиг знает, может это общепринятное соглашение, и эти r и c используются 100 раз в коде, но что-то я сомневаюсь, что они писали 100 похожих парсеров.
Ноборот — они там 5 строчках используются. И в них легко понять — что это за переменные и что они делают.
Вы пытаетесь читать программу на C89 опираясь на подходы какого-то другого языка (C++? Python?) — отсюда сложности.
Глобальные надо менять, когда реально состояние приложения изменилось.
Опять-таки — это подход современных языков и современных приложений. Которые, типа, могут прочитать конфиг и поменять его «на лету» (ага, три раза). Программки на C обычно читают конфиг один раз и если он неправильный — выдают ошибку. Зачем тут лишние сущности устраивать?vitaliy2
17.02.2018 23:16Понял, да, я применял подходы других языков. Просто я обычно даю переменным имена, которые явно показывают, для чего они предназначены. Сокращать до одной буквы очень редко имеет смысл.
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) не пускают…vitaliy2
17.02.2018 23:58c — character, s — string, f — function, p — pointer — это всё нормально. Но там попался какой-то «r».
Но ещё в своём языке я привык объявлять переменные по мере использования. Простоconst c
— такого не бывает, а вотconst c = s[i]
— может быть, т.?е. несмотря на короткое имя, назначение очень понятно.
Но таких коротких переменных можно пересчитать по пальцем, даже a — array — не всегда хороший вариант, потому что если это не совсем временная переменная, лучше назвать users, к примеру. А там все переменные так названы =)
0xd34df00d
18.02.2018 21:42Один из признаков хорошего программиста, на мой взгляд — умение переучиваться и обновлять свои привычки в соответствии с изменяющимися условиями.
Это было бы «ну так себе нормальненько», если бы этому коду было лет 30, а не 9.
firk
18.02.2018 03:56C99 ещё не везде, так что да, приходится описывать переменные в начале функции, а не там, где они нужны…
Конкретно в этом коде переменные в середине функции объявляются. (int was_created = -1;) — мне это сразу резануло глаза. Не знаю что в этой "фиче" хорошего, тоже писал так 10 лет назад по глупости, потом перестал.
khim
18.02.2018 08:35+1Не знаю что в этой «фиче» хорошего, тоже писал так 10 лет назад по глупости, потом перестал.
Хорошего то, что легко можно увидеть где и как эта переменная используется.
А то, что тут у нас смесь C89 и C99 стилей — это как раз плохо. Надо бы выбрать что-нибудь одно, по хорошему-то…
0xd34df00d
18.02.2018 21:41C99 ещё не везде, так что да, приходится описывать переменные в начале функции, а не там, где они нужны…
Только мне кажется, что проект, который «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. Можно посмотреть на входы и выходы каждой функции и сделать выводы, с чем она работает и от чего она зависит, а также что она меняет и на что может повлиять.
Чтение много раз — дело десятое.firk
19.02.2018 01:35Потому что о программах без глобального состояния проще
Не всегда. А в случае высоконагруженного специализированного процесса — почти всегда наоборот. А если точнее, то "глобальное состояние" там — это состояние всего сервера (железки) с операционной системой. А любой процесс — уже локален, считайте что это экземпляр объекта "сервер" со своими полями. Вас же не смущает, когда методы класса меняют состояние класса, а не только свои локальные переменные? А оверхед "модного ооп-кода" убрали — он тут ни к чему, экземпляр этого объекта строго один на процесс, а может быть и на серверную железку, и поддержка нескольких экземпляров одновременно только создаёт лишнюю нагрузку (например обратиться к this->a всегда сложнее чем к глобальной переменной a).
0xd34df00d
19.02.2018 09:34А в случае высоконагруженного специализированного процесса — почти всегда наоборот. А если точнее, то «глобальное состояние» там — это состояние всего сервера (железки) с операционной системой.
Почему специализированный у нас процесс, а состояние — вся железка?
Вас же не смущает, когда методы класса меняют состояние класса, а не только свои локальные переменные?
Немножко смущает, я по возможности стараюсь писать свободные функции в анонимном неймспейсе и дёргать их из методов класса, если это локально имеет смысл (то есть, тупо передавать им пол-класса смысла нет). Или хотя бы думаю о том, можно ли так попробовать сделать в каждом конкретном случае.
И классы с большим количеством состояния меня тоже смущают.
например обратиться к this->a всегда сложнее чем к глобальной переменной a
Если объект на стеке, то нет. Если объект на хипе и короткоживущий, то по сравнению с лишним дёрганием хип менеджера это ничто. Если объект на хипе и долгоживущий и в горячем коде, тобранчиндирекшон предиктор быстро обучится.firk
19.02.2018 12:05Почему специализированный у нас процесс, а состояние — вся железка?
Потому что там ещё было слово "высоконагруженный". В таких случаях на каждого функционального демона выделяется своя железка, а то и несколько железок (как в вк). И цель оптимизаций — выжать максимум из железки для конкретного одного демона, и полностью плевать на сценарии, где на том же компе будет запущено что-то ещё.
то бранч индирекшон предиктор быстро обучится.
Вам всё равно придётся держать лишний занятый регистр под этот this и тратить несколько лишних байт кода чтобы в него загрузить нужное значение. Может быть это и не особо большой оверхед (хотя насчёт занятого регистра мне всё-таки кажется что заметный) но польза то от этого вообще нулевая в данном случае.
0xd34df00d
19.02.2018 19:35Потому что там ещё было слово «высоконагруженный». В таких случаях на каждого функционального демона выделяется своя железка, а то и несколько железок (как в вк).
И выделяется одна железка под высоконагруженный парсер конфигов?
Может быть это и не особо большой оверхед (хотя насчёт занятого регистра мне всё-таки кажется что заметный) но польза то от этого вообще нулевая в данном случае.
Вы правда уверены, что парсинг конфигов — горячая часть этого сервиса?
Распарсили конфиг, чисто, аккуратно, без состояния, написали тестируемый, читаемый и поддерживаемый код, а уже в горячем коде сложили хоть в глобальные переменные, хоть куда хочешь. Тоже один раз.
И да, индирекшон всё равно есть.khim
19.02.2018 20:28И да, индирекшон всё равно есть.
Где? %rip это ж не регистр, это просто запись такая, адрес в декодере вычисляется…
lastrix
19.02.2018 08:19Потому что о программах без глобального состояния проще
Не всегда.
Вы представляете себе, чем бы являлись системы логгирования, будь они строго локальны? Т.е. инициализация происходила бы на каждый класс?0xd34df00d
19.02.2018 09:32Вы слышали что-нибудь о вещах вроде MonadWriter?
mayorovp
19.02.2018 10:01А какое отношение MonadWriter имеет к системам логирования? Существует ли у MonadWriter файл конфигурации, по сложности сравнимый с конфигами семейства log4xxx и их наследников (logback, NLog)?
(Это был риторический вопрос, можете не рассказывать мне что такое MonadWriter)0xd34df00d
19.02.2018 10:19Это дело десятое. Речь-то о подходе и о возможности избежать глобального состояния даже в этом случае.
mayorovp
19.02.2018 10:21Чем больше конфиг — тем дороже повторное чтение его каждый раз.
0xd34df00d
19.02.2018 10:24Зачем его читать много раз?
В конце концов, говоря на С++-ном, голая глобальная переменная и private static-поле — это ж две сильно разные вещи по возможным последствиям.firk
19.02.2018 12:11Глобальная static-переменная мало чем отличается, у неё точно так же ограничена область видимости окружающим её кодом (для static-поля окружающий код это класс, для глобальной static-переменой — файл исходника с ней, а есть ещё локальные static-переменные с областью видимости — функией, где она объявлена).
lastrix
19.02.2018 10:16Это относится к функциональным языкам — у них есть своя специфика, которая и позволяет обходить глобальные состояния… за счет глобальных монад. Да что уж, предлагаю пойти дальше — класс, функция — это тоже глобальный объект, в своем роде. Только вот их глобальность скрыта ЯП и не доступна, обычно, программисту. Хотя умельцы патчат классы в рантайме прямо в виртуалке при загрузке этих классов — AspectJ как пример.
И да, как решение для ликвидации глобального состояния — ФОП отличное решение.
А в остальных случаях как? Или идеализм и перфекционизм вездесущи и все строем должны идти учить хаскель?0xd34df00d
19.02.2018 10:22Это относится к функциональным языкам — у них есть своя специфика, которая и позволяет обходить глобальные состояния… за счет глобальных монад.
Я не очень понимаю, что такое глобальная монада.
Или идеализм и перфекционизм вездесущи и все строем должны идти учить хаскель?
Его стоит выучить хотя бы потому, что он очень сильно расширяетсознаниенабор доступных техник и паттернов даже в императивных языках.
Ну и в конце концов, мы же тут об отличниках говорим?
Skler0z
19.02.2018 11:02+2«Зачем? Посмотрите где...»
Ну давайте посмотрим на «с».
c = *s;
Ок, пошли смотреть на «s»
char *ptr, *s;
Хорошо. Ищем инициализацию «s».
ptr = s = cfg_cur
Ура! Всё сразу понятно стало, сэкономленное на оформлении кода время окупилось, разработчику — премию (сарказм!).
Вот так и ходишь и смотришь большую часть времени, вместо того, чтобы просто читать понятный код.
Такое оформление, по которому нужно «Посмотрите где...» — это то же самое, что и «идите на...» по отношению к тому, кто в дальнейшем будет работать с кодом.
Пойдешь вот так, как Вы предлагаете, смотреть, что означает переменная "_suprknadel", а через полчаса обнаруживаешь 15 открытых модулей и еще больше вопросов.
Поубивал бы.
Извините за эмоции, но я только что вынырнул из модуля в 17000 строк, с которым работаю :(
0xd34df00d
18.02.2018 21:37А мне больше понравилось, как функция парсинга конфига заодно резолвит какие-то хостнеймы парой десятков строк ниже.
youngmysteriouslight
17.02.2018 19:44В когнитивной психологии ту часть памяти, в которой непосредственно производятся вычисления «в уме», называют кратковременной и рабочей. Там всё сложно и неоднозначно, но как её ни назови, а объём этой памяти сильно ограничен. Разные исследователи называют «магические числа» семь и пять. Это средние значения. Объём «рабочей» памяти зависит от обстоятельств и коррелирует с интеллектуальными способностями.
— Петька, приборы?
— 42.
— Что «42»?!
— А что «приборы»?
В каких единицах числа приведены? В битах? Байтах? Вариках?SergeyGalanin Автор
17.02.2018 19:54Тут всё интересно. Пять и семь — это количество неких «объектов». Если заставить человека запоминать случайную последовательность букв, то такими объектами будут буквы, и человек запомнит в среднем примерно семь букв. А если слова — то примерно семь слов. А букв в этих словах будет существенно больше.
youngmysteriouslight
17.02.2018 20:12Однажды мне потребовалось запомнить последовательность из 3 иероглифов, чтобы через время их воспроизвести. Две минуты старался, но не осилил. При этом иероглифы были не сложными, до 5 штрихов каждый. Оказалось, проще было сфотографировать на телефон.
Это я к тому, что число объяснять надо. Вы говорите, что рассматривается случайная последовательность букв, но в тексте этого нет. Да и код отнюдь не случаен. Да даже для случайной последовательности следует указать размер алфавита «объектов» (7 букв запомнить — не 7 слов, что в свою очередь не 7 иероглифов).
P.S. я знаю про один экспериментНа линейной шкале (оттенки серого, размеров и т.п.) выбирается в определённом смысле равноудалённо n точек и затем предлагается случайная последовательность этих точек человеку, чтобы он идентифицировал каждую точку. Шкалу он видит только единожды, перед началом классификации, число n знает. Оказало, наиболее комфортно человек классифицирует при n<9, причём эта цифра почти не зависит от природы линейной шкалы, лишь бы границы ощущались как диаметрально противоположные (белый-черный, точка-метр).SergeyGalanin Автор
17.02.2018 20:37А Вы знали значение этих иероглифов? Если бы знали значение и знали наизусть их начертание — запомнили бы без труда. А так, задача запомнить произвольный набор из 10+ штрихов — непосильная для человека западной культуры. Это куда сложнее, чем запомнить 10+ произвольных букв.
А вот семь букв или семь слов (знакомых) для нас — это как раз всё равно. Потому что те и другие мы обрабатываем как целостные объекты, гештальты.youngmysteriouslight
17.02.2018 21:20А Вы знали значение этих иероглифов?
Разве это существенно? Скажем, иероглифы хираганы я могу запомнить вряд до 15, если при восстановлении будет под рукой таблица, и до 7-10, если не будет. Китайские иероглифы даже в количестве 5 штук я не восстановлю, даже если под рукой будет соответствующая таблица. Значение ни тех, ни иных я не знаю. Просто алфавит меньше.
А вот семь букв или семь слов (знакомых) для нас — это как раз всё равно. Потому что те и другие мы обрабатываем как целостные объекты, гештальты.
Опять же. Что проще, запомнить «оывхзку» («о! ы-ы-ы-ы… вот хз… ку» — уже запомнил) и «овации пароходом гештальту пенсне шизофазия велюром седло»? Букв-то всего 33 и многовероятно появление слогов и других знакомых групп. А слов больше и далеко не каждое вызывает устойчивый запоминаемый образ.
Или же под объектом в тексте понимается именно образ? Но тогда как сделать однозначное сопоставления объекта и формальных языковых конструкций (букв, слов, словосочетаний)? У каждого же по-разному.khim
17.02.2018 21:35+1Опять же. Что проще, запомнить «оывхзку» («о! ы-ы-ы-ы… вот хз… ку» — уже запомнил) и «овации пароходом гештальту пенсне шизофазия велюром седло»?
Во втором случае очень много редких слов, а часть — явно распадается на два (шизофазия) или вообще не воспринимается как слово (гештальту). Если бы там не было таких ужасов — разницы бы не было.
А слов больше и далеко не каждое вызывает устойчивый запоминаемый образ.
Это да, некоторые слова будут занимать не один «обьект» в голове, а два или три.
Или же под объектом в тексте понимается именно образ? Но тогда как сделать однозначное сопоставления объекта и формальных языковых конструкций (букв, слов, словосочетаний)? У каждого же по-разному.
Именно поэтому мы не можем сказать точно сколько обьектов нужно держать в голове, чтобы осознать как работает функция. Можем только оценить.
Но можно заметить, что 5-7 обьектов — это столько, сколько мы можем «захватить» не напрягаясь. Если «загружать» в сознание обьекты постепенно и если это — не случайные, никак не связанные друг с другом обьекты, то можно уместить гораздо больше.
При написании программ очень мало функций укалыдваются в это ограничение — потому и требуется над кодом посидеть и подумать, чтобы понять. Даже если код хорошо написан.
vitaliy2
17.02.2018 22:48иероглифы хираганы
В хирагане нет иероглифов. Это слоговая азбука. Т.?е. в японском используют сразу хирагану, катаканы и иероглифы одновременно (например, начало слова может писаться иероглифами, а конец хираганой).
Знаки хираганы называются знаками хираганы (или знаками каны, если более обобщённо).Kobalt_x
18.02.2018 10:07+1При этом эти знаки каны очевидно являются упрощениями все тех же китайских иероглифов
tetramino
19.02.2018 19:10Это слоговая азбука.
Это не характеристика типа знаков системы. Слоговую азбуку можно кодировать иероглифами, буквами, рисунками, канцелярскими скрепками — чем угодно.
tetramino
19.02.2018 19:07Разве это существенно?
Да. Значение и происхождение иероглифов помогает их запоминать куда быстрее. Это не моё мнение, это практика моих знакомых японистов из МГУ.
decomeron
18.02.2018 03:04Проще запомнить много знакомого, чем мало незнакомого. Например, те же иерогрифы. Нам они кажутся темным лесом, и даже один нам трудно запомнить, зато читая многие слова, напримр: элктчтво, мы его прочтем, даже если нет некоторых букв, просто по памяти. А память наша держит сотни и тысячи русских слов.
DonArmaturo
17.02.2018 19:51Резюме понравилось.
Любая индустриальная технология основана на расчётах, на возможности их проверки. Любой алгоритм должен давать простое понимание границ его применимости. Computing science должна быть доказательной и повторимой, как любая наука.SBKarr
17.02.2018 22:16Как я написал выше, программирование как разработка программных систем это не только science, но ещё и art. Причём art как раз того порядка, про который мы пока только догадки строим: предсказания на основе непонятных внутренних эвристик. По сути, это как NP-задача, мы можем построить полиномиальные метрики к ней, но придумать полиномиальное решение, подходящее для всех, не можем, и даже не знаем, есть ли оно.
tetramino
19.02.2018 19:18Computing science должна быть доказательной и повторимой, как любая наука.
Вы, видимо, не знакомы с принятой ныне структурой научного знания.0xd34df00d
19.02.2018 19:38Ну это одно из определений, в общем-то.
tetramino
19.02.2018 19:57Определение того, что именуется ядром науки, а не наукой в целом, если следовать именно принятому в философии делению. Бернал, Прайс, Ильин — почитайте))
Yu_Sh
17.02.2018 19:55+1Должна быть какая-то оптимальная компактность программного кода. Слишком сжатое изложение мысли трудно для восприятия из-за перегруженности смыслом, а слишком пространное — из-за большого объема. Как в задачке, с которой начиналась статья: подробное решение сложнее осмыслить и проверить, чем краткое. Но этот оптимум зависит от квалификации.
RUa
17.02.2018 19:57С гипотезой не согласен. С началом изучения действительно, бывало, писал длинные и запутанные портянки. На данный момент главная тенденция — удобочитаемость кода. Функции/процедуры/ и т.п стараюсь вместить на один экран, если допустимо. По длине строк — так же. Даже если объект более 1 раза не используется — ничего страшного. Главное — чтобы эти блоки были логически и мнемонически ясны тебе через месяц/год/и т.п. А если твой код смогут понять без труда другие программисты — то это она самая и есть — гениальность :))). И никакая оперативная мозговая память тут ни при чем.
А отличники пишут запутанный код 1) из-за спешки 2) Из-за неуважения к себе и другимSergeyGalanin Автор
17.02.2018 19:58Это потому, что Вы наступили на достаточное количество граблей и перешли на следующий уровень. Опытный программист отличается от неопытного тем, что пишет понятный код.
Некоторые из отличников пишут длинный запутанный код потому, что могут это делать, интеллект позволяет. А опыт ещё не подсказывает, что так делать нельзя.
CantaTronic
17.02.2018 20:02+1Полагаю, что исходная посылка статьи растёт из определённого, достаточно распространённого метода преподавания. И не является, в общем случае, универсальной истиной.
Нам, отличникам, всё это ни к чему. Зачем писать столько ненужных промежуточных действий, когда можно сразу готовый ответ?
Звучит примерно как: «Тестировать свой код — это для троечников. Зачем писать столько ненужного лишнего когда, если программа и так будет работать как-нибудь?» Ну… Чем не точка зрения, конечно.
Я тоже училась на все пятёрки и помню, какой это был понт, когда ты промежуточных вычислений не записываешь. Зачастую это приводило к ошибкам, которые трудно было отследить и исправить (что осложняло работу учителя в разы, как я поняла в дальнейшем, когда сама стала преподавать), но мы велись, и это всё счастье до сих пор живо в наших школах. Но мало ли на что школьники ещё ведутся: что курить — это круто, что если все пойдут с крыши прыгать…
Называть ли это всё «горем от ума»? Я бы, скорее, говорила о попытке самоутвердиться в своей социальной группе. У разных групп — свои критерии «крутизны», одними и теми же методами стать крутым вообще везде сложно (и это очевидно). А оценки — это просто оценки, они учителе-зависимые. Когда ты ещё ребёнок и не понимаешь, что оценивание твоей контрольной работы на 5 или 4 не имеет ничего общего с оценкой тебя, как человека, ты начинаешь за этой оценкой гоняться. А учителя — разные. Кто-то за многостраничную работу сразу ставит 5, не читая (ибо лень), а кто-то гарантированно снижает на балл-другой (потому что читать было лень, но всё равно пришлось).
Если ребёнку на уроках информатики начать снижать оценки за нечитабельный код, то через пару месяцев у «завзятого отличника» код станет самым читабельным в классе. Не думаю, что он от этого как-то резко поглупеет.
Школа она в любом случае и хорошо, что была, и хорошо, что была окончена. Если её выкинуть из головы, хуже не станет.SergeyGalanin Автор
17.02.2018 20:03Вот бы и правда кто-то стал снижать оценки за нечитабельный код… Мечта…
SbWereWolf
17.02.2018 20:05хотелось бы познакомиться алгоритмом вычисления метрики когнитивный вес, очень очень, или вес это количество объектов?
SergeyGalanin Автор
17.02.2018 20:32Нет пока ещё такого алгоритма. Есть предположение, что, возможно, такая метрика может оказаться полезной. Что в неё следует включать — не до конца ясно. Объекты, которыми оперирует интеллект программиста при написании участка кода. Ясно, что какими объектами он оперирует, те и пишет в код. Но какие именно объекты? Переменные, вызовы методов, операции, константы, элементы структур — что? Какие именно из этих объектов занимают место в рабочей памяти программиста, а какие — нет? Проблема очерчена — есть, над чем поработать.
Почитайте «Программный код и его метрики», и особенно метрики Холстеда. Там много пищи для размышления.smer44
17.02.2018 20:51имхо берёшь AST кода, задаёшь каждому узлу ( не только листу, но и ветке включая внутренние узлы) тэг классификации по смыслу, то есть «в этом цикле считается количество домов в городе» а не «в этом цикле переменная и увеличивается от 0 до 1000», определяешь метрики= расстояние между смыслами.
А всякие количественные метрики это ерунда — ту же самую программу можно переписать в другом виде чтоб весь тот расчёт был другой, то есть он не репрезентативен.
vladob
18.02.2018 01:11Нет пока ещё такого алгоритма
Думаю, и не будет. По крайней мере — одного для всех.
Многообразие метрик от равнозначных по солнцеподобности гуру свидетельствует, на мой взгляд, о многообразии одинаково качественных способов достижения цели.
Метрики будут действовать в границах, которые вы обязаны будете выбрать и наложить — выбором языка, парадигмы программирования, платформы, страны проживания, и т.п.
Подавляющее большинство практических задач натуральным образом являются граничными (краевыми) задачами, и чем длиннее граница очерченной области, тем больше гитик.
apro
19.02.2018 04:20Есть Цикломатическая сложность некоторые linter'ы ее умеют считать и выдавать предупреждение, например rust-clippy
Garruz
17.02.2018 20:39Хорошая тема, очень правильная и актуальная.
До сих пор помню один из самых обидных фейлов в жизни.
На одной из пар (насколько помню, по диффурам) была задача, что-то там про пулю, которая врезается в крутящийся барабан. Решил её раньше всех – сразу было ясно, что всё решается методами простейшей физики и геометрии, тупо школьный курс же.
Но получил «трояк». Ибо препод решил, что «не по уставу». Даже несмотря на то, что ответ полностью сошёлся с ответамигоре-отличников, корпевших над «уставным» решением чуть ли не вдвое дольше…
Мораль сей басни такова – хорош не тот, кто просто зубрит, а тот, кто понимает предмет в целом и суть конкретного вопроса в частности. И на оценки тут уже плевать – они важны только лишь в узких рамках ВУЗа, а дальше жизнь сама расставит всё и всех по своим местам… ;)
P.S. Хорошо, что хоть по информатике нам достался хоть и «советски»-отсталый, но крайне здравый преподаватель – «неуставные» решения не рубил и не критиковал, а сам приходил от них в восторг. До сих пор вспоминаю его с искренней теплотой… ^_^JekaMas
18.02.2018 13:27+1Хорош тот, кто в состоянии в задании преподавателя увидеть задачу для себя. В данном случае она должна была быть "изучение конкретных подходов к решению дифференциальных уравнений", а не в "раньше всех сказать ответ". Ты тройка, видимо, была именно по дефурам.
Garruz
18.02.2018 19:41увидеть задачу для себя
Вот именно об этом я и говорил.
Образ мышления отличника – решить всё «правильно, как учили». Образ мышления программиста – решить всё максимально рационально, пусть даже это будет «не канонично». Иначе говоря, «труъ-программистское решение» – найти путь к тому же (!) результату, но меньшими усилиями и меньшей тратой ресурсов. Оптимизация же, и всё такое (о чём, кстати, вообще и статья)…
Конечно, идеально, когда оба варианта совпадают. Но если вдруг не совпадают – то, всё же, второй вариант видится как-то намного более предпочтительным.lastrix
19.02.2018 08:26Ты решение из другой сферы взял, и при этом не достиг цели.
Вот если бы ты в контексте дифуров придумал свое решение, пусть даже менее элегантное — это было бы круто.
Ваш вариант — это в соревновании бега в мешках пробить в нем дно и бежать.
Решение не подпадает под заданную цель. Считайте это как ТЗ.
В целом же, в абстрактном случае, получи вы такую же задачу с просьбой решить — ваше решение было бы как раз самым правильным, потому что дифуры — это микроскопом гвозди забивать, когда есть более простое и доступное решение.
Где же в вашем первоначальном комментарии "правильно, как учили"?
Garruz
20.02.2018 00:59Решение не подпадает под заданную цель. Считайте это как ТЗ.
ИМХО, для программиста заданная цель – не конкретные методы решения, а решение в целом. Оно и является настоящим ТЗ (если только, конечно, ограничения в методах не вызваны объективными причинами).
дифуры — это микроскопом гвозди забивать, когда есть более простое и доступное решение.
Вот, оно самое, о том и речь!
Это и есть «образ мышления настоящего программиста». Что также во многом зависит и от методов обучения, кстати. Если учили думать – ищи методы оптимизации. Если учили решать «в лоб», «только как положено» – забивай гвозди микроскопом и прочими не предназначенными для этого гаджетами.
Ведь настоящая цель программиста не просто «решить и проставить галочку» (это как раз пресловутая «проблема отличника», описанная в статье).
Настоящая цель – решить оптимально! Чтобы потом не получались тонны «индусского кода» даже в простых проектах (что как раз схоже с решением той приведённой мной ранее задачи – моё было в несколько строчек, «оригинальное» в несколько раз длиннее)…Druu
20.02.2018 03:25> Настоящая цель – решить оптимально!
Чтобы решать _оптимально_ надо уметь эффективно использовать широкий спектр методов, понимать как они работают. Если же вместо того, чтобы отрабатывать эти методы, ты занимался «ищи методы оптимизации», то никакого уменя не будет и оптимизировать, соответственно, будет нечего.
Если человек вечно рисует картинки, вместо того, чтобы формулировать диффур, то он просто и не научится формулировать диффуры (тот самый наук, на развитие которого и дают подобного рода задачи). Это на самом деле _очень_ сложно (в реальных задачах, в учебных задачах для тренировки, конечно, просто).Garruz
20.02.2018 14:09Если же вместо того, чтобы отрабатывать эти методы, ты занимался «ищи методы оптимизации», то никакого уменя не будет и оптимизировать, соответственно, будет нечего.
А разве кто-то говорил, что одно исключает другое? Вовсе ведь нет – никто не призывает отказываться от навыков составления диффуров.
Говорилось о том, что важно понимать, какие конкретно методы наиболее оптимально использовать конкретно в этой в поставленной задаче. Если диффуры – то диффуры, если простая геометрия+арифметика – значит, именно их.
Иначе говоря, превыше всего соотношение «усилия/результат». И, кстати, не только у программистов – без этой формулы не было бы вообще совершенно никакого технического прогресса. Поэтому ради данной формулы всегда стоит хотя бы немного обдумать оптимизацию задачи перед тем, как начинать решать её «в лоб»…
В противном случае, условно говоря – так и будут использовать кучу «линейного» кода вместо того, чтобы предварительно подумать над более изящными и скоростными решениями.
P.S. Кстати, в том примере также виден явный «подход отличника» – со стороны составителей задачника (не помню уж, кто там был). Те самые «шоры» просто помешали им сразу же понять, что в этой задаче вообще нечего городить диффуры. ))VolCh
20.02.2018 14:13В современных условиях, если оценка времени "решить в лоб" меньше оценки "подумать и найти изящное решение", то по умолчанию надо выбирать "в лоб". Думать надо начинать, когда решение "в лоб" станет узким местом. Увы, но так :(
Garruz
20.02.2018 14:37Согласен, порой оптимизация может отнять больше времени, чем «лобовой» вариант. И проще выбрать «в лоб». Но принятие такого решения – тоже есть в своём роде оптимизация. Как минимум, по времени разработки.
А если получается наоборот, то это тоже своего рода «профессиональная патология», которая называется перфекционизмом. Что является другой крайностью – эта штука в излишних количествах может мешать работе не менее сильно, чем отсутствие оптимизации.VolCh
20.02.2018 14:43Так "по умолчанию" означает, что разработчику принимать решение не нужно, оно уже принято за него.
Garruz
20.02.2018 14:58Не вполне понял, почему это адресовано мне. Но отвечу…
Хороший разработчик тем и отличается от «масс-кодера», что способен поспорить за действительно правильное решение. Иначе говоря – ему НЕ плевать на результат работы, он не просто пассивный исполнитель из серии «любая тупость за ваши деньги».
Да и вообще, собственно, это касается настоящих профессионалов в совершенно любых областях, не только айтишных.
И все мои слова означают как раз то, что спорить с ТЗ порой чертовски нужно – если видите либо его некорректность, либо изъяны в требуемых методах, либо ещё что-то, либо всё вместе.
На то вы и специалист, чтобы знать свою работу лучше заказчика. И чтобы при необходимости указать ему на ошибки и/или альтернативные варианты решений.
P.S. При этом вновь оговорюсь, что даже в этом благом деле нужен разумный баланс между реальными обоснованными замечаниями к ТЗ и собственными амбициями. Иначе, с другой стороны, получается не профессионал, а просто скандалист-социофоб с манией величия… ))VolCh
20.02.2018 15:35Потому что:
по умолчанию надо выбирать "в лоб"
Но принятие такого решения – тоже есть в своём роде оптимизация.В целом индустрия приняла такое решение в качестве умолчания, для ситуаций когда выбор способа решения за исполнителем — по умолчанию оптимизировать нужно по скорости разработки(в кратко-, средне- или долгосрочной перспективе — локальные нюансы).
khim
20.02.2018 16:11Не очень понятно о чём вы спорите. Для разработчика — во многих случаях «лобовое» решение — правильный выбор. Для ученика — нет.
Потому что первому таки-надо решить задачу. Второму-таки нужно научиться определённым приёмам.Garruz
20.02.2018 17:17Для разработчика — во многих случаях «лобовое» решение — правильный выбор.
Не «правильное» – а просто самое удобное (что есть разные понятия). Особенно если всё поставлено на поток и надо штамповать по стопицот проектов в месяц – тут уж не до глубоких размышлений, разумеется…
Не всегда могу назвать это халтурой, но и высоким профессионализмом назвать тоже не могу. Как уже писал – выбор между вариантами «в лоб» и «как лучше» зависит от множества параметров…
Garruz
20.02.2018 17:11по умолчанию оптимизировать нужно по скорости разработки
Во-первых, речь не только о скорости исполнения, но и о скорости разработки…
А) Три дня мудохаться, писать «линейный» код. После каждого исправления переписывать большую часть.
Б) Один день подумать, ещё за день написать чётко структурированный код, в котором всё строится всего на паре-тройке ключевых параметров. Исправления делаются за несколько минут.
В первом случае – решение «в лоб».
Во втором – та самая оптимизация.
Недавно как раз был такой веб-проект. Нанятые разрабы писали всё сразу «набело» (то бишь, «в лоб») – в итоге чего каждое исправление/комментарий вылетали минимум в день-два (а то и больше) полного переписывания всех функций, плюс полной отладки заново. Просто вот их так научили – не думать, сразу писать.
После всей ругачки и «поучений» (кряхтя, вспомнил все азы) – таки добились того, что теперь в проекте любые исправления обрабатываются максимум за пару-тройку часов. За счёт той самой оптимизации кода, да…
И в каком варианте в итоге получилась бОльшая скорость разработки, как вы считаете?VolCh
20.02.2018 17:15Я не зря упомянул про разносрочные перспективы.
Garruz
20.02.2018 17:29Да здесь даже почти независимо от перспектив…
ИМХО – разработчик сразу (!) должен писать так, чтобы быть готовым к любым возможным исправлениям. То есть – сначала продуманная структура, только потом код.
Тем более, что ему же самому придётся нереально мудохаться, случись вдруг какие действительно серьёзные исправления. Если даже не «профессионализьму ради» – так хоть ради собственного комфорта…
P.S. Не зря ведь есть старинная пословица: «Семь раз отмерь, один отрежь». ;)VolCh
20.02.2018 17:42К любым возможным исправлениям всегда быть готовым невозможно практически. ЧТобы принять решение о подготовке к некоторым изменениям нужно оценить
- стоимость подготовки
- стоимость внесения изменений при условии подготовки
- стоимость внесения изменений при условии отсутствия подготовки
- вероятность появления необходимости внесения изменений
Garruz
20.02.2018 17:59Тут всё проще… )
Чтобы написать действительно хороший проект – прежде всего, вы должны его понять. Это, пожалуй, самая сложная задача. И вот как раз она требует хотя бы 20-25% от общего времени разработки (и это лишь как самый минимум).
А дальше уже относительно «проще». Если вы действительно понимаете проект в самой сути – вы уже с достаточно высокой долей вероятности можете предвидеть, какие конкретно параметры могут меняться в дальнейшем. И на основе этого пишете код, в котором заранее максимально предусмотрены любые возможные изменения.
Совершенно всего, разумеется, предугадать невозможно (клиенты хоть и редко, но бывают крайне внезапны))) – но от будущего геморроя такой подход точно избавит.
То есть, как уже писал ранее – сначала чёткая структура, потом код. Это избавит от совершенно большей части указанных вами пунктов…
P.S. Кстати, стоимость как раз проще всего накручивать на «тупо-работах» – вроде переделок и прочего описанного выше. И, в любом случае – вашу зарплату это никак не поднимет, всю пенку снимет работодатель…VolCh
20.02.2018 18:04Предвидеть, что может измениться — это уровень понимания бизнеса, а не проекта.
lastrix
20.02.2018 05:00-1Превосходно. У вас есть GPU (или любой другой специализированный вычислитель) и необходимо решить задачу через матричные вычисления, но у вас же есть "свои" методы, которыми вы успешно решаете на CPU.
Это провал Карл! Ваше решение не оптимально!
Дифуры и физика — это всего лишь инструменты, так же как CPU и GPU. И нужно уметь пользоваться ими, а не показать, какой вы молодец. И замечу — способность видеть множество решений — это только плюс вам. Но решение обязано подпадать под ТЗ. Иначе вы подставляете человека.
Просто подумайте, у вас попросили отмерить 1 метр оптоволокна, но вы решили, что отмерить 2 фута будет проще. Как потом быть заказчику? Смысл именно в инструментах и стандартах.
Garruz
20.02.2018 14:24У вас есть GPU (или любой другой специализированный вычислитель) и необходимо решить задачу через матричные вычисления, но у вас же есть «свои» методы, которыми вы успешно решаете на CPU.
Если оптимальнее будет на GPU – решаем на GPU. Если оптимальнее на СPU – решаем на СPU. Просто же… ;)
Но решение обязано подпадать под ТЗ. Иначе вы подставляете человека.
Какого человека?
Если того, кто пишет ТЗ – то прежде всего проверяется само ТЗ на предмет компетентности составителя и актуальности поставленных задач. Затем проводится анализ всех методов. Затем, если у вас появляются замечания по ТЗ и если вы считаете, что результата можно и нужно достичь иными способами – проводите переговоры с заказчиком, аргуметированно формулируя ему свою точку зрения.
Да, это намного больше возни, чем просто «отработать по ТЗ». Но только так и становятся настоящими профессионалами – думая не только об исполнении, но и о результате.
Просто подумайте, у вас попросили отмерить 1 метр оптоволокна, но вы решили, что отмерить 2 фута будет проще. Как потом быть заказчику?
Если «вместо» 2 метров заказчик получит 6,5617 фута – он получит именно то, что просил. Но если мне удобнее мерять в футах – он получит свои 2 метра быстрее. Что уже есть оптимизация. Просто же… ;)
Ну и где тут «подстава человека»? ))
potan
17.02.2018 20:41Можно работать с большим количеством просто устроенных сущностей, а можно с небольшим, но устроенных достаточно сложно. Вычисления «по шагам» относятся к первому варианту, и функции по 150 строк.
А если работать со сложными сущностями, то IDE, по типам данных, может выдавать полезные советы и помогать анализировать код, в языках со статической типизацией.
leossnet
17.02.2018 21:28На мой взгляд, в предложенной гипотезе имеется логическая ошибка, связанная со смешением понятия «отличник» и «умный».
При написании любого кода умным программистом учитывается использование кода в следующих контекстах:
— решение текущей задачи самим программистом (контекст – только я);
— модификация кода самим программистом по прошествии времени, когда смысл кода уже подзабыт (контекст – я и мое будущее);
— использование и/или модификация кода другими программистами (контекст – я и другие люди).
С другой стороны, всех отличников можно разделить на две большие категории:
— «умные», обладающие гармонично развитым интеллектом, способные не только к усвоению учебного материала, но и к пониманию, как его можно применить в будущем, при этом учитывающие свои предпочтения и навыки в общении с другими людьми;
— «ботаники», способные только к усвоению учебного материала, при слабой развитости к видению своего будущего и слабых навыках социализации.
С учетом предложенной классификации проблему написания длинного кода можно сформулировать следующим образом — «непонятный код пишут ботаники», так как они игнорируют свое будущее и проблемы других людей.
Если же ботаник действительно талантлив и может писать работоспособный код, то для оптимизации и (само-)документирования кода ему нужно просто приставить помощника, не сильно талантливого, но дисциплинированного и добросовестного. И такая команда сможет работать гораздо эффективнее, чем два отдельных умных программиста. А это уже проблема и сфера ответственности руководителя такого ботаника.
sbnur
17.02.2018 21:58Пример с дифференцированием не показателен — все же дифференцирование — это строго определенный процесс.
С программированием лучше проводить аналогию взятия интегралов, а лучше решение дифференциальных или интегральных уравнений.
То есть вначале надо определить способ решения задачи, а потом его реализовать.
В таком случае трудно говорить о пропуске шагов — удобный (оптимальный) способ нужно знать — не знаешь такой способ (например, фреймворк), придется долго и мучительно писать килобайты кода.
А знание — это долговременная память.
Насчет кратковременной памяти — современные среды разработки можно сказать ее заменяют
morr
17.02.2018 23:10Человеческий разум штука такая… ни в какую не хочет делать лишнюю работу, ни в какую не хочет признавать собственные недостатки и всегда ищет оправдания. Эта статья отличный тому пример.
Давайте просто честно скажем, что чаще всего мы пишем плохой код не потому что бла-бла-бла куча серьёзных, важных причин и независящих от нас обстоятельств. Всё намного проще: мы ленивы и эгоистичны.
Нам лень потому, что это дольше и сложнее.
Нам плевать потому, что с этим кодом потом будет работать кто-то другой.
В большинстве случаев диагноз этого такой: человек некомпетентен как разработчик.
fukkit
17.02.2018 23:16Просто это две разные задачи: «сделать чтобы работало» и «сделать, чтобы работало и было понятно среднему индусу». Второе требует больше времени на разжевывание и развернутое комментирование, за что клиент не всегда готов платить (в этот момент он плохо понимает, что это, в общем то, ему уменьшит общую стоимость владения (сопровождения)). Если совесть не спит, можно упомянуть об этом и дать клиенту выбор. Иногда она спит. Иногда клиент не понимает или имеет внешние ограничения по бюджету, и ему, в принципе, все равно как будет сделано, абы работало.
В общем, не нужно слепо винить отличников, бывают и обстоятельства.Marui
17.02.2018 23:38сделать, чтобы работало и было понятно среднему индусу
Вы видели код библиотеки из какого-нибудь Facebook? Для работы, например с распределенными графами? Или что-то иное? Как средний индус будет писать тесты для вот этого:
github.com/facebook/rocksdb/blob/master/db/compaction_job.cc#L683fukkit
18.02.2018 02:37Не совсем понял, к какому моему тезису у вас вопрос.
Код не видел, посмотрел, чудес не заметил. Вероятно, необходимо подтянуть контекст, чтобы понять, что именно там происходит. Комментарии в наличии. Что Вас смущает?
GeMir
17.02.2018 23:45Мы задумывались на несколько секунд и записывали готовый результат
…и не получали полное количество баллов за задание, если учителю было важно не одно лишь (неизвестно откуда взявшее) нетривиальное решение.
Умение (и желание!) быть понятным — такая же профессиональная компетенция, как и умение решать проблемы.questor
18.02.2018 11:03+1Учитель должен давать не только задачу, но и критерии оценки результата.
Druu
19.02.2018 10:54> Учитель должен давать не только задачу, но и критерии оценки результата.
Задач про бучении бывает всего две:
1. тренировка навыка
2. проверка навыка
Ни ту, ни другую голый ответ не решает.
SergeyGalanin Автор
19.02.2018 11:19+2Почему голый ответ не тренирует навык? Я же задачу решал, значит, навык потренировал. А что шаги не записал — ну так это просто лень ручкой по бумаге водить. Голова-то работала…
netch80
19.02.2018 11:27Как проверить, что она работала, и отработала именно нужные навыки?
SergeyGalanin Автор
19.02.2018 11:37+1А как проверить, что она работала, когда все шаги записаны? Можно ведь и списать?
Я думаю, учитель всегда прекрасно знает каждого ученика: его способности и меру ответственности. И если способный и ответственный ученик записывает готовый ответ, учитель, как правило, будет ему доверять (хотя, наверное, будет вздыхать при этом). С таким учеником можно быть уверенным, что если записал ответ без шагов — значит, справился с решением в уме.
А к не очень ответственным и не очень способным — к тем да, возникают вопросы.netch80
19.02.2018 11:49А как проверить, что она работала, когда все шаги записаны? Можно ведь и списать?
Против этого наработан ряд стандартных приёмов, начиная с переименования переменных и сдвига коэффициентов :) Если ученик справляется с таким — он достаточно разбирается в теме, даже если отдельные элементы где-то подсмотрел.
Но для случая голого ответа это не работает в принципе.
Я думаю, учитель всегда прекрасно знает каждого ученика: его способности и меру ответственности.
Я вижу, что даже в мелких группах вроде 10-15 человек, как в наших вузах, это не так, погрешность очень велика. Кто-то учит в последнюю ночь, но сдаёт потом с блеском. Кто-то вдруг влюбился и в голове что угодно, кроме дифуров. И так далее. Чтобы это контролировать, надо иметь ежедневное плотное общение с каждым. Такое только в фантастике или при индивидуальном обучении.
Исключения есть, но чем выше уровень предмета, тем они меньше.
SergeyGalanin Автор
19.02.2018 11:51А, если про универ говорить — то да, всё так.
netch80
19.02.2018 11:58Так если речь про дифуры — то сложно предполагать другой контекст. Разве что физ-мат школы высокого уровня, но там уже примерно та же специфика.
VolCh
19.02.2018 11:39Для начала сообщить обучаемому какие навыки должна вводить, закреплять и проверять данная задача. Каковы функциональные и нефункциональные требования к процессу решения.
netch80
19.02.2018 11:57+1Для начала сообщить обучаемому
Это не то. Это требование поставки результата в конкретном виде, а не метод проверки результата, который уже оказался в несоответствующем виде.
Разумеется, проще всего не принять формально несоответствующий результат. Но это 1) как раз то, что обсуждается в формате "а почему вообще не принимать?", 2) отвратит наиболее умных и ленивых — которые как раз потенциально самые интересные для будущего развития.
VolCh
19.02.2018 12:18Если нам требуется тренировать и проверять навык решения задач определенного типа, то нам достаточно результата. Если нам требуется тренировать и проверять навык документирования процесса решения, то достаточно документации с итоговым, пускай и неверным, ответом. Если нам требуется тренировать и проверять навык решения задач определенного типа определенным способом, то нам нужно и документирование процесса решения, для усиления гарантий того, что задача решалась определенным методом, и соответствие результата ожидаемому, для гарантий того, что задача решена.
Druu
19.02.2018 12:47> Если нам требуется тренировать и проверять навык решения задач определенного типа, то нам достаточно результата.
Нет, не достаточно. Доказательством наличия навыка является процесс решения, а не результат.
> определенным способом
«определенным способом» — это и есть навык. Если у вас задача «есть три мальчика, у каждого по два яблока, сколько вместе» — то это, почти наверняка, задача на умение умножать. И если вы написали «6» путем сложения 2+2+2=6, то вы ни черта не продемонстрировали, кроме того, что до вас медленно доходит.VolCh
19.02.2018 13:50Доказательством наличия навыка является процесс решения, а не результат.
Не согласен. Многократно получены правильные результаты на задачах одного типа — вероятность наличия навыка много выше случайного угадывания.
«определенным способом» — это и есть навык.
Навык решать задачи определенного типа является суперпозицией навыков решать задачи данного типа разными способами, но необходим и достаточен только один. Навык выбора наиболее оптимального в данном контексте способа — отдельный навык. Навыки определения контекста и метрик оптимальности в данном контексте — тоже отдельные навыки.
то это, почти наверняка, задача на умение умножать.
"Почти" не считается. Например в первом классе и на втором, кажется, курсе, мои решения "зарезали" за использование умножения на подобных задачах.
Druu
19.02.2018 14:01> Многократно получены правильные результаты на задачах одного типа — вероятность наличия навыка много выше случайного угадывания.
Но наличие навыка это не демонстрирует.
> Навык решать задачи определенного типа является суперпозицией навыков решать задачи данного типа разными способами, но необходим и достаточен только один.
Необходим и достаточен для чего? Учебные задачи дают не для того, чтобы научиться решать учебные задачи. Их дают для того, чтобы освоить именно тот или иной _способ решения_. Который вы потом будете применять на _других_ задачах. А школьные задачи вы нигде кроме как в школе решать не будете.
Это как этюды в музыке, направленные на выработку конкретного технического приема. Их смысл не в том, чтобы научиться играть (как-то) этюд, а в том, чтобы отработать прием и использовать его уже на другом (не обязательно уже учебном) материале. А если вы играете этюд каким-то особенным читерским способом, то и толку от него нет, просто трата времени в никуда.
> «Почти» не считается.
К счастью, в реальности (а не в модельной ситуации) у ученика есть стопроцентное знание, без почти.VolCh
19.02.2018 15:25-1Но наличие навыка это не демонстрирует.
Ну как не демонстрирует?! Навык решения задач определенного типа как раз и демонстрирует выдача правильного результата на достаточно большой выборке задач этого типа.
Учебные задачи дают не для того, чтобы научиться решать учебные задачи. Их дают для того, чтобы освоить именно тот или иной способ решения.
Это обычно не сообщается ученикам перед решением задач. Об этом чаще сообщается при отказе принять решение за верное на основании "ну и что, что ответ правильный. этот пример в главе про умножение, а значит решать его надо умножением, а не сложением или взятием интеграла". В лучше случае ученикам сообщается об ожидаемом способе решения и форме его оформления: "учитель сказал надо таким способом решать и так оформлять — на "отлично" не рассчитывай при ином подходе". Цель этого не доводится до учеников.
Druu
19.02.2018 15:34+1> Ну как не демонстрирует?! Навык решения задач определенного типа как раз и демонстрирует выдача правильного результата на достаточно большой выборке задач этого типа.
Навык решения школьных задач никому не нужен. В школе не учат решать школьные задачи. Школа не для этого.
> Это обычно не сообщается ученикам перед решением задач. Об этом чаще сообщается при отказе принять решение за верное на основании «ну и что, что ответ правильный. этот пример в главе про умножение, а значит решать его надо умножением, а не сложением или взятием интеграла».
Даже если предположить, что заранее не сообщается, после первого (окей, пусть второго-третьего) «этот пример в главе про умножение, а значит решать его надо умножением, а не сложением или взятием интеграла» даже до дятла дойдет, в чем тут дело. И проблема в итоге не в непонимании, а в лени.VolCh
19.02.2018 15:47Навык решения школьных задач никому не нужен. В школе не учат решать школьные задачи. Школа не для этого.
Нужность или ненужность навыков, прививаемых де-факто в школе — отдельный большой разговор. Но речь шла о демонстрации владении навыка решения задач.
И проблема в итоге не в непонимании, а в лени.
Слишком категорично, чтобы быть правдой. Во-первых, может быть недостаточно быть развит навык использования неполной индукции. Во-вторых, может быть неприятие (инстинктивное или специально воспитанное — не суть) авторитарных методов управления типа "Делай так, как я сказал, потому что я лучше знаю, что тебе нужно". В-третьих… Множество может быть причин, включая психические расстройства различных спектров.
Druu
19.02.2018 15:50> Но речь шла о демонстрации владении навыка решения задач.
Нет, не шла. Ученику не требуется демонстрировать навык решения задач. Ему требуется демонстрировать наличие наличие навыков использования определенных методов.
> Слишком категорично, чтобы быть правдой. Во-первых, может быть недостаточно быть развит навык использования неполной индукции.
Это все замечательные рассуждения, но к реальности они отношения не имеют. В реальности в 99 случаях из ста все ученик прекрасно понимает, но не делает как дОлжно из-за лени и собственного ЧСВ.
tetramino
19.02.2018 19:31Ну как не демонстрирует?! Навык решения задач определенного типа как раз и демонстрирует выдача правильного результата на достаточно большой выборке задач этого типа.
Оценка по методу черного ящика недостаточна точна и эффективна для задачи обучения людей.
Это обычно не сообщается ученикам перед решением задач.
На этапах, когда они способны осознать, им это обычно сообщают. Со школьниками сложнее из-за не до конца развитого мышления, поэтому зачастую сообщать в некоторых случаях попросту бесполезно.
Druu
19.02.2018 12:42> Для начала сообщить обучаемому какие навыки должна вводить, закреплять и проверять данная задача.
Даже в сегодняшней школе вида 2018 года не бывает такого, что до учеников данная информация не доводится во вполне понятном и однозначном виде. Другое дело, если ученик — дятел, и упорно не захотел эту информацию воспринять. Даже после того, как ему нный раз снизили оценку, и объяснили, в чем дело, _лично_.VolCh
19.02.2018 15:13Не согласен. В лучшем случае обычно доводятся формальные требования к форме решения. Информация о навыках находится где-то в педагогической методологической литературе типа "задачи данного типа должны сформировать у учеников навык такой-то. Особое внимание следует обращать на то-то".
tetramino
19.02.2018 19:33задачи данного типа должны сформировать у учеников навык такой-то
Для формирования навыка не надо об этом сообщать. Зачастую это даже вредно.VolCh
19.02.2018 19:37Тогда потом не надо удивляться "улетучившимся" навыкам, которые закреплены были с мотивацией "чтоб учитель "отлично" поставил".
tetramino
19.02.2018 20:00Тогда потом не надо удивляться «улетучившимся» навыкам, которые закреплены были с мотивацией «чтоб учитель „отлично“ поставил».
По большинству вопросов я с вами согласен, но с данным утверждением согласиться не могу, так как одно из другого не следует, а что из чего следует, всё-таки достаточно неплохо изучили психология и педагогика. И результат следующий: объяснять истинную цель до сих пор следует не всегда.
Druu
19.02.2018 12:37> Почему голый ответ не тренирует навык?
А с чего вы взяли, что не тренирует? Раз речь шла об оценке, то в нашем случае речь не о тренировке навыка (тренировка, очевидно, не может оцениваться), а о его проверке. Записав голый ответ, вы навык не продемонстрировали. Преподаватель ведь должен исходить из фактов, а не из вашего честного «ну я учил»? Вот он и исходит.VolCh
19.02.2018 15:16Есть задача — даю её ответ. Какая ещё демонстрация навыка решения задач нужна?
tetramino
19.02.2018 19:43Путь поиска ответа важен. Вдруг вы пример 2+2 решаете при помощи порождающих грамматик или вообще просто помните наизусть?
VolCh
19.02.2018 20:07Какая разница, если почти всегда я даю верный результат в приемлемое время?
Druu
19.02.2018 20:23Разница в том, что у преподавателя не стояло задачи научить вас бездумно повторять «дваждыдваравночетыре», как попка дурак, стояла другая цель. Конечно, если это хороший преподаватель — но последнее время образование уверенно идет в близкую вам сторону с надрачиванием бездумной расстановки галочек в бессмысленных задачках и прочими подобными прелестями.
tetramino
19.02.2018 23:45Непредсказуемость. Система образования обслуживает экономику по достаточно четким требованиям, и ваш подход в них не вполне укладывается. Это не значит, что он не верен, он просто не подходит, о чем система и сигнализирует отметками.
Я сам сталкивался с аналогичной проблемой, если честно))
bopoh13
19.02.2018 11:35-1Критерии всегда одни: либо понять насколько студент понял материал, либо начихать и завалить.
VolCh
17.02.2018 23:55Основа проблемы что не можешь разобраться в собственном коде полгода спустя (и некоторых багов) в том, по-моему, что при написании кода ты вычеркиваешь из кратковременной памяти то, что уже использовал и не планируешь использовать дальше, например, временные переменные, или, наоборот, держишь в ней некоторый контекст. А позже, разбираясь с этим кодом или держишь в уме ненужные сущности, или зашёл в участок кода без восстановления контекста.
khim
18.02.2018 00:02Основа проблемы что не можешь разобраться в собственном коде полгода спустя
А мне вот что интересно. Я слышу про эту проблему постоянно, но на личном опыте её не наблюдал.
Она вообще — реально существует? Потому у меня возникали проблемы только с пониманием кода, в который полгода кто-то другой втыкал костыли, не пытаясь разобраться в том, что там происходит, но никогда — с пониманием моего собственно кода, написанного что полгода, что 10 лет назад.
То есть да, я вижу места, где я сделал «некрасиво» и сегодня, наверное, сделал бы «красивее», но понятнее… это же мой код — как он может быть непонятным?VolCh
18.02.2018 00:25+1Существует, особенно если напрямую работаешь с неформализованными требованиями бизнеса. Да и просто, попался на глаза какой-то приём, паттерн, формула, теорема, и тут же задача идеально ложащаяся на них. А потом долгое время не используется и выветривается из памяти, пока, как минимум, не возникнет сильная ассоциация.
khim
18.02.2018 02:14Существует, особенно если напрямую работаешь с неформализованными требованиями бизнеса.
Ok, будем знать.
А потом долгое время не используется и выветривается из памяти, пока, как минимум, не возникнет сильная ассоциация.
Ну не весь же вы код так пишете!
То есть, да, могу допустить, что среди всего написанного мной кода найдутся несколько процентов, которые мне самому будет сложно понять. Но пока — такое не попадалось, так что особенно заморачиваться на эту мне кажется странным.
VolCh
18.02.2018 00:20Что я хотел сказать в целом: даже при одинаковых когнитивных способностях маловероятно, что код будет одинаково понятным в момент написания и в момент чтения, если контекст сильно поменялся. На только что написанный код надо смотреть пускай не глазами «троечника», но хотя бы своими глазами вне контекста, вычеркнув всё, что не касается локальной области видимости, максимум одной над ней, а лучше даже текущего экрана с размером не более 25 строк максимум. Лучше выделить (разумно) куски текущей подпрограммы в отдельные подпрограммы без всякой надежды на повторное использование, чем через полгода разбираться, что ты имел в виду. Не можешь выделить — напиши себе комментарий, восстанавливающий контекст. Например, ссылку на описание алгоритма типа RSA-шифрования, который ты реализовал, не разбираясь в нём настолько, чтобы логтчески что-то выделять.
vladob
18.02.2018 00:14-1Спасибо за статью.
Исходные положения в статье близки к моим собственным представлениям о предмете.
Пропускают промежуточные выкладки и записывают результат тогда, когда им не нужно думать, потому что знают .
Много кода пишут, когда не знают, но настойчивы.
Хороший программист может писать много кода, который может выглядеть неряшливым…
А вы видели что пишут математики или физики-теоретики на салфетках в ресторане?
Это потом хороший программист отрефакторит, до такой степени, чтоб даже сопливому "духу" показалось, что он тоже так может.
А физик запишет окончательное:
E=m*c^2GeMir
18.02.2018 00:25А физик запишет окончательное E=m*c^2
А физик, знакомый с TeX, аккуратное:
;)vladob
18.02.2018 00:57:) Хотел.
Не решился. Пробую...Я дописывал формулу уже когда редактировал свое сообщение, после того, как случайно сабмитнул раньше времени. Не увидел значка формулы и не стал исследовать, возможно ли это в режиме редактирования.
Markdown при этом почему-то не кликнулся.
А режим редактирования Хабр включает на очень короткое время (на что я напоролся раньше), посему спешил.
Можно я здесь попробую? :)
$$display$$E=mc^2$$display$$
Ну вот же — не сработало… :(
gaploid
18.02.2018 01:11Я не думаю, что чем длинее код, тем умнее автор. Наоборот очень сложно сделать инкапсулированную логику и разбить ее на части заранее, что бы можно было их реиспользовать позднее.
vladob
18.02.2018 02:22И я не думаю.
Автор тем умнее, чем больше сложных задач он может решить.
Комфортный для человека способ достижения одной и той же цели может различаться для разных людей.
Одни летят самолетами, вторые плывут пароходами…
Длина/объем кода, сгенерированный в процессе разработки и потом убитый — одна вещь.
Неструктурированный, с кучей мусора код в продакшене — другое.
ragequit
18.02.2018 01:24>У нас, технарей, рабочая память для хранения «технических» элементов объёмнее, чем у гуманитариев.
Учился в МРТИ, пропускал целые цепи интегральных вычислений (что было понятно только преподавателю, но не отличникам), в итоге — гуманитарий и филолог.
Что-то в вашей логике не так.vladob
18.02.2018 01:38Видел довольно много «технарей», перешедших
на сторону злав гуманитарии, менеджеры, идеологи — во времена, когда это было выгодно.
По пальцам могу пересчитать гуманитариев, ставших отпетыми технарями даже сейчас, когда технарем вроде как проще выжить.
Ваш случай только показывает, что множества, на которые мы лепим ярлыки «технарь», «гуманитарий», «длинная память», «короткая память» — это нечеткие множества.ragequit
18.02.2018 01:46Суть в том, что меня «натаскивали» в технари с малых ногтей, я с чистой совестью и сердцем мечтал стать инженером, но перешел на сторону гуманитариев, причем гуманитариев в чистом виде: меня захватывает язык (русский, белорусский и английский), морфология, фонетика и все то, что было презренно мной в качестве технаря.
//На самом деле изучение русского языка — главный и огромнейший вызов в моей жизни и я не уверен, что ее хватит на то, чтобы освоить его в должной мере//vladob
18.02.2018 02:05Привет земляку! :)
Я же и говорю — границы условны, их, может, четких и вообще нет.
DoctorMoriarty
18.02.2018 21:39А есть и иная группа. Не уклонившихся ни в
ересьоднобокость технарства, ни в однобокость гуманитарщины. Но черпающая в методологии из обоих подходов, прекрасно взаимодополняющих.
"Специалист подобен флюсу" (с)vladob
19.02.2018 00:12Я бы предпочел чтобы такое качество — не впадать в крайности и не возносить их — признавалось бы нормой.
Но узкая специализация в некоторой области дает конкурентное преимущество во внутренней конкуренции.
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!
firk
18.02.2018 02:54Это не огромная функция. Она просто не маленькая. А с учётом того что половина строк в ней — пустые, комментарии или фигурные закрывающие скобки — она на самом деле меньше чем кажется. Огромная это например вот.
Error1024
18.02.2018 03:02Безусловно, есть и бОльшие функции нежели эта, данная функция пример функции имеющей большой «когнитивный» размер — очень много надо неочевидных связей держать в голове, написать ее было сложно, читать спустя время — не менее сложно. При том что имел дело с функциями под 700 строк, но достаточно линейными, чтобы не вызывать сложностей в написании/чтении.
charypopper
18.02.2018 10:25+1почему бы не использовать inline чтобы выделить какое то поддействие?
Error1024
18.02.2018 16:04По причине того что inline лишь «рекомендует» компилятору заинлайнить функцию, кроме того это код на C89.
Кроме того, от разделения конкретно этой функции на «действия» станет только непонятнее ее работа.
DistortNeo
18.02.2018 15:54Вполне нормальный и читаемый код. Кстати, не стоит бояться бить функцию на мелкие — с оптимизацией в современных компиляторах не всё так ужасно.
Если есть желание, можно переписать то же самое на C++ — будет компактнее.Error1024
18.02.2018 16:06Данная либа должна компилироваться везде, где только есть более-менее работающий C, поэтому доверить inline компилятору я не могу.
firk
18.02.2018 19:54Для сокращения коротких участков кода в ещё более короткие можно использовать макросы — они гарантированно «инлайнятся». Но в этой функции это ни к чему, с ней и так всё в порядке.
Kobalt_x
18.02.2018 20:54а потом очень долго искать ошибку при помощи препроцессора и страдать при отладке этого кода в макросах, т.к. информация о символах как правило генерится по препроцессированному коду
Error1024
18.02.2018 23:33А еще в «функциях»-макросах не создать локальных переменных(про C), что приведет функцию в вид фарша.
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 — давать им выглядеть как функции с возвращаемыми значениями. Но и без этого уже есть возможность не пачкать внешнее пространство.
Error1024
19.02.2018 13:07Так можно делать только с С99 или при наличии у компилятора соответствующего расширения. В C89 так нельзя.
netch80
19.02.2018 15:06Вы с прямым углом перепутали, то есть с определением переменных после первого исполняемого оператора блока.
Определять переменные в начале любого блока до первого исполняемого оператора допускается и в C89, и ранее (от ANSI-85 и вплоть до исходного K&R, в той версии, как он попал в книгу), они будут существовать в пределах этого блока.
alexunder
18.02.2018 02:37Вообще, это называется unconscious bias. В крупных компаниях один из первых тренингов о том, как не быть предвзятым к чему-либо. В данном случае «отличник», «троечник» — ненужные категории, они привели к холиварчику в комментариях, приведут и на работе. Пишите понятный код — вполне себе вывод без всяких предрассудков.
apapacy
18.02.2018 03:00Согласен абсолютно. Пока предубеждения касаеются технических вопросов это просто раздражает. Когда касаются людей это немного страшно. Когда руководство это не присекает а поощряет работа прерващается в абсурд. «Саймон сказал ...»
Treg
18.02.2018 02:55Из опыта могу сказать, что программист != математик. Программист — он больше стратег, архитектор, обладающий сильным объемным мышлением. А математик — тактик, который может оптимальнее решать локальные задачи какими-то сложными формулами и алгоритмами, но в больших масштабах его код будет чрезмерно мудреным, что пойдет только во вред.
BOM
18.02.2018 03:27Откуда у автора уверенность в том, что для написания длинных функций необходимо обладать какими-то особыми навыками, отличной памятью и незаурядным интеллектом? Писать длинные лапшеобразные функции как раз таки очень и очень легко и именно такой код и пишут все начинающие программисты, потому что это написание кода в потоке, которое встречает минимальное сопротивление. Сам помню, когда я начинал писать функцию, понятия не имея, что я буду писать дальше, и по ходу написания сотой строки по двадцать раз пробегал глазами по всему написанному, чтобы вспомнить, чего я там нагородил и какой из if-else отвечает за тот результат, который я сейчас использую.
Следовать DRY, SOLID и какой-то осмысленной архитектуре сложнее на порядок, чем впихивать невпихуемое в один составной оператор. Именно поэтому длинные раздутые контроллеры пишет каждый второй вкатившийся в айти, а до проектирования нормальной архитектуры дорастают единицы.
Когда я вижу функцию из 300 строк, последнее о чем я могу подумать, так это о том, что этот код писал отличник.
Писать длинные функции легко и с хорошей памятью это никак не коррелирует. Это, несомненно, очень энергозатратный процесс, но не более.
shybovycha
18.02.2018 03:38Столько умных фраз для описания различия между опытным
разработчикомспециалистом и малоопытным...
Пример с математикой считаю не совсем корректным — в зависимости от постановки задачи требуется либо показать последовательность действий (требует записи по шагам), либо предоставить результат (требуется только конечный результат — так зачем заморачиваться?).
В программировании же все несколько иначе — код пишется для других программистов, которые будут читать или даже модифицировать решение через некоторое время. И скорей всего автор исходного кода не будет присутствовать при его чтении чтобы дать объяснения почему так а не иначе код был написан.
А уж работа компилятора — сделать из исходника оптимальный набор инструкций. Да, иногда приходится писать хитровыдуманные извращения с целью помочь компилятору сделать более оптимальный бинарник.
И вот понимание факта, что твое решение будут читать другие люди, не всегда оперирующие теми же понятиями и разбирающимися в специфике области и проекта, и отличает опытного специалиста от малоопытного. Комментарии, тесты и прочие изголения выглядят излишней тратой энергии и времени в глазах джуниора (сам таким был), но они-то и были придуманы затем, чтобы решение не требовало приложенного автора, который объяснял бы ход своих мыслей всем читающим.
BOM
18.02.2018 03:54Мне кажется, что если кто-то не понял твой код, то это необязательно означает, что он менее опытен и меньше разбирается в специфике области и проекта. Джуниоры частенько такой код могут нагородить, в котором сеньор не сразу может что-то понять и со словами «Слышь, что за нафиг» зовут автора строк объяснить, зачем он встроил тернарный оператор с присвоением в тернарный оператор с анонимной функцией, которая по итогу окажется нерабочей и всегда возвращающей пустой массив, когда на самом деле можно было обойтись двумя строками с if.
shybovycha
19.02.2018 01:44Вы неправильно поняли суть моего комментария — имелось в виду, что менее опытные разработчики пишут код "в потоке мысли", который тяжело понять другим специалистам (неважно какого уровня).
BlackSCORPION
18.02.2018 10:32Может умение держать в памяти много обьектов и дает какое то преимущество в программировании, но НЕ ключевое, меньшее кол-во багов при первом запуске и вроде того.
Имхо талантливого программиста отличает умение быстро находить оптимальное решение проблемы, стабильно, раз за разом. Некая способность к инсайту, способность видеть суть так как не могут видеть другие. Возможно это более мощная концетрация, чем у среднего человека, воображение, мотивация но точно не обьем оперативки, так как иногда допускают банальные ошибки которые любой джуник сразу заметит. Некое внутренее чутье которое помогает им смотреть почти всегда сразу в нужную сторону.
nefedovgeka
18.02.2018 10:33+2В детстве мне казалась скучной алгебра и я пребывал "на своей волне" на уроках, благодаря чему имел по ней "3". Во время контрольных я решал задачи исходя из моей логики не зная того как преподавали решение, мое решение не засчитывали так как ход его был не правильный но результат правильный. Вот от куда берутся "троечники" у которых потом бизнес и все в жизни отлично)).
a4k
18.02.2018 10:44+2Ученики послабее записывали решение по шагам и тратили существенно больше времени.
Нам, отличникам, всё это ни к чему. Зачем писать столько ненужных промежуточных действий, когда можно сразу готовый ответ? Мы же хотим поскорее разделаться с этим примером, чтобы перейти к следующему!
Гипотеза. Чем умнее программист (чем более объёмной рабочей памятью он располагает), тем более длинные методы и функции он пишет.
Какой-то странный для меня вывод.
Имхо как раз логичнее будет что троечник привыкнув расписывать все по шагам будет так же писать длинные методы. К тому же писать код в одном большом методе на много проще чем разбивать его на меньшие.
Троечнику сложнее думать абстрактно чем отличнику, а что бы писать короткие методы надо держать в голове код других методов вынесенных из текущего, а в идеале держать в голове весь код, что бы повторно использовать уже существующий код.
А портянки можно писать особо не запоминая даже что делалось на 10 строк выше.SergeyGalanin Автор
18.02.2018 11:16Вот критика по существу вопроса. Спасибо!
Я проводил такую аналогию. Тот, кто привык решать задачу, записывая каждый маленький шаг, тот и машину будет программировать так, чтобы она продвигалась к решению маленькими шагами. А тот, кто привык получать сразу готовое решение «из головы», и машину запрограммирует так, чтобы она тоже выдавала готовый результат без фиксации промежуточных шагов.
Разумеется, такая индукция не может претендовать на полноту. Не всякий «отличник» будет писать исключительно готовые решения, и не всякий «троечник» будет придерживаться принципа единственной ответственности.anjensan
18.02.2018 12:35Тот, кто привык решать задачу, записывая каждый маленький шаг, тот и напишет большую портянку кода. А потом будет ее итеративно рефакторить, маленькими шажками, разбивать все это дело на меньшие куски. Вероятно будет.
А тот, кто привык получать сразу готовое решение «из головы» (замечу, короткое решение!), и для машины сразу напишет готовое решение «из головы». И оно тоже будет короткое.
theArhar
18.02.2018 13:03+1Самый главный вопрос, который не увидел в комментариях — откуда такие умозаключения?
Для подобных выводов необходимо изучить довольно большое количество людей, их код и корреляцию с их уровнем интеллекта.SergeyGalanin Автор
18.02.2018 14:11А выводов-то, собственно, ещё и нет. Я же написал: «гипотеза». То, что она не очевидна, не значит, что она не имеет права на существование. Да, она ещё не подтверждена, ну так ведь и не опровергнута. Большинство доводов «против» мне кажутся такими же туманными, как моим оппонентам — мои доводы «за». Хотя никаких особенных доводов я и не стремился приводить — так, высказал идею, предположение.
Брайан Фитцпатрик и Бен Коллинз-Сассмэн в книге «Идеальная IT-компания» в первой же главе утверждают и доказывают, что любую идею нужно выносить на обсуждение. Иначе высока вероятность наделать ошибок в самом начале пути, когда их цена особенно высока. Кому интересно — пункт «Скрываться вредно».
Подтверждение гипотезы — вопрос времени и будущих усилий. Наблюдения, эксприменты, анализ кода, плотное изучение когнитивной теории, наконец.
urgotto
18.02.2018 13:07Интересная статья, вот только, как мне кажется, не правильная. Автор описывает «озу» так будто это один из главных критериев интеллекта, при этом считая, что, как он выразился, «умные» люди пишут длинные и сложные алгоритмы, а это как-раз совсем не так, в данном случае показателем интеллекта как раз будет код, который больше похож на те формулы, что троешники писали в школе потому-что именно способность разделить проблему на минимально допустимые, в пределах контекста, составляющие отличает хорошего программиста от плохого.
dikkini
18.02.2018 14:17+3Вся статья — ЧСВ отличника. Чтобы быть умным — не надо решать примеры в уме. Чтобы писать длинные методы — не надо помнить в голове 78 (!!!) объектов, можно писать метод в умной IDE и получать автокомплит и прочие фишки. А умение решать примеры в голове — еще не говорит, об интеллекте или уме человека. Итого: отличник != ум, длинный метод != автор отличник, оценки в школе/универе не влияют на итоговые умственные способности человека.
Arris
18.02.2018 15:57Лично для меня нет проблемы удержать в памяти длинный, на 120 (или даже 300) строк метод. У меня есть такие ;) Мало, но есть.
Просто комментарии расставляешь и пишешь попроще, а если где-то применяешь изящную магию — сам себе оставляешь пометку «как это работает» (через несколько месяцев возвращаешься, читаешь, удивляешься и думаешь — да, черт возьми, красиво же).
Что для меня проблема — так это удержать в сознании несколько (>3 в среднем) уровней абстракции. Особенно если промежуточные слои не несут никакого практического смысла, а сделаны ради «красивого кода», «красивого оформления методов» итп.
Когда начинаются слои абстракции ради абстракции в стиле «я сделал еще один слой абстракции бикоз ай кэн» — это больно. Потому что приходится удерживать в памяти слой трансляций из одного представления в другое, при этом практического смысла эти трансляции не несут.
P.S. К примеру, разбираясь с библиотекой аутентификации Laravel/Sentinel, я чувстововал реальную боль.VolCh
19.02.2018 11:37+2Абстракции для того и создаются, чтобы не держать в голове уровни под ними. Другое дело, что бывает, что абстракции текут, или задачи ставят сразу на нескольких уровнях, типа "в столбце N отчёта "агрегированные показатели подразделения за отчётный период" должна быть сумма столбца К из таблицы T базы данных D отнесённая к средневзвешенной численности подразделения".
Arris
19.02.2018 16:07Но когда приходится искать чужую багу и разбираться, как это все работает — приходится удерживать в голове всю эту иерархию. А уж когда по библиотеке документация практически отсутствует, поведение функций отличается от описанного в документации, а слои абстракций создавались в стиле «смотрите, я могу» — это превращается в ужас.
Нет, я понимаю необходимость абстрагирования. Но у этого должна быть цель, а не «вводим два слоя абстракции ради красивой реализации геттера и сеттера».VolCh
19.02.2018 17:25+1Если приходится удерживать именно иерархию, значит очень дырявые абстракции. Наверное, являются абстракциями синтаксически (класс, интерфейс), но ничего по факту не абстрагируют.
emacsway
20.02.2018 02:11Если абстракции текут, значит, инкапсуляция не выполняет своей функции по защите абстракций) Так всегда бывает когда нет должного внимания к качеству инкапсуляции.
khim
20.02.2018 03:06К сожалению вашу фразу можно сократить до так всегда бывает. Очень мало абстракций, которые действительно никогда не текут. Как какой-нибудь TCP, который превращает ненадёжное средство доставки в надёжное… но так вещь не бывает! Если я кабель выдернуть — как вы куда-либо что-либо «надёжно» доставите? И как «качество инкапсуляции» вам поможет?
Smey
18.02.2018 16:46Гипотеза интересная, но лично мой опыт её не подтверждает.
Мне кажется, что размер метода в первую очередь связан не с уровнем знания предметной области (назову это так, терминология «отличник — троечник» сомнительна), а с особенностями мышления. Т.е. есть конкретные люди, которые при любой возможности пишут большие методы.
AxisPod
18.02.2018 19:29Умозаключение основанное на 1 человеке, это даже не совпадение и тем более не статистика. Я могу писать крайне непонятный код, но я этого не делаю, потому что мне же придётся его поддерживать, а потом и самому понять сложно. Единственное исключение было в оптимизациях на ZX-Spectrum и борьба за байты и такты. Шаблонную магию в C++ не считаю непонятным кодом и тоже всё же стараюсь делать аккуратно и понятно по максимуму.
SergeyGalanin Автор
19.02.2018 10:46+3О боже, спектрум! Какие воспоминания!
Да, борьбу за байты помню как сейчас. Был у меня тогда самодельный набор хакера. В zeus assembler написал утилитку, которая позволяла делать разнообразные дампы, а потом и дизассемблировать код. Утилитка «жила» в экранной памяти, в средней и нижней трети, чтобы остаток от 48К ОЗУ был свободен для подопытных программ. Когда писал дизассемблер, дозволенные 4 Кб закончились, и пришлось переписывать весь дизассемблер с нуля. Получилось, да ещё несколько сот байт дополнительно освободилось.
Много чего в той утилитке было: к полному дизассемблеру Z80 — дампы памяти в десятичном, шестнадцатеричном и символьном видах, в виде спрайтов, поиск байтов и слов, плавная попиксельная прокрутка рабочей области экрана, потом собственный загрузчик добавился и ещё что-то там — не помню.
Сам zeus я тоже дизассемблировал. Хотел стырить код для парсинга команд, и нашёл внутри команду «What is the meaning of life?», которая всегда выдавала какие-то «42» и ничего больше не делала. Тогда я ещё не читал Дугласа Адамса и не понял прикола.
sand14
18.02.2018 21:59В статье под отличниками понимаются отличники-математики?
Если при разработке ПО действовать как математики, то код действительно может получиться "непонятным".
Сократили дроби (убрали вывод формулы и получили итоговое решение) — точнее, сократили число слоев абстракций, а где то еще для "упрощения модели" сделали и протечку абстракций.
Но разработка это прежде всего технология, и уже потом — искусство и наука.
Сокращать и протекать абстракции тут нельзя.
Тут важна не готовая "формула", а прослеживаемость ее вывода и масштабируемость — получение новых "формул" путем небольшого подкручивания параметров в слоях абстракций.
Если же имеет место готовая "формула", то при изменении требований ее придется полностью переписывать, точнее, с нуля выводить новую формулу.
На примере:
Пусть у нас есть Web API, реализованное в виде MVC.
Если кому-то придет идея "а давайте упрощать модель — пусть к слою данных напрямую обращается контроллер, а то этот контроллер сейчас какой пустой", то в этот момент проект "приехал".
netch80
18.02.2018 22:13Функция composite_cut в примере безусловно плоха, но описание того, чем именно она плоха, не ложится на понятия отличников или троечников. Её проблемы не в количестве сущностей — там как раз нормальное структурирование. Сложно не понять, что она делает. Сложно это доказать, хотя бы самому себе. Суть проблемы — она попросту нетестируема. Как бы автор или читатель не был уверен в корректности, тесты для такой задачи необходимы — например, чтобы подтвердить соответствие нижележащего API ожиданиям, воплощённым в коде, или просто отловить банальные опечатки, на которые «глаз замыливается» даже у лучшего отличника. Здесь имеем несколько этапов, результаты которых используются для следующих этапов, но проверить их по выходным данным сложно или просто нельзя. Эту тему хорошо отработал, например, Майкл Физерс, вместе с методами решения, не буду повторяться, кроме того, что её надо было именно для этого разрезать на несколько независимых частей.
Точно так же, необходимость следить при визуальной верификации за тем, что результаты предыдущих этапов не портятся до их использования в результате коллизий имён, сильно усложняет визуальную верификацию. (Программную — не рассматриваю, в силу её редкости и дороговизны, но визуальную — вплоть до простого код-ревью — необходимо учитывать и способствовать ей.) Тут ещё и не было необходимости, как мне кажется, экономить на вызовах подфункций.
Как отличники, так и троечники могут обладать высокой внимательностью к деталям, а могут не замечать на ровном месте ошибки типа anspk вместо anpsk (пример реальный с точностью до букв — я с таким боролся в старом фортрановском коде). В крупных неразделённых блоках кода гарантированно следить за целостностью (через длительное развитие и изменение) могут только люди с определёнными классами отклонений (например, аутизм). Таких, увы, сложно найти, большая редкость — чтобы ещё и программировали; но если и найти — их невыгодно использовать из пушки по воробьям.
Karpion
19.02.2018 04:03У меня есть чёткое ощущение вида «количество функций примерно соответствует количеству слоёв абстракции». А современный мир как раз страдает избыточностью слоёв абстракции — причём эта избыточность как раз затрудняет понимание системы (не говоря уж о замедлении работы и об увеличении расхода памяти).
Допустим, программист уложил необходимую работу в 150 строк кода. Что улучшится от того, что он разобьёт этот код на пять функций по тридцать строк? Добавятся имена функций? Ну так можно вписать эти имена в виде комментариев в исходные 150 строк и не париться.
Т.е. задача сводится к подробному комментированию кода, и всё.
Ну, функции обладают полезной возможностью использования локальных переменных. Ну так и линейный код тоже может использовать локальные переменные внутри фигурных скобок.
И ещё:
Похоже, автор полагает, что код надо написать так, чтобы его мог прочесть и понять слабый программист. Причём с малым расходом сил.
Хм-м-м… А может, надо поднимать планку и не пускать в профессию слабых программистов?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% тех, кто сейчас успешно работает. Повторюсь — в отрасли останутся аутисты и безумные гениальные счётчики в уме. Вы тоже будете выкинуты на мороз, аутисты не пишут такие комментарии на хабр :)
Karpion
20.02.2018 01:52нельзя временно навесить const на переменную, а потом его снять
Вы что-то не сообразили:
В каждой части я могу объявить локальными переменные, которые в ней вообще не используются. Это значит, что даже если внутри этой части что-то делается с этими переменными — наружу последствия этих действий не вылезут.
Это я чисто на тему «можно или нельзя» — но не на тему «надо или не надо так делать».
А в случае раздельных функций это выполняется примитивно и прямолинейно — foo и buka просто принимаются как результат 1-й подфункции (неважно, как часть возвращаемого значения, по указателю, по ссылке, как-то ещё) и не передаются во 2-ю, а в 3-ю и 4-ю передаются только по значению (копируются).
А вот это уже серьёзный аргумент.
Второй — обеспечение доверия к качеству реализации через тестирование.
Тоже хороший аргумент.
Но там нет возможности запретить видимость переменных внешнего блока.
Гы! В классическом Pascal даже выделение кода в функцию не спасает от возможности поменять глобальную переменную.
Если требовать от программистов абсолютно высокого внимания ко всем деталям, то придётся выкинуть 99% тех, кто сейчас успешно работает.
А может, станут меняться программисты и система образования?netch80
20.02.2018 10:42В каждой части я могу объявить локальными переменные, которые в ней вообще не используются. Это значит, что даже если внутри этой части что-то делается с этими переменными — наружу последствия этих действий не вылезут.
Вы имеете в виду вариант: чтобы не менять внешнюю foo, мы объявляем свою foo, но не используем её?
Если нет, то какое это имеет отношение к тому, как защититься от изменения этой переменной кодом, которому не положено это делать?
Если да… ну, возможно, в качестве очень грязного и очень странного трюка это можно рассмотреть. Но тогда надо подавить все варнинги на тему затенения и неиспользования переменных… вред от этого подавления может быть даже больше.
Гы! В классическом Pascal даже выделение кода в функцию не спасает от возможности поменять глобальную переменную.
Для глобальной — так это точно так же и в C, C++. Это один из недостатков глобальности.
Но в классическом Pascal можно делать у процедуры несколько блоков var, и если вложенная процедура объявлена после первого, но до второго, она не увидит переменные охватывающей процедуры из второго var. Этим можно активно пользоваться. (Вместо процедуры Pascal тут везде могут быть и функции.)
Для C аналога такой вложенности не существует, если не смотреть на расширения GCC; для C++ это лямбды с явным заданием используемых переменных.
А может, станут меняться программисты и система образования?
На какую? 90% будет занимать дрессировка внимательности к тончайшим мелочам и точного воспроизведения одних и тех же действий? Самим превращаться в компьютеры?
Я понимаю делать такое там, где людям самим интересна точность и воспроизводимость результата (например, в живой музыке). Но при анализе кода… не буду возражать, но выражу очень плотные сомнения. Если пока что движение в основном было в противоположном направлении — завлечь разнообразием и качеством средств и подходов тех, кто не был готов писать на предыдущих поколениях (например, не хотел мучаться с управлением памятью в unmanaged средах) — наверно, к этому есть не только рыночные причины.
VolCh
19.02.2018 11:49Похоже, автор полагает, что код надо написать так, чтобы его мог прочесть и понять слабый программист. Причём с малым расходом сил.
Хм-м-м… А может, надо поднимать планку и не пускать в профессию слабых программистов?Что, в общем случае, значит "не пускать"? Ввести строгое госурегулирование типа как у врачей? С одной стороны, а кому это надо? С другой, результат всё равно будет далёк от ожидаемого.
Полно аналитики, показывающей, что рынок испытывает большой дефицит разработчиков. Огромные ресурсы тратятся на то, чтобы его ликвидировать и заметная их часть тратится на уменьшение порога входа в разработку.
firk
19.02.2018 12:24Что, в общем случае, значит "не пускать"? Ввести строгое госурегулирование типа как у врачей?
Думаю, имелось ввиду — наплевать на их существование и делать всё так, как будто их нет. Таким образом вы поставите свою долю преград на их пути, по крайней мере к вашему коду.
VolCh
19.02.2018 15:27Так я рискую обрушить свою профессиональную репутацию до уровня "волшебника", которому лучше ничего не доверять, потому что всё работает на базе непонятной магии.
Karpion
19.02.2018 20:50Почему-то во многих профессиях, от которых зависит жизнь людей, есть контроль качества работников. Даже водителей контролируют. А программистов — не контролируют, при том, что они уже зачастую работают с очень опасными системами, от которых зависит очень многое, в т.ч. жизни людей.
Критические приложения надо расписывать? Или сами знаете?
Я не знаю, как именно «не пускать». Это можно обсудить здесь.
Но как минимум — надо вводить ответственность программистов за косяки. Например, когда BIOS зависает, если размер HDD превышает 32 гигабайта (олдфаги помнят) — то такого программиста совершенно точно надо репрессировать. Ну или репрессировать того, кто допустил их до написания BIOS. Репрессии отпугнут долбоклюев и фуфлогонов. А вот угроза увольнения — не отпугнёт, это вполне очевидно.
Мне кажется, Вы не понимаете, что тупой программист создаёт потребность в программистах.
Тупой криворукий дебил пишет любую программу — и на сопровождение этой программы приходится бросать армию тупых программистов, т.к. приличный человек не способен вынести тот треш, угар и содомию, которую налепил моральный урод. А на рефакторинг, как всегда, нет денег и времени.
Тупой криворукий дебил пишет Windows — и на борьбу с косяками Windows требуется бросить армии прикладных программистов.
Надо не понижать порог входа в программирование, а повышать уровень специалистов. Увы, но повсеменстно деградирующая система образования на это не способна — благодарите толерастов, которые добились запрета дискриминации альтернативно одарённых и добились пропорционального представительства разных национальностей в профессии. Тьфу, срамота!
Upd: А что качается «обрушить свою профессиональную репутацию до уровня „волшебника“, которому лучше ничего не доверять, потому что всё работает на базе непонятной магии» — так надо прямо в коде писать комментарии с указанием нужной потребности в квалификации. Например, «эту функцию имеет право редактировать только тот, кто освоил предитикативную алгебру» (и хорошо бы указать список литературы).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. И что — отвлекать ценного спеца для выравнивания отступов в коде?
emacsway
19.02.2018 05:45+1У автора, безусловно, есть неплохой потенциал писать грамотные статьи, но боюсь, что в данном конкретном случае его статья еще больше запутывает и без того непонятную для многих тему качества кода.
По поводу влияния памяти автор сказал совершенно верно, в основе качественного кода лежит магическое число семь.
Кстати, слово refactoring происходит от математического слова факторить (фактор), т.е. декомпозиция. Декомпозиция — как способ управления сложностью, чтобы детали реализации рассматриваемой обязанности не превышали это число 7.
Но… проблема умных людей в программировании действительно существует. Хорошо раскрывает эту тему Кент Бек в книге «Экстремальное программирование». Особенно это хорошо заметно в России, где алгоритмический аспект программирования часто превосходит коммерческий аспект сопровождаемости программы.
На самом деле, если «умному человеку» дать немного знаний по экономике разработки ПО, а книга Бека является лучшим пособием по этому вопросу, то проблема исчезает.
Druu
19.02.2018 10:34> У нас, технарей, рабочая память для хранения «технических» элементов объёмнее, чем у гуманитариев. Чем больше памяти, тем больше промежуточных шагов мы можем накапливать в ней, не записывая.
Промежуточные шаги никто не накапливает и не сохраняет, они _пропускаются_. Условный отличник из примера отличается не тем, что выполняет действия в уме, а тем, что он их вообще не выполняет. В принципе. Он сразу знает (из опыта) что в случае Х результат Y, без декомпозиции задачи на подзадачи.
А размер кратковременной памяти у всех людей практически одинаков, так что никакого существенного влияния он не оказывает. Оказывает та самая способность «пропускать шаги».SergeyGalanin Автор
19.02.2018 11:22Бывает и так, но не всегда. Не все задачи нам раньше попадались, не на все ответ мы знаем. Иногда приходится решать новые, незнакомые задачи. Некоторые несложные вполне по силам и в уме решить.
Druu
19.02.2018 12:52> Иногда приходится решать новые, незнакомые задачи.
Если задача совершенно новая и незнакомая, то, внезапно, ваша «технарскость» вам ничем и не поможет по сравнению с гуманитарием.
sondern
Вы не думаете что могло быть так, что сначала было написано 1500 строк, а потом за несколько проходов оптимизировано или воообще переписано? Тогда не надо голове держать много. Наверное есть гении которые сразу пишут оптимизированный код, но я думаю что это больше связано с опытом а не с тем скольк можно в голове удержать.
SergeyGalanin Автор
Согласен с каждым словом. Примерно так я и сам часто пишу, и собираюсь рассказать об этом в следующем посте. Более того, наши гуру-наставники советуют всегда рефакторить код после написания, потому что хороший код никогда не получается с первого раза. Так что сначала 1500 строк, а потом рефакторинг — это нормально и правильно.
Способность писать сразу понятный код именно что связана с опытом, а не со способностью удерживать в памяти много объектов.
Только вот чтобы сначала написать 1500 строк, нужно их всё таки все держать в памяти. А во вторых, рефакторинг 1500 строк до 10 раз по 150 — это не очень хороший рефакторинг. Надо тогда уж хотя бы до 100 раз по 15.
php7
На одном месте я видал ваши рефакторинги на 100 функций по 15 строк.
HueyOne
Логичнее писать псевдокод, его оптимизировать, а потом уже реализовывать (и еще раз оптимизировать). Сам псевдокод можно оставить в комментарии к исходнику.
Bringoff
1500 строк псевдокода — хотелось бы посмотреть :)
HueyOne
Любую книгу по алгоритмам откройте.
Хотя современным «программистам» зачем оно…
marsermd
… И вы там не найдете такого псевдокода:)
Алгоритмы обычно более короткие.
HueyOne
Распишите-ка алгоритм, например, работы банкомата с картой.
marsermd
А такого вы и не увидите в книгах по алгоритмам.
Вы можете увидеть псевдокод RSA, можете увидеть декартово дерево. Но до 1500 строк там очень далеко:)
AllexIn
Нельзя на псевдокоде писать алгоритмы. Одна из проблем псевдокода — отсутствие спецификации.
Простой пример — двойное отрицание над int в С++.
Двойное отрицание дает нам приведение к строгому bool.
Но в псевдокоде что даст двойное отрицание? Это будет логическая операция или бинарная? Конкретно в случае двойного отрицания понятно, что оно бессмысленно в случае бинарной операции. Но в любом случае однозначности нет.
VolCh
Язык псевдокода может быть достаточным образом формализован и однозначен. Основное его отличие от языка программирования лишь в том, что он не предназначен для исполнения машиной, например, написан исходя из предположения бесконечной памяти и скорости.
HueyOne
Большинство нынешних «разработчиков» это и есть машина для исполнения псевдокода. Причем, очень некачественная.
PS и да, если вы не можете написать свои сишные уродцы типа «двойного отрицания над int» русским языком, то ваш код сразу можно выкинуть в помойку. Только там место недокументированному коду. Такому коду нельзя доверять, пока его сам не проверишь целиком. А, значит, проще написать заново.
VolCh
Математически строгая верификация кода очень трудоемка, если вообще возможна в общем случае. Так или иначе, коду приходится доверять и неважно кто его писал.
HueyOne
А потом у нас у всех хартблид или иные факапы сходного масштаба
HueyOne
то, что тут написано, и есть псевдокод.
в чем проблема написать «строгий boolean»?