Целта на практическите обекти

Аз обичам програмирането, но програмирането е трудно и съществуващите парадигми, които непреклонно настояват за съвършенство, не го правят по-лесно. Това не означава, че парадигмите и моделите създават лош код, но определени изявления от връстници, лидери на мисли и приятели проникват в пространството в главата ми, когато се опитвам да разреша проблеми.

  • „Този ​​подход е по-добър, защото работи по-бързо“
  • „Този ​​код нарушава SOLID“
  • „Трябва да създадем собствена библиотека, вместо да използваме тази рамка“

Приех тези твърдения присърце. Прекалено анализирах, създавах проблеми за решаване там, където преди това не е съществувало, предвиждах проблеми, вместо да решавам съществуващите. Мисля, че целта, която имах, беше да контролирам сложността, но много пъти сложността, създадена само от придържането към „най-добрите практики“, излизаше извън контрол. Имаме склонност да мислим за нашите класове като за малки градини. Разпръскваме дизайнерски модели в нашия код, сякаш думи като Decorator, Factory и Flyweight, защото искаме удовлетворението да видим тези думи следващия път отваряме редактора, а не защото те наистина са решили проблем.

Обичам дизайнерски модели. Те могат да решат много проблеми, но добавят сложност и избягването на тази сложност е фокусът на тази серия. Искам да изразя мислите си относно предотвратяването на сложността и въвеждането й бавно. Не се притеснявайте, ние ще напишем много код по пътя. Това е пътуване в практическото използване на обекти и как да ги използвате за продуктивно решаване на проблеми.

Какво ви е необходимо за тази статия

За съжаление, това не е статия за „начало на C#“. По същество се надявам, че вече разбирате езика за програмиране C# (или поне език с класове, така че да следвате общата схема на написания код). Така че, за да разберете този материал, вероятно трябва да сте запознати поне с:

  • Езикът за програмиране C#
  • Редактор на код или IDE
  • Инструментите на командния ред dotnet

Да поговорим за судоку

Примерен судоку пъзел.

За да представим концепциите в тази поредица от статии, ще се съсредоточим върху играта пъзел Судоку. Ако не сте виждали судоку преди, основната предпоставка е, че ви е дадена мрежа 9x9. Тази мрежа може да се разглежда като 9 независими реда, 9 независими колони и 9 независими квадрата 3x3. Целта на судоку е да попълни всеки от тези независими елементи с числата от 1 до 9. Ако използвате едно и също число два пъти на едно от тези места (редове, колони, квадрати), тогава пъзелът е невалиден.

Използваме судоку по няколко причини:

  1. Това е добре проучен проблем. Има много теория, както и много конкретни подробности за това как работи судоку. Това означава, че можете да вземете всеки урок, който ви дам тук, и да навлезете по-дълбоко в темата без мен.
  2. Судоку като игра има изненадващо много случаи на употреба. Това означава, че можем да изследваме валидиране на пъзели, решаване на пъзели, създаване на нови пъзели, творчески презентации и много повече.
  3. По принцип представянето е просто (това е само 81 числа в кутия), така че можем да започнем с нещо тривиално и да въведем нови абстракции, когато проблемът стане по-сложен.

Днешният проблем: Валидиране на пъзел

Представете си, че работите в малък издател, потенциално вестник с ежедневен тираж. Длъжността ви е Уеб програмист, но тъй като знаете как работят компютрите, често получавате тези еднократни проекти от други отдели. Обикновено те включват рестартиране на компютри или писане на формули в Excel, но една сутрин получавате този имейл от вашия мениджър.

Здравей Куил, редакторът на нашата ежедневна секция с пъзели има проект за теб. Мисля, че това може да ви се стори интересно! Той получава судоку пъзели от изпълнител всеки ден и те често имат грешки. Можете ли да му напишете бърза помощна програма, така че да може да провери отново дали е валиден пъзел? Пъзелите са наистина важни за нашите читатели, така че можете ли да сготвите нещо до края на деня?

Не намираме това за интересно. Но ние сме скапани! Ще се възползваме от възможността да разкрием предизвикателство.

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

  • Скорост на развитие
  • Коректност

Може за кратко да си помислим, че тези две са в противоречие, но с малко обмисляне на нашия процес и чрез подходящо използване на обекти, можем да постигнем и двете.

Решението за използване на обекти

Ако основните ни грижи са скоростта и коректността, тогава сме решили, че общото качество на кода е или по-малко важно. Въпреки това, ние също искаме да бъде правилен, така че чудесен начин да го постигнете е да напишете предварителни тестове сравнително рано в процеса. Това може да звучи като повече работа като цяло, но ще ни спести време с добре разбран проблем като судоку. Не забравяйте, че става въпрос за постигане на две предизвикателни цели наведнъж и осигуряване на исканата бизнес стойност (знаете, причината да ви плащат да пишете код) навреме. Нека да разгледаме предимствата от използването на обект като абстракция.

Обектите предпазват нашите проблеми от проблемите на нашите потребители

Текущата ни задача е да решим бизнес проблем за нашия редактор. За да направим това, трябва да им дадем решение, което премахва възможно най-много умствени разходи. По същество това е целта на интерфейса. Имайте предвид, че не говоря за концепцията за C# интерфейс, а просто за идеята за създаване на набор от команди, които позволяват на нашия потребител (редактора в този случай) да се съсредоточи върху проблема, който иска да реши, а не върху детайлите как им помагаме. След това вземаме данните, които този интерфейс ни предоставя, и ги използваме, за да дефинираме по-тясно собствения си бизнес проблем. Правейки това, ние свиваме проблема за нашия потребител до управляема част и си даваме добре дефинирано пространство за работа.

Това е основният интерфейс, който дефинираме за нашия потребител.

Когато разгледаме дадения ни по-горе проблем, той наистина не трябва да бъде по-сложен от това. Създаваме клас Судоку, казваме на нашия потребител, че трябва да ни предостави списък с цели числа, които представляват пъзела, и след това предоставяме прост метод (Проверка), за да оценим дали нашият пъзел е валиден. Който консумира този предмет, трябва да знае две неща:

  1. Как да създадете клас судоку
  2. What is означава извикването на Check() да върне true или false.

Обектите крият детайлите, докато не ни потрябват

Сега, когато имаме начин да кажем на нашите потребители от какво се нуждаем и какво ще им върнем, трябва действително да разрешим собствения си проблем, който е валидирането на судоку пъзел. В този момент основната ни грижа е скоростта, така че ще възприемем наивен подход и просто ще копираме списъка с числа във вътрешно представяне. Може също така да потвърдим числата само малко, за да гарантираме, че нищо неочаквано не влиза в проблемното пространство на нашия пъзел.

Какво спечелихме, като написахме код по този начин? Позволихме си да приемем наивен подход и просто да използваме масив. Можехме да използваме многоизмерен масив или назъбен масив и да съхраним нашите числа в структура, която по-точно съответства на мрежа. Въпреки това, ние просто искахме нашият потребител да въведе списък с числа, така че всяко вътрешно представяне, което се отклонява от това, трябва да бъде преведено, което означава, че ще отделим повече време на конструктора, а не на проблема пред нас. Това може да е по-поддържан подход в дългосрочен план, но това беше компромис, който направихме в интерес на времето. Това е може би най-подходящият урок, който се надявам да предам с тази серия. Искам да ви науча на стратегии за оценка на тези компромиси с увереност.

Важно е също да се отбележи, че „по-поддържаем“ е много субективна мярка. Бихте могли също толкова лесно да намерите плоския масив като най-наивния подход в зависимост от вашите умения и умения за абстрактно мислене. Най-важното нещо, което трябва да отбележим тук, е, че този подход ни позволи лукса да напишем нещо, за което ние можем да разсъждаваме бързо.

Обектите позволяват ефективно тестване на нашето решение

Голяма част от това се свежда до способността ни да се съсредоточим върху даден проблем и да се справим с него с минимално разсейване. По същество последното парче, от което се нуждаем, за да ни освободи от разсейването, е процес, който ни позволява да пишем код, да получаваме бърза обратна връзка и да разбираме какво се обърка. За обектно-ориентиран подход малко неща постигат това като единичен тест. Може да звучи контраинтуитивно да отделяме повече време за писане на код, за да тестваме съществуващия код, но това е мястото, където инструментите за разработчици могат да се използват за ускоряване на нашия процес. И реалистично погледнато, така или иначе ще тествате кода си върху валиден пъзел, така че писането на код, който да повтаря този тест завинаги, в крайна сметка ще ви спести повече време, отколкото използва.

Нашите тестови пъзели с модулни тестове за валидиране

В крайна сметка написах повече тестове като цяло, но се чувствах удобно да започна само с два. Целта е да се пише и променя код, докато те преминат. Истинската сила идва само от провеждането на тези тестове на живо. Ако използвате инструментите на командния ред dotnet, това е просто.

Последният ред е най-важен: Waiting for a file to change before restarting dotnet.... Това ни позволява да правим промени бързо, да запазваме файл и да видим дали нашата промяна работи направо в конзолата. В този момент просто подредете прозореца на конзолата до текстовия си редактор и преработете своя път към славата. Ако срещнете проблем или се окажете блокирани, винаги можете да стартирате кода си в програма за отстраняване на грешки и да преминете бавно, но това е страхотно, когато като цяло знаете какво трябва да напишете и просто искате потвърждение, че работата ви е завършена.

Сега за големия финал

До този момент трябва да стане ясно, че действителният код за решаването на пъзели Sudoku всъщност не е целта на тази публикация, но също така би била непълна без него. Ако се интересувате от практикуването на подхода, който очертах, бих ви насърчил да създадете проект и да напишете свой собствен наивен подход. Дайте си ограничение във времето, ако искате предизвикателство. Ще включа кода за класа за проверка на судоку по-долу и ако искате да разгледате цялото решение, можете да разгледате тази връзка в Github.

Какво следва

В момента целта ми е тази серия да продължи и да помогне да очертая моите стратегии за правене на практически компромиси с обектно-ориентираното програмиране. Някои други теми, които ще разгледам в бъдеще, са:

  • Рефакторинг за поддръжка
  • Рефакторинг за производителност
  • Разширяване на вашите обекти с повече функции
  • Разширяване на конфигурируемостта на вашите обекти