Найгірші анти-шаблони, з якими ви стикалися [закрито]


9

Які найгірші анти-шаблони, з якими ви стикалися у своїй кар'єрі програміста?

Я в основному займаюся Java, хоча це, мабуть, не залежить від мови.

Я думаю, що найгірше це те, що я називаю основним антидіаграмою . Це означає програма, що складається з одного, надзвичайно великого класу (іноді супроводжується парою невеликих класів), що містить всю логіку. Зазвичай з великим циклом, в якому міститься вся бізнес-логіка, іноді маючи десятки тисяч рядків коду.

Відповіді:


38

Коментований код. Блоки його, можливо, сотні рядків. Теорія, будучи, це прокоментується, не приносить ніякої шкоди, і, можливо, нам це буде потрібно в майбутньому.


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

@Cyrena, ти теж працював з Еріком?!?
CaffGeek

Я колись мав купу коду, який використовував #ifdef COMMENT для блокування речей. Працював чудово, поки хтось не визначив КОМЕНТАР.
Майкл Коне

9
Це ще один випадок, коли використання контролю версій окупається. Ви можете видалити код, не запитуючи, чи може він вам знадобиться в майбутньому, оскільки його можна буде знову отримати за допомогою декількох натискань клавіш.
Джейсон Б

5
Я думаю, що коментований код має місце, якщо ви додасте його до коментаря, який пояснює, чому його існує. Іноді я залишу коментований блок, який відображає потенційну дорогу, про яку я думав пройти, і залишу його з коментарем про те, чому я цього не зробив. @Jason, я безумовно чую вас про те, що це роль контролю версій, але видалений код у контролі версій не дуже виявляється.
nlawalker

19

Я вдарю ще одного очевидного з "копію-макаронами". Скопіюйте код, який майже ідентичний бажаному, а потім змінити декілька речей (замість вилучення в метод).

Це особливо поширено в деяких функціональних і тестових кодах API з кінця 90-х: буквально сотні (або навіть тисячі) майже однакових тестових випадків, які могли бути розбиті на кілька функцій, що приймають 3 або 4 параметри - або, ще краще , щось кероване даними. Моєю першою роботою поза коледжем було буквально 8 місяців переписування та перефабрикування тисяч рядків копій-макаронів, які використовували застарілі методи. На той момент, коли я закінчив, тестові файли були меншими за 10-ту частину оригінального розміру та набагато більш ремонтовані (і читабельні!).


16

Я думаю, що я можу багато писати про Pattern Mania та рішеннях, які можна було б вирішити набагато менше зусиль, але я б скоріше вказав на чудову статтю, яку я прочитав недавно, з фантастичним прикладом того, як просте рішення може бути надскладним .

Як (не) писати Factorial на Java або так ми вкладаємо завод у ваш алгоритм


3
Дивовижно! Зараз де FactorialWebService? : P
FrustratedWithFormsDesigner

1
Я називаю це зразком лихоманки ... кожен отримує це в один момент своєї кар’єри. Краще серед нас зростає поза ним. У мене було інтерв'ю, де хлопець запитав мене, коли я повинен думати про схеми. Я сказав йому, що я дозволяю їм розвиватися в систему. Він сказав: "Ні, ви повинні використовувати шаблони з самого початку".
Майкл Браун

FactoryFactories - це лише симптом того, щоб прагнути максимально відкласти фактичний вибір, але він все-таки закінчується або жорстким кодуванням, або зіставленням зовнішнього значення рядка з фрагментом коду. Вприскування залежностей - це краще рішення.

Візерунки - це артефакти гарного дизайну - до них слід ставитися як до таких. Мені подобається описувати їх як визначення, а не як рішення. Вони корисні при спілкуванні, але не обов'язково при розробці дизайну.
Майкл К

Дякую за це, добре читайте.
Сиг


14

Регіони

У C # ви можете визначити область коду, яку можна згортати в IDE, таким чином приховуючи його, якщо ви не хочете мати справу з цим кодом. Я працював над проектом, в якому регіони охоплювали сотні ліній (хотілося б, щоб я перебільшував), а в тисячі ліній було декілька регіонів (я знову хочу, що я жартую).

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

Регіони заохочують розробників "приховувати" своє лайно на очах.


15
+1 для регіонів заохочують розробників "приховувати" свої лайна на очах. Однак при правильному використанні я вважаю, що регіони допомагають логічно згрупувати код і легко знайти їх у більш пізній час.
Даррен Янг

Це вже давно проблема зі складанням редакторів. Раніше я робив те саме, що востаннє програмувався в OCCAM.
Майкл Коне

2
Я люблю регіони ... але тільки за організацію ... не приховуючи цифрових повторів коду.
IАнотація

3
+1. Тому також використання регіонів порушує правило StyleCop SA1124 DoNotUseRegions.
Арсеній Муренко

1
У мене є проекти, які працюють з величезною кількістю полів у SQL, і код, який її оновлює / створює, - це багато рядків. Цей регіон #region SQL Updateробить його розбірним, тому потрібно менше прокручування.
JYelton


9

Не перевантажують методи:

// Do something
public int doSomething(Data d);

// Do same thing, but with some other data
public int doSomething2(SomeOtherData d);

Ясно видно, що програміст не розумів перевантаження.


5

Послідовності перемикання циклу

http://en.wikipedia.org/wiki/Loop-switch_sequence

Вони мене дратують до кінця і справді показують, наскільки досвідченим був диявол


Ах, автомат, що закінчується :)

Чому ви повинні виховувати ці поховані спогади? У мене був такий приємний день.
Малахій

5

М'яке кодування , тобто коли програмісти виходять із шляху, щоб уникнути жорсткого кодування та опинитися на іншій стороні шкали - «жорстко кодовані» залежності.


4

Тримайте стан у клієнта.

Колись працював з веб-додатком, де весь стан зберігався у браузері. (Для забезпечення безпроблемної масштабованості всі винятки були проігноровані).


Чи можете ви, будь ласка, докладно? Імхо, для веб-програми, це добре, коли єдиний стан знаходиться в браузері (тобто файли cookie), а сервер "не поділяє нічого". Або ви маєте на увазі "стан", як у "базі даних додатків"?
кеппла

Стан: Як і у фактичних даних, для яких потрібно працювати.

OO ви маєте мої найглибші співчуття.
кеппла

4

Масивні чеки

Я ненавиджу, коли бачу, що розробник не робив реєстрацію за тиждень. Це означає, що він або застряг і не звернувся за допомогою, або він з’єднав купу функцій в один великий заїзд. (Я покинув найгірший сценарій, він просто нічого не робить. Це легко вирішити ... два слова звучать так, як тебе найняли.)

Якщо ви робите велику реєстрацію, ви втрачаєте багато переваг SCM, як, наприклад, можливість пов’язати набір змін із певною функцією. Також, ймовірно, вам доведеться зробити багато злиття, і це не обов'язково легко отримати правильно.


1
Не робити нічого не завжди є найгіршим сценарієм. Іноді краще писати це з нуля, ніж мати код для переписування ...
Малахій,

4

Наразі я працюю зі старим кодом, і мені подобається те, як попередній кодер отримує перший елемент списку:

String result;
for(int i = 0; i < someList.size(); i++) {
    result = someList.get(i);
    break;
}

Але найгірше, що я бачив у цьому коді - це визначення класів вбудованих сторінок JSP, написання всіх HTML, CSS та Javascript за допомогою scriptlet та out.println :-(


4

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

Те, що це відомча політика, зробило її ще гіршою, ніж у випадку такого поведінки одного розробника.


3

Блокування на лінійному рядку

synchronized("one") { /* block one A*/ }

synchronized("one") { /* block one B*/ }

Дуже довгі назви класів. (в JRE)

com.sun.java.swing.plaf.nimbus.
InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState

Погана структура спадкування

com.sun.corba.se.internal.Interceptors.PIORB extends
com.sun.corba.se.internal.POA.POAORB extends
com.sun.corba.se.internal.iiop.ORB extends
com.sun.corba.se.impl.orb.ORBImpl extends
com.sun.corba.se.spi.orb.ORB extends
com.sun.corba.se.org.omg.CORBA.ORB extends 
org.omg.CORBA_2_3.ORB extends
org.omg.CORBA.ORB

Виняток, якого немає.

public interface FlavorException { }

Безглузді та критичні помилки

if (properties.size() > 10000)
   System.exit(0);

Непотрібне створення об’єктів

Class clazz = new Integer(0).getClass();
int num = new Integer(text).intValue();

Викидання виключення для інших цілей

try {
    Integer i = null;
    Integer j = i.intValue();
} catch (NullPointerException e) {
    System.out.println("Entering "+e.getStackTrace()[0]);
}

Використання об'єктів екземпляра для статичних методів.

Thread.currentThread().sleep(100);

Синхронізація на неповному полі

synchronized(list) {
   list = new ArrayList();
}

Безглузда копія постійної струни

String s = new String("Hello world");

Безглуздий дзвінок на String.toString ()

String s = "Hello";
String t = s.toString() + " World";

Дзвінки до System.gc (), щоб звільнити деяку кількість пам'яті

Встановлення локальної змінної до нуля, щоб звільнити деяку пам'ять

    // list is out of scope anyway.
    list = null;
}

Використання ++ i замість i ++ з міркувань продуктивності (або будь-якої іншої мікро-мікро-оптимізації)


Це не обов'язково анти-шаблони, а лише неправильне кодування.
Gary Willoughby

@ Гарі, або погані моделі розвитку я бачу повторені. Можливо, не входить в чітке визначення анти-зразка.
Пітер Лорі

1
@Peter: "Дзвінки до System.gc (), щоб звільнити деяку пам'ять", я бачив один випадок, коли .NET вибухне за винятком OutOfMemory, якщо тільки GC не викликався явно. Звичайно, це було скоріше виняток, ніж правило.
Кодер

3

Код, посипаний:

// TODO: 

або

// TODO: implement feature 

без додаткової інформації.


2

Ітератор для муляжів:

Iterator iCollection = collection.iterator();
for(int i = 0 ; i < collection.size() ; i++ ){
    if(collection.get(i) == something){
       iCollection.remove();
    }
 }

Singletono-Factory:

public class SomeObject{
   private SomeObject() {}
   public static SomeObject getInstance(){
       return new SomeObject();
   }
}

якщо інше керується розвитком (також називається принципом відкритого закриття - відкритим для модифікації, близьким для розуміння):

if (sth1){
...  
}else if(sth2){
..
}
...
..
else if(sth1000000000000){
...
}

StringPattern (також називається StringObject):

a) sendercode
if(sth1)
   str+="#a";
if(sth2)
   str+="#b";
...
if(sth1000)
   str+="#n";

b) receiver
   regexp testing if str contains #a, #b, ... #n

Це else ifчасто буває , то єдиний спосіб отримати речі зробити, хоча. Я думаю про струни; не вдається використовувати перемикач. Умови повинні бути однаковими, щоб вона була корисною.
Майкл К

IMHO кожен if / else може бути замінений простим малюнком карти або відвідувачем. У разі рядків, тобто у вас може бути файл властивостей на зразок: someString1 = some.package.ObjectToHandleSomeString1
Marcin Michalski,

2
Сингл - фабрика . З цим кодом немає нічого поганого. Єдине, що може бути неправильним, це те, що зовнішній код робить припущення, що кожен виклик getInstanceповертає один і той же екземпляр. Таке припущення може порушити інкапсуляцію і насправді є однією з найпоширеніших антитіл.
back2dos

саме тому це так заплутано :) якби метод називався create (), або він би повертав той самий екземпляр кожного разу, коли б все було ідеально
Marcin Michalski

2

Це не стільки шаблон кодування, скільки поведінковий зразок, але це зовсім погано: змінити щось у коді (скажімо, змінилися вимоги), потім налаштувати всі тести одиниці, поки код не пройде його. Налаштування або просто видалення всього тестового коду з методу тестування, але залишення методу там.

Це пов'язано з більш загальним, хоча шаблон That '' робити , ось репрезентативний рядок коду для нього:

int num = new Integer( stringParam ).parseInt( stringParam );

Це працює, зрештою.


2

Я абсолютно зневажаю абстракцію інверсії , або винаходити примітиви низького рівня поверх примітивів високого рівня. Однак іноді це спричиняють погані мовні дизайнери, а не погані програмісти. Приклади:

  1. Використання одного класу методів без змінних членів та відповідного інтерфейсу (реалізованого в термінах таблиць покажчиків функцій) замість вказівника функції. Зауважте, що у таких мовах, як Java, у вас може не бути вибору.

  2. У MATLAB та R наполягають на тому, що все є вектором / матрицею, а не примітивом.

  3. Поки ми базуємо MATLAB, як щодо того, що він не має цілих чисел, тож коли вам потрібно ціле число, ви повинні використовувати подвійне.

  4. Чисто функціональні мови, де вам потрібно використовувати виклики функцій для написання циклу.


1

Це було б точно копіювати / вставляти, я бачив багато поганого коду, що робиться через це, кодування ковбоя і все, що виходить з цього. (Класи Бога, надзвичайно великі методи, алгоритми поганого продумання тощо)

І якщо дозволені шаблони дизайну, я б сказав: Робити проект як набір дій із плану, не роблячи аналізу дизайну чи домену.


1

Багаторазове використання квасолі Java -

Яєчна квасоля з великою кількістю змінних, що використовується в декількох різних операціях. Кожна операція використовує деякі довільні підмножини змінних bean, а інші ігнорує. Кілька змінних для стану gui, кілька змінних, перекинутих для проходження між компонентами, кілька, які, ймовірно, вже не використовуються. Найкращі приклади не мають жодної документації, яка б перешкоджала оцінці шаблону.

Крім того, не можна забути коханого

try{ 
   ... //many lines of likely dangerous operations
}
catch(Exception e){}

ІМХО, винятки смердять. Вони занадто важкі, щоб їх правильно виправити, і вони додають помилкового почуття безпеки.
Coder

Якою б не була думка про смердючість винятків, мовчки ковтаючи одного, мусить більше смердити.
Стів Б.

1

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


1

Щось, що викликало у мене багато горя, - це «Велика карта в небі». Метання навколо карти замість використання належних об’єктів. Ви не маєте уявлення про те, які "змінні" він містить без налагодження, і ви не знаєте, що воно може містити, не відстежуючи код назад. Зазвичай відображає рядки для об'єктів або рядки для рядків, які, можливо, слід розібрати на примітиви.


Схоже, покладаючись на Session і ViewState в ASP.NET, щоб передавати дані між сторінками, що, на жаль, часто потрібно ...
Wayne Molina,

1

Один з моїх улюблених анти-шаблонів розробки - використання «дизайну» бази даних, яка вимагає постійного додавання додаткових стовпців до однієї або декількох таблиць програмно . Це двоюрідний брат «дизайну», який створює нову таблицю для кожного примірника суб’єкта. Обидва неминуче потрапляють до обмежень сервера баз даних, але зазвичай не до тих пір, поки система не випускається досить довго.


0

Я думаю, що одна з найгірших антидіапазонів, яку я бачив, передбачає використання таблиці баз даних як тимчасове сховище замість використання пам'яті комп'ютера.

Домен проблеми є власною, що не дозволяє мені пояснювати її, але не потрібно розуміти основну проблему. Це додаток для графічного інтерфейсу, написане на Java з базовою базою даних. Потрібно було брати певні вхідні дані, маніпулювати ними, а потім фіксувати оброблені дані до бази даних.

Наш проект має досить складний алгоритм, який зберігає проміжні значення для подальшої обробки. Замість інкапсуляції тимчасових об'єктів у ... об’єктах була створена таблиця бази даних на зразок "t_object". Кожен раз, коли було обчислено значення, воно додається до цієї таблиці. Після того, як алгоритм закінчив свою роботу, він вибрав би всі проміжні значення та обробив їх все в одному великому об’єкті Map. Після того, як вся обробка буде завершена, залишилися значення, позначені як збережені, будуть додані до реальної схеми бази даних, а тимчасові записи в таблиці "t_object" будуть викинуті.

Таблиця також використовувалася як унікальний список, дані могли існувати лише один раз. Це, можливо, було б гідною особливістю дизайну, якби ми реалізували обмеження на таблиці, але ми закінчили ітерацію через всю таблицю, щоб побачити, чи існують дані чи ні. (Ні, ми навіть не використовували запити, які використовувались, коли пропозиції з CONTAINS)

Деякі проблеми, з якими ми зіткнулися завдяки цій конструкції, були спеціально налагодженням. Додаток було побудовано для конвеєрних даних, щоб не було декількох графічних інтерфейсів, які попередньо обробляли б дані, перш ніж надходити до цього алгоритму. Процес налагодження повинен був обробити тестовий випадок, а потім зробити паузу відразу після закінчення вищевказаного розділу. Тоді ми б запитали базу даних, щоб побачити, які дані містяться в цій таблиці.

Ще однією проблемою, яку ми виявили, було те, що дані не видаляються належним чином із цієї тимчасової таблиці, що може заважати запуску в майбутньому. Ми виявили, що це сталося через те, що Винятки не обробляються належним чином, і тому програма не виходить належним чином та не видаляє дані в таблиці, над якою вона контролюється.

Якби ми використовували базовий об’єктно-орієнтований дизайн і зберігали все в пам’яті, цих вищезазначених проблем ніколи б не виникло. По-перше, налагодження було б простим, оскільки ми могли легко встановити точки перерв у програмі, а потім перевірити пам'ять у стеку та купі. По-друге, при ненормальному виході з програми пам'ять Java буде очищена природним шляхом, не турбуючись про видалення її з бази даних.

ПРИМІТКА. Я не кажу, що ця закономірність є по суті поганою, але в цьому прикладі я вважаю, що це не є зайвим, коли базові принципи ОО були б достатніми.

Я не впевнений у назві цього анти-шаблону, оскільки це вперше я бачив щось подібне. Якісь хороші імена, які ви, хлопці, можете придумати за цією схемою?


Я б не назвав це проблемою ковдри. Це залежатиме від того, скільки тимчасових даних зберігається та що з ними робиться.
GrandmasterB

Мені слід додати більше до публікації, але головна проблема полягала в тому, що замість зміни об’єктів та доступу до даних із пам'яті, дані маніпулювали хаком sql-кодом. Це призвело до збільшення складності та серйозних проблем з виконанням.
jluzwick

2
Ви не згадуєте про свій проблемний домен, але не завжди це погано, якщо збереження стану в іншому місці може призвести до можливого масштабування процесів та їх самоаналізу протягом тривалого часу, а також допомогти у налагодженні. Чи викликав доступ до БД проблеми або продуктивність?
Черга Jé

Я відредагував статтю, щоб краще відобразити, як це було використано в нашому проекті, але у нас виникли численні проблеми при налагодженні, зокрема тому, що нам довелося запитувати базу даних, щоб побачити тимчасові змінні. Також у нас виникли великі проблеми, пов’язані з продуктивністю, через те, що база даних постійно запитується на дані та перевіряється, чи вже існували нові дані.
jluzwick

0

Кошик перед конем - він же YouMightNeedIt

Наприклад:

  • Створення схеми RDMB з абстрактними поняттями, перехресними посиланнями - по суті, надто узагальнений куб даних ... І ТОГО особливості написання навколо моделі "все".

Це був би злий брат-близнюк ЯГНІ, правда?
Уейн Моліна

0

ІМО - найгірший антидіапазон, який я бачив, - це "Нам не потрібні жодні смугові візерунки" Анти-Шаблон: Ідея, що шаблони дизайну - це витрата часу, і ви можете швидше писати код, просто проклавши його разом і скопіюйте / обклеювання за потребою.

Почесна згадка стосується наявності коду, який завантажує об'єкт із бази даних, використовуючи старий стиль VB6:

Foobar oFoo = new Foobar();
oFoo.FooID = 42;
if (oFoo.Load()) { 
    // do something with oFoo
}

насправді не є анти-зразком, але само по собі демонструє відсутність використання належної архітектури та розділення проблем.

Також такі речі:

// this name is misleading, we may not always want to stand in fire,
// we may want to stand in slime or voidzones or ice patches...
public Foobar StandInFire() { }

// why is this here???
public string BeatWithNerfBat(string whom) { }

// ????
public int GivePony(string to) { }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.