Приложение в твоем смартфоне
Приложение в твоем смартфоне
Приложение в твоем смартфоне
Приложение в твоем смартфоне
27 мая 2012 в 15:08

Три ключевых принципа ПО, которые вы должны понимать перевод tutorial


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

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

DRY – Don’t repeat yourself (не повторяй себя)


Этот принцип настолько важен, что не требует повторения! Обычно его упоминают акронимом DRY, который впервые появился в небезызвестной книге "The pragmatic programmer", но концепт, сам по себе, был известен довольно давно. Он относится к самым мелким частям вашего ПО.

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

Самый простой подход по уменьшению сложности — разделить систему на управляемые части.

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

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

Принцип DRY требует, чтобы такие части информации встречались в вашем коде один, и только один раз.


Эти части должны иметь одно представление.

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

Каждая часть данных должна иметь четкое, надежное представление в системе.

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

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


Задача архитектуры – управлять сложностью


Перестаем повторяться

Путей ликвидировать повторения довольно много. Hunt и Thomas предлагают генераторы кода и трансформацию данных. Но DRY, в итоге, является философией выдачи логики через представления.
Каждая часть вашего приложения может быть представлением, каждая часть выдает определенную логику – модуль управления авторизацией дает доступ вашим пользователям, класс пользователя содержит информацию про текущего пользователя с набором его свойств. Этот класс, в свою очередь, получает данные через представление БД.

DRY — это философия, разбивающая логику на представления.

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

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

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

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

В реальных проектах достичь 100% DRY практически нереально. Но, в свою очередь, проектов, которые не-DRY на неприемлемом уровне, и которыми сложно управлять, довольно много. И, возможно это для вас будет сюрпризом – 50% всех наших проектов провальны, если взглянуть на их код.

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

Пример

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

Редко плохой код пишут плохие программисты.

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

Если вы посмотрите на историю самых успешных IT компаний, многие из них были созданы людьми с пониманием проблемы — Bill Gates, Mark Zuckerberg, Steve Wozniak, Steve Jobs, Larry Page, Sergey Brin, Larry Ellison – эти люди знали, что им предстоит преодолеть для решения той или иной задачи. Но есть и компании, которые передают системное управление в руки бухгалтеров, а концептуальное – в руки консультантов. Ни те, ни другие не способны управлять такими областями.

DRY достигается совместным планированием.

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

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

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

Если вас просят не совать нос куда не нужно, читайте дальше – принцип YAGNI спасет вас!

KISS – keep it simple stupid (делайте вещи проще)


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

Зачастую самое простое объяснение является самым правильным решением.

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

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


Большая часть прогресса в истории человечества была достигнута благодаря неординарным мыслителям.


HTTP

Протокол HTTP очень часто приводится, как пример идеального, простого решения – изначально созданный для передачи гипертекстовых документов, сегодня он является основой для многих интерактивных приложений. Возможно, нам иногда приходится искать обходные решения проблем, связанных с ограничениями это протокола, и может быть в будущем его сменит другой протокол. Но на сегодня факт остается фактом: основываясь не нескольких методах запросов (GET/POST), кодах статусов и простых текстовых аргументах, HTTP является достаточно гибким и надежным. Именно поэтому веб-разработчики стараются выжимать из него максимум, и именно поэтому этот протокол все еще в строю.

Подход делать вещи проще довольно очевидный, но история разработки ПО полна различных плохих, сырых решений. Их еще часто называют отдельным словом – bloatware, или DOA (dead on arrival) — мертвое при рождении. Относительного такого софта можно применить теорию, похожую на теорию не-DRY кода… Тем не менее, успех интернета можно объяснить простыми, эффективными решениями.

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

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

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

И мы решили внедрить импорт из формата CSV. Решение заняло несколько строк кода, не было перегружено данными (если сравнивать форматы CSV и Excel), легко управлялось и поддерживалось. Excel запросто может экспортировать данные в формате CSV (как и многие другие программы, которыми клиент мог воспользоваться в будущем). И, учитывая минимальные затраты на реализацию этого требования, данное решение является отличным примером KISS.

Мораль – старайтесь рассмотреть вещи с простой стороны, если они выглядят сложными. Если клиент вам рассказывает свои требования, реализация которых вам кажется сложной, вы правы в любом случае. Даже учитывая, что некоторые вещи действительно сложны в реализации, мы нередко сталкиваемся с решениями, которые перегружены необоснованно. Это случается, т.к. в процесс разработки вовлечены некоторые люди, не имеющие технического опыта для правильного расчета затраты/выгода. И они просто не видят всей проблемы. Поэтому всегда дважды проверяйте требования клиента, и убедитесь, что это именно то, что ему нужно. Обсудите критические моменты, объясните ему, почему другие решения могут подойти лучше.

You ain’t gonna need it – вам это не понадобится


Когда Google запустил Google+, Mark Zuckerberg, основатель Facebook-а, был одним из первых зарегистрированных в социалке, которая была призвана превзойти его сеть. Он написал всего лишь одну строку в разделе “Обо мне” – «Я строю вещи». Лично я считаю это блестящим предложением, раскрывающим всю суть программирования. Почему вы выбрали путь кодера? Энтузиазм в технических решениях? Красота эффективности? Чтобы вы не ответили, скорее всего это не будет «построить 100500-ый корпоративный сайт со стандартным функционалом». И тем не менее, многие из нас зарабатывают именно этим. Где бы вы не работали, вам периодически приходится сталкиваться со скучными, рутинными задачами.

Я программирую. Я строю вещи.

Принцип «Вам это не понадобится» (YAGNI – you ain’t gonna need it) как раз призван решать такие задачи.

Это значит, что то, что не задумано в системе, не должно появляться в коде. К примеру, достаточно часто доступ к БД осуществляется через абстракцию, которая может иметь реализацию для разных драйверов – MySQL, PostgreSQL, Oracle. Если вы работаете над сайтом, который размещается на LAMP стеке – какова вероятность того, что клиент сменит БД? Не забывайте, что концепт всегда пишется под бюджет – верно?

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

Вы, должно быть, заметили разницу между YAGNI и DRY системами. Последняя призвана уменьшать сложность, разделяя систему на управляемые компоненты, в то время, как первая уменьшает сложность, уменьшая количество этих компонент. Принцип YAGNI похож на KISS – он старается делать вещи как можно проще. Но KISS старается искать простые решения, а YAGNI просто не делает никаких решений!

Теодор Старджон, американский фантаст, выдвинул закон – «90% всего – полная чушь». Довольно радикальное утверждение, и не всегда применимое в реальных проектах. Не забывайте, что «чушь» может отнимать уйму времени. Существует негласное правило: примерно 80% затраченного времени на разработку тратится на реализацию всего лишь 20% функционала системы. Вспомните ваши проекты. Каждый раз, когда я пересматриваю свои, я постоянно убеждаюсь, как точно работает правило 80/20.

80% затраченного времени на разработку тратится на реализацию всего лишь 20% функционала системы.

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

Тем не менее, даже если этот подход может казаться довольно простым, зачастую не так то и просто отделить нужные от ненужных частей. К примеру, даже если у вас реализована абстракция, это не даст вам никакого выигрыша при дампе БД. Ключевым моментом является то, как мы смотрим на ПО – нас учили писать код, который легко поддерживать, и который будет выгоден в будущем. Т.е. нас учили смотреть наперед, учитывая все возможные изменения. Иногда это критично для больших проектов, но никак не для маленьких. Перестаньте думать о будущем! Если вдруг небольшому сайту потребуются радикальные изменения, будет лучше начать все с нуля. И это не такая уж и проблема, учитывая общие инвестиции.

Планирование проекта


Начиная планирование нового проекта, постарайтесь учесть следующее:

  • Достичь меньшей сложности путем уменьшения уровня абстракций
  • Разделить функционал от возможностей (features)
  • Учесть небольшие не-функциональные требования
  • Определить затратные по времени задачи, чтобы избавиться от них

Давайте разберем это подробнее. По первому пункту я уже приводил пример – не стоит реализовывать абстракцию к драйверу БД. Старайтесь тщательнее оценивать все, что может добавить сложности вашей системе. Учтите, что зачастую многие абстракции реализовываются в сторонних продуктах и библиотеках. К примеру, смотря на каком языке вы пишите, Hibernate (Java), Doctrine (PHP) или Active Record (Ruby) – все идут с уровнем абстракции вокруг БД, и ORM. Каждая из этих библиотек добавляет сложности. И ею придется управлять. Обновления, патчи, исправления в безопасности – все это вам придется делать/применять в будущем.

Каждый день мы внедряем новые возможности, которые, как нам кажется, будут полезны. Следовательно, мы загадываем наперед, и реализовываем слишком много. К примеру, многие клиенты хотят иметь мобильные версии своих сайтов. Мобильность может быть представлена многими значениями, это не обязательно дизайнерское решение. Это сценарий использования! Люди, которые пользуются мобильными сайтами, являются мобильными. Это значит, что им может понадобиться другая информация, или функционал, чем тем, которые пользуются десктопной версией. Представьте сайт кинотеатра – пользователи на пути в кинотеатр, в автобусе, скорее всего захотят увидеть время начала сеанса, а не 50-метровый трейлер.

С адекватным бюджетом, вы постараетесь сделать отдельный анализ требований к мобильной версии. Без такого анализа вы просто выдадите ту же информацию, что и для десктопа. И этого может быть достаточно для многих проектов. Потому что на сегодня, многие мобильные браузеры способны правильно настраивать вид сайта, и здесь можно применить радикальный подход YAGNI – не делать мобильной версии вообще!

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

Не-функциональные требования не описывают поведения системы, они описывают дополнительные свойства, по которым можно оценить качество продукта. Т.к. описание качества предполагает знание продукта, плохие концепты можно часто определить по отсутствию не-функциональных требований. Возможность поддержки, уровень документации, легкость интеграции – все это примеры не-функциональных требований. Эти требования должны быть оценимыми. Т.е. «Сайт должен грузиться быстро» — слишком обобщенно, а вот «Сайт должен грузиться за 2 секунды в процессе теста производительности» — очень даже конкретно, и ясно. Если вы хотите применить подход YAGNI, постарайтесь учесть некоторые не-функциональные требования, даже если они не учтены в концепте (или учтены, но не очень четкие). Когда вы пишете такое требование, будьте реалистами – небольшой сайт, с 20-50 посещениями в день, не требует трехдневной настройки производительности, т.к. сайт будет грузиться быстро и так, если сервер не перегружен. Даже если компания сможет повысить свою посещаемость, купить более мощный хостинг не должно составить проблем.

Ну и напоследок, всегда помните правило 80/20. Старайтесь определить затратные по времени задачи. Если такая задача обязательна к реализации, придется ее сделать. Вопрос будет только как это сделать. Нужен ли нам еще один фреймворк с небольшим комьюнити? Придется ли вам переходить на только что вышедшую версию библиотеки, если документация по ней все еще не обновлена? Есть ли необходимость использовать новую CMS, если не все расширения к ней работоспособны? Насколько глубокий анализ придется провести, чтобы реализовать вашу задачу? Подход «так приходится делать всегда» — не очень захватывающий, но он поможет вам решить задачу без сюрпризов.

Также важно понимать, что все это вовсе не значит, что можно сесть и писать плохой код, приправленный хаками. Вы просто пишете небольшое приложение, а не плохое! Тем не менее, подход «вам это не понадобится» довольно практичен. Если он помогает сократить несколько строк кода, лично я считаю, что можно внести эту работу в бюджет, и небольшое не-DRY вполне приемлемо. Т.е. можно согласиться не немного возросшие затраты по поддержке – мы живем в реальном мире.

Давайте вернемся в нашей основной идее – мы строим вещи. Бетховен написал “Diabelli Variations” по контракту. Я не думаю, что он шел на компромиссы по бюджету. Он потратил больше времени, но не выпустил плохую музыку – он стремился написать идеальную.

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

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


Заключение


Принципы ПО являются точками зрения на это ПО. Для меня, хороший принцип должен основываться на простом концепте, который должен развиваться в сложную конструкцию идей, сталкиваясь с другими подходами и философиями. Какие ваши любимые принципы ПО?
+114
16031
775
creage 6,1 G+

комментарии (54)

–1
second_pilot, #
>>> Если вы работаете над сайтом, который размещается на LAMP стеке – какова вероятность того, что клиент сменит БД

Был какраз этот случай. С мускуля на постгрес через несколько лет разработки с plain sql запросами в коде. Внезапно понадобилось переходить. Шанс обысно мизерный, но если такое случится, сложно представить сколько человеко-часов придется затратить. В таком случае лучше использовать сразу какой-нибудь Zend_Query, заодно у вас будет единая точка для запросов куда можно воткнуть профилирование, кеширование и прочая. Менджмент рисков никто не отменял.
+6
AndrewStephanoff, #
Никто ведь не говорит, что нужно писать запросы в DB прямо в бизнес-логике. Можно ввести DAO — это тоже абстракция, но абстракция, покрывающая именно ваши проблемы. При смене DB вам потребуется лишь реализовать новые DAO классы, причём public contract и сигнатура методов сохранятся, равно как и юнит тесты. Кстати, даже используя Zend_Db, при смене DB вам также придётся переписывать запросы.
По поводу кеширования, профилирования и прочее — то при чём здесь Zend_Db? Вы серьёзно считаете, что без использования Zend_Db этого не достичь?
+5
ping, #
Если не секрет, какие были причины смены SQL сервера? Я человек в базах не сильно сведущий, Postgre даёт значительный прирост производительности или что-то ещё?
+1
eugenius_nsk, #
У PostgreSQL намного лучше планировщик запросов, что очень сильно влияет на сложных запросах с кучей подзапросов/джойнов. MySQL в таких случаях норовит сделать full table scan, а PostrgeSQL обходится выборкой по индексу.
+5
iFrolov, #
Компоненты-компоненты… Эх, а вы видели, что сейчас происходит в Google Play? Хочу я к примеру найти плеер для интернет-радио: огромный выбор чего только можно, каждое приложение лезет в телефонную книгу, в вайфай, в автозапуск и всем обязательно нужен доступ к GPS, ну или как минимум к данным сети. Без всего этого проиграть интернет-радио невозможно. После скачивания приложения что нужно сделать? Не, не читать Readme, даже не лазить в настройки, нужно обязательно авторизоваться через твиттер, фейсбук или что-то подобное. Мне интересно, там вообще есть приложения без социальных сетей? Каждое второе приложение в собственном стиле, изобретает свои UI-виджеты. Обязательно, в каждом плеере должен быть будильник, магазин треков и возможность отобразить обложку играющего трека.

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

А вы говорите про 80% затрат на 20% функционала. Где он, этот функционал? Нужный мне функционал на j2me был реализован в пределах 100 строк, включая UI. Видимо, придется не только заниматься своей версией Icecast, но и создавать плеер.
+2
grimich, #
Более того, такого легковесного simple-плеера с трудом найдешь и под винду :) Винамп 2.97 только молодец в этом плане…
+3
1514m, #
AIMP.
+1
AndrewStephanoff, #
foobar
0
grimich, #
Не зря мною написано было «легковесный». Винамп кушает до 20мб оперативки, в то время как аимп и фубар стремятся к 40-50+
+7
AndrewStephanoff, #
Давно уже не смотрю, сколько памяти отбирает проигрыватель — на фоне современных приложений он у меня даже не в первой десятке.
+1
Iliapan, #
foobar у меня занимает 13МБ при проигрывании. У вас что-то не так :)
+1
1514m, #
AIMP занимает 15 МБ.
0
brammator, #
Может, дело в бюджете? Например, приложение без социалок, магазина треков и ещё тысячи свистелок не монетизируется и, следовательно, может быть написано «для себя», но не в маркет.
0
VolCh, #
Судя по комменту iFrolov он бы рад и купить такое приложение, но нет.
0
brammator, #
Возможно, прибыль от покупки сотней энтузиастов не котируется по сравнению с доходами от тысячи «условно-бесплатно» закабаленных.
0
creage, #
Эта статья как раз и призвана научить программистов писать код грамотно, не тратя времени на «нужные» (читай ненужные) фичи.

По поводу 80/20, в плане фич, есть старая, но очень хорошая статья.
0
tipugin, #
Читал оригинал, статья замечательная.
+1
vt4a2h, #
Вероятно, стоило перевести статью более литературно, а не так дословно. Всё-таки такие понятия как информация, знания и данные различаются по смыслу. Так же различаются понятия класса и объекта.
Например, сразу бросилось в глаза:
Принцип DRY требует, чтобы такие части информации встречались в вашем коде один, и только один раз.

The DRY principle states that these small pieces of knowledge may only occur exactly once in your entire system.

После прочтения оригинала, мне показалось, что под термином «piece of knowledge», автор статьи понимает как формализацию знаний о том, как что-то сделать, в виде алгоритма, выраженного на ЯП, так и некоторую информацию, представленную в виде данных, к которым можно обращаться, используя некоторую переменную. Таким образом, смысл цитаты можно свести к тому, что не надо повторять одинаковые фрагменты кода и дублировать данные без необходимости.
+1
AndrewStephanoff, #
Это ещё нормально. Вы бы видели как переводят книги по Computer Sience на русский — коллега заказал как-то Фаулера, так смысл некоторых фраз мы искали в моём англоязычном варианте.
0
creage, #
Не могу не согласиться. Но мне кажется, если переводить эту цитату, вырвав из контекста — ваш вариант более понятен. Но если ее читать в рамках статьи — суть остается той же. Ну и вообще — довольно непросто философствовать о принципах ПО на литературном языке.
0
creage, #
Ой, это ответ на этот комментарий.
0
Grawl, #
Зубодробительное месилово. Читал с блеском в глазах.
+5
flaMaster, #
Статья, если честно, неглубока. Я не знаю, кем должен быть читатель на Хабре, чтобы никогда не слышать о принципе Парето («20 % усилий дают 80% результата, а остальные 80 % усилий — лишь 20% результата») и о бритве Оккама («не плоди сущностей без надобности»). Ладно, это мелочи. Но про Эйнштейна, конечно, лихо. Если верить автору, Эйнштейн просто выкинул эфир и суждение что «время не является константой» и тут же изобрел ОТО. Между прочим, до подтвержения Хабблом факта расширения Вселенной Эйншейн на 12 лет включил в свою теорию космологическую постоянную, потому что придерживался теории статической Вселенной, а потом сокрушался своей ошибке. Тут у него kiss-принцип, видимо, не сработал.

Вообще, проблема разработки чего-то сложного не нова. Я помню интервью одного нашего космонавта, который верно заметил, что успех космических программ имел в основе не столько технологии, сколько способность разработчиков взаимно увязывать компоненты системы. Одному агрегату нужно больше питания, значит, нужны батареи потяжелее, значит нужно нарастить мощность ракеты, а она ограничена, в итоге ищем альтернативный способ подзарядки и т.д. Архитектору программных систем приходится решать эту задачу оптимизации постоянно. Для решения есть полный арсенал — шаблоны проектирования, интерфейсы, корпоративные стандарты документирования, UML и т.д. Планирование, увы, не всегда срабатывает, поскольку решения не всегда лежат на поверхности, а то бы Гугл еще до Цукенберга запланировал сделать мегасоцсеть. Боюсь, реально работающий рецепт один — приобретать опыт, учиться, пробовать и быть дисциплинированным в работе.
0
creage, #
Вы немного отвлеклись от смысла статьи. Ваши комментарии относятся к деталям, которые приводятся для сравнения, или же имеют некую аналогию с идеями, которые хочет донести автор. Цель статьи — научить/рассказать/напомнить программистам о трех постулатах разработки.
0
dborovikov, #
Кто-нибудь может мне объснить в чем конкретно заключается принцип DRY? По описанию вроде бы похоже на модульный подход, но зачем какой-то новый термин? И почему нельзя повторять именно себя?
0
creage, #
Фишка DRY — как можно больше атомарной реализации. У вас всегда должна быть возможность внести некоторые изменения в алгоритмах, без страха, что вся система рухнет.

P.S. Википедия, первый абзац — очень четкая, понятная формулировка.
+2
VolCh, #
Грубо говоря — не копипастить код из одной системы/подсистемы/функции/участка функции в другую, даже используя в качестве буфера мозг. Основная причина, имхо — сложность поддержки двух и более одинаковых кусков кода (нашли баг в одном куске — нужно не забыть исправить в других местах, где этот же код используется или, например, два почти одинаковых куска кода и сложно заметить, а заметив понять, различие). Дополнительная — общее уменьшение количества кода и, как следствие, размеров бинарников. И термину 100 лет в обед.
0
dex7er, #
Больше б подобных статей на хабре. Вечер удался :)
+1
VolCh, #
А DRY не противоречит ли KISS и, особенно, YAGNI?

Пускай есть код вроде

users = new Set();
result = mysql.query("SELECT * FROM users");
while (user = mysql.fetch(result)) {
  users.add(user);
} 


Встретился он один раз, вроде не противоречит ни одному из принципов. Встречается второй раз… По DRY его просто необходимо вынести в отдельную функцию/метод get_users (а по некоторым методикам даже если один раз встретился такой код, его нужно выносить в отдельный слой), а по YAGNI не нужно предусматривать, что может измениться имя таблицы, СУБД или вообще что хранилище может перейти на плоские файлы или в облако.

DRY является усложнением кода (вводятся новые сущности, новые связи между ними и т. д.) ради облегчения поддержки, а KISS и YAGNI постулируют обратный процесс «фиг с ней с поддержкой будущей, главное чтобы сейчас было как можно проще (и быстрее)». Или не противоречат?
+1
creage, #
Вы правы, и все зависит именно от контекста реализации. Если у вас в системе уже предусмотрены разные источники данных — стоит использовать DRY. Но если в требованиях этого нет — все делаем KISS/YAGNI.
+1
dborovikov, #
Вроде не противоречат. Согласно KISS мы не должны применять принцип DRY преждевременно.
+1
Ryadovoy, #
При написании кода второй раз необходимо произвести рефакторинг и вынести общий код в отдельную функцию.
0
m36, #
Рефакторинг — это не добавление и не изменение функционала. YAGNI распространяется на функционал, а не на рефакторинг. Если что-то повторяется — рефакторинг обязателен. Говорить про рефакторинг «нам это не понадобится» — нельзя. Поэтому не противоречит.

Вообще со статьей местами очень не согласен. YAGNI — это основополагающий принцип и не вижу проблем в сложных проектах его использовать
0
m36, #
Даже не совсем так. YAGNI не только на функционал, но и на хитрые реализации, паттерны распространяется. Но не на рефакторинг. Рефакторинг — механическая вещь, ведущая к KISS. И он делается просто на каждом шаге по ТДД. Это неотъемлемая часть процесса разработки.
0
ivan2kh, #
Не нравится мне такой перевод:
впомнив фразу из моего любимого фильма «Касабланка» — в любви законов новых нет — так создан свет
.
В оригинале:
The fundamental things apply, as time goes by.

Я бы перевел так: «Со временем, фундаментальные вещи берут верх».
В крайнем случае «Любовь приходит и уходит, а кушать хочется всегда».
+1
creage, #
Я сам долго пытался найти естественный перевод, перепробовал разные варианты, но ни один из них не доносил смысла, который автор хотел передать. Бросив, просто нашел перевод песни, который, как мне кажется, действительно полноценен.
–1
bitterman, #
Я смысл статьи понял как:

Пишите код хорошо, и у вас будет хороший код.

Как-то так.
+1
mekegi, #
Как бы парадоксально сие не было, но большинство разработчиков очень сильно сопротивляются написанию «хорошего кода». Они могут придумать сотню отмазок почему надо писать абы какой код, и почему нет времени на написание хорошего. Ежики и кактус…
Если код писать хорошо и проектировать приложение не торопясь — то проект запустится намного раньше и съест намного меньше денег.
Типичные будни сотфверных компаний:
Аврал! Красная кнопка. Люди орут бегают туда сюда, кто то принес огнетушитель. Грузовик с костылями уже въезжает во двор, главный архитектор раздает программерам их пачками и все несутся к рушащемуся зданию прибивать эти самые костыли со всех сторон.
П.С. Делать качественно всегда дешевле и быстрее, но людям очень сложно сломать этот стереотип
0
VolCh, #
Под разработчиками вы имеете в виду только программистов или всю команду, включая менеджмент?
0
mekegi, #
Под разработчиками я имел ввиду программистов. тим лидов и архитекторов. Тех кто отвечает за разработку и проектирование системы.
0
Funcraft, #
Один из моих основных принципов при программировании (на самом деле и в остальных сферах жизни) — «Телепатов нет»

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

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

Вообще, чем меньше вы оставите места для «додумывания» (да простит меня Русский язык), тем лучше.
+1
eyeofhell, #
Плюсики, конечно, везде проставил. Но в рамках стариковского брюзжания скажу, что мне не нравятся такие статьи. Есть в них что-то от небезызвестной книги «Банды Четырех», которая, по мнению многих разработчиков, нанесла чудовищный удар индустрии программирования.

DRY, KISS и YAGNI — это великолепные принципы. Замечательные. Но это инструменты — и, как у любых инструментов, у них есть цена использования. Для чего предназначены эти принципы? В первую очередь — для борьбы со сложностью, с «complexity problem». А как показывает практика, сложность программного решения — это некая константаня величина, диктуемая его объемом. Ее нельзя просто взять и убрать. Ее можно спрятать во фреймворк — тогда на верхнем уровне будет несколько красивых строчек кода а под ними — айсберг. Ее можно спрятать в иерархию — тогда вместо копипасты будет вызов метода. Можно спрятать в абстракцию — тогда вместо ручного управления памятью будут умные указатели. Но ее, #$!#!#@, нельзя убрать из кода :(.

И все эти замечательные принципы убирают сложность в одном месте, добавляя ее в другом. Так же как упомянутые мной паттерные проектирования убирали архитектурную сложность в одном месте — добавляя ее в другом за счет введения дополнительного слоя абстракции (для большинства паттернов). И если, не зная этих лежащх в основе концепций, применять DRY, KISS и YAGNI — то можно легко получить ситуации, когда разработчик убирает три копипасты по две строчки, заменяя их классом на двадцать. Или, в соответствии с принципом KISS, не делает абстракции базы данных, потому что «ну кто же будет в LAMP базу данных менять»?

Только вот про основы, борьбу добра и зла программистов с проблеммой сложности кода, что именно дает DRY или YAGNI, зачем они нужны — не пишут. Пишут готовые кулинарные рецепты, бережно передаваемые из поколения в поколение — «об этом еще Дейкстра говорил!». Не уверен, что это есть хорошо.
+1
creage, #
Задача этих принципов не ликвидировать сложность, это нереально. Эти принципы позволяют снизить сложность, раздробить ее на мелкие, управляемые части, или вообще не писать сложных вещей.
–1
eyeofhell, #
Сложность можно снизить, только если решение усложнено. Если решение не усложнено (а это, на вскидку, прмерно половина случаев) — то можно только понизить концентрацию сложности в одном конкретном месте куда путем переноса части сложности в другие места. Про это никто не пишет, что меня немного огорчает.

Наверное, это всем очевидно. Только почему тогда основная масса кода такого низкого качества? :)
+2
creage, #
Нельзя быть немного беременным. Если решение сложное — его стоит упростить, а не прятать куда либо.

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

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

У нас один чудак написал проект для переливки таблицы из эксель в БД. Там тысячи классов. Понесло, что называется. Искусство ради искусства. Куча паттернов, куча совершенно не обоснованных решений. Погоня за гибкостью на самокате. )))
Один из примеров. В базе есть справочник, который он создал. У элементов справочника есть целочисленные идентификаторы. Но он решил, что в коде пользоваться идентификаторами — хардкод и опасно (он вообще странный). И поэтому дал имена элементам справочника вроде «Item_1», «Item_2» и т.д. Потом в коде парсит и находит цифру. Она уже как бы от идентификатора не зависит.

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

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

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

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

Так и с любым кодом. Если люди начинают что-то прятать, высовывать — то это или рефакторинг, чтобы лучше код соответствовал задаче или не совсем понимают, зачем это нужно.
0
eyeofhell, #
Так и с любым кодом. Если люди начинают что-то прятать, высовывать — то это или рефакторинг, чтобы лучше код соответствовал задаче или не совсем понимают, зачем это нужно.


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

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

Но никто почему-то про это не пишет. Большинство бегает и кричит — «А-а-а-а-а, применяйте DRY, он кле-е-е-е-евый, он копипасту убирает! Он превращает быдлокод в мегакод!». Но это не так, это ложь. Он не бесплатно убирает копипасту — он ее убирает ценой добавления еще одного уровня абстракции. Это цена, и в ряде случаев мы совсем не хотим ее платить. Но никто это не оценивает, а потом получается код, где количество слоев абстракции настолько высоко, что даже я его понять не могу :(.

Как уже говорилось, это в рамках старческого брюзжания, не обращайте внимания :). Все эти проблемы возникают когда все остальное более-менее. Когда же стоит вопрос, что написанное студентов решение в 10000 строк на самом деле можно написать в 100 просто другим способом — то тут проблемы применения паттернов отходят на второй план :).
0
m36, #
да нет же! ))
Если сложный кусок повторяется несколько раз, то во столько же раз и сложность растет. Если условно сложность куска кода равна единице, то пять повторений — сумма — сложность 5. Сведение в одно место уменьшает сложность.

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

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

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

Всё несет нагрузку. Просто надо в комплексе рассматривать. Для меня основной критерий — это отражение требований. Т.е. ясность кода с т.з. предметной области. Кое чем можно жертвовать, оценивать по разным параметром код, но этот критерий — главный.
0
eyeofhell, #
Если сложный кусок повторяется несколько раз, то во столько же раз и сложность растет. Если условно сложность куска кода равна единице, то пять повторений — сумма — сложность 5. Сведение в одно место уменьшает сложность.


Это… очень смелое предположение :). «Сложность» — абстрактное понятие. Что именно вырастет в пять раз? Какие операции для разработчика станут в пять раз сложнее?

Вот этот фрагмент:

books = FindBooks( "flibusta.net" )
SaveBooks( books )

books = FindBooks( "fenzin.org" )
SaveBooks( books )

books = FindBooks( "bookz.ru" )
SaveBooks( books )


Неужели в три раза сложнее чем:

books = FindBooks( "flibusta.net" )
SaveBooks( books )


Не верю :)

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


Вы как-то странно со мной не соглашаетесь, полностью повторяя мои выкладки о цене применяемых методов O_O.
0
m36, #
Сложность — не совсем абстрактное понятие. В него уже вкладывают смысл. Повторю: у майкрософта в студии встроен анализатор кода, который показывает индекс, насколько код хорош. Конечно, эта вещь не абсолютна, т.к. мерки снимает автоматические. Но стоит посмотреть на эти коэфициенты. Проводят исследования и как-то сложность превращают в вычислимую величину.

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

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

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

«Вы как-то странно со мной не соглашаетесь, полностью повторяя мои выкладки о цене применяемых методов O_O.»

А я с вами и не несоглашаюсь. Только не соглашаюсь с отдельным моментом — что сведение сокращение повторений сложных кусков не уменьшает сложность.
0
eyeofhell, #
Повторю: у майкрософта в студии встроен анализатор кода, который показывает индекс, насколько код хорош. Конечно, эта вещь не абсолютна, т.к. мерки снимает автоматические. Но стоит посмотреть на эти коэфициенты. Проводят исследования и как-то сложность превращают в вычислимую величину.


Цикломатическая сложность — это как тест на IQ. Позволят отделить безнадежных даунов от всех остальных :). Как уже говорилось, коду, в котором зашкаливает цикломатическая сложность DRY не поможет — его изначально неправильно написали — другая проблема, другие решения.

Только не соглашаюсь с отдельным моментом — что сведение сокращение повторений сложных кусков не уменьшает сложность.


Соглашусь, что мое высказывание было не совсем корректным. Мы не можем адекватно и точно померить сложность, поэтому более корректно будет, что на мой взгляд «применение шаблона проектирования или техники написания кода не убирает сложность, а переносит ее в другое место. При этом сложность в целом может как повыситься, так и понизиться — но в общем случае у нас нет адекватных инструментов чтобы это оценить».
0
StrangeAttractor, #
не стоит реализовывать абстракцию к драйверу БД. Старайтесь тщательнее оценивать все, что может добавить сложности вашей системе. Учтите, что зачастую многие абстракции реализовываются в сторонних продуктах и библиотеках. К примеру, смотря на каком языке вы пишите, Hibernate (Java), Doctrine (PHP) или Active Record (Ruby) – все идут с уровнем абстракции вокруг БД, и ORM.

По моему опыту «стандартные» ORM — почти всегда зло, особенно если недостаточно хорошо их знаешь.

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