
8. Златен чук
Златен чук е антимодел, дефиниран от увереността, че определено решение е универсално приложимо. Примери:-
След като се сблъска с проблем и намери шаблон за идеалното решение, програмистът се опитва да залепи този шаблон навсякъде, прилагайки го към текущи и всички бъдещи проекти, instead of да търси подходящите решения за конкретни случаи.
-
Някои разработчици веднъж създадоха свой собствен вариант на кеш за конкретна ситуация (тъй като нищо друго не беше подходящо). По-късно, при следващия проект, който не включваше специална кеш логика, те отново използваха техния вариант, instead of да използват готови библиотеки (например Ehcache). Резултатът беше куп бъгове и несъвместимости, Howто и много загубено време и изпържени нерви.
Всеки може да си падне по този антимодел. Ако сте начинаещ, може да не сте запознати с моделите на проектиране. Това може да ви накара да се опитате да разрешите всички проблеми по единствения начин, който сте усвоor. Ако говорим за професионалисти, тогава наричаме това професионална деформация or nerdview. Имате свои собствени предпочитани дизайнерски модели и instead of да използвате правилния, използвате любимия си, като приемате, че доброто напасване в миналото гарантира същия резултат в бъдеще.
Тази клопка може да доведе до много тъжни резултати - от лошо, нестабилно и трудно за поддържане изпълнение до пълен провал на проекта. Точно Howто няма едно хапче за всички болести, няма и един модел за дизайн за всички случаи.
9. Преждевременна оптимизация
Преждевременната оптимизация е анти-модел, чието име говори само за себе си.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 */
}
}
Тази верига ни принуждава да търсим отговори на въпроси като:
-
Колко метода
VolkswagenAmarok
има? -
Какъв тип трябва да се вмъкне instead of въпросителния знак, за да се постигне максимална абстракция:
? someObj = new VolkswagenAmarok(); someObj.brake();
15. Случайна сложност
Излишната сложност е анти-модел, при който се въвеждат ненужни усложнения в решението.
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 тя избягва анти-моделите. Невежеството е най-лошият враг, защото трябва да познавате враговете си по очите. Е, това е всичко, което имам за днес. Благодаря на всички! :)
GO TO FULL VERSION