Пользователь
0,0
рейтинг
21 октября 2011 в 15:26

Разработка → Признаки плохого программиста перевод

Неспособность рассуждать о коде


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

Симптомы

  • Наличие «волшебного», «вуду» кода или кода, который не имеет никакого отношения к целям программы, но всё равно тщательно поддерживается (например, инициализация переменных, которые никогда не используются, вызов функций, не имеющих отношения к цели, создание выходных данных, которые не используются, и т.д.).
  • Многократные вызовы идемпотентных функций (например, вызов save() по нескольку раз, «чтобы уж точно»).
  • Исправление ошибок написанием избыточного кода, который замещает данные, полученные при исполнении неисправного кода.
  • «Йо-йо код», который конвертирует значения в различные представления, а потом конвертирует их обратно ровно в то же представление, с которого начинали (например, преобразование десятичного числа в строку, а потом обратно в десятичное число, или padding строчки с последующим trim'ом).
  • «Бульдозерный код», который создает впечатление рефакторинга посредством разбития кусков кода на процедуры, которые, правда, затем невозможно использовать где-либо еще (высокая когезия).


Лечение

Чтобы справиться с этим пороком, программисту следует пользоваться встроенным в IDE debugger'ом как помощником в случае неспособности «шагать» по коду построчно. В Visual Studio, например, можно установить breakpoint в начале «проблемной» зоны и затем шагать, нажимая F11, параллельно следя за значениями переменных, до тех пор пока не станет ясно, что именно код делает. Если в целевом окружении нет такой возможности, следует практиковаться в том, в котором это возможно.

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

Плохое понимание модели языка программирования


Объектно-ориентированное программирование — пример модели языка программирования, равно как и функциональное, и декларативное программирование. Все они существенно отличаются от процедурного или императивного программирования, точно так же как и процедурное программирование существенно отличается от ассемблера или программирования с помощью GOTO-инструкций. Также существуют языки, которые следуют какой-то распространённой модели программирования (скажем, объектно-ориентированному программированию), но вносят в неё какие-то усовершенствования, как например генераторные выражения (list comprehensions), обобщенное программирование (generics), утиная типизация (duck typing) и т.п.

Симптомы

  • Использование любого необходимого синтаксиса для того, чтобы «вырваться» из предлагаемой языком модели, и написание оставшейся части программы в императивном/процедурном стиле.
  • (ООП) Попытки вызова не статических функций или присвоения переменных в неинстанциированных классах, проблемы с пониманием, почему такие конструкции не компилируются.
  • (ООП) Наличие огромного количества «....Manager» классов, которые содержат все методы манипуляции с объектами, которые, в свою очередь, совсем не содержат (или содержат мало) методов.
  • (Реляционное) Обращение с базой данных как с хранилищем объектов, исполнение всех JOIN'ов и проверки целостности на клиентской стороне.
  • (Функциональное) Создание многих версий одного и того же алгоритма для обработки разных типов или операторов вместо передачи функций высшего порядка обобщенному алгоритму.
  • (Функциональное) Ручное кэширование результатов детерминистических функций на платформах, которые делают это автоматически (SQL или Haskell).
  • (Функциональное с «чистыми»(pure) функциями) Использование копипасты из чужого кода для того, чтобы побороть I/O и монады.
  • (Декларативное) Установление индивидуальных значений в императивном коде вместо использования связывания данных (data binding).


Лечение

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

Шаг 1: «ООП — это просто структуры с методами».
Шаг 2: «Методы в ООП — это просто функции, исполняющие мини-программу со своим собственным набором глобальных переменных».
Шаг 3: «Глобальные переменные называются полями, некоторые из них приватные и невидимы снаружи мини-программ».
Шаг 4: «Сама идея наличия приватных и публичных элементов — скрыть детали реализации и выставить наружу чистый интерфейс, и называется это инкапсуляция».
Шаг 5: «Инкапсуляция означает, что моя бизнес-логика не должна засоряться деталями реализации».

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

Шаг 1: «Функциональное программирование — это когда всё делается через цепочки детерминистических функций».
Шаг 2: «Когда функции детерминистические, их не нужно вычислять до тех пор, пока это не потребовалось в выходных данных, и вычислять необходимо только ту часть, которая действительно потребовалась. Это называется ленивыми и частичными вычислениями».
Шаг 3: «Для того чтобы поддерживать ленивые и частичные вычисления, компилятор требует, чтобы я писал функции в терминах трасформации одного параметра, иногда делая результатом таких преобразований другую функцию. Это называется каррированием (currying)».
Шаг 4: «Когда все функции каррируемы, это позволяет компилятору выбрать наилучший план исполнения с помощью constraint solver'а».
Шаг 5: «Позволяя constraint solver'у самому решать все неважные детали, я могу писать программы, описывая, что я хочу, а не как именно это получить».

Дефицит исследовательских навыков / Хронически плохое знание возможностей платформы



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

Симптомы

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

  • Изобретение или создание механизмов, которые уже встроены в язык, например, event'ы и handler'ы, регулярные выражения.
  • Изобретение классов и функций, которые уже есть в фрэймворке (например, таймеры, коллекции, алгоритмы сортировки и поиска).*
  • Сообщения «Напишите мне код, плиз!» в различных форумах.
  • «Окольный код», который выполняет свою задачу с гораздо большим количеством инструкций, чем требуется (например, округление числа через преобразование к строке и обратно).
  • Постоянное использование старомодных техник, даже если новые лучше в текущей ситуации (например, создание полноценных именованных функций там, где нужно лямбда-выражение «на раз»).
  • Нереального размера «зона комфорта», когда человек готов пройти экстремально длинный путь, решая проблему примитивными средствами.

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

Лечение

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

Неспособность понять указатели


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

Симптомы

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

Лечение

Мой друг Джо жил в том же отеле, что и я, но я не знал, в каком именно номере. Однако я знал, где остановился его знакомый Фрэнк. Так что я пошел туда, постучал в дверь и спросил Фрэнка: «Где остановился Джо?». Фрэнк не знал, но он знал, в какой комнате живет Теодор, коллега Джо. Так что я пошел в комнату Теодора и спросил, где остановился Джо, и Теодор сказал мне, что Джо в комнате 414. Там-то я его и нашел!

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

Сложности с рекурсией


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

Симптомы

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


Лечение

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

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

Признаки заурядного программиста



Неспособность мыслить коллекциями


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

Симптомы

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

  • Исполнение атомарных операций над элементами коллекции внутри цикла for или foreach.
  • Map или reduce функции, содержащие циклы для итерации по набору данных.
  • Получение большого набора данных с сервера и вычисление сумм на клиенте, вместо использования агрегирующих функций в запросе.
  • Написание функций бизнес-логики с трагическими сайд-эффектами, вроде изменения пользовательского интерфейса или выполнения I/O функций.
  • Классы сущностей, которые открывают свои собственные соединения с базой данных или получают файловые дескрипторы и держат их активными всё время жизни каждого из объектов.


Лечение

Представляйте себе дилера в казино, который сдвигает колоду карт и перемешивает две части вместе пролистыванием, это может подтолкнуть вас к размышлениям о коллекциях и о том, как вы можете оперировать ими. Другие стимулирующие визуализации:
  • въезд на платную дорогу, оборудованный несколькими пунктами оплаты (параллельная обработка);
  • ручейки, которые соединяются в потоки, которые соединяются в рукава, из которых получается река (парралельное исполнение reduce / агрегирующие функции);
  • застёжка-молния (простые join'ы);
  • траспортная РНК, собирающая аминокислоты и соединяющаяся с информационной РНК внутри рибосомы, чтобы стать протеином (многостадийные funtion-driven join'ы);
  • то же самое, происходящее в миллиардах клеток в апельсиновом дереве, чтобы превратить почву, воду и солнечный свет в апельсиновый сок (map/reduce в больших распределенных кластерах);

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

Отсутствие критического мышления


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

Симптомы

  • «Движки бизнес-правил».
  • Толстые классы со статическими утилитами, или библиотеки, решающие множество разных задач, но имеющие одну область имён (namespace).
  • Архитектуры, которым начали требоваться эпициклы.
  • Добавление в таблицы колонок для не имеющих прямого отношения к этой таблице данных.
  • Несоблюдение однородности в именовании переменных и методов.
  • Ментальность «мужика с кувалдой», или изменение условий задачи так, чтобы она могла быть решена с помощью одной конкретной технологии.
  • Программы, которые своей сложностью затмевают задачу, которую они должны решать.
  • Патологическое и излишнее «защитное» программирование (defensive programming), «энтэрпрайзненький код».

Лечение

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

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

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

Пинбол-программирование



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

Симптомы

  • Один try-catch блок, включающий в себя всё тело Main(), рестартующий программу.
  • Использование строк или целых чисел для значений, которые могли бы иметь более подходящий им тип в языке со строгой типизацией.
  • Упаковка сложных данных в разделённые строчки и их парсинг в каждой функции, где эти данные используются.
  • Неспособность использовать утверждения или контракты методов на функциях, которые делают предположения о своих аргументах.
  • Использование sleep() для ожидания пока другой thread закончит свою работу.
  • Инструкции Switch над неперечисляемыми значениями без блока «иначе».
  • Использоватие automethod'ов или reflection'ов для вызова методов, исходя из неподготовленного пользовательского ввода.
  • Использование глобальных переменных для возврата из функции более одного значения.
  • Классы с одним методом и набором полей, которым необходимо установить значения, по сути, для передачи параметров в метод.
  • Обновление связанных данных в БД без использования транзакций.
  • Попытки восстановить состояние базы данных без транзакций и rollback.

Лечение

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

Вам нужно ознакомиться с механизмами вашей платформы, которые позволяют сделать вашу программу надёжной и пластичной. Три основных вида таких механизмов:
  • Те, что останавливают исполнение программы до того, как причинён какой-либо ущерб тем, что произошло что-то неожиданное, а потом помогают вам определить, что именно пошло не так (системы типов, assert'ы, exception'ы).
  • Те, что направляют программу по пути, который наилучшим образом обрабатывает неожиданности (try-catch блоки, мультиметоды (multiple dispatch), событийно-ориентированное (event-driven) программирование).
  • Те, что приостанавливают thread до достижения необходимого состояния (инструкции WaitUntil, мьютексы и семафоры, SyncLock'и).

Есть ещё и четвёртый механизм — unit тестирование, которое вы используете во время проектирования и разработки.

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

Незнание принципов безопасности


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

Симптомы

  • Хранение важной информации (имена, номера кредитных карт, пароли) без какого-либо шифрования.
  • Хранение важной информации с использованием неэффективных средств шифрования (симметричные коды с ключами, встроенными в саму программу; простые пароли; шифры подстановки; самостоятельно разработанные и непроверенные коды).
  • Программы, которые не ограничивают собственные привилегии перед тем, как принимать сетевые соединения или интерпретировать входные данные из ненадёжных источников.
  • Невыполнение проверок границ и других проверок входных данных, особенно в неуправляемых окружениях.
  • Создание SQL-запросов конкатенацией строк с необработанными входными данными.
  • Код, который пытается предотвратить использование уязвимости, пытаясь найти характерные особенности применения этой уязвимости.
  • Номера кредитных карт и пароли хэшируются без соли.


Лечение

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

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

Далее, проверьте запросы к базам данных, которые конкатенируют неизменённые входные данные в SQL запрос, и перепишите этот код с использованием параметризированных запросов, если это позволяет ваша платформа. Ну, или добавьте фильтрацию/экранирование всех входных данных, если нет. Это чтобы предотвратить атаки с SQL-инъекциями.

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

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

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

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

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

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

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

Признаки того, что вам не стоило бы быть программистом


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

Неспособность определить порядок исполнения программы



Симптомы

a = 5
b = 10
a = b

print a

Вы смотрите на этот код и не уверены, какое именно число будет напечатано.

Альтернативные профессии

  • Электрик
  • Слесарь
  • Архитектор
  • Инженер-строитель


Неспособность мыслить абстрактно



Симптомы

  • Сложности с пониманием различия между объектами и классами.
  • Сложности реализации шаблонов проектирования в ваших программах.
  • Сложности написания функций с низкой когезией.
  • Некомпетентность в регулярных выражениях.
  • LISP для вас непостижим.
  • Не можете понять тезис Чёрча-Тьюринга.


Альтернативные профессии

  • Уполномоченный по согласованию контрактов
  • Актёр


Синдром Плюшкина



Симптомы

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

Альтернативные профессии

  • Торговец антиквариатом
  • Бездомный с огромной тележкой хлама


Нарушение причинно-следственных связей



Симптомы

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

Альтернативные профессии

  • Завсегдатай заведений с игровыми автоматами


Безразличие к результату


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

Симптомы

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

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

Альтернативные профессии

  • Специалист по взысканию задолженности
  • Телемаркетинг
Перевод: cwenham
Виктор Билык @victorb
карма
133,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

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

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

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

            И какой смысл был указывать на мою опечатку? Вроде общеизвестно, что комментарии исправлять нельзя, но, немного пораскинув мозгами, можно дойти до того, что вместо «плохо» должно стоять «много». Или Вы намекаете, что я должен был написать еще один комментарий, с принесением извинений всем, чью психику я потревожил?
      • +1
        В отличии от статей по GTD, тут указаны конкретные ошибки, типа слабое знание платформы, не использование _название_фичи_ и пр. Вдруг кому-то поможет? Мясо явно больше, чем в большинстве статей по GTD.
    • +7
      Вас просто могут уволить за то что вы читаете вместо работы ;)
    • +1
      Да тут прямо руководство «как надо жить»
    • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Ну и, по традиции, привели бы кратенький список литературы по типу “Как стать хорошим программистом”
    • 0
      А также источник сведений о существовании в Haskell поддержки кэширования результатов вызова функций. Google выдаёт ссылку на Stack Overflow, где обсуждается эта тема и говорится, что в Haskell этой возможности нет.
  • +2
    Все не осилил. Надо будет прочитать. При взгляде не код вспоминается «краткость — сестра таланта». Это и к программистам тоже применимо :).
    • +4
      Я думаю, если учесть весь жизненный опыт, на котором основана статья, то процент сжатия информации получится неплохой. Вы когда мануал читаете к дремучему SDK, тоже жалуетесь на объем? =)
  • +4
    Исправление ошибок написанием избыточного кода, который замещает данные, полученные при исполнении неисправного кода.
    =============
    вот тут не соглашусь — это не всегда какой то симптом — часто это старый чужой проект в котором тебе дали быстренько пофиксить какую-то проблему
    • 0
      А мне позвольте не согласиться с Вами: даже если это «старый чужой проект», нельзя исправлять ошибки таким образом. Впоследствии после Вас может придти следующий человек, которому «дали быстренько пофиксить какую-то проблему», и в итоге ничего хорошего не получится.
      • +5
        проекты бывают разные, как и клиенты… бывают правки за которые никто не заплатит при этом искать ошибку можно несколько дней
      • +10
        В идеальном сферическом мире, возможно, так и должно быть. А в реальном мире никто не знает, как именно этот код работает. Документации нет. Тесты? Не, не слышал. Сроки ограничены. В результате лезть глубоко просто тупо страшно, да и некогда.
  • +13
    Бррр… Я по ходу эт… пошел вешаться...(
    • +3
      Я в фаербаге это проверил:

      a = 5
      b = 10
      a = b

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

    Вопрос к таким горе-программерам: нахера козе баян — нахера вообще писать на том, что не умеешь готовить? :-)
    • +2
      А есть еще способы научиться готовить?
      • 0
        Я думаю, что подразумевалось написание кода, используемого в производстве, т. е. не для самообучения. Но даже если и для обучения, то все равно тупое использование копипасты бесполезно, все равно что зубрежка.
  • –5
    Очень сумбурно написано. До конца не осилил.
    Лучше бы посоветовали прочесть «Совершенный код» макконела. Там все подробно, с доказательствами и нормальными рассуждениями.
    • +2
      Значит, у вас не наболело…
  • +28
    > Многократные вызовы идемпотентных функций (например вызов 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) вставил посередине.
    • 0
      И все равно это тяп-ляп. По-хорошему нужно разобраться почему его может не получиться удалить и починить правильно.
      • +10
        > И все равно это тяп-ляп

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

            нет, так тоже нельзя.
            • 0
              Я поэтому и написал: " или пока операция не будет отменена". IO операции в UI треде, разумеется, делать не стоит.
            • НЛО прилетело и опубликовало эту надпись здесь
              • –1
                Моё мнение, тезисно:
                1. два delete подряд — не ошибка
                2. это не идеальное решение
                3. это решение — максимально полезное среди решений со схожей сложностью
                4. выбирая между простым частичным решением (оно же, по мнению интернет-аналитиков, «экстравагантный» «говнокод») и увеличением сроков разработки в разы, я бы, на месте гугла, выбрал простое частичное решение и послал бы интернет-аналитиков в задницу. К сожалению, я не гугл и не могу так поступить :)
                • НЛО прилетело и опубликовало эту надпись здесь
    • +1
      Удаление файла — идемпотентная операция? Ну, у меня для вас плохие новости.
      А кроме того, так можно удалить чужой файл, например.
  • +11
    Вопрос к переводчику: «Вам послайсить или целым писом?»
  • 0
    Отличная статья и, в кои-то веки, близкий к отличному перевод! Спасибо.
    • –16
      не заметил ни каких пометок в начале и конце текста что это перевод и ссылку на источник. Плагиат?
      • +3
        Рядом с заголовком иконка z>я, в футере ссылка на оригинал и автора (cwenham).
        • –12
          как тут (на хабре) всё сложно…
          нет бы написать текстом, зачем такой выпендрёж нужен…
          • +1
            Нет бы разобраться в терминологии и основных концепциях Хабра, перед тем как беспочвенно обвинять людей в плагиате.
            • –5
              мозги где? там значок вопроса не видно, да?
              • 0
                да заткнитесь уже
      • +7
        image
        image
        • –10
          какая досада, почтовик картинки не кажет, пришлось сайт открывать.
      • +1
        (блин, в каждой статье про перевод это)

        И в начале, и в конце текста есть пометки, в начале — Z->A, в конце — ссылка на автора, рядом с ником автора перевода.
        • –5
          а мне видимо надо было от рождения это знать, чтож поделать, родители не доработали, нужную программу не до грузили в мозг :)
          • НЛО прилетело и опубликовало эту надпись здесь
            • –2
              разве? по моему я подъёбывал, не всем же дано целую библиотеку в голове с рождения иметь :)
    • –1
      Да на троечку перевод, если честно.
  • –2
    Указатели, рекурсии — может стоит переименовать статью «Признаки плохого С++ программиста»? В том же php указатели в большинстве случаев не нужны, и даже вредны, так как усложняют понимание программы не принося ощутимой пользы, или в силу заморочек интерпретатора создают труднонаходимые баги. А рекурсии опасны и их часто лучше заменить более сложным итеративным алгоритмом, одна рекурсия при неосторожной работе с памятью съест всю память на сервере что положит сайт и кучу бэкграунда, проц тоже может весь скушать, да можно писать без утечек памяти, но программ без багов не бывает и рекурсия может проявить себя только в условиях которые не были предусмотрены при написании. С итеративным алгоритмом вероятность такого меньше.

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

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

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

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

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

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

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

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

      }

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ===========

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

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

    • +2
      Согласен с Вами полностью.
      Код становится читаемым!
    • 0
      «когезия» — это наверное «связность» по-русски? Нет?
      • 0
        видимо да. но мне лично не понятно, чем когезия отличается от коуплинга.
        в википедии на инглише 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
        нужно внимательно их прочесть, но завтра — утро вечера мудренее)
      • 0
        видимо да. но мне лично не понятно, чем когезия отличается от коуплинга.
        в википедии на инглише 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
        нужно внимательно их прочесть, но завтра — утро вечера мудренее)
        • +1
          Cohesion — связность — что-то типа силы интеграции внутри самого модуля (насколько связаны части модуля друг с другом). Чем она выше (сильнее связи), тем лучше (но в меру).

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

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

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

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

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

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

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

      Да, создатели MSO и LO программисты не плохие, но тоже без меры гордые.
    • 0
      или Intelij Idea
    • 0
      А что, разве нет? По мне так, одна из самых кривых IDE, что я видел.
  • 0
    спорно.
  • НЛО прилетело и опубликовало эту надпись здесь
    • –2
      Хм… А зачем в борделе понтоваться? :)
  • –1
    > Ваша программа производит выходные данные, которые обрабатываются другой программой (например, браузером)

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

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

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

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

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

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

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

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

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


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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      Если да, то хорошо ли вы понимаете в чем смысл hot spot'ов и что именно это значит для ваших бенчмарков?
  • 0
    Десериализация на 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-компиляции, но до этого уровня анализа кода я еще не добрался :( Хотя и хочется разобраться, что там внутри у байт-машины. Но сначала надо обработку распараллелить. Опять буду велосипед изобретать, судя по всему :(

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

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

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