Четири правила једноставнијег иОС софтверског дизајна

Крајем 1990-их, током развоја екстремног програмирања, познати програмер софтвера Кент Бецк смислио је листу правила за једноставно дизајнирање софтвера.

Према Кент Бецк-у, добар софтверски дизајн:

  • Покреће све тестове
  • Не садржи дуплирање
  • Изражава намеру програмера
  • Минимизира број часова и метода

У овом ћемо чланку говорити о томе како се та правила могу примијенити на свијет развоја иОС-а пружајући практичне примјере иОС-а и разговарајући о томе како од њих можемо имати користи.

Покреће све тестове

Дизајн софтвера помаже нам да створимо систем који делује онако како је предвиђено. Али како да потврдимо да ће систем деловати онако како је првобитно пројектовано? Одговор је стварањем тестова који га потврђују.

Нажалост, тестови универзума за развој иОС-а се углавном избегавају ... Али да бисмо створили добро дизајниран софтвер, увек бисмо требали писати Свифт код са предвидљивошћу.

Хајде да разговарамо о два принципа који могу поједноставити писање тестова и дизајн система. А они су принцип појединачне одговорности и убризгавање зависности.

Принцип јединствене одговорности (СРП)

СРП наводи да класа треба да има један и само један разлог за промену. СРП је један од најједноставнијих принципа и један од најтежих за исправити. Мијешање одговорности је нешто што природно радимо.

Дајмо пример неког кода који је заиста тешко тестирати, а након тога га поново претворите користећи СРП. Затим разговарајте о томе како је код направио тестирати.

Претпоставимо да тренутно морамо да представимо ПаиментВиевЦонтроллер од нашег тренутног контролера приказа, ПаиментВиевЦонтроллер треба да конфигурише свој поглед, у зависности од цене производа за плаћање. У нашем случају, цена је променљива у зависности од неких спољних догађаја корисника.

Код за ову имплементацију тренутно изгледа овако:

Како можемо да тестирамо овај код? Шта прво треба да тестирамо? Да ли је попуст цена обрачунат правилно? Како да исмевамо догађаје плаћања да бисмо тестирали попуст?

Писање тестова за ову класу било би компликовано, требало би пронаћи бољи начин да се пишу. Па, прво да решимо велики проблем. Морамо да уклонимо своје зависности.

Видимо да имамо логику за учитавање нашег производа. Имамо догађаје плаћања који кориснику омогућавају попуст. Имамо попусте, обрачун попуста и листа се наставља.

Зато покушајмо да их једноставно преведемо у Свифт код.

Направили смо ПаиментМанагер који управља нашом логиком плаћања и одвојени ПрицеЦалцулатор који је лако тестирати. Такође, уређај за учитавање података који је одговоран за интеракцију мреже или базе података за учитавање наших производа.

Такође смо споменули да нам је потребна класа одговорна за управљање попустима. Назовимо га ЦоупонМанагер и нека тако добро управља купонима за попуст корисника.

Наш контролер приказа плаћања тада може изгледати на следећи начин:

Сада можемо да пишемо тестове попут

  • тестЦалцулатингФиналПрицеВитхоутЦоупон
  • тестЦалцулатингФиналПрицеВитхЦоупон
  • тестЦоупонЕкистс

и многи други! Стварањем засебних објеката сада избегавамо непотребно дуплирање и такође смо креирали код за који је лако писати тестове.

Убризгавање зависност

Други принцип је убризгавање зависности. А из горњих примера смо видели да смо већ користили ињекцију зависности на нашим објектним иницијализаторима.

Постоје две главне предности убризгавања наших зависности као горе. Јасно нам показује на које се зависности ослањају наши типови и омогућава нам да убацимо подругљиве предмете када желимо да тестирамо уместо правих.

Добра техника је креирање протокола за наше објекте и пружање конкретне имплементације од стварног и подсмешаног објекта као што је следеће:

Сада можемо лако да одлучимо коју класу желимо да унесемо као зависност.

Чврсто спајање отежава писање тестова. Дакле, слично, што више тестова пишемо, више користимо принципе попут ДИП-а и алате попут убризгавања зависности, интерфејса и апстракције за минимализацију повезивања.

Ако код постане тестиранији, не само да елиминира наш страх од кршења (јер ћемо написати тест који ће нас подупријети), већ и доприноси писању чистијег кода.

Овај део чланка се више бавио начином писања кода који ће бити тестиран него писањем стварног јединичног теста. Ако желите да сазнате више о писању јединице теста, можете погледати овај чланак где ја креирам игру живота користећи развојни тест.

Не садржи дуплирање

Умножавање је главни непријатељ добро дизајнираног система. Представља додатни рад, додатни ризик, додаје непотребну сложеност.

У овом одељку ћемо говорити о томе како можемо да користимо образац дизајна шаблона за уклањање уобичајених дупликација у иОС-у. Да бисмо га лакше разумјели идемо на рефактор имплементацију разговора из стварног живота.

Претпоставимо да тренутно у нашој апликацији имамо стандардни одјељак за цхат. Појављује се нови захтев и сада желимо да применимо нову врсту чет - ливе цхат. Цхат који треба да садржи поруке са највише 20 знакова, а овај цхат ће нестати када одбацимо приказ за ћаскање.

Овај цхат ће имати исте приказе као и наш тренутни цхат, али имаће неколико различитих правила:

  1. Мрежни захтев за слање порука за цхат ће бити другачији.

2. Поруке за ћаскање морају бити кратке, не више од 20 знакова за поруку.

3. Поруке за чет не би требале бити задржане у нашој локалној бази података.

Претпоставимо да користимо МВП архитектуру и тренутно обрађујемо логику за слање цхат порука у нашем презентатору. Покушајмо да додамо нова правила за наш нови тип цхат који се зове ливе-цхат.

Наивна примјена била би сљедећа:

Али шта ће се догодити ако ћемо убудуће имати много више врста разговора?
Ако наставимо да додамо ако у било којој функцији провере стање нашег ћаскања, код ће постати неуредан за читање и одржавање. Такође, тешко је тестирати и државна провера ће се дуплирати у целом домену презентатора.

Овде се користи образац шаблона. Образац предлошка користи се када нам је потребно вишеструка имплементација алгоритма. Предложак се дефинише и затим надограђује с додатним варијацијама. Користите ову методу када већина подкласа мора применити исто понашање.

Можемо креирати протокол за Цхат Пресентер и одвајамо методе које ће различити имплементирати конкретни објекти у фазама Цхат Пресентер.

Сада можемо да наша презентатора ускладимо са ИЦхатПресентер-ом

Наш Пресентер сада обрађује слање порука позивањем заједничких функција унутар себе и делегира функције које се могу другачије имплементирати.

Сада можемо пружити Стварање објеката који се уклапају у фазе презентатора и који конфигуришу ове функције у складу са њиховим потребама.

Ако користимо убризгавање зависности у нашем регулатору приказа, сада можемо поново користити исти контролер погледа у два различита случаја.

Користећи дизајнерске узорке заиста можемо поједноставити свој иОС код. Ако желите знати више о томе, сљедећи чланак пружа додатно објашњење.

Експресивно

Већина трошкова софтверског пројекта је у дугорочном одржавању. Писање једноставних за читање и одржавање кода је неопходно за програмере софтвера.

Можемо понудити експресивнији код коришћењем доброг назива Наминг, СРП и Вритинг.

Именовање

Број једна ствар која код чини експресивнијом - а то је именовање. Важно је написати имена која:

  • Откривање намере
  • Избегавајте дезинформације
  • Лако их можете претраживати

Када је у питању именовање класа и функција, добар трик је употреба именице или именице за класе и корисничке глаголе или називе глаголских фраза за методе.

Такође када користите различите обрасце дизајна понекад је добро додати називе образаца као што су Цомманд или Виситор у назив класе. Тако би читалац одмах знао који се образац тамо користи, а да не мора читати читав код да би сазнао о томе.

Коришћење СРП-а

Још једна ствар која кода чини изражајним је коришћење принципа јединствене одговорности који је споменут горе. Можете се изразити задржавајући своје функције и часове малим и у једну сврху. Мале часове и функције обично је лако именовати, лако их је написати и лако их је разумети. Функција треба да служи само у једну сврху.

Писмени тест

Писање тестова такође доноси пуно јасноће, посебно када се ради са наслијеђеним кодом. Добро написани јединични тестови су такође изражајни. Примарни циљ тестова је да делује као документација на примеру. Неко ко чита наше тестове требало би да буде у стању да брзо схвати о чему се ради.

Смањите број часова и метода

Функције класе морају остати кратке, функција би увек требало да обавља само једну ствар. Ако функција има превише линија, то би могло бити случај да изводи радње које се могу раздвојити на две или више засебних функција.

Добар приступ је бројање физичких линија и покушавање циљања на максимално четири до шест линија функција, у већини случајева све што пређе више од броја линија може постати тешко за читање и одржавање.

Добра идеја у иОС-у је да исечете конфигурационе позиве које обично радимо на функцијама виевДидЛоад или виевДидАппеар.

На овај начин свака би функција била мала и одржива, умјесто једне функције виевДидЛоад. Исто би требало да важи и за делегата апликације. Требали бисмо избегавати бацање сваке конфигурационе методе ондидФинисхЛаунцхингВитхОптионс и засебних функција конфигурације или још боље конфигурационе класе.

С функцијама је мало лакше измерити да ли је држимо дуго или кратко, већину пута се можемо само ослонити на бројање физичких линија. Код наставе користимо другачију меру. Рачунамо на одговорности. Ако класа има само пет метода, то не значи да је класа мала, можда има превише одговорности само са тим методама.

Познати проблем у иОС-у је велика величина УИВиевЦонтроллерс. Истина је да је дизајнирањем контролера за преглед јабука тешко задржати ове објекте у једну сврху, али требали бисмо покушати.

Много је начина да УИВиевЦонтроллерс учиним малим мојом жељом да користим архитектуру која има боље раздвајање проблема попут ВИПЕР-а или МВП-а, али то не значи да не можемо боље да направимо и јабучни МВЦ.

Покушавајући да одвојимо што више брига можемо постићи прилично пристојан код са било којом архитектуром. Идеја је створити једнонаменске класе које могу послужити као помагачи контролерима приказа и учинити код читљивијим и тестиранијим.

Неке ствари које се могу једноставно избећи без изговора у погледу контролора приказа су:

  • Уместо да директно пишете мрежни код, требало би да постоји НетворкМанагер класа која је одговорна за мрежне позиве
  • Уместо да манипулирамо подацима у контролерима приказа, једноставно можемо креирати ДатаМанагер класу која је за то одговорна.
  • Уместо да се играмо са УсерДефаултс низовима у УИВиевЦонтроллер, преко тога можемо да створимо фасаду.

У закључку

Вјерујем да бисмо требали саставити софтвер из компоненти које су тачно именоване, једноставне, мале, одговорне за једну ствар и вишекратну употребу.

У овом чланку смо разговарали о четири правила за једноставан дизајн Кент Бецк-а и дали смо практичне примере како их можемо имплементирати у иОС развојно окружење.

Ако сте уживали у овом чланку, побрините се да пљешћете како бисте показали своју подршку. Пратите ме да бисте прегледали још много чланака који ће ваше вештине иОС Девелопер-а подићи на нови ниво.

Ако имате било каквих питања или коментара, слободно оставите белешку овде или ми пошаљите е-пошту на арлиндалиу.дев@гмаил.цом.