Pull to refresh

Comments 260

Боже, сколько букв… Если я все прочту, я стану хорошим программистом?
Хуже точно не станете.
Станете хорошим если будете много писать кода, а так эта статья сродни GTD-статьям — вроде все правильно, а все равно читать это в сотый раз уже опостылело.
Можно всю жизнь писать очень плохо плохого кода. А можно — прочитать хоть раз подобную статью и задуматься.
Я вот тоже после каждой статьи про «правильный» код, про «правильное планирование» задумываюсь — только вот результаты у меня улучшаются только после того как я делать что-то начинаю, а чаще переделывать.

Если этот код никому не сдавать, не находить в нем баги, не делать саморевизии, делать все время разные задачи, то ясен перец, что какашка будет выходить. Но дважды написать какашный код для одной и тоже задачи — нонсенс.
А Можно пойти работать в компанию где практикуется code review и следование корпоративному(проектному) code convention и начать писать лучше уже после первого же ревью
Одно другому не мешает, разумеется. Есть куча способов писать хорошо. Но code review не сможет дать понятия, например, чем класс отличается от объекта, и прочим неочевидным вещам не научит. Игнорирование последних может научить «писать так, потому что я так вон там видел».
точно, без статьи никак:)
Задуматься и продолжить писать «очень плохо плохого кода».
Тогда не понятно, по какой причине вообще человек пишет код.

И какой смысл был указывать на мою опечатку? Вроде общеизвестно, что комментарии исправлять нельзя, но, немного пораскинув мозгами, можно дойти до того, что вместо «плохо» должно стоять «много». Или Вы намекаете, что я должен был написать еще один комментарий, с принесением извинений всем, чью психику я потревожил?
В отличии от статей по GTD, тут указаны конкретные ошибки, типа слабое знание платформы, не использование _название_фичи_ и пр. Вдруг кому-то поможет? Мясо явно больше, чем в большинстве статей по GTD.
Вас просто могут уволить за то что вы читаете вместо работы ;)
Да тут прямо руководство «как надо жить»
UFO just landed and posted this here
Ну и, по традиции, привели бы кратенький список литературы по типу “Как стать хорошим программистом”
А также источник сведений о существовании в Haskell поддержки кэширования результатов вызова функций. Google выдаёт ссылку на Stack Overflow, где обсуждается эта тема и говорится, что в Haskell этой возможности нет.
Все не осилил. Надо будет прочитать. При взгляде не код вспоминается «краткость — сестра таланта». Это и к программистам тоже применимо :).
Я думаю, если учесть весь жизненный опыт, на котором основана статья, то процент сжатия информации получится неплохой. Вы когда мануал читаете к дремучему SDK, тоже жалуетесь на объем? =)
Исправление ошибок написанием избыточного кода, который замещает данные, полученные при исполнении неисправного кода.
=============
вот тут не соглашусь — это не всегда какой то симптом — часто это старый чужой проект в котором тебе дали быстренько пофиксить какую-то проблему
UFO just landed and posted this here
проекты бывают разные, как и клиенты… бывают правки за которые никто не заплатит при этом искать ошибку можно несколько дней
В идеальном сферическом мире, возможно, так и должно быть. А в реальном мире никто не знает, как именно этот код работает. Документации нет. Тесты? Не, не слышал. Сроки ограничены. В результате лезть глубоко просто тупо страшно, да и некогда.
Бррр… Я по ходу эт… пошел вешаться...(
Я в фаербаге это проверил:

a = 5
b = 10
a = b

У меня есть надежда :)

Надо в голове, без фаербагов, тогда будет надежда ;-)
… О НЕЕЕЕЕТ :((((
Не вышло короче. AlexRed, подождите, вместе пойдем.
у человека есть смекалка-значит не все потеряно
А еще ответом может быть «0» (в смысле False) :)
Охренеть. Если не Ваш коммент, так бы и думал, что ответ 5 и задача для дураков.
Всё, спать пора. Или в отпуск.
Так, тренировка на класической задаче обмена
a = 3
b = 2
a = b + a
b = a — b

Вроде ещё сгожусь.
Всё, спать.
А вот нет.
a = 3
b = 2
a = b + a
b = a — b
a = a — b

Вот теперь всё. Точно спать.
var a = 3
var b = 2
function(){
c=a
a=b
b=c
}()

Хватит с эти, завязываю. Спать.
а как там 5 вообще могло получиться?
Результат зависит от языка. Вдруг оператор присвоения перегружен?
а там везде альтернативные профессии указаны, вешаться не обязательно!
ну не компетентен я в регулярных выражениях и lisp не знаю и о боже prolog и brainfuck, а на кой черт они мне для написания например приложений на том же C/С++.
Я ненавижу регулярные выражения. У них синтаксис какой-то забубенный, нечеловеческий…
Используйте #define Все_заглавные_буквы_ASCII \A-Z
Есть такая шутка:
Если у вас есть проблема, и вы собираетесь решать ее с использованием регулярных выражений, то у вас есть две проблемы.

Но на самом деле штука просто замечательная, к тому же применима для запугивания неподготовленных людей. Показываешь им строчку кода с каким-нибудь замудрёной регуляркой, а тебе в ответ: «Едрить, магия какая-то!».
Проблемы начинаются, когда регулярными выражениями начинают решать не те задачи. Мне однажды попался класс, где вся работа со стоками была сделана на регулярках. Это было ужасно.
Самое смешное, что синтаксис у них довольно таки человеческий :) Легенды гласят, что регулярки придумали для описания процессов в нервной системе человека (тыц)
возможно автор имел в виде «способность всосать»
не компетентен я в регулярных выражениях
Зря, очень зря. Их надо знать хотя бы для перемалывания тонн текста через grep и sed.
Не у всех есть такие задачи. А некоторые даже сидят на (о боже!) виндоусе :-)
сижу на винде, но без православных sed и grep жить не смог, скачал их для win32
а затем подтянул архив с bash'ем, включая эмулятор терминала, теперь радуюсь нормальной консоли в винде
Скачивал я как-то цыгвин. Не понравился мне тамошний терминал. Хотя это было N лет назад, может уже и получше стал :-)
цигвин на виндовом терминале работает, у меня так же можно просто bash выполнить и получить консоль баш с ограничением по ширине и кривой кодировкой. А в эмуляторе все норм.
т.е. если я хочу попасть в русский линух то нужно пользоваться putty, а в иностранный можно прям с консоли ssh name@host
+ авторизация по ключам работает из каталога ~/.ssh
И что, прям настоящий терминал? Без проблем с копированием/вставкой текста?

И чем русский линукс от буржуйского отличается? Там sshd другой? :-)
Там кодировки с cmd не совместимы
А проблем нет. Даже ктрл д работает
сижу на винде, но без православных sed и grep жить не смог, скачал их для win32
а затем подтянул архив с bash'ем, включая эмулятор терминала, теперь радуюсь нормальной консоли в винде

Потом накатили xOrg, поставили kde, используете ext вместо ntfs, grub, как загрузчик, Гимп, ЛибреОфис, Firefox, MPlayer в качестве прикладного ПО. На чём вы, говорите, сидите? =)
Кстати, одно время пользовался связкой coLinux + Xming, и да — границы стирались.
на счет kde вы угадали :)
браузер chrome dev-m
еще Xming есть
Рецептом не поделитесь? Или направлением для раскопок? А то начинать гуглинг с «эмулятор терминала windows» не производительно… Слишком много вариантов, чтобы экспериментировать.
Банально расширяют кругозор. Может оказаться, что используя идеи из LISP можно более эфектно решать задачи на том же C/C++. Самый простой пример — абстрактные алгоритмы из STL и boost.
Никто не говорит что вы должны знать лисп, речь идет только о непостижимости.

Вообще, лисп достаточно простой язык и при этом очень интересный.

В универе курс лиспа очень нравился :)
Должен признаться, одна вещи в лиспе для меня точно непостижима: затем столько скобок???
Прочитайте Practical Common Lisp. Мне хватило недели, чтобы освоиться с синтаксисом и привыкнуть к скобкам, а после написания первых макросов отпал вопрос о количестве скобок. Не надо бояться нового — просто читайте, пишите код, и скоро поймёте, в чём суть и сила Lisp.
Регэкспы нужны для разбора строк средней сложности, язык программирования тут не при чем. То что на Вашей задаче не нужно работать со строками, не означает что в будущем не появится другая задача.

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


Вспоминаю и смеюсь, когда много лет назад мой друг сохранял вижуалбейсиковый проект в среде Visual Studio, несколько раз подряд нажимая Save на панели инструментов, и своего друга научил так делать. Я был удивлен.
Вот не знаю по поводу VS но вот MS Office приучил целое поколение по внутреннему таймеру тыкать Ctrl+s дабы не утерять плоды своего труда, что часто случается до приобретения данного рефлекса. Вероятно, отсюда же растут ноги и у повторного нажатия кнопки «Сохранить».
UFO just landed and posted this here
Аээ, простите. У меня глубокая ночь. Я должен был уточнить, что все нажатия совершались в течение 10 секунд. Около 7-8 нажатий за 10 секунд перед выходом из IDE.
На самом деле, сработает только 1 раз, а когда клава залипает надежнее жмакнуть пар раз, так чтоб наверняка. А так я чаще встречаю людей которые не могут осилить эту комбинацию, и жалуются что у них не сохраняются файлы.
или люди которые свято верят в то что если они закрывают программу им обязательно вылетит окошко с предложением сохранится. Причем уже более 10 раз теряли результаты, но никак не обучаются, собаки павлова думаю и то сообразительнее были
Вживую столкнулся однажды с такой проблемой: пользователи а) дабл-кликали по кнопкам в тулбаре (это давно было, привычка ещё с вин 3.11), причём б) делали это плохо — т.е. иногда у них получалось, а иногда выходило просто два клика подоят.
Пришлось ставить защиту и от такого дурака — отучить их от оказалось нереально.
«Вы считаете само собой разумеющимся наличие скрытых переменных и не задумываясь валите любые проблемы с программой на них!»

Если кто нибудь пояснит мне что такое «скрытые переменные» я начну валить на них все баги!
Возможно, подразумевался shadowing, когда одна переменная в локальной области видимости перекрывала другую с таким же именем, но на уровень (несколько уровней) выше. Могу ошибаться.
Судя по всему абзацу мне показалось, что «скрытые переменные» — это нечто, влияющее на Вашу программу, но не написанное в коде. Т.е. системная переменная, хранящая например фазу луны и влияющую на работу кода.
Я тоже склоняюсь к варианту, который предложил <~demand>. Когда переводил еще подумывал развернуть эту мысль, но решил не трогать авторский текст.
Скорее, это понятие из физики :-)
Не каждый «Йо-Йо код» плох. Как пример из текущего проекта: парсится CSV файл, в котором содержится дамп общения device<->device. В памяти по логике работы лучше держать фреймы, в которых лежит нормальное бинарное представление сообщений. Так же некоторые фреймы могут быть отображены, в процессе отображения идет приведение массива байт к его визуализации, что является обратным действием к парсингу сообщения.

Если исходить из предпосылки, что Йо-Йо код плохо и его нужно однозначно выкинуть, то видится 2 решения:
1. в лоб: хранить как и считанную строку дампа, так и распарсенный дамп в каждом фрейме.
2. хранить только считанную строку дампа, но когда нужна работа по посылке или анализу приводить все к массиву байт.
Лишний раз убедился, что не зря выбрал эту профессию =)
>(ООП) Наличие огромного количества «....Manager» классов, которые содержат все методы манипуляции с объектами, которые в свою очередь совсем не содержат (или содержат мало) методов.

Думаю, что очень много людей не согласятся с этим. Особенно джавистов. Я предпочитаю держать модели «чистыми» и ничего плохого в этом не вижу, кроме того, что якобы это не ООП.
а вы так уверены, что вы — хороший программист?:)
Я-то тут при чем? Это же вы пишете: «Я предпочитаю… и ничего плохого в этом не вижу». Т.е. в качестве аргумента вы приводите лишь свой авторитет.
Первое — я не увидел агрументов, почему менеджеры для управления объектами это плохо. Второе — я не приводил свой пример как единственно правильный путь («толстые модели это плохо» vs «тонкие модели это плохо»).
На самом деле helions8 прав. Тут или делать Manager-ов, которые умеют сохранять модели, и тогда это якобы не ООП. Или делать модели, которые умеют сохранять сами себя, но тогда нарушается принцип SRP, и тогда это тоже кагбе плохое ооп
Хоть вы и сказали с иронией, но оба решения действительно проблемные и вы правильно все расписали. Я пришел к выводу, что истинна где-то по средине :) Модели сохранять должен репозиторий. Manger должен реализовывать конечные сценарии. В модели — только инкапсуляция данных и некоторое базовое (я бы сказал даже аксиоматическое) поведение. Ну и для сложных случаев контекстные модели-обертки (CDI или Bounded Context из DDD).
Полностью поддерживаю. Ни то, ни другое. Менеджеры чаще всего содержат вообще все, что только можно придумать для объекта. Верно, это должны быть разные компоненты — одни отвечают за сохранение, другие за какое-нибудь кэширование, третие — еще за что-нибудь. Менеджер может быть чисто «for convenience» — набором из нескольких наиболее используемых методов.
Вот пример, который на мой взгляд отражает суть этого утверждения:

class Point
{
protected $_x;
protected $_y;
}


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

(Функциональное с «чистыми»(pure) функциями) Использование копипасты из чужого кода для того чтобы побороть I/O и монады.

Вопрос к таким горе-программерам: нахера козе баян — нахера вообще писать на том, что не умеешь готовить? :-)
А есть еще способы научиться готовить?
Я думаю, что подразумевалось написание кода, используемого в производстве, т. е. не для самообучения. Но даже если и для обучения, то все равно тупое использование копипасты бесполезно, все равно что зубрежка.
Очень сумбурно написано. До конца не осилил.
Лучше бы посоветовали прочесть «Совершенный код» макконела. Там все подробно, с доказательствами и нормальными рассуждениями.
Значит, у вас не наболело…
> Многократные вызовы идемпотентных функций (например вызов save() по нескольку раз, «чтобы уж точно»).

цитирую из статьи про анализ исходников Google Chromium
if (!file_util::Delete(db_name, false) &&
        !file_util::Delete(db_name, false)) {
    // Try to delete twice. If we can't, fail.
    LOG(ERROR) << "unable to delete old TopSites file";
    return false;
}

Этот код может показаться многим программистам странным. Какой смысл два раза пробовать удалить файл? А смысл есть. Тот, кто его писал, достиг просветления и суть бытия программ. Файл однозначно удаляется или не удаляется только в учебниках и абстрактном мире. В реальной системе бывает так, что файл только что нельзя было удалить и мгновением позже — можно. Причиной тому могут быть антивирусы, вирусы, системы контроля версий, и бог весть что ещё. Программисты часто не задумываются о подобных ситуациях. Они мыслят так, раз не удалость удалить файл, то значит и не получится. Но, если хочется сделать хорошо и не мусорить в каталогах, нужно учитывать эти посторонние воздействия. Я сталкивался с ровно такой же ситуацией, когда файл не удаляется один раз на 1000 запусков. И решение было ровно таким же. Ну, разве что я ещё на всякий случай Sleep(0) вставил посередине.
И все равно это тяп-ляп. По-хорошему нужно разобраться почему его может не получиться удалить и починить правильно.
> И все равно это тяп-ляп

Добро пожаловать в реальный мир, Нео.

> нужно разобраться почему его может не получиться удалить
написано же, почему (я к списку добавил бы — если в windows — построитель превьюшек в проводнике, который лочит jpg-файлы и avi-файлы)

а как бы вы поступили, кстати?
Может быть и также, сильно зависит от ситуации. Но как пример я бы этот код приводить не стал.
ну, я понимаю эту ситуацию примерно так, что:

бывает много ситуаций, когда файл лочится на микросекундное время. и если делать delete один раз, то файл не будет удаляться в 30% случаев (что много), а если делать два delete, то файл останется только в 0.1% случаев (что по крайней мере приемлимо)
цифры процентов я сейчас взял с потолка, но идею вроде бы описал.

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

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

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

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

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

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

stackoverflow.com/questions/1040/how-do-i-delete-a-file-which-is-locked-by-another-process-in-c

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


Google Chromium кроссплатформенный
В юниксах вроде как нет проблемы с блокированием файлов. Ну и есть IFDEF-ы.
ну, вот и оцените теперь время/стоимость кросс-платформенной разработки и тестирования этой фичи, со всеми ифами и ифдефами, которые срабатывать будут редко во время какой-то не самой частой операции.

Начинали с того, что пример плохой. Разобрали, предложили варианты. Понаставили мне минусов. Надо было поставить плюсик и идти дальше писать говнокод. Был неправ.
я конечно немного поздно сделал этот скриншот, но минусов я вам не ставил
clip2net.com/s/1gfjI

разобрали, предложили варианты, которые увеличат время разработки проекта раз наверное в 5 и все эти 80% нового кода будут проявляться в мелких несущественных с вероятностью 1 к 10000 ситуациях.
да, звучит разумно, сейчас поставлю напишу в саппорт гуглу попрошу их всё переделать
Согласен, это говнокод. Можно было хотя бы попытаться определить причину первой ошибки, и пытаться удалять второй раз после задержки. А вообще, для подобных ситуаций, есть понятия таймаута и числа повторов.
рискну предположить, что задержку там поставить нельзя, потому что это UI-тред.
:-) тем хуже для кода…
удаление файлов в контексте UI-треда — это экстравагантно
Моё мнение, тезисно:
1. два delete подряд — не ошибка
2. это не идеальное решение
3. это решение — максимально полезное среди решений со схожей сложностью
4. выбирая между простым частичным решением (оно же, по мнению интернет-аналитиков, «экстравагантный» «говнокод») и увеличением сроков разработки в разы, я бы, на месте гугла, выбрал простое частичное решение и послал бы интернет-аналитиков в задницу. К сожалению, я не гугл и не могу так поступить :)
Отличный ответ! Спасибо, особенно по пункту 4.
Вынужден полностью с Вами согласиться.
И все равно это тяп-ляп. По-хорошему нужно разобраться почему его может не получиться удалить и починить правильно.

Пф… У меня в VS 2008 проекты новые не создаются, пока их же секьюрити эссеншиалс не выключу. Мне вот инетерсно, если бы вместо ошибки «ой, не могу» в МС начали работать над хотфиксом, сколько бы времени ушло на «починить правильно»…
Интересный подход. Скажите, а почему вы пробуете удалять только дважды? Ведь если попробовать удалить три раза подряд, то вероятность удаления вырастет на 50%!
Это если удалить можно было мы максимум за 6 раз! Откуда такая уверенность, или просто число шесть нравится? :-D
>> Откуда такая уверенность?
— Какова вероятность встретить крокодила на улице города?
— 50/50: Или встречу, или нет!
Если удалить можно по крайней мере один раз за сто попыток, то вероятность вовсе не 0,5, как у Вас, а совсем даже 0,01.
задам вам тот же вопрос, что и первому комментатору. а как бы вы поступили?
>> а как бы вы поступили
Все зависит от задачи. Можно попробовать удалить заблокированный файл позже, при наступлении похожего события, т.е. удалять не конкретный файл, а сразу некоторое множество, в которое попадет и текущий файл, и все неудачные предыдущие попытки. Можно n раз пытаться удалять файл через определенное время, например, через каждые 0,1мсек (предложенный выще вариант — частный случай с n = 2 и 0сек). Можно аналогичного события не ждать, а подписаться на события файловой системы, и удалять файл по освобождению. Можно удалять при закрытии программы. Можно при следующем запуске. Вобщем, вариантов масса.
насколько я знаю, нет события «файл разлочен». про первый вариант с паузой я написал чуть выше.
третий и четвёртый — да, хорошие варианты. я бы скомбинировал их с delete&&delete
Если так уж нужно удалить файл, то логично делать это не два раза подряд в коде (как тут заметили, возникает вопрос, а почему два раза, а не три или не тридцать три), а в цикле, пока не удалится или пока операция не будет отменена.
а в цикле, пока у пользователя не кончится терпение смотреть на белый не реагирующий на нажатия экран браузера и он не прибьёт процесс таскменеджером.

нет, так тоже нельзя.
Я поэтому и написал: " или пока операция не будет отменена". IO операции в UI треде, разумеется, делать не стоит.
UFO just landed and posted this here
Моё мнение, тезисно:
1. два delete подряд — не ошибка
2. это не идеальное решение
3. это решение — максимально полезное среди решений со схожей сложностью
4. выбирая между простым частичным решением (оно же, по мнению интернет-аналитиков, «экстравагантный» «говнокод») и увеличением сроков разработки в разы, я бы, на месте гугла, выбрал простое частичное решение и послал бы интернет-аналитиков в задницу. К сожалению, я не гугл и не могу так поступить :)
UFO just landed and posted this here
Удаление файла — идемпотентная операция? Ну, у меня для вас плохие новости.
А кроме того, так можно удалить чужой файл, например.
Вопрос к переводчику: «Вам послайсить или целым писом?»
Отличная статья и, в кои-то веки, близкий к отличному перевод! Спасибо.
UFO just landed and posted this here
Рядом с заголовком иконка z>я, в футере ссылка на оригинал и автора (cwenham).
UFO just landed and posted this here
Нет бы разобраться в терминологии и основных концепциях Хабра, перед тем как беспочвенно обвинять людей в плагиате.
UFO just landed and posted this here
UFO just landed and posted this here
(блин, в каждой статье про перевод это)

И в начале, и в конце текста есть пометки, в начале — Z->A, в конце — ссылка на автора, рядом с ником автора перевода.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Да на троечку перевод, если честно.
Указатели, рекурсии — может стоит переименовать статью «Признаки плохого С++ программиста»? В том же php указатели в большинстве случаев не нужны, и даже вредны, так как усложняют понимание программы не принося ощутимой пользы, или в силу заморочек интерпретатора создают труднонаходимые баги. А рекурсии опасны и их часто лучше заменить более сложным итеративным алгоритмом, одна рекурсия при неосторожной работе с памятью съест всю память на сервере что положит сайт и кучу бэкграунда, проц тоже может весь скушать, да можно писать без утечек памяти, но программ без багов не бывает и рекурсия может проявить себя только в условиях которые не были предусмотрены при написании. С итеративным алгоритмом вероятность такого меньше.

Lisp, тезис Чёрча-Тьюринга — вы серьезно, без этого нельзя быть хорошим программистом?

Регулярные выражения — тоже спорно, гуру в регулярках может быть плохим архитектором, обратное тоже верно.

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

Но Lisp (а так же prolog) это языки требующие своего особого мышления. Сам лично сталкивался, люди только начинающие изучать программирование, с «чистым мозгом» осваивали lisp лучше и быстрее людей у которых уже был небольшой опыт в программировании на языках типа С++, php, pascal и пр. Но это не сдалало их как ни странно хорошими программистами. Мне чтобы понять lisp преходилось «вывернуть» мозг привычный к алгоритмическим языкам (назовем их так, не могу подобрать другого слова). Расширения кругозора имеет не только плюсы но и свои минусы, используя подходы lisp в php (для примера) можно так извратить код, что другому программисту будет крайне сложно с ним работать. А теперь представьте что над проектом параллельно работают 10 программистов и каждый со своим вот таким расширенным кругозором в какую нибудь сторону (а у кому-то из них и брейнфак в качестве хобби нравится). Через сколько времени команда разругается а проект превратится в полный шлак? Так что всего в меру и очень осторожно. Вот только как я уже писал вырабатывается определенный стиль мышления, и понять когда можно применять неродные для языка подходы а когда нельзя, наверное будет очень сложно самостоятельно.

А по поводу всей области: В мире сотни, если не тысячи языков программирования, что стоит изучить их все? Я считаю что только основные, которые могут быть как то связаны с выбранной для специализации областью. Я не спорю что С++, Java полезно знать на минимальном или среднем уровне, но Lisp имеет свою узкую нишу, и вряд ли достаточно (чтобы оправдать потраченное на него время) можно из него вынести например в веб-программирование. Может лучше уделить время оттачиванию знаний в своей подобласти чем разбрасыватся по всей области для расширения кругозора?

И еще, поверхностное знание это всего лишь ступень к знанию, к пониманию если угодно, само по себе оно ничего не стоит, так как не закреплено опытом а значит не может принести какую-нибудь идею в другую область (увы, так работает мозг) и не позволяет работать в своей. Чтобы хоть как-то «знать» язык нужно хотя бы пару месяцев на нем пописать на реальном проекте, а это уже не поверхностное знание.
Lisp — дедушка современных динамически-типизированных языков. Учитывая что почти все современные языки движутся (обратно?) в сторону различных функциональных возможностей, а lisp в значительной мере функциональный язык, то знать его «трюки» нужно для того чтобы хорошо писать на этих языках, кмк. По большому счету, в ruby, python, [вставьте свой любимый динамический язык] от лиспа отличается система типов, стандартные библиотеки и синтаксис (пробелы, скобочки — какая разница?). А приёмы всё те же.
По поводу рекурсии, кстати.

/*
«Итерация свойственна человеку, рекурсия божественна». Л. Питер Дойч
Видно, у бога стек длинный. А мы останемся людьми.
*/

for( int i = 0; i < depth; i++ ) {

}

© ithappens.ru/story/7508
Видно, у бога стек длинный.


Видно комментатор кода несилен в языках, и не знает, что хвостовой рекурсии (Tail call optimization) сто лет в обед, и никакого стека, блджад.
1977 год, между прочим, Guy Steele. Вот вам и польза от знания Lisp'а налицо, что называется, а вы говорите СкрипачLisp не нужен. Рекурсия божественна, воистину!
Из википедии (да знаю что она не всегда соответствует истине, если где неправда поправте):
«Хвостовая рекурсия — специальный случай рекурсии, при котором рекурсивный вызов функцией самой себя является её последней операцией.[1] Подобный вид рекурсии примечателен тем, что может быть легко заменён на итерацию, что реализовано во многих оптимизирующих компиляторах.»,
«Создатели функционального языка Scheme, одного из диалектов Lisp, оценили важность хвостовой рекурсии настолько, что в спецификации языка предписали каждому транслятору этого языка в обязательном порядке реализовывать оптимизацию хвостовой рекурсии.» — Ну и смысл огород городить если все равно все сводится к итерации? Где практическая польза этого вида рекурсии (ну за исключением языков где это одна из основ)?
Вы не понимаете принципа функционального программирования, как программирования без побочных эффектов в идеале (Haskell, например, или Scheme). Итерация в C и C-подобных языках императивна, имеет побочные эффекты в форме изменения переменной-счетчика, например.

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

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

Мазохизм.
О точно, императивные, спасибо :)
Так там и не надо избавляться. Основа ООП, объект, имеет состояние. Да он имеет методы, но методы в основном для изменения состояния этого объекта. Я изменяю состояние, я опираюсь на состояние одного объекта чтобы изменить состояние другого. Я инкапсулирую те части состояния этого объекта (или цикла, или метода) которые не касаются внешнего окружения внутри его области видимости, и это не позволяет сломать внешний код. Глобальный переменных (глобального состояния) почти нет. Невозможно сломать внешнее окружение ну например счетчиком для итерации (при минимальной окуратности с именами переменных).

Объект отражает набор данных (фактически состояние, или у вас другая трактовка этого понятия?) и методов для работы с ними. Все просто, понятно, легко делится на атомарные и более крупные части (каждая со своим набором логики и данных) и связывается в сложные архитектурные решения. И мне это нравится. Я не могу понять проблем связанных с изменением состояния.

Вообще есть ООП парадигма и в функциональном мире — Common Lisp, OHaskell, OCaml. ООП, насколько мне известно, не означает изменение состояния; оно о другом.

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

функция / отображение в математике: у неё есть входные параметры, она отображает их в выходные данные.

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

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

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

Это если мы говорим о чистом функциональном программировании.
Не использовать глобальные переменные, вот и все решение проблемы :)
По крайней мере для php. Мне не нужно напрямую работать с памятью (с адресами). Да бывают и довольно часто случаи когда нужно изменить состояние, но это состояние объекта в который входит эта функция (вернее метод). Если не создавать монструозных классов то это тоже не проблема, ее весьма легко контролировать. Есть глобальные состояния, переменные окружения, но если обернуть их в объект, который будет их контролировать то эта проблема тоже становится минимальной. Зато отслеживая состояние я могу четко отслеживать ход выполнения программы (при отладке например).

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

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

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

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

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

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

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

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

Разные задачи, разные проблемы и разные подходы.
Это не считая того, что существует мнение, что хвостовая рекурсия может вообще избавить язык (ну или отдельно взятую программу на нём) от изменяемого состояния. Что, несомненно, благо.
Ну, вообще, как бы, одной только хвостовой рекурсии недостаточно, чтобы избавить язык от глобально изменяемого состояния (читай, сделать его чисто функциональным), но такие языки есть, да — Haskell.
Ага, только не во всех компиляторах есть эта оптимизация, далеко не во всех :-)
Ну, в Lisp, во многих из 70 реализаций Scheme он, что называется, «из коробки», причем из лохматых годов прошлого века (см. выше), в OCaml, Haskell, да чего уж там — Erlang.

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

Хотя бы этот вопрос, Is anyone using Racket commercially? на Stackoverflow.
Ну это я к тому, что даже захудалый паскаль и то более промышленен, нежели схема с хаскелем :-)
Смотря что Вы подразумеваете под термином «промышленен».

Если «распространен в промышленности», то я согласен с Вами бесспорно, но в то же время и опечален.

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

Со Scheme все чуточку сложнее. Для Хаскеля всего пара-тройка реализаций, при том что полноценной считается GHC, а реализаций Схемы — за 70, в т. ч. от Microsoft. Последнее обстоятельство порождает несовместимость стандартов и самих реализаций, что не играет на пользу распространенности Scheme в производстве, хотя ее там вполне можно встретить.

Лисп, безусловно, распространен, Эрланг. В банковских системах, отказоустойчивых сервисах, метро и т. д.

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

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

Условия то есть, и программирование точная наука. Вот только можете ли вы быть уверены на 100% что кусок кода который вы пишите ни содержит ошибок (логических) которые могут создать проблему в сколь угодно отдаленной перспективе при любом окружении? Понятное дело кусок кода должен быть сложнее «hello world». Я нет. Я знаю что ошибки бывают всегда и что может существовать ситуация (о которой я заранее и не догадываюсь) когда вот эта логика при определенной ситуации может через год-два когда о ней все забудут или когда ее используют нетрадиционным образом создаст большую проблему (думаю примеры придумать легко, увеличение базы пользователей например в 10 раз больше планируемого, или кто-то использует этот кусок кода в своей рекурсии :) и если сейчас эта рекурсия есть 100 Мб памяти то в такой ситуации она сьест 10Гб и задушит сервер (цифры для примера)). Поэтому я стараюсь избегать решений которые в принципе могут съесть всю память или процессор, попортить данные и пр. а если это не возможно стараюсь выбрать такое решение где вероятность этого наименьшая. Поэтому я избегаю рекурсий если есть альтернативное подходящее решение, так как знаю что не всеведущ и все предусмотреть не могу, сколько бы у меня опыта, времени и желания не было.

Так в чем ваша проблема?
Передавайте тот же счетчик что вы повесили на цикл в рекурсионную функцию.

1Tiger1 сделал неосторожный пасс рукой и рекурсия вышла из под его контроля.

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

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

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

Поэтому 1Tiger1 старается и избегать кода который выйдет из под контроля. Вот такой вот шаман-перестраховщик я.
А, ну, судя по профилю, вы сами в курсе.
Смотря какие, вот как без рекурсии красиво реализовать команду rm -rf /?
Циклом по очереди имён файлов для удаления?
Да, но хороший архитектор, скорее всего способен составить регулярное выражение.
Мне кажется, что тут вопрос не в том, может ли программист сходу, с закрытыми глазами набросать регулярку, а в том, может ли он это сделать вообще. ИМХО, если человек в принципе не способен (не «лень» и не «как-то не приходилось», а именно «в принципе не способен») освоить регулярные выражения, то вряд ли он сможет работать программистом.
Не поверите, в нашем универе люди, не подозревающие, что у технологии регулярных выражений длинная борода и широкое применение, преподают :-(
«Вы считаете, что присутствие кода в программе может изменить её поведение, даже если он никогда не вызывается.»

У меня было, что наличие комментария в коде влияло на работоспособность программы.
В компиляторе тоже бывают ошибки!
В php к примеру можно с помощью Reflection получить текст комментария и дальше дело техники, только пока пример придумать не могу :)
Я такое для DI использую :)
осторожнее с opcode cacher'ами, они могут вырезать комментарии
А могут и не вырезать :)
Я еще до того как решил использовать комментарии для определения поведения проверил этот момент.
Так
(Ну, не то чтоб HTML это прям код, но все же)
Ошибки в процессорах, ошибки в компиляторах, ошибки в сторонних библиотеках — что угодно может привести к багам в программе из за факта присутствия никогда не вызываемого кода.
Например: habrahabr.ru/blogs/windows/103903/
например, перестает работать. прочитайте 15 пазл из java puzzlers.
Интересно, почему автор текста считает, что duck typing к ООП что-то добавляет? Для него ООП == статическая типизация?
Не, это вещи ортогональные: генераторы тоже ничего особо к ООП, как к идее об обмене сообщениями между изолированными «штуками», не добавляют, как и дженерики, которые просто фича системы типов.
> Не можете понять тезис Чёрча-Тьюринга.

Не очень понял его из статьи в википедии.

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

Может, присоветуете пару хороших книг, раз такое дело?

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

Эта фраза пока что слишком неочевидна для меня.
алгоритм — неформальное понятие, бытовое, алгоритм на машине тьюринга — формальное, конкретный набор инструкций для переходов. Тезис просто утверждает, что отныне алгоритмами будем считать только то, что можно представить на машине Тьюринга, не больше, не меньше. По поводу пары хороших книг… " Theory of Computation" Брайнерда. Но теория вычислимости непростой раздел математики, обычно программистам хватает матчасти из SICP, проект перевода sicp.sergeykhenkin.com/
Не могли бы вы пояснить, как конкретно этот тезис может помочь на практике?
Лучше Вы поясните, как такие приземленные люди, как Вы, могут быть программистами? Что надо учить программисту? Названия функций из стандартной библиотеки и наизусть алгоритмы? Программист это не просто тот, кто набивает код для решения обыденных задач, это ещё отчасти и ученый. Это подтверждает факт того, насколько ценятся такие специалисты, не ограничивающие свой кругозор рамками «полезности», наколько её понимает говорящий на данный момент.
«Рассуждать о коде» значит понимать порядок исполнения инструкций («исполнять программу в голове»), зная, каково предназначение кода.

На форумах и при удалённом обсуждении кода большинсво супер-программистов программистов даже не вдумываеся в код. Если они увидели, что в конструкции кода или синтаксисе построена не по ихнему даже мелкая деталька (хотя ни скорость, ни порядок исполнения программы от этого не изменяется) сразу начинают отписывать своё мнение и ругаться (с обязательной ссылкой на свой многовековой опыт).
А можно пример подобной дискуссии? Ни разу такого не видел.
Расскажите в чём плохи «Движки бизнес-правил»?
Тангенциальные данные, неконсистентные naming convetions, когезиея… Тваюжтымать! Куда я влез? Все, ухожу на биржу труда, посыпая голову пеплом…
Я подозреваю, что это побочный эффект от перевода.
  1. «Танкенциальные данные». Tangential — не имеющий прямого отношения (к чему-л.)
  2. «неконсистентные naming convetions» должно было звучать как несоблюдение однородности в именовании переменных
Я думаю, стоит поискать в интернете определения этим понятиям, как сразу возникнет мысль «да, по-моему я это где-то в своей работе встречал, только не знал, что так называется».
Это конечно — интересно ведь что все-таки имеется в виду. Просто при первом приближении впал в некоторый ступор типа «Чо?».
Скорее всего это просто недоперевод.
>(ООП) Наличие огромного количества «....Manager» классов, которые содержат все методы манипуляции с объектами, которые, в свою очередь, совсем не содержат (или содержат мало) методов.

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

===========

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

DoXXX(..);
DoYYY(..);
if (smth)
    DoZZZ(...);
else
    DoAAA(...);
...

Согласен с Вами полностью.
Код становится читаемым!
«когезия» — это наверное «связность» по-русски? Нет?
видимо да. но мне лично не понятно, чем когезия отличается от коуплинга.
в википедии на инглише 2 статьи en.wikipedia.org/wiki/Cohesion_(computer_science) и en.wikipedia.org/wiki/Coupling_(computer_science), обе ссылаются на ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29
нужно внимательно их прочесть, но завтра — утро вечера мудренее)
видимо да. но мне лично не понятно, чем когезия отличается от коуплинга.
в википедии на инглише 2 статьи en.wikipedia.org/wiki/Cohesion_(computer_science) и en.wikipedia.org/wiki/Coupling_(computer_science), обе ссылаются на ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29
нужно внимательно их прочесть, но завтра — утро вечера мудренее)
Cohesion — связность — что-то типа силы интеграции внутри самого модуля (насколько связаны части модуля друг с другом). Чем она выше (сильнее связи), тем лучше (но в меру).

Coupling — связанность — насколько независимые модули связанны друг с другом. Чем она выше (сильнее связи), тем хуже (но тоже в меру).

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

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

Смешно, если честно. Народ лет десять(или больше?) копья ломает anemic vs rich а оно вот как на самом деле!..
> Ваш инсталлятор молча разворачивает не согласованное с пользователем программное обеспечение, которое даже отношения к вашей программе не имеет.

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

*упал в обморок*
Предприниматели-то и хрен бы с ними. А я вот сегодня ставил LibreOffice 3.4.2 в провинциальном филиале одной бюрократической структуры, оборудованном скверным доступом к Интернету (≈10 килобайтов в секунду). И оказалось, что дистрибутив-то от LibreOffice я принёс, но он полагается на то, что Java в системе ужé есть: какой-то сукин сын постеснялся засунуть в дистрибутив и затем «разворачивать программное обеспечение, которое даже отношения к программе не имеет». Пришлось убить лишние четверть часа, выкачивая Джаву с сайта Оракла.
Нахрена либре жаба? Там пара плагинов на ней завязана
думаю, тут говорилось о радостях типа Google Toolbar или плагинов для файрфокса
Ваша программа демонстрирует свои претенциозность и великолепие сверх необходимого, например, показывает сплэш поверх активных программ, пока грузится в фоне, или распихивает свои иконки запуска по всем возможным местам.

Обоже, создатели Code::Blocks — плохие программисты.
А вы видите в описанном поведении что-то хорошее?
Нет, но это никак не говорит о программистских навыках. Ровно как и большая часть симптомов, названных автором.
Ну, конкретно под этот признак есть сноска, снимающая вину с программиста. А по поводу большей части не соглашусь. Есть конечно несколько спорных моментов, например с Manager'ами и функциями, вызываемыми только один раз, но все таки большая часть описанного в статье — действительно признаки не очень хорошего программиста.
Один симптом ни о чём не говорит. В данном случае говорит, но всего-лишь о том что разработчикам надо бы поубавить гордость и обратить внимание на юзабилити.

Да, создатели MSO и LO программисты не плохие, но тоже без меры гордые.
А что, разве нет? По мне так, одна из самых кривых IDE, что я видел.
UFO just landed and posted this here
Хм… А зачем в борделе понтоваться? :)
> Ваша программа производит выходные данные, которые обрабатываются другой программой (например, браузером)

О нет, весь подход unix way — ересь, а всем разработчикам субдшечек надо срочно переквалифицироваться в телемаркетологов
А теперь дочитайте предложение:
… полагаясь на то, что с «той стороны» программное обеспечение прощает значительные нарушения спецификаций.
как бороться с ленью способа не придумано. Лень — основная беда программиста.
Спасибо за перевод. Согласен с подавляющей частью статьи, буду рекомендовать её к прочтению всем, чьё невежество в профессии меня бесит — это будет продуктивнее и гуманнее, чем высказывать всё накипевшее.
Извините, ответил случайно на ваш комментарий, а хотел на пост.

Насчёт лени согласен, кстати: одно дело, когда объективно не хватает времени на написание кода, и совсем другое — когда ищут отмазки вроде «да ладно, всё равно никто не увидит» или «тут слишком много писать».
Лень — основа программирования.

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

Много лет делал JOIN с помощью sql запросов и уперся в то, что такая бд горизонтально не шардится и зачастую проще и быстрее сделать два запроса (и более) на стороне клиента (серверный скрипт), чем делать классический join. И да — храним объекты. Да и вообще — в последнее время есть такая мода — уходить от JOIN.
Пришлось однажды отказаться ото всех удобств из за феерично бажного mysql embedded… Теперь вот думаю отказаться от mysql embedded, ибо производительность страдает. Но баги в мускуле просто доставляли… получалось какое-то стохастическое программирование. Никогда больше не буду линковаться с этой бякой, которая падает при порождении тредов.
Тот самый случай, когда комментарии к статье интереснее самой статьи.
Интересно, а каким считается программист в таком случае:
Необходимо в короткий срок написать веб-сервис на PHP. Есть БД с 20-ю таблицами. Программист начинает с того, что под каждую таблицу пишет классы. У него получается по 2 класса на одну таблицу. Классы для каждой таблицы расположены в отдельном файле, в итоге получается 40 классов в 20-и файлах. Все запросы к БД прописаны в классах.

Плохой или хороший?

P.S.: Реальная ситуация (студента на работу взяли). Только количество таблиц на самом деле другое.
P.P.S.: Причём, во всех классах нет метода, который выполнял бы банальный select по произвольному запросу.
Мне после этой статьи кошмары будут сниться. От «Один try-catch блок, включающий в себя всё тело Main(), рестартующий программу.» и подобных до сих пор мурашки по коже.
Еще один симптом: Вы постоянно теоретизируете о программировании! Damn! Просто сядь и начни писать код!
А объясните заурядному программисту симптом
«Map или reduce функции, содержащие циклы для итерации по набору данных»? или тут про исходный набор данных?
Да, про исходный. Потерялось во время правок.
Да, спорных моментов немало. Что бросилось в глаза:

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

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

•(ООП) Наличие огромного количества «....Manager» классов, которые содержат все методы манипуляции с объектами, которые, в свою очередь, совсем не содержат (или содержат мало) методов.


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

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


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

•Изобретение классов и функций, которые уже есть в фрэймворке (например, таймеры, коллекции, алгоритмы сортировки и поиска).*

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

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

Для создания лямбда-выражения компилятору придется создать замыкание (closure) текущей функции, заморозить ее переменные. А это очень долго. Когда я впервые увидел описание yield return, то был в восторге — пока не попробовал его применить. Получил замедление работы в 4 раза, и решил, что лучше уж по-старинке…

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

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

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

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

Здесь, как обычно, вылезает вопрос об эффективности. Если алгоритмы для целых и вещественных чисел совпадают на 98%, но различаются в самом узком месте, то может быть, лучше продублировать? Конечно, qsort показывает, что можно обойтись одним алгоритмом, но он — произведение искусства :)
Вам знаком принцип DRY? Не потрудитесь ли вы объяснить зачем дублировать и чем это, как вы выразились «лучше»?

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

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

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

Перечитайте пожалуйста секцию «Безразличие к результату». Это ваше «быстрее» кому-нибудь потом поддерживать, разбираться и править. Нет, серьезно, перечитайте.
Перечитал. Так и быть, напишу я к этим трем строчкам комментарий — чтобы тот, кто придет потом, знал, что это сортировка. А может быть, воспользуюсь функцией Array.Sort с лямбда-выражением. Но я проверил — даже на массиве из 1000 элементов Sort с лямбда-выражением работает дольше, чем простейшая сортировка Шелла.

лучше написать две функции, отличающиеся одним оператором

Это очень удобно для поддержки, да.
Не менее удобно, чем поддерживать одну фунцию, делающую, в зависимости от параметра, две слегка разные вещи. Да еще и соптимизированную.
Фунция занималась тем, что читала описание некоторого многомерного геометрического объекта и строила модель этого объекта в памяти.
Десериализация на 1000 строк, вы серьезно?

А несколько наносекунд во внутреннем цикле могут обернуться десятками секунд ожидния у пользователя.
Вам знакомо такое понятие как premature optimization? Вы всерьез считаете, что где ни попадя оперировать предположениями «может обернуться десятками секунд» допустимо?

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

А может быть, воспользуюсь функцией Array.Sort с лямбда-выражением. Но я проверил — даже на массиве из 1000 элементов Sort с лямбда-выражением работает дольше, чем простейшая сортировка Шелла.
Я не знаю о каком именно окружении идет речь, но судя по всему, неплохо было бы что-то в нём заменить. Функция, которая сравнивает два элемента массива, не является замыканием, не использует переменных снаружи. И если ваш компилятор не смог оптимизировать такой простой случай и/или рантайм-окружение не определило это место как «горячее» и не заинлайнило его, я бы на вашем месте подумал о замене компилятора, окружения. Ну раз уж вы занимаетесь задачами, в которых важны наносекунды.

Но я проверил — даже на массиве из 1000 элементов Sort с лямбда-выражением работает дольше, чем простейшая сортировка Шелла.
Чует моё сердце, что это действительно какой-то JIT-рантайм. CLR, скорее всего, судя по вашей подготовке и культуре труда. Я прав?

Если да, то хорошо ли вы понимаете в чем смысл hot spot'ов и что именно это значит для ваших бенчмарков?
Десериализация на 1000 строк, вы серьезно?
Если серьезно, то линейного кода там было около 500 строк, еще 500 — реализация классов, представляющих объект в памяти, и 400 — на один из вспомогательных алгоритмов. Десериализацизация состояла из 8 этапов — разбор файла, построение группы симметрии объекта, вычисление положений гиперплоскостей его граней, вычисление комбинаторной структуры поверхности, вычисление положений гиперплоскостей разрезов, применение этих разрезов к поверхности объекта (перечисление частей поверхности и построение их комбинаторной структуры), построение групп вращений слоев объекта вдоль каждой из гиперплоскостей разреза, вычисление перестановок частей при этих вращениях. (в общем, это многомерный многогранник Рубика общего вида). Этапы идут подряд, код в них почти не повторяется.

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

Функция, которая сравнивает два элемента массива, не является замыканием, не использует переменных снаружи.
В качестве модельного примера я брал такой:
double[]A;
int[]B;
....
Array.Sort<int>(B,(i,j)=>(A[i]<A[j] ? -1 : A[i]>A[j] ? 1 : 0));


Чует моё сердце, что это действительно какой-то JIT-рантайм. CLR, скорее всего, судя по вашей подготовке и культуре труда. Я прав?
С#

Смысл hot spot'ов я не понимаю. Вики говорит, что оно как-то связано с различным уровнем оптимизаций на этапе JIT-компиляции, но до этого уровня анализа кода я еще не добрался :( Хотя и хочется разобраться, что там внутри у байт-машины. Но сначала надо обработку распараллелить. Опять буду велосипед изобретать, судя по всему :(

(ООП) Наличие огромного количества «....Manager» классов, которые содержат все методы манипуляции с объектами, которые, в свою очередь, совсем не содержат (или содержат мало) методов.

То есть, классы сервисного слоя в Java-приложениях, которые оперируют объектами anemic моделей — это признак плохого программиста?
Sign up to leave a comment.

Articles