Pull to refresh

Comments 99

Полностью с Вами согласен, очень много неудачных применений паттернов, из-за этого их считают ненужными и вредными. Не редко слышу на собеседованиях: «я не использую паттерны, это зло», это мнение удручает. Но проект, с правильно подобранной архитектурой, читать и расширять — вправду удовольствие!
Лучше знание академических методов программирования + умение правильно применять ООП, чем тупое следование каким-либо паттернам. Паттерны действительно зло в том плане, что для того, чтобы уметь их применять нужно сначала понимание концепции, которое никак не появиться после тупого изучения оных…
Так можно сказать про все знания. Бездумное применение фреймворков, которые не подходят проекту — зло, но мы не называем фреймворки злом. Всё надо уметь применять с умом, но, пожалуй, всё-же надо знать больше, пусть один раз ошибиться и понять разницу, чем просто говорить, что это всё зло и читать не буду!
… но мы не называем фреймворки злом.

Я называю… Фреймворки — зло!
А еще созданы они для того, чтобы не простаивали ресурсы серверов. :-)
Разница огромна. Фреймворк это инструмент, паттерн это некое навязывания определенного стиля мышления.

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

Вобщем имхо развивать надо «обще-разработческую эрудицию», а для этого надо решать РАЗНЫЕ задачи. Ну если конечно не хочешь всю жизнь подметать улицу быть Junior'ом.
Паттерны это всё же возможные способы решения возможных проблем. Если нет проблемы, то не нужен паттерн, если есть проблема, то её можно решить и другим способом, если он по каким-то критериям заметно эффективнее. Паттерн нужно использовать когда проблема есть, но решать её нестандартно особого смысла нет — профита мало, а вот читаемость кода ухудшится — читателю придется разбираться с деталями реализации, а не просто пробежать глазами код, увидев знакомое название.
Да, знакомое название — это практически треть, если не половина пользы от паттернов. Хорошо экономит внимание…
Я считаю, что паттерны — это не формулы, и они не навязывают стиль мышления, они просто показывают, как какую-то задачку можно здорово решить. Это просто как посмотреть чужой код и научиться чему-то, а не писать неудачные велосипеды (как удачно сказано ниже VolCh).

Я абсолютно согласен, что надо решать разные задачи и что паттерны не способны сильно изменить ситуацию, но это знания, это опыт других разработчиков, зачем его бояться?
Согласен :) не надо бояться чужого опыта… я ведь не против паттернов, я просто против того чтобы их ставить во главу угла… А сейчас, некоторые молодые ИТ-специалисты размахивают ими как маньяк бензопилой…
Просто нужно себе задавать вопрос «зачем я тут собираюсь использовать паттерн? Вижу возможность или необходимость?» У каждого паттерна есть проблема, которую он решает, если нет проблемы или в данном случае он её решает плохо (проблема похожа, но не точно та, или недостаки, которые есть у многих паттернов в проекте критичны), то просто не нужно его применять.

Это я не вам лично, а некоторым молодым ИТ-специалистам :)
Я стал применять паттерны, после того как прочитал книги и увидел, что часть я изобрел сам почти как в книгах, часть изобрёл так, что лучше бы не изобретал, а с частью проблем просто не сталкивался.
часть изобрёл так, что лучше бы не изобретал
Интересно бы узнать, какие и как. Чисто с психологической точки зрения — интересно «как бывает»…
Синглтон тот же. :) Вот нужна была мне глобальная переменная конкретного типа, но обычное создание в каждом файле почему-то не устраивало. Не мог, кажется, подходящего места выбрать, чтобы строго один раз иницииализировались без кучи проверок, но наворотил там. как-то недогадался статический метод типа get_instance сделать.
Ну, до того, что акцессорный метод вместо публичного поля — это не только инкапсуляция, это надо специально догадываться, тем более когда педалируют именно инкапсуляцию;-) А отсутствие привычки к приёму рефакторинга «Encapsulate field» (которая вырабатывается использованием внутри IDE, имеющих её) дополнительно осложняет догадывание…

Кстати, нынче синглтон числится в анти-паттернах…
Я тогда и слов типа рефакторнг-то не знал.
Кстати, нынче синглтон числится в анти-паттернах…

если не сложно, можно чуть подробнее?
Грубо говоря, те же недостатки, что и у глобальных переменных.
И в чём же недостаток? Постоянно едят память?
Увеличивают связанность различных модулей, причем делает её неявной. Особенно, если запись в них происходит не один раз при инициализации процесса, а в разных местах. Бывает весьма затруднительно выяснить откуда в ней появилось то или иное значение.
Ну так код же разработчики пишут, поэтому они должны знать, где и зачем используется переменная и когда её можно использовать, а когда не надо.
Это легко говорить, когда ты один пишешь и код на один экран влезает. А чем больше кода и чем больше народу, тем сложнее держать всё в голове.
Проблема не в памяти. Проблемы следующие:
1) Вызовы статических методов намертво привязывают вас к реализации. В каноническом GetInstance нет возможности сконструировать другой тип, вы тащите за собой синглтон и все его зависимости
2) Тестируемость приложения. Не дай бог синглтон завязан на внешние зависимости (конексты, сервисы, бд). Все, что использует такой контекст становится не тестируемым
3) Нарушение области видимости: все имеют доступ к синглтону, что заставляет вас делать инстанс immutable

Лучшее решение — отделить логику создания от контракта. Для этого нужно использовать IOC-контейнер и внедрение зависимостей. Вы получите тот-же результат, но в качестве обычного не-статического поля вашего класса.
Во-во, долгое время я никак не мог прочитать GoF, даже когда купил книжку. Наконец, заставил себя, предвкушая новые идеи, и разочаровался: 70-80% паттернов я уже знал. Из них часть я даже паттернами не мог назвать, т.к. с моей точки зрения они очевидны для решения той задачи, для которой предназначены. С другой стороны, что-то новое я все же узнал и теперь, быть может, даже смогу назвать паттерн по названию :)
Тут уже писали — чуть ли не половина пользы паттернов в том, что они ввели стандартные имена для стандартных решений.
Согласен. Вот только память у меня дырявая на всякие названия.
Чтобы умело применять какой-либо паттерн, нужно сначала написать что-то близкое по реализации к нему использую лишь свой ум. Потом, узнав о существовании подобного паттерна, вы уже никогда не будите применять его как попало, ибо точно понимаете для каких ситуаций он был создан. Можно сказать, что чтобы применять паттерны правильно нужно переизобрести их хотя бы раз.
Не столько по реализации, сколько по проблематике.
На переизобретение некоторых подходов и патернов у меня уходило по пять десять лет, ибо я как-бы рос вместе с индустрией. И да, я согласен, что когда ты своей кровью допер почему нужно комментировать сразу и всё, как тяжело жить без ИДЕ, и в каких местах нужно использовать ORM а в каких чистый запрос, и почему не всегда стоит доверять оптимизаторам, то это бесценно. Но если все программисты будут все вещи переизобретать, то мы так далеко не уедем.
Читая паттерны программист записывает себе «под корку» решение проблемы, с которой он еще не встречался. Хвалебные отзывы о правильности применения паттернов заставляют нашего программиста пытаться искать места применения данных шаблонов, но так как он все еще не встречался с решаемой паттерном проблемой, в большинстве случаем идентификация правильности применения паттерна производиться не правильно, что и приводит к казусам мельком описанным в статье. Я вижу два пути правильного изучения паттернов:
1 ) потом и кровью — на собственных реализациях
2) путем привлечения советов от более опытных коллег, которые возможно когда-то шли первым путем.

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

На самом деле мне кажется нужно просто понимание того, что знать паттерны конечно надо, но считать их серебрянной пулей не обязательно. У ждуниора пока он ждет свой опыт должны быть два теоретических знания — что паттерны, и знание о том, что паттерны нужны не всегда. А уже навыки понимания уместности придут к нему или с кровью, или с советами старших товарищей…
Имхо, знание, что есть паттерны обычно перевешивает, знание того, что они не всегда нужны.
кровь на то и нужна )))
Можэно обойтись и без этого… Сорри за очепятки… Я сейчас Агату слушаю…
Именно поэтому всегда дополняют: «должен уметь применять паттерны», знать когда они нужны, а когда вредны
Я знаю, откуда берутся паттерны и пародию на что они из себя представляют. Причём с прообразом познакомился раньше, чем с пародией. Поэтому я не использую паттерны, я просто стараюсь программировать в функциональном стиле.
Мне кажется, что многие паттерны не подходят для функционального программирования
На мой взгляд, они являются пародией на часть типовых примеров применения принципов функционального программирования.
Зато часто начинается обратный процесс: в функциональном языке пытаться использовать принципы ООП.
Многие просто для ФП не нужны. Скорее эти паттерны являются попыткой реализовать отсутсвующую в ООП функциональность, которая в ФП из коробки.
Этот тезис надо бы вдалбливать в голову перед изучением паттернов…
Для этого надо сначала ФП давать.
" Мы сделали Java-проект, который в ООП-виде представлял его жизнь, его друзей и разные интересности, с которыми он взаимодействует. "

А можете исходник выложить? Реально интересно стало
Этот проект содержит много личной информации, так что выложить его было бы не очень этично.
UFO just landed and posted this here
Отличная статья, как и все у DreamWalker

Некоторое время назад писал здесь текст о трёх уровнях развития программиста.

Данная статья великолепно иллюстрирует переход от второй ступени программиста — «сделаем всё и везде идеально и накрутим сложной архитектуры» (у меня есть знакомый, который называет таких товарищей «архирастами») — к третьей, которые понимают, что микроскоп — это микроскоп, а молоток — это молоток, и использовать микроскоп для того, чтобы забить гвоздь, только потому, что это более совершенный инструмент, смысла нет.
Эти три уровня выделены весьма верно. Больше всего мне нравится третья стадия «Здравомыслие», но, увы, на сегодняшний день очень мал процент программистов, которых действительно можно назвать здравомыслящими.
Вот побольше таких статей, как твоя, и их станет больше :)
Знать все патерны это круто, но для меня зубрежка хуже адовой муки. А в результате — полный формат после нескольких месяцев. Я всегда пишу код вначале подумав о том, как я его буду рефакторить. И всегда себя спрашиваю что хочет код, что хочу я и как это совместить. Если код хочет развалиться на составляющие части или он хочет схлопнуться во что-то более компактное — значит пора рефакторить и при необходимости читать литературу как это делать.

Интересно, как это классифицировать?
А не надо их знать наизусть. Надо уметь увидеть какую-то проблему (возможно только потенциальную), вспомнить что есть паттерн её решающий, открыть справочник, посмотреть там название и реализацию, после чего реализовать и назвать как в справочнике (если действительно это ваша проблема и она уже есть — если ваша, но пока ещё её нет, то поставить тудушку «когда нужно будет извещать второй объект — реализовать наблюдателя», чтобы потом не рыться).
Знать все патерны это круто, но для меня зубрежка хуже адовой муки
Есть полушутливый «отмаз»: их придумал немец;-) Эрих Гамма, причём швейцарский немец — а это (по словам самих швейцарских немцев;-) ) «немцы в квадрате». Немцы умеют своей аккуратностью компенсировать дефективность организации/дизайна (что хорошо) и могут создавать нечто в расчёте на наличие такого умения у пользователя (что плохо) ;-)

Лучше учить ФП ;-).
А вот меня всегда интересовало: зачем применять костыли?
Предполагаю, что просто из-за недостатка времени или лени. Я имею ввиду, что вся проблема в незнании некоторых инструментов API языка программирования: например, вместо KVO постоянно следить за параметрами при помощи тех же таймеров (потому что таймеры мы уже знаем, а документацию специализированного паттерна еще не изучили).
У меня еще не было опыта работы в большой софтверной компании, так что прошу ответить на вопрос более опытных программистов: прав ли я в своем предположении?
Вы проводите равенство между ленью и незнанием/непониманием? Это две разных причины появления костылей.
Мне кажется, что понять можно все (в области уже существующих в IT технологий); нужно только время и желание. Я придерживаюсь мнения, что непонимания, как такового, быть не может в принципе (его не существует). Тем более с нынешним уровнем документации: все описано достаточно подробно.
Следовательно, я не провожу равенство, так как не признаю слово «непонимание».
Под пониманием я имею в виду осознание что ли. Плюс может быть неправильное понимание. Ну и про незнание вы ничего не сказали. Равняете вы его с ленью? Незнание может быть не от лени, а от отсутствия информации или просто из-за других приоритетах. Решил человек пока не забивать себе голову паттернами, а хорошенько изучить алгоритмы или библиотеку.
Про незнание:
Что может препятствовать пониманию? Только незнание.
А от чего может быть незнание? Возможно, от лени, недостатка информации, недостатка времени или низкоприоритетности знаний.
— В случае с современными языками программирования (а в частности, с их документацией), недостаток информации отсеивается: информации достаточно.
— При недостатке времени в первую очередь главное закончить задачу, а после уже узнавать как. Говорить «я не понимаю, как я это сделал» — как минимум, глупо. Стоит говорить «Я пока что не знаю, как у меня это получилось». Почему «Пока что»? Потому что хороший программист (мое предположение) должен быть любопытным, и в итоге он докопается до истины.
— Если задача низкоприоритетна, то ее можно решить любым способом. Когда мне нужно порезать мясо для последующего прогона через мясорубку, совершенно неважно, чем я буду его резать: специализированным ножом или заточенным мачете. Я не знаю, что лучше, но мачете под рукой, а специализированный нож на кухне у соседей.
В случае, если времени достаточно и задача приоритетна, то для незнания остается лишь одно оправдание — лень.

Про непонимание:
О чем Вы думаете, когда говорите «Я не понимаю»? Может быть, «Я не знаю, как это работает?»

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

И в самом конце, прилагаю интересное видео от сотрудника русского подразделения EA:

Я не понимаю, как я не понимаю по-русски

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

А про незнание — про приоритеты я имел в виду приоритеты в получении знаний. Утрируя, человек спросил что нужно знать, чтобы стать программистом и получил список из пары десятков книг и начал их читать, но на момент решения задачи прочитал только 19, а 20, в которой описывался какой-то алгоритм или паттерн ещё не прочитал. А может ему книгу с этим паттерном или алгоритмом даже не назвал никто. И подсказать некому.
Думаю, это от того, что, что так быстрее и (что важнее) проще для человека, который пишет сам костыль. Ведь это быстрое, толком не продуманное решение — но оно пришло человеку в голову первым, значит будет для него самым очевидным и понятным. Даже если есть готовые методы, о которых он не знает — ведь они реализованы не им, а значит не так близки и структурированы (для костылеклепателя).
Спасибо. Я обычно тоже пишу небольшие костыли, которые первыми пришли в голову; а потом занимаюсь рефакторингом, постепенно сводя число костылей к нулю.

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

Вот например у себя в коде нашел, сначала клиент получал один набор событий, потом добавили еще, и вместо того что бы менять логику приложения просто нафигачили кода в EventEmitter-е:

было:
emit: function (event, users, options) {
  users.forEach(function (user) {
    SessionRepository.find({ uid: user.id }).then(function (sids) {
      sids.forEach(function (sid) {
        publisher.publish(sid, event, options);
      });
    });
  });
}


стало:
emit: function (event, users, options) {
  users.forEach(function (user) {
    if (~[this.EVENT_NEW_SHOT, this.EVENT_SHOT_FAIL, this.EVENT_SHOT_SUCCESS].indexOf(event.id)
        && user.id === event.data.sourceUser.id) {
      if (event.id === this.EVENT_SHOT_SUCCESS) {
        event.id = this.EVENT_GET_FRAG;
      } else if (event.id === this.EVENT_SHOT_FAIL) {
        event.id = this.EVENT_YOU_FAIL;
      }
    }
  
    SessionRepository.find({ uid: user.id }).then(function (sids) {
      sids.forEach(function (sid) {
        publisher.publish(sid, event, options);
      });
    });
  });
}


Красиво? — нет. Работает? — да. :)
Проблема в том, что в большом проекте сложно с самого начала спроектировать грамотную архитектуру, которая будет рассчитана на все ситуации, которые могут возникнуть в проекте. Рано или поздно в проекте появляется задача, которая на текущие подходы никак не ложится. И мы встаём перед выбором: либо тратим пару дней на переправку архитектуры, либо пишем костыль на несколько строк кода. И проблема тут не в лени, а в нерентабельности пересмотра системы.
Существует ещё много разных типов костылей, но я описал те, о которых велась речь в статье.
Поэтому и существует понятие эволюционный рефакторинг.
Прямо сейчас я вместо явных формул для вычисления частных производных некоторого преобразования собираюсь запрограммировать их численное вычисление. С моей точки зрения, это костыль. Почему выбираю такой путь?
1) так быстрее написать
2) скорость и точность вычисления в этом месте не очень важны
3) меньше шансов ошибиться — формулы достаточно сложные, и даже при переносе их из системы символьных вычислений может случиться опечатка
4) для облегчения поддержки: если исходное преобразование придётся поменять, то явные формулы пришлось бы пересчитывать, а здесь — разве что изменить число переменных.

Есть ещё одна возможная причина применения костылей — параметр подобран экспериментально, с ним алгоритм работает лучше всего. А обосновать или автоматизировать подбор этого параметра пока не получается: для этого потребовался бы искусственный интеллект.
А почему это костыль? Это как-раз и есть дизайнерское решение: Вы уменьшили количество кода и упростили его поддержку. Это как использовать define.
Экспериментальный подбор параметров — это тоже не костыль, это интегрирование естественных наук.
Как по мне, то многие паттерны не нужно применять заранее, а только когда есть реальная необходимость. Взять тот же Visitor — пока нет необходимости делать много операций над многими объектами, то и не надо его применять, просто тупо захардкодить. Появится необходимость — ещё раз захрдкодим и отрефакторим, увидев, что нарушаются DRY и KISS. Тоже самое с абстракциями — незачем делать скажем интерфейс, если только пока одна его реализация есть.

Плюс нужно учитывать специфику языка — многие практики имеют в виду ЯП с сильной статической типизацией (Java, C++, C#) и без учета функциональных возможностей, а в рамках ЯП с со слабой динамической типизацией (PHP, JavaScript) и реализующие многое из ФП некоторые паттерны становятся просто не нужны.
Мне кажется, здесь в первую очередь YAGNI, сейчас во многих проектах очень большой архитектурный оверхед, который простые вещи заставляет делать через длинную цепочку и десять слоёв абстракции.
Насчёт Визитора — смотрю en.wikipedia.org/wiki/Visitor_pattern#Java_example и вижу, что интерфейс CarElement косвенно (через клсаа CarElementVisitor) зависит от реализующих его классов Wheel, Engine, Body и Car . Петля зависимости. Бывает ли Visitor без циклической зависимости — я не знаю, полагаю что нет. Порок дизайна во всей красе, врождённый, принципиально неустранимый.

«Но мы его любим не за это», более того, естественно бы предположить, что минусы сделаны ради плюсов, которые должны из перевешивать. Плюсы есть, и немалые: вся конкретная функциональность вынесена в отдельный класс и «обынтерфейсена» (на неё натянут «паттерн 'Стратегия'», в нормальных IDE для Java делается через пункт контекстного меню «Refactor» -> «Extract interface»), может при использовании нормальных контейнеров быть подменена через Dependency Injection. Для контейнерного элемента (превед, «паттерн 'Композит'») при реализации другой «Стратегии», которая "CarElement" реализован «паттерн 'Шаблонный метод'», тупо последовательно транслирующий к элементам вызов «остратеженного» метода «Стратегии».

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

Интерфейс нужно делать тогда когда он нужен.
Цели могут быть разные — к примеру его можно использовать как часть TDD. Сначала придумываем АПИ, пишем под него интерфейс, потом его реализуем. Вроде можно сделать класс пустышку, но если АПИ продумывает один разработчик а реализует другой, то лучше это разделить.
Это общий пример.
Мне показалось что статья не несёт никаких идей. Вы рассматриваете очень много возможных событий и описываете очевидные для таких событий действия.
Проект без поддержки — можно лепить костыли
Проект с поддержкой — костыли это плохо
Сложный проект — продумывать архетектуру
Простой проект — в нём разберуться даже если чесать ухо ногой

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

Я бы добавил, что для того, чтобы стать хорошим программистом, нужно определенное время поработать подмастерьем у мастера. Как было правильно замечено, можно начитаться кучи книг про паттерны, алгоритмы и написание кода и потом неоправданно лепить это где надо и где не надо. Нужен рядом опытный программист, который будет указывать на ошибки написания кода и показывать на способы их исправления. А также будет направлять в совершенствовании кода.
Я думаю, это характерно для любой профессиональной деятельности. На начальных этапах любой деятельности всегда нужен ментор, учитель, сенсей (выберите подходящее)
Как возможная замена выставление своего кода в паблик и сбор комментов. А также чтение чужого. Единственное надо как-то отсеивать неадекватов, теоретиков и т. п.
А также чтение чужого.
Ага, чтение исходного кода классов Java оставило у меня впечатление, что я пишу хорошо;-) Позже оно было драматически развеяно (даже испытательный срок завалил), а про код классов Java из сановской «коробки» я понял, что в плане качества кода это приличная помойка, что потом подтвердили и другие…

Теперь, правда, они его уже подпричесали…
Ну, сначала надо было проконсультировать у народа, какой код можно считать хорошим.
Казалось бы, есть ли лучший кандидат на «народ», чем сотрудники фирмы-создателя языка?..
А они вам сказали, что код хороший? Или вы так решили почему-то? :)
Совершенно с вами согласен.
Но вы уже начинаете писать про методики, а я больше писал именно про правильное отношение человека к своему ремеслу. Если оно изначально сформировано не так, как нужно, то мастера не помогут.
Но именно мастера, как мне кажется, и закладывают данное отношение. Человек может штамповать рабочий код и быть уверенным, что все замечательно. А сложности с развитием кода списывать на сложность ремесла.
Со мной произошло именно так. Я только начал изучать Java после 1С, и мне досталась в управление маленькая заготовка проекта для Android. Мне практически пришлось все переписать с нуля, т.к. код валился от ошибок. Да, и просто был наколенной поделкой. Я начал развивать этот проект как OpenSource. Проект рос и я делал его один. В определенный момент я стал понимать, что мне все сложнее и сложнее вносить в него изменения. Мне казалось, что все дело лишь в том, что кода стало много. Но вот на некоторое время к проекту подключился опытный человек. Он переписал больше половины того, что было сделано мною и при этом заметил, что проект очень маленький. Именно тогда я узнал про паттерны, и про то, что одного знания ООП мало. Его участие в проекте, путь и кратковременное, дало мне хороший толчок и новый взгляд на разработку ПО. И достаточно тяжело и медленно идет рост сейчас, когда такого мастера нет рядом.
Я считаю, что код по возможности нужно писать красивый, но если костыльное (через unsafe с указателями, например) решение даёт хороший прирост к производительности (имеется в виду как прирост от костыля в одном месте, так и суммарный прирост от костылей в разных местах), то лучше использовать его, потому что, как уже было сказано в посте, «пользователей не волнует, насколько красив ваш код и насколько хороша архитектура, их волнует, чтобы проект хорошо работал».
Ведь на костылях и построены многие вещи, радикально изменившие представление о компьютерах. Commander Keen, благодаря которому на ПК появились плавные sidescroller'ы, использовал особенности фреймбуфера EGA, а Quake тормозил бы, если бы не костыль с исправлением перспективы только каждые 8-16 пикселей (которое, кстати, реализовано на ассемблере так, чтобы операция деления производилась совместно с целочисленными операциями).
FXAA, кстати, тоже можно считать немного костылём — вместо того, чтобы сглаживать реальные грани полигонов, оно их ищет на отрисованном изображении.
Думаю, так стоит делать только если без костыля код работает будет плохо.
Не надо доводить код до того, чтобы он работал плохо. Вряд ли вы будете писать комментарий вроде «этот код очень чистый, но может быть медленным», а вот «HACK: ...» сами пальцы так и хотят написать. Поэтому источники багов от костылей искать проще (Ctrl+F > "// HACK"), чем источники тормозов от чистоты, даже несмотря на профилировщики.

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

Допустим, у нас уже 5-6 человек и проект на несколько месяцев.… Лучше бы следить, чтобы костыли особо не накапливались.

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

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

Можно держать в уме — не значит нужно. Держать в уме — категорически нельзя! Использовать костыли в таком случае можно, а часто и нужно. НО! их нужно обязательно(!!!) документировать. А в идеале ассертсы вставлять. Указал ассерт на максимальное количество итераций, и уже можешь спать спокойно, что если оно ляжет, то не от переполнения или нехватки памяти, а по асертсу. Через полгода сам же и не разберешься. А накатать полстраницы комментариев, хоть в стиле «поток сознания» — это много усилий не потребует.

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

Мне одному кажется что здесь был виноват консультант а не манагеры? Рефакторинг ради рефакторинга это глупо. Собственно об этом вся статья. Рефакторнг подразумевает некую цель. Это простота обслуживания, простота дальнейшей разработки, скорость работы кода и т.п.
Если мы говорим манагеру что «нам нужно две недели на рефакторинг, чтобы код был лучше», то он не поймет.
А если сказать: «Игорь, у нас до 20% времени уходит на отлов старых фич которые отваливаются после добавления новых, так что дай нам две недели на рефакторинг и хоть минимальное покрытие кода тестами, и мы будем двигаться быстрее», или «Шеф, в таком виде как сейчас мы не можем внедрить новую функциональность, нам нужно _подготовить_ систему к внедрению», то манагер будет понимать, что результатом рефакторинга у нас стало «увеличение скорости работы разработчиков на 20%» или «техническая готовность системы к внедрению нового функционала». Тогда и вопроса не будет. (Вообще думаю что пример был слегка выдуманным, не думаю что консультант реально так тупил).

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

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

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

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

Ох, как же мне знакома эта проблема ;) Эта, на первый взгляд, глупая убеждённость в том, что всё должно быть идеально, сильно сказывается на повседневной жизни — везде начинаешь видеть недочёты и недостатки.
Но это круто — круто, когда делаешь так, что даже по мелочам не придерешься :)
Подскажите что за шрифт на картинке, хотел попробовать его в коде.
Картинку делал с помощью сервиса Instacode. Какой именно шрифт используется — не возьмусь сказать.
Спс, наверно он, хотя маленькая буква «L» не похожа.
Не похожа?
Я по ней и определил.
Sign up to leave a comment.