«Лучшие практики» повсюду в нашей отрасли. Поиск Google на «кодировании лучших практик» появляется около 1,5 миллионов результатов. Идея, кажется, приносит утешение многим; просто следуйте инструкциям, и все будет хорошо.
Когда я читаю о лучшей практике - например, я недавно прочитал несколько из них в Чистом коде - я нервничаю. Значит ли это, что я всегда должен использовать эту практику? Есть ли условия прилагается? Существуют ли ситуации, когда это не может быть хорошей практикой? Как я могу знать наверняка, пока не узнаю больше о проблеме?
Некоторые из методов, упомянутых в Чистом коде , не подходили мне, но я, честно говоря, не уверен, что это потому, что они потенциально плохие, или это просто мой личный уклон. Я знаю, что многие видные люди в технологической отрасли, кажется, считают, что нет лучших практик , поэтому, по крайней мере, мои ноющие сомнения ставят меня в хорошую компанию.
Количество лучших практик, о которых я читал, слишком велико, чтобы перечислять их здесь или задавать отдельные вопросы, поэтому я хотел бы сформулировать это как общий вопрос:
Какие методы кодирования, которые обычно обозначаются как «лучшие практики», могут быть неоптимальными или даже вредными при определенных обстоятельствах? Каковы эти обстоятельства и почему они делают практику плохой?
Я бы предпочел услышать о конкретных примерах и опыте.
источник
Ответы:
Я думаю, что вы ударили гвоздь по голове этим заявлением
Я игнорирую почти все лучшие практики, когда они не объясняют, почему они существуют.
Раймонд Чен лучше всего описывает эту статью, когда говорит
источник
Можно также выбросить это на ринг:
Нет, это не так.
Полная цитата:
Это означает, что вы используете конкретные стратегические улучшения производительности на протяжении всего процесса проектирования. Это означает, что вы используете структуры данных и алгоритмы, которые соответствуют целям производительности. Это означает, что вы знаете о конструктивных соображениях, влияющих на производительность. Но это также означает, что вы не будете легкомысленно оптимизировать, так как это даст вам небольшие выгоды за счет удобства обслуживания.
Приложения должны быть хорошо спроектированы, чтобы они не падали в конце, когда вы прикладываете к ним небольшую нагрузку, а затем вы переписываете их. Опасность сокращенной цитаты заключается в том, что разработчики слишком часто используют ее в качестве предлога, чтобы вообще не думать о производительности до конца, когда уже может быть слишком поздно что-либо предпринимать. Лучше добиться хорошей производительности с самого начала, если вы не сосредоточены на мелочах.
Допустим, вы создаете приложение реального времени для встроенной системы. Вы выбираете Python в качестве языка программирования, потому что «Преждевременная оптимизация - корень всего зла». Теперь я ничего не имею против Python, но это интерпретируемый язык. Если вычислительная мощность ограничена, и определенное количество работы необходимо выполнить в режиме реального времени или почти в реальном времени, и вы выбираете язык, который требует большей вычислительной мощности для работы, чем вы, вы по-королевски облажались, потому что вы Теперь придется начинать все сначала со способного языка.
источник
Один возврат на функцию / метод.
источник
return
заявлений. Либо глубоко вложенные структуры управления или постоянные проверки. Это действительно может раздуть метод, когдаif return
действительно может упростить эту проблему.Не изобретайте велосипед - широко используемая догма. Его идея заключается в том, что если существует подходящее решение, используйте его вместо создания собственного; В дополнение к экономии усилий, существующее решение, вероятно, лучше реализовано (без ошибок, эффективно, протестировано), чем то, что вы изначально придумали. Все идет нормально.
Проблема в том, что 100% подходящее решение редко существует. Может существовать 80% подходящее решение, и его использование, вероятно, подойдет. А как на 60% подойдет? 40% Где вы проводите черту? Если вы не проведете линию, вы можете в конечном итоге включить раздутую библиотеку в свой проект, потому что вы используете 10% ее возможностей - просто потому, что вы хотите избежать «изобретать колесо».
Если вы изобретаете велосипед, вы получите именно то, что вы хотите. Вы также узнаете, как сделать колеса. Обучение на практике не следует недооценивать. И, в конце концов, нестандартное колесо может быть лучше, чем стандартное колесо.
источник
«Модульная проверка всего».
Я часто слышал, что весь код должен иметь модульные тесты, с чем я не согласен. Когда у вас есть тест для метода, любое изменение в выводе или структуре этого метода должно быть сделано дважды (один раз в коде, один раз в тесте).
Таким образом, модульные тесты должны быть, на мой взгляд, пропорциональны структурной стабильности кода. Если я пишу многоуровневую систему снизу вверх, у моего уровня доступа к данным будут тесты wazoo; мой уровень бизнес-логики будет довольно хорошо протестирован, мой уровень представления будет иметь несколько тестов, и мои представления будут практически не тестироваться.
источник
Всегда программируйте на интерфейсы.
Иногда будет только одна реализация. Если мы задержим процесс извлечения интерфейса до того момента, когда мы увидим необходимость в нем, мы часто обнаружим, что в этом нет необходимости.
источник
Не используйте ничего с открытым исходным кодом (или не для Microsoft .NET для вас)
Если Microsoft не разработала его - мы не используем его здесь. Хочешь использовать ORM - EF, хочешь использовать IOC - Unity, хочешь войти - блок приложения корпоративной регистрации. Существует так много лучших библиотек - и все же я всегда зацикливаюсь на заказе в долларовом меню мира разработки. Я клянусь, что каждый раз, когда я слышу о Microsoft Best Practices, я думаю, что «Правила питания McDonald's». Конечно, вы, вероятно, будете жить, если вы последуете за ними, но вы также будете недоедать и иметь избыточный вес.
источник
Ориентация объекта
Существует предположение, просто потому, что код «объектно-ориентированный», он магически хорош. Поэтому люди продолжают сжимать функциональность в классы и методы, просто чтобы быть объектно-ориентированными.
источник
Весь код должен быть прокомментирован.
Нет, не должно быть. Некоторое время у вас есть очевидный код, например, сеттеры не должны комментироваться, пока они не сделают что-то особенное. Кроме того, почему я должен комментировать это:
источник
/** sets rank. */ void setRank(int rank) { this.rank = rank; }
я приму комментарий как глупый. Почему это написано?/** */
нужен формат вместо/* */
комментария формата. Или для .NET это было бы///
}//end if
,}//end for
,}//end while
являются лучшим примером расточительного комментирования я когда - либо сталкивался. Я видел это много раз, когда открывающая скобка была не более чем на 2 строки выше. ИМХО, если вам нужны эти комментарии, тогда ваш код нуждается в перефакторинге ... или вам нужно потратить 20 долларов и купить IDE / текстовый редактор, который выделяет соответствующие фигурные скобки.Методологии, особенно разборки. Я не могу сохранять спокойствие, когда слышу, как взрослые используют фразу «Scrum Master». Я так устал от того, что разработчики протестуют, что некоторые аспекты Методологии X не работают для их компании, а только о том, что Гуру так-то и-то сказал, что причина, по которой он не работает, в том, что они на самом деле не настоящие практики Методологии X. "Скрай сложнее, ты должен, мой ученик падаван!"
В гибких методологиях есть кусочки мудрости - многие из них - но они часто засыпаны таким большим количеством навоза, что я не могу побороть свой рвотный рефлекс. Возьми этот бит со страницы Scrum в Википедии :
В самом деле? Вы говорите, свиньи и куры? Захватывающий! Не могу дождаться, чтобы передать это моему боссу ...
источник
Реляционное сопоставление объектов ... http://en.wikipedia.org/wiki/Object-relational_mapping
Я не хочу быть отвлеченным от своих данных, и при этом я не хочу терять тот точный контроль и оптимизацию. Мой опыт работы с этими системами был крайне плохим ... Запросы, генерируемые этими уровнями абстракции, еще хуже, чем то, что я видел из офшоринга.
источник
Написание имен функций, как если бы они были английскими предложениями:
и т.д. Это может выглядеть великолепно, но это неприятно, когда вы изучаете API. Насколько проще искать в индексе «Все, что начинается с Foo»?
и т.п.
источник
Foo.Draw()
,Foo.Write()
иFoo.Create()
, чтобы вы могли это сделатьFoo.methods.sort
илиFoo.methods.grep([what I seek]).sort
MVC - я часто нахожу, что включение многих проблем веб-дизайна в подход MVC - это больше радость фреймворка (рельсов и т. Д.), Чем простота или структура. MVC является фаворитом "астронавтов архитектуры", которые, кажется, ценят чрезмерные строительные леса за простоту. YMMV.
OO на основе классов - на мой взгляд, поощряет сложные структуры изменяемого состояния. единственные убедительные случаи, которые я обнаружил для ОО на основе классов за эти годы, - это банальные примеры "shape-> rectangle-> square", которые составляют главу 1 любой книги о OO
источник
Square(10).Draw()
этого достаточноRectangle(10, 10).Draw()
. так что я думаю, это означает, что квадрат является подклассом прямоугольника. НоmySquare.setWidthHeight(5,10)
это нонсенс (т.е., он не соответствует принципу подстановки Лискова), квадрат не может иметь разную высоту и ширину, хотя прямоугольник может, так что подразумевается, что прямоугольник является подклассом квадрата. В других контекстах это известно как «проблема круга, эллипса»YAGNI
( Тебе это не понадобится )
Этот подход стоил мне часов и часов, когда мне приходилось реализовывать функции в существующей кодовой базе, где тщательное планирование включало бы эти функции заранее.
Мои идеи часто отклонялись из-за ЯГНИ, и большую часть времени кому-то приходилось платить за это решение позже.
(Конечно, можно утверждать, что хорошо продуманная кодовая база также позволит добавлять функции позже, но реальность другая)
источник
Для SQL
Для того, чтобы:
Они особенность, которая имеет свое место. У вас есть несколько путей обновления таблицы или требуется 100% аудит?
Просто почему? Я бы сделал, если бы я занимался рефакторингом, чтобы поддержать контракт, но не тогда, когда я прочитал, что люди меняют представление, чтобы соответствовать любым изменениям таблицы
Редактировать:
Номер 3: Избегать * с EXISTS. Попробуйте 1/0. Оно работает. Список столбцов не оценивается в соответствии со стандартом SQL. Страница 191
источник
Дизайн моделей в основном. Они более и менее используются.
источник
Принцип единой ответственности
(«У каждого класса должна быть только одна ответственность; иными словами, у каждого класса должна быть одна и только одна причина для изменения»)
Я не согласен. Я думаю, что метод должен иметь только одну причину для изменения, и все методы в классе должны иметь логическое отношение друг к другу , но сам класс может фактически делать несколько (связанных) вещей.
По моему опыту, этот принцип слишком часто применяется слишком усердно, и в результате вы получаете множество крошечных классов с одним методом. Оба проворных магазина, в которых я работал, сделали это.
Представьте себе, если бы у создателей .Net API был такой менталитет: вместо List.Sort (), List.Reverse (), List.Find () и т. Д. У нас были бы классы ListSorter, ListReverser и ListSearcher!
Вместо того, чтобы больше спорить с SRP (что само по себе не страшно в теории) , я поделюсь некоторыми из моих давних анекдотических событий:
В одном месте, где я работал, я написал очень простое средство определения максимального потока, которое состояло из пяти классов: узла, графа, создателя графа, решателя графа и класса, чтобы использовать создателя / решателя графа для решения задачи. реальная проблема. Ни один из них не был особенно сложным или длинным (решатель был самым длинным в ~ 150 строк). Однако было решено, что у классов слишком много «обязанностей», поэтому мои коллеги приступили к рефакторингу кода. Когда они были сделаны, мои 5 классов были расширены до 25 классов, чьи строки кода были более чем в три раза больше, чем они были изначально. Поток кода больше не был очевиден, как и цель новых юнит-тестов; Теперь мне было трудно понять, что сделал мой собственный код.
В то же время почти у каждого класса был только один метод (его единственная «ответственность»). Следование потоку внутри программы было почти невозможно, и большинство юнит-тестов состояло из проверки того, что этот класс вызывал код из другого класса , оба из которых были для меня загадкой. Были буквально сотни классов, в которых (ИМО) должны были быть только десятки. Каждый класс делал только одну «вещь» , но даже с соглашениями об именах, такими как «AdminUserCreationAttemptorFactory» , было трудно определить связь между классами.
В другом месте (где также существовал менталитет « класс должен иметь только один метод» ), мы пытались оптимизировать метод, который занимал 95% времени во время определенной операции. После некоторой (довольно глупой) оптимизации его я переключил свое внимание на то, почему его называют баджиллионным разом. Он вызывался в цикле в классе ... чей метод вызывался в цикле в другом классе ... который также вызывался в цикле ...
В общей сложности было пять уровней петель, разбросанных по 13 классам (серьезно). То, что на самом деле делал какой-то один класс, было невозможно определить, просто взглянув на него - вам пришлось нарисовать мысленный график того, какие методы он вызывал, какие методы вызывали эти методы и так далее. Если бы все это было объединено в один метод, то было бы всего около 70 строк с нашим проблемным методом, вложенным в пять сразу очевидных уровней циклов.
Моя просьба о реорганизации этих 13 классов в один класс была отклонена.
источник
Теперь, когда вы упомянули Чистый код, хотя он содержит несколько хороших идей, я думаю, что его одержимость реорганизовать все методы в подметоды и методы в субподметоды и т. Д. Зашла слишком далеко. Вместо пары методов из десяти строк вы должны предпочесть двадцать (предположительно хорошо названных) однострочников. Очевидно, кто-то думает, что это чисто, но мне кажется, что это намного хуже, чем оригинальная версия.
Кроме того, заменяя простые элементарные вещи, такие как
в классе с помощью вызова собственного метода класса, такого как
это сомнительное "улучшение" ИМХО. Дополнение: Разница в том, что первая проверка делает именно то, что говорит: проверяет, равна ли длина массива 0. Хорошо,
isEmpty()
может проверить длину массива тоже. Но это также может быть реализовано так:То есть включает в себя неявную нулевую проверку! Это может быть хорошим поведением для открытого метода - если массив равен нулю, тогда что-то определенно пусто - но когда мы говорим о внутренних классах, это не так хорошо. Хотя инкапсуляция во внешнюю среду является обязательной, внутренние компоненты класса должны точно знать, что происходит внутри класса. Вы не можете инкапсулировать класс от себя . Явное лучше, чем неявное.
Это не значит, что ломать длинные методы или проводить логические сравнения не годится; конечно, но в какой степени это сделать - где сладкое место - это, очевидно, вопрос вкуса. Разбивка длинного метода приводит к появлению новых методов, и это не бесплатно. Вы должны просмотреть исходный код, чтобы увидеть, что на самом деле происходит, когда вы можете увидеть это с первого взгляда, если бы все эти вещи были в одном методе.
Я бы даже сказал, что в некоторых случаях однострочный метод слишком короток, чтобы его можно было назвать методом.
источник
«Будьте либеральны с комментариями»
Комментарии, безусловно, хорошая вещь, но слишком много таких же плохих, если не хуже, чем недостаточно. Почему? Ну, люди склонны отключать комментарии, если видят слишком много ненужных. Я не говорю, что вы можете иметь совершенно самодокументируемый код, но предпочтительнее кода, который нуждается в комментариях для объяснения.
источник
GoTo считается вредным
Если вы реализуете конечный автомат, оператор GOTO может иметь больше смысла (удобочитаемость и эффективный код), чем подход «структурированного программирования». Некоторых коллег действительно беспокоило, когда первый фрагмент кода, который я написал на новой работе, включал не одно, а несколько операторов goto. К счастью, они были достаточно умны, чтобы понять, что это действительно лучшее решение в данном конкретном случае.
Любая «лучшая практика», которая не допускает разумных и документированных исключений из ее правил, просто страшна.
источник
import re
Мы приносим жертвы, чтобы сделать код тестируемым
Я прыгаю через много обручей, чтобы сделать мой код тестируемым, но я не претендую на то, что я бы не стал, если бы у меня был выбор. Однако я часто слышу, как люди выдвигают идею, что это «лучшие практики». Эти практики включают в себя (написано на языке .Net, но относится и к другим языкам) :
new MyClass()
это намного проще, чем написать фабрику, но теперь метод, который ее создает, нельзя тестировать изолированно. Если бы не этот факт, я бы сделал только 1/20 числа фабричных классов, которые я делаю сейчас.Итак, что мы можем сделать, чтобы это исправить? Нам нужно радикальное изменение в языковой архитектуре:
Короче говоря, нам нужен язык, разработанный с нуля с учетом тестируемости .
источник
Разделение приложений на уровни; Уровень данных, бизнес-уровень, уровень пользовательского интерфейса
Основная причина, по которой мне это не нравится, заключается в том, что большинство мест, которые следуют этому методу, используют очень хрупкие фреймворки для его выполнения. IE UI Layer кодируется вручную для работы с объектами бизнес-уровня, объекты бизнес-уровня кодируются вручную для работы с бизнес-правилами и базой данных, база данных является SQL и уже довольно хрупкая и управляется группой «DBA», которой не нравятся изменения.
Почему это плохо? Наиболее распространенным запросом на улучшение является, вероятно, «Мне нужно поле на экране X с Y». Взрыв! У вас просто есть новая функция, которая влияет на каждый слой, и если вы разделяете слои с разными программистами, это просто стало большой проблемой, затрагивающей несколько человек и группы, для очень простого изменения.
Кроме того, я не знаю, сколько раз я был в спорах, которые приводят что-то вроде этого. «Максимальная длина поля имени - 30, это уровень пользовательского интерфейса, бизнес-уровень или проблема уровня данных?» И есть сто аргументов, и нет правильного ответа. Ответ один и тот же, он влияет на все слои, вы не хотите, чтобы пользовательский интерфейс был немым, и вам нужно было пройти через все слои и потерпеть неудачу в базе данных, просто чтобы пользователь обнаружил, что его запись слишком длинная. Если вы измените его, это повлияет на все слои и т. Д.
«Слои» также имеют тенденцию протекать; Если какой-либо слой физически разделен границами процесса / компьютера (веб-интерфейс IE и логика бизнес-бэкенда), правила дублируются, чтобы все работало достаточно хорошо. Т.е. некоторая бизнес-логика заканчивается в пользовательском интерфейсе, даже если это «бизнес-правило», потому что пользователь должен реагировать на пользовательский интерфейс.
Если используемая структура или используемая архитектура устойчива к небольшим изменениям и утечкам, т.е. основана на метаданных, и динамически настраивается на всех уровнях, это может быть менее болезненным. Но для большинства фреймворков это непростая задача, требующая изменений пользовательского интерфейса, изменений бизнес-уровня и базы данных для каждого небольшого изменения и требующая больше работы и меньшего количества помощи, чем предполагается для этого метода.
Я, вероятно, получу удар за это, но это так :)
источник
JavaBeans
Использование JavaBeans в Java. См. Мой вопрос Почему я не должен использовать неизменяемые POJO вместо JavaBeans? на StackOverflow.
источник
Истории пользователей / Случаи использования / Персоны
Я понимаю необходимость в них, когда вы программируете для отрасли, с которой вы не знакомы, но я думаю, что когда они реализуются в полную силу, они становятся слишком корпоративными и становятся пустой тратой времени.
источник
80 знаков / строка ограничены
Я понимаю, что необходимо пойти на некоторые компромиссы, чтобы соответствовать темпу самого медленного бегуна на стороне графического интерфейса пользователя (ограничения разрешения экрана и т. Д.), Но почему это правило применяется к форматированию кода?
Понимаете ... Это было маленькое изобретение, называемое горизонтальной полосой прокрутки, которое было создано для управления виртуальным пространством экрана за пределами крайней правой границы пикселя. Почему разработчики, которым удалось создать отличные инструменты повышения производительности, такие как подсветка синтаксиса и автозаполнение, не используют его?
Конечно, есть редакторы CLI, неукоснительно используемые * nix динозаврами, которые следуют устаревшим ограничениям своих терминалов VT220, но почему остальные из нас придерживаются того же стандарта?
Я говорю, винт предел 80 символов. Если динозавры достаточно эпичны, чтобы взломать emacs / vim весь день, почему они не могут создавать расширение, которое автоматически оборачивает строки или предоставляет возможности горизонтальной прокрутки для их IDE CLI?
Мониторы с разрешением 1920x1080 в конечном итоге станут нормой, и разработчики во всем мире по-прежнему живут под теми же ограничениями, не имея никакого отношения к тому, почему они это делают, за исключением того, что им сказали делать старшие, когда они только начинали программировать.
Ограничения в 80 символов не лучшая практика, но нишевая практика для очень небольшого числа программистов, и к ней следует относиться как к таковой.
Редактировать:
Понятно, что многим разработчикам не нравится горизонтальная полоса прокрутки, потому что она требует жеста мыши, так что ... Почему бы не увеличить ограничение ширины столбца до большего числа (чем 80) для тех из нас, кто использует современные дисплеи.
Когда компьютерные мониторы 800x600 стали нормой для большинства пользователей, веб-разработчики увеличили ширину своего сайта, чтобы приспособить большинство ... Почему разработчики не могут сделать то же самое.
источник
Измерить, измерить, измерить
Так хорошо, отмерить, но для выявления ошибок в производительности, измерение работает так же, как и последовательное устранение. Вот метод, который я использую.
Я пытался найти источник меры "мудрости". Кто-то с достаточно высоким мыльным ящиком сказал это, и теперь он путешествует.
источник
Мой учитель требует, чтобы я начинал все свои идентификаторы (не включая константы) строчными буквами, например
myVariable
.Я знаю, что это кажется незначительным, но многие языки программирования требуют, чтобы переменные начинались с заглавных букв. Я ценю последовательность, поэтому у меня есть привычка начинать все с заглавных букв.
источник
Используйте синглтоны
Когда у вас должен быть только один экземпляр чего-либо. Я не могу не согласиться больше. Никогда не используйте одиночный код, просто выделите его один раз и передайте указатель / объект / ссылку по мере необходимости. Нет абсолютно никаких причин не делать этого.
источник
Использование unsigned int в качестве итератора
Когда они узнают, что использование подписанного int намного безопаснее и менее подвержено ошибкам. Почему так важно, чтобы индекс массива мог быть только положительным числом, чтобы все были рады игнорировать тот факт, что 4 - 5 - это 4294967295?
источник
0
уменьшается на1
, вы фактически получаете максимальное положительное значение, которое может хранить unsigned int?Методы не должны быть длиннее одного экрана
Я полностью согласен с принципом единой ответственности, но почему люди воспринимают его как «функция / метод может иметь не более одной ответственности на самом тонком уровне логической детализации»?
Идея проста. Функция / метод должен выполнять одну задачу. Если часть этой функции / метода может быть использована в другом месте, выделите ее в свою собственную функцию / метод. Если он может быть использован в другом месте проекта, переместите его в свой собственный класс или в служебный класс и сделайте его внутренне доступным.
Наличие класса, который содержит 27 вспомогательных методов, которые в коде вызываются только один раз, - это глупость, пустая трата пространства, ненужное увеличение сложности и значительный расход времени. Это больше похоже на хорошее правило для людей, которые хотят выглядеть занятыми рефакторингом кода, но не производят много.
Вот мое правило ...
Напишите функции / методы для достижения чего-либо
Если вы собираетесь скопировать / вставить некоторый код, спросите себя, лучше ли было бы создать функцию / метод для этого кода. Если функция / метод вызывается только один раз в другой функции / методе, есть ли смысл вначале иметь его (будет ли он вызываться чаще в будущем). Стоит ли добавлять дополнительные переходы в функции / методы во время отладки (т. Е. Делает ли добавленный переход облегчение или сложность отладки)?
Я полностью согласен с тем, что функции / методы, длина которых превышает 200 строк, требуют тщательного изучения, но некоторые функции выполняют только одну задачу в таком количестве строк и не содержат полезных частей, которые можно абстрагировать / использовать в остальной части проекта.
Я смотрю на это с точки зрения разработчика API ... Если бы новый пользователь посмотрел на диаграмму классов вашего кода, сколько частей этой диаграммы имело бы смысл в большей части проекта, и сколько их будет существовать только как помощники в других частях проекта.
Если бы мне пришлось выбирать между двумя программистами: первый имеет тенденцию писать функции / методы, которые пытаются делать слишком много; вторая разбивает каждую часть каждой функции / метода на самый высокий уровень детализации; Я бы выбрал первые руки вниз. Первый будет выполнять больше (т. Е. Писать больше кода для приложения), его код будет легче отлаживать (из-за меньшего количества переходов / вылетов функций / методов во время отладки), и он будет тратить меньше времени на занятую работу, совершенствуя, как код выглядит против совершенствования работы кода.
Ограничьте ненужные абстракции и не загрязняйте автозаполнение.
источник