Йерархична декомпозиция

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

Декомпозицията трябва да се извърши йерархично – първо системата се разделя на големи функционални модули/подсистеми, които описват нейната работа в най-общ вид. След това получените модули се анализират по-подробно и се разделят на подмодули or обекти.

Преди да изберете обекти, разделете системата на основни семантични блокове, поне психически. В малки applications това обикновено е много лесно да се направи: няколко нива на йерархия са напълно достатъчни, тъй като системата първо е разделена на подсистеми / пакети, а пакетите са разделени на класове.

Йерархична декомпозиция

Тази идея не е толкова тривиална, колкото изглежда. Например, Howва е същността на такъв общ „архитектурен модел“ като Model-View-Controller (MVC)?

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

Тогава се оказва, че модулите трябва по няHowъв начин да си взаимодействат, за това добавят контролер, чиято задача е да управлява взаимодействието на модулите. Също така в мобилната (класическа) version на MVC моделът Observer е добавен към него, така че View да може да получава събития от модела и да променя показаните данни в реално време.

Типичните модули от най-високо ниво, получени в резултат на първото разделяне на системата на най-големите компоненти, са именно:

  • Бизнес логика;
  • Потребителски интерфейс;
  • База данни;
  • Система за съобщения;
  • Контейнер за обекти.

Първото разделяне обикновено разделя цялото приложение на 2-7 (максимум 10 части). Ако го разделим на повече части, тогава ще има желание да ги групираме и отново ще получим 2-7 модула от най-високо ниво.

Функционално разграждане

Разделянето на модули/подсистеми е най-добре на базата на задачите, които системата решава . Основната задача е разделена на съставните й подзадачи, които могат да се решават/изпълняват автономно, независимо една от друга.

Всеки модул трябва да отговаря за решаването на няHowва подзадача и да изпълнява съответната функция . В допълнение към функционалното преднаmeaning, модулът се характеризира и с набор от данни, необходими за изпълнението на функцията му, а именно:

Модул = Функция + Данни, необходими за нейното изпълнение.

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

Модулът не е произволна част от codeа, а отделна функционално значима и завършена програмна единица (подпрограма), която предоставя решение на определена задача и в идеалния случай може да работи самостоятелно or в друга среда и да се използва повторно. Модулът трябва да бъде един вид "интегритет, способен на относителна независимост в поведението и развитието". (Кристофър Александър)

По този начин компетентното разлагане се основава преди всичко на анализа на системните функции и данните, необходими за изпълнението на тези функции. Функциите в този случай не са функции от класове и модули, защото не са обекти. Ако имате само няколко часа в модул, значи сте прекалor.

Силна и слаба свързаност

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

Основният критерий за качеството на декомпозицията е доколко модулите са фокусирани върху решаването на задачите си и са независими.

Това обикновено се формулира по следния начин: "Модулите, получени в резултат на разлагане, трябва да бъдат максимално спрегнати вътрешно (висока вътрешна кохезия) и минимално свързани помежду си (ниско външно свързване)."

Висока кохезия, висока кохезия or „кохезия“ в рамките на модула, показва, че модулът е фокусиран върху решаването на един тесен проблем и не е ангажиран с изпълнение на разнородни функции or несвързани отговорности.

Кохезията характеризира степента, в която задачите, изпълнявани от модула, са свързани една с друга.

Следствие от High Cohesion е Принципът на единната отговорност - първият от петте принципа на SOLID , според който всеки обект/модул трябва да има само една отговорност и не трябва да има повече от една причина за промяната му.

Low Coupling , слабо свързване, означава, че модулите, на които е разделена системата, трябва да бъдат, ако е възможно, независими or слабо свързани един с друг. Те трябва да могат да си взаимодействат, но в същото време да знаят възможно най-малко един за друг.

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

При правилен дизайн, ако промените един модул, няма да се налага да редактирате други or тези промени ще бъдат минимални. Колкото по-хлабава е връзката, толкова по-лесно е да напишете/разберете/разширите/поправите програмата.

Смята се, че добре проектираните модули трябва да имат следните свойства:

  • Функционална цялост и пълнота - всеки модул изпълнява една функция, но я изпълнява добре и напълно, модулът самостоятелно изпълнява пълен набор от операции за изпълнение на своята функция.
  • Един вход и един изход - на входа програмният модул получава определен набор от първоначални данни, извършва смислена обработка и връща един набор от резултатни данни, т.е. прилага се стандартният IPO принцип - вход -\u003e процес -\u003e изход.
  • Логическа независимост - резултатът от работата на програмния модул зависи само от първоначалните данни, но не зависи от работата на други модули.
  • Слаби информационни връзки с други модули - обменът на информация между модулите трябва да бъде сведен до минимум, ако е възможно.

Много е трудно за начинаещ да разбере How да намали още повече свързаността на модулите. Отчасти това знание идва с опит, отчасти - след четене на умни книги. Но най-добре е да анализирате архитектурите на съществуващите applications.

Композиция instead of наследство

Компетентното разлагане е вид изкуство и трудна задача за повечето програмисти. Тук простотата е измамна, а грешките струват скъпо.

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

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

При декомпозиране на система е желателно да проверите нейното качество, като си зададете въпросите: „Каква задача изпълнява всеки модул?“, „Колко лесни са модулите за тестване?“, „Възможно ли е да използвате модулите самостоятелно or в друга среда?" да повлияят на другите?"

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

Ако не, тогава и тук не всичко е загубено. Има редица специални техники и модели, които ви позволяват допълнително да минимизирате и отслабите връзките между подсистемите. Например в случая на MVC моделът Observer е използван за тази цел, но са възможни и други решения.

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