CodeGym /Java блог /Случаен /Какво представляват антимоделите? Нека да разгледаме няко...
John Squirrels
Ниво
San Francisco

Какво представляват антимоделите? Нека да разгледаме някои примери (Част 2)

Публикувано в групата
Какво представляват антимоделите? Нека да разгледаме някои примери (Част 1) Днес продължаваме нашия преглед на най-популярните анти-модели. Ако сте пропуснали първата част, ето я. Какво представляват антимоделите?  Нека да разгледаме някои примери (Част 2) - 1Така че шаблоните за проектиране са най-добрите практики. С други думи, те са примери за добри, изпитани във времето начини за решаване на конкретни проблеми. От своя страна, антимоделите са тяхната точна противоположност, в смисъл, че те са модели на клопки or грешки при решаването на различни проблеми (зли модели). Нека да продължим към следващия анти-модел за разработка на софтуер.

8. Златен чук

Златен чук е антимодел, дефиниран от увереността, че определено решение е универсално приложимо. Примери:
  1. След като се сблъска с проблем и намери шаблон за идеалното решение, програмистът се опитва да залепи този шаблон навсякъде, прилагайки го към текущи и всички бъдещи проекти, instead of да търси подходящите решения за конкретни случаи.

  2. Някои разработчици веднъж създадоха свой собствен вариант на кеш за конкретна ситуация (тъй като нищо друго не беше подходящо). По-късно, при следващия проект, който не включваше специална кеш логика, те отново използваха техния вариант, instead of да използват готови библиотеки (например Ehcache). Резултатът беше куп бъгове и несъвместимости, Howто и много загубено време и изпържени нерви.

    Всеки може да си падне по този антимодел. Ако сте начинаещ, може да не сте запознати с моделите на проектиране. Това може да ви накара да се опитате да разрешите всички проблеми по единствения начин, който сте усвоor. Ако говорим за професионалисти, тогава наричаме това професионална деформация or nerdview. Имате свои собствени предпочитани дизайнерски модели и instead of да използвате правилния, използвате любимия си, като приемате, че доброто напасване в миналото гарантира същия резултат в бъдеще.

    Тази клопка може да доведе до много тъжни резултати - от лошо, нестабилно и трудно за поддържане изпълнение до пълен провал на проекта. Точно Howто няма едно хапче за всички болести, няма и един модел за дизайн за всички случаи.

9. Преждевременна оптимизация

Преждевременната оптимизация е анти-модел, чието име говори само за себе си.
„Програмистите прекарват огромно количество време в мислене и безпокойство за некритични места в codeа и се опитват да ги оптимизират, което само се отразява негативно на последващото отстраняване на грешки и поддръжка. Като цяло трябва да забравим за оптимизацията, да речем, в 97% от случаите. Освен това , преждевременната оптимизация е коренът на всяко зло. Въпреки това трябва да обърнем цялото си внимание на оставащите 3%." — Доналд Кнут
Например преждевременно добавяне на индекси към база данни. Защо това е лошо? Е, това е лошо, индексите се съхраняват като двоично дърво. В резултат на това всеки път, когато се добавя и изтрива нова стойност, дървото ще се преизчислява и това отнема ресурси и време. Следователно индексите трябва да се добавят само когато има спешна нужда (ако имате голямо количество данни и заявките отнемат твърде много време) и само за най-важните полета (полетата, които са най-често търсени).

10. Спагети code

Spaghetti codeът е анти-шаблон, дефиниран от code, който е зле структуриран, объркващ и труден за разбиране, съдържащ всички видове разклонения, като обвиващи изключения, условия и цикли. Преди това операторът goto беше основният съюзник на този анти-модел. Инструкциите Goto всъщност вече не се използват, което за щастие елиминира редица свързани трудности и проблеми.

public boolean someDifficultMethod(List<String> XMLAttrList) {
           ...
   int prefix = stringPool.getPrefixForQName(elementType);
   int elementURI;
   try {
       if (prefix == -1) {
        ...
           if (elementURI != -1) {
               stringPool.setURIForQName(...);
           }
       } else {
        ...
           if (elementURI == -1) {
           ...
           }
       }
   } catch (Exception e) {
       return false;
   }
   if (attrIndex != -1) {
       int index = attrList.getFirstAttr(attrIndex);
       while (index != -1) {
           int attName = attrList.getAttrName(index);
           if (!stringPool.equalNames(...)){
           ...
               if (attPrefix != namespacesPrefix) {
                   if (attPrefix == -1) {
                    ...
                   } else {
                       if (uri == -1) {
                       ...
                       }
                       stringPool.setURIForQName(attName, uri);
                   ...
                   }
                   if (elementDepth >= 0) {
                   ...
                   }
                   elementDepth++;
                   if (elementDepth == fElementTypeStack.length) {
                   ...
                   }
               ...
                   return contentSpecType == fCHILDRENSymbol;
               }
           }
       }
   }
}
Изглежда ужасно, нали? За съжаление, това е най-често срещаният анти-модел :( Дори човекът, който пише такъв code, няма да може да го разбере в бъдеще. Други разработчици, които видят codeа, ще си помислят: „Е, ако работи, тогава добре — по-добре е да не го докосвате". Често методът първоначално е прост и много прозрачен, но с добавянето на нови изисквания методът постепенно се натоварва с все повече и повече условни изрази, превръщайки го в чудовище като това. Ако такъв метод се появи, трябва да го преработите напълно or поне най-объркващите части. Обикновено, когато планирате проект, се отделя време за преработване, например 30% от времето за спринт е за преработване и тестове. Разбира се, това предполага че няма бързане (но кога изобщо се случва това).тук _

11. Магически числа

Магическите числа са анти-модел, в който се използват всяHowви константи в програма без ниHowво обяснение на тяхната цел or meaning. Тоест, те обикновено са лошо назовани or в крайни случаи няма коментар, обясняващ Howви са коментарите or защо. Подобно на спагети codeа, това е един от най-често срещаните анти-модели. Някой, който не е написал codeа, може or не може да има представа за магическите числа or How работят (и след време самият автор няма да може да ги обясни). В резултат на това промяната or премахването на номер кара codeа магически да спре да работи заедно. Например 36 и 73. За да се борите с този анти-модел, препоръчвам преглед на codeа. Вашият code трябва да бъде прегледан от разработчици, които не участват в съответните раздели на codeа. Очите им ще бъдат свежи и ще имат въпроси: Howво е това и защо го направихте? И разбира се, трябва да използвате обяснителни имена or да оставите коментари.

12. Програмиране чрез копиране и поставяне

Програмирането чрез копиране и поставяне е анти-модел, при който codeът на някой друг се копира и поставя безмислено, което може да доведе до неочаквани странични ефекти. Например методи за копиране и поставяне с математически изчисления or сложни алгоритми, които не разбираме напълно. Може да работи за нашия конкретен случай, но при някои други обстоятелства може да доведе до проблеми. Да предположим, че имам нужда от метод за определяне на максималния брой в масив. Ровейки се из Интернет, намерих това решение:

public static int max(int[] array) {
   int max = 0;
   for(int i = 0; i < array.length; i++) {
       if (Math.abs(array[i]) > max){
           max = array[i];
       }
   }
   return max;
}
Получаваме масив с числата 3, 6, 1, 4 и 2, а методът връща 6. Страхотно, нека го запазим! Но по-късно получаваме масив, състоящ се от 2,5, -7, 2 и 3 и тогава нашият резултат е -7. И този резултат не е добър. Проблемът тук е, че Math.abs() връща абсолютната стойност. Незнанието на това води до бедствие, но само в определени ситуации. Без задълбочено разбиране на решението има много случаи, които няма да можете да проверите. Копираният code може също така да надхвърли вътрешната структура на приложението, Howто стorстично, така и на по-фундаментално, архитектурно ниво. Такъв code ще бъде по-труден за четене и поддръжка. И разбира се, не трябва да забравяме, че направо копирането на чужд code е специален вид плагиатство.

13. Преоткриване на колелото

Преоткриването на колелото е анти-модел, понякога известен също като преоткриване на квадратното колело. По същество този шаблон е обратното на анти-модела за копиране и поставяне, разгледан по-горе. В този анти-модел разработчикът прилага свое собствено решение за проблем, за който вече съществуват решения. Понякога тези съществуващи решения са по-добри от това, което програмистът измисля. Най-често това води само до загуба на време и по-ниска производителност: програмистът може изобщо да не намери решение or да намери решение, което далеч не е най-доброто. Въпреки това не можем да изключим възможността за създаване на независимо решение, защото това е пряк път към копиране и поставяне на програмиране. Програмистът трябва да се ръководи от конкретните програмни задачи, които възникват, за да ги решава компетентно, независимо дали чрез използване на готови решения or чрез създаване на решения по поръчка. Много често, причината за използването на този анти-модел е просто бързането. Резултатът е плитък анализ на (търсене) на готови решения. Преоткриването на квадратното колело е случай, при който разглежданият антимодел има отрицателен резултат. Тоест проектът изисква персонализирано решение и разработчикът го създава, но зле. В същото време добър вариант вече съществува и други го използват успешно. Изводът: губи се огромно количество време. Първо създаваме нещо, което не работи. След това се опитваме да го преработим и накрая го заменяме с нещо, което вече съществува. Пример е внедряването на ваш собствен персонализиран кеш, когато вече съществуват много реализации. Без meaning колко талантлив сте като програмист, трябва да запомните, че преоткриването на квадратно колело е най-малкото загуба на време. А Howто знаете, времето е най-ценният ресурс.

14. Йо-йо проблем

Проблемът йо-йо е анти-модел, при който структурата на приложението е прекалено сложна поради прекомерна фрагментация (например прекомерно подразделена верига на наследяване). „Йо-йо проблемът“ възниква, когато трябва да разберете програма, чиято йерархия на наследяване е дълга и сложна, създавайки дълбоко вложени извиквания на методи. В резултат на това програмистите трябва да навигират между много различни класове и методи, за да проверят поведението на програмата. Името на този антимодел идва от името на играчката. Като пример, нека разгледаме следната верига на наследяване: Имаме технологичен интерфейс:

public interface Technology {
   void turnOn();
}
Транспортният интерфейс го наследява:

public interface Transport extends Technology {
   boolean fillUp();
}
И тогава имаме друг интерфейс, GroundTransport:

public interface GroundTransportation extends Transport {
   void startMove();
   void brake();
}
И оттам извличаме абстрактен клас автомобor:

public abstract class Car implements GroundTransportation {
   @Override
   public boolean fillUp() {
       /* some implementation */
       return true;
   }
   @Override
   public void turnOn() {
       /* some implementation */
   }
   public boolean openTheDoor() {
       /* some implementation */
       return true;
   }
   public abstract void fixCar();
}
Следва абстрактният клас Volkswagen:

public abstract class Volkswagen extends Car {
   @Override
   public void startMove() {
       /* some implementation */
   }
   @Override
   public void brake() {
       /* some implementation */
   }
}
И накрая, конкретен модел:

public class VolkswagenAmarok extends Volkswagen {
   @Override
   public void fixCar(){
       /* some implementation */
   }
}
Тази верига ни принуждава да търсим отговори на въпроси като:
  1. Колко метода VolkswagenAmarokима?

  2. Какъв тип трябва да се вмъкне instead of въпросителния знак, за да се постигне максимална абстракция:

    
    ? someObj = new VolkswagenAmarok();
           someObj.brake();
    
Трудно е да се отговори бързо на такива въпроси — изисква се да погледнем и да проучим и е лесно да се объркаме. И Howво ще стане, ако йерархията е много по-голяма, по-дълга и по-сложна, с всяHowви претоварвания и отмени? Структурата, която щяхме да имаме, щеше да бъде скрита поради прекомерна фрагментация. Най-доброто решение би било да се намалят ненужните разделения. В нашия случай бихме оставor Technology → Car → VolkswagenAmarok.

15. Случайна сложност

Излишната сложност е анти-модел, при който се въвеждат ненужни усложнения в решението.
"Всеки глупак може да напише code, който компютърът може да разбере. Добрите програмисти пишат code, който хората могат да разберат." — Мартин Фаулър
И така, Howво е сложност? Може да се определи като степента на трудност, с която се извършва всяка операция в програмата. По правило сложността може да бъде разделена на два вида. Първият вид сложност е броят на функциите, които една система има. Тя може да бъде намалена само по един начин - чрез премахване на няHowва функция. Съществуващите методи трябва да бъдат наблюдавани. Метод трябва да бъде премахнат, ако вече не се използва or все още се използва, но без да носи ниHowва стойност. Нещо повече, трябва да прецените How се използват всички методи в приложението, за да разберете къде инвестициите биха си стрували (много повторно използване на code) и на Howво можете да кажете „не“. Вторият тип сложност е ненужната сложност. Може да се излекува само чрез професионален подход. Вместо да направиш нещо "готино" (младите разработчици не са единствените податливи на това заболяване), трябва да помислите How да го направите възможно най-просто, защото най-доброто решение винаги е просто. Да предположим например, че имаме малки свързани таблици с описания на някои обекти, като например потребител: Какво представляват антимоделите?  Нека да разгледаме някои примери (Част 2) - 3И така, имаме идентификатора на потребителя, идентификатора на езика, на който е напequalsо описанието, и самото описание. По същия начин имаме спомагателни дескриптори за коли, файлове, планове и таблици с клиенти. Тогава How би изглеждало вмъкването на нови стойности в такива таблици?

public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description)throws Exception {
   switch (type){
       case CAR:
           jdbcTemplate.update(CREATE_RELATION_WITH_CAR, languageId, serviceId, description);
       case USER:
           jdbcTemplate.update(CREATE_RELATION_WITH_USER, languageId, serviceId, description);
       case FILE:
           jdbcTemplate.update(CREATE_RELATION_WITH_FILE, languageId, serviceId, description);
       case PLAN:
           jdbcTemplate.update(CREATE_RELATION_WITH_PLAN, languageId, serviceId, description);
       case CUSTOMER:
           jdbcTemplate.update(CREATE_RELATION_WITH_CUSTOMER, languageId, serviceId, description);
       default:
           throw new Exception();
   }
}
И съответно имаме това изброяване:

public enum ServiceType {
   CAR(),
   USER(),
   FILE(),
   PLAN(),
   CUSTOMER()
}
Всичко изглежда просто и добре... Но Howво да кажем за другите методи? Наистина, всички те също ще имат куп switchизявления и куп почти идентични заявки към база данни, което от своя страна значително ще усложни и раздуе нашия клас. Как може всичко това да стане по-лесно? Нека надградим малко нашето enum:

@Getter
@AllArgsConstructor
public enum ServiceType {
   CAR("cars_descriptions", "car_id"),
   USER("users_descriptions", "user_id"),
   FILE("files_descriptions", "file_id"),
   PLAN("plans_descriptions", "plan_id"),
   CUSTOMER("customers_descriptions", "customer_id");
   private String tableName;
   private String columnName;
}
Сега всеки тип има имената на оригиналните полета на своята table. В резултат на това методът за създаване на описание става:

private static final String CREATE_RELATION_WITH_SERVICE = "INSERT INTO %s(language_id, %s, description) VALUES (?, ?, ?)";
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description) {
   jdbcTemplate.update(String.format(CREATE_RELATION_WITH_SERVICE, type.getTableName(), type.getColumnName()), languageId, serviceId, description);
   }
Удобно, просто и компактно, не мислите ли? Индикацията за добър разработчик дори не е колко често той or тя използва шаблони, а по-скоро колко често той or тя избягва анти-моделите. Невежеството е най-лошият враг, защото трябва да познавате враговете си по очите. Е, това е всичко, което имам за днес. Благодаря на всички! :)
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION