Вашият уебсайт се движи напред и вие бързо се разраствате. Ruby / Rails е най-добрият ви вариант за програмиране. Вашият екип е по-голям и вече сте оставили концепцията 'дебели модели, тънки драйвери' ( дебели модели, кльощави контролери ) като стил на дизайн за вашите Rails приложения. Все пак не искате да спрете да използвате Rails.
Няма проблем. Днес ще обсъдим как да използвате най-добрите практики за OOP, за да направите кода си по-чист, по-изолиран и отделен.
Нека започнем, като разгледаме как трябва да решите дали вашето приложение е добър кандидат за рефакторинг.
Ето списък с показатели и въпроси, които обикновено си задавам, за да определя дали моите кодове се нуждаят от рефакторинг или не.
Опитайте да използвате нещо подобно, за да разберете колко реда на изходния код на Ruby имате:
find app -iname '*.rb' -type f -exec cat {} ;| wc -l
как да събираме данни от Twitter
Тази команда ще търси всички файлове с разширение .rb (рубинни файлове) в папката / app, след което ще отпечата броя на редовете. Моля, имайте предвид, че това число е само приблизително, тъй като в него ще бъдат включени редове за коментари.
Друг по-точен и информативен вариант е да използвате задачата гребло stats
Rails, който излага кратко обобщение на редове код, брой класове, брой методи, съотношението на методите към класовете и съотношението на редове код на метод:
*bundle exec rake stats* +----------------------+-------+-----+-------+---------+-----+-------+ | Nombre | Líneas | LOC | Clase | Método | M/C | LOC/M | +----------------------+-------+-----+-------+---------+-----+-------+ | Controladores | 195 | 153 | 6 | 18 | 3 | 6 | | Helpers | 14 | 13 | 0 | 2 | 0 | 4 | | Modelos | 120 | 84 | 5 | 12 | 2 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 45 | 12 | 0 | 3 | 0 | 2 | | Bibliotecas | 0 | 0 | 0 | 0 | 0 | 0 | | Controlador specs | 106 | 75 | 0 | 0 | 0 | 0 | | Helper specs | 15 | 4 | 0 | 0 | 0 | 0 | | Modelo specs | 238 | 182 | 0 | 0 | 0 | 0 | | Petición specs | 699 | 489 | 0 | 14 | 0 | 32 | | Routing specs | 35 | 26 | 0 | 0 | 0 | 0 | | Vista specs | 5 | 4 | 0 | 0 | 0 | 0 | +----------------------+-------+-----+-------+---------+-----+-------+ | Total | 1472 |1042 | 11 | 49 | 4 | 19 | +----------------------+-------+-----+-------+---------+-----+-------+ Código LOC: 262 Prueba LOC: 780 Ratio Código a Prueba: 1:3.0
Нека започнем с пример от реалния живот.
Да предположим, че искаме да напишем приложение, което проследява времето за хора, които джогинг; На главната страница потребителят може да види въведените часове.
Всеки от записите за време има дата, разстояние, продължителност и допълнителна подходяща информация за състоянието (напр. Времето, тип терен и т.н.) и средна скорост, която може да бъде изчислена, когато е необходимо.
Нуждаем се от отчет, който да показва средната скорост и разстояние за седмица. Ако средната скорост на входа е по-голяма от средната скорост общо, ние ще уведомим потребителя чрез SMS (за този пример ще използваме Nexmo RESTful API за да изпратите SMS).
Главната страница ще ви позволи да изберете разстоянието, датата и часа, в които бягате, за да създадете запис, подобен на този:
Имаме и страница estadísticas
, която по същество е седмичен отчет, който включва средната скорост и изминатото разстояние за седмица.
Структурата на директориите на aplicación
изглежда подобно на това:
⇒ tree . ├── assets │ └── ... ├── controllers │ ├── application_controller.rb │ ├── entries_controller.rb │ └── statistics_controller.rb ├── helpers │ ├── application_helper.rb │ ├── entries_helper.rb │ └── statistics_helper.rb ├── mailers ├── models │ ├── entry.rb │ └── user.rb └── views ├── devise │ └── ... ├── entries │ ├── _entry.html.erb │ ├── _form.html.erb │ └── index.html.erb ├── layouts │ └── application.html.erb └── statistics └── index.html.erb
Няма да обсъждам модела Usuario
тъй като не е нещо необичайно, тъй като го използваме с Девиз за внедряване на удостоверяване.
Що се отнася до модела Entrada
, той съдържа бизнес логиката за нашето приложение.
Всеки Entrada
принадлежи на Usuario
.
Ние проверяваме наличието на следните атрибути за всеки вход distancia
, períodode_tiempo
, fecha_hora
и estatus
.
Всеки път, когато създаваме запис, сравняваме средната скорост на потребителя със средната стойност на всички потребители в системата и уведомяваме потребителя чрез SMS, използвайки Nexmo (Няма да обсъждаме как се използва библиотеката Nexmo, въпреки че исках да демонстрирам случай, в който използваме външна библиотека).
Имайте предвид, че Entrada
моделът съдържа повече от бизнес логика сама. Той също така обработва някои проверки и повиквания.
entries_controller.rb
има дяловете ЖЕСТКО main (макар и без актуализация). EntriesController#index
получава записите за текущия потребител и сортира записите по дата на създаване, докато EntriesController#create
създайте нов запис. Не е необходимо да се обсъждат очевидните или отговорностите на EntriesController#destroy
:
Докато statistics_controller.rb
отговаря за изчисляването на седмичния отчет, StatisticsController#index
получава входовете за влезлия потребител и ги групира по седмици, използвайки #group_by
който е в класа Изброими в Rails. След това опитайте да декорирате резултатите, като използвате някои частни методи.
Тук не обсъждаме мнения много, тъй като изходният код е обяснителен.
По-долу е изгледът за изброяване на записите за влезлия потребител (index.html.erb
). Това е моделът, който ще се използва за показване на резултатите от действието на индекса (метода) във входния манипулатор:
Имайте предвид, че използваме render @entries
Частици, за да приведе споделения код в частичен модел _entry.html.erb
за да можем да запазим нашия код СУХА и за многократна употреба:
Същото се отнася и за _forma
частично. Вместо да използваме същия код с (нови и редактирани) действия, ние създаваме многократна частична форма:
По отношение на изгледа на страницата на седмичния отчет, statistics/index.html.erb
показва някои статистически данни и отчети за седмичните дейности на потребителя чрез групиране на някои записи:
И накрая, помощник за входове, entries_helper.rb
, включва две помощници readable_time_period
и readable_speed
което трябва да направи атрибутите по-лесни за четене:
Засега нищо твърде сложно.
Повечето от вас могат да твърдят, че рефакторирането на това противоречи на принципа ЦЕЛУВАЙ и ще направи системата по-сложна.
Така че наистина ли това приложение трябва да бъде рефакторирано?
Абсолютно не , но ние ще го разгледаме само за примерни цели.
В крайна сметка, ако разгледате следващия раздел и характеристиките, които показват, че дадено приложение се нуждае от рефакторинг, става очевидно, че приложението в нашия пример не е валиден кандидат за рефакторинг.
Нека започнем с обяснение на структурния модел MVC в Rails.
Обикновено започва с търсачката, като отправя заявка като https://www.toptal.com/jogging/show/1
.
Уеб сървърът получава заявката и използва rutas
за да се определи какво controlador
използване.
функционалните документи са предназначени за
Контролерите извършват работата по анализ на потребителски заявки, доставки на данни, бисквитки, сесии и т.н., а след това питат modelo
вземете данните.
modelos
Те са класове на Ruby, които говорят с базата данни, запазват и валидират данните, изпълняват бизнес логиката и правят тежката работа. Изгледите са това, което потребителят може да види: HTML, CSS, XML, Javascript, JSON.
Ако искаме да покажем последователността на заявка за жизнения цикъл на Rails, тя ще изглежда така:
Това, което искам да постигна, е да добавя повече абстракция, използвайки PORO и да направя модела нещо подобно на следното за действията create/update
И нещо подобно на това за действия list/show
:
Добавяйки абстракции от PORO, ние гарантираме пълно разделение между отговорностите СЪКЪЛ , нещо, което Rails не владее напълно.
За да постигна новия дизайн, ще използвам указанията по-долу, но имайте предвид, че това не са правила, които трябва да спазвате до писмото. Мислете за тях като за гъвкави насоки, които улесняват рефакторинга.
Моделите ActiveRecord могат да съдържат асоциации и константи, но нищо друго. Това означава, че няма да има обаждания (използвайте сервизни обекти и добавете повикванията там) и няма проверки (употреба Формирайте обекти да включва имена и валидации за модела).
Дръжте контролерите като тънки слоеве и винаги извиквайте сервизни обекти. Някои от вас може да се чудят защо да използват контролери, ако искаме да продължим да извикваме сервизни обекти, за да съдържат логиката? Е, контролерите са добро място да имате маршрутизиране HTTP, разбор на параметри, удостоверяване, договаряне на съдържание, извикване на правилната услуга или обект на редактор, улавяне на изключения, форматиране на отговори и връщане на правилното състояние на HTTP кода.
Заявки трябва да се направи с предмети заявка . Обектни методи Заявка трябва да върне обект, a хеш или масив , но не и ActiveRecord асоциация.
Избягвайте да използвате Помощници , по-добре използвайте декоратори. Защо? Често срещана трудност с помощници в Rails е, че те могат да бъдат превърнати в куп не- ОО , които споделят име на интервал и се припокриват помежду си. Но е много по-лошо, фактът, че не може да се използва полиморфизъм с помощници Rails - чрез предоставяне на различни изпълнения за различен контекст или тип и заобикаляне или подкласифициране на помощници. Мисля, че видовете помощник в Rails те обикновено трябва да се използват за полезни методи, а не за конкретни случаи на употреба; как да форматирате атрибути на модел за всяка логика на презентацията. Поддържайте ги леки и лесни за следване. По-добре декоратори / Делегати. ** Защо? В края на краищата, грижите изглежда са част от Rails и те могат да изсъхнат ( Изсушавам ) код, когато се споделя между множество модели. По-големият проблем обаче е, че опасенията не правят обекта на модела по-сплотен. Само кодът е по-добре организиран. С други думи, няма реална промяна в API на модела.
Опитайте се да извлечете Ценни предмети от моделите за да запазите кода си по-чист и групираните атрибути.
Преди да започна, искам да обсъдя нещо друго. Когато рефакторингът започне, обикновено се чудите: „Добър рефакторинг ли е?“
Ако смятате, че правите повече разделение или изолация между отговорностите (дори това да означава добавяне на повече код и нови файлове), това е нещо добро. В крайна сметка отделянето на приложение е много добра практика и ни улеснява да направим подходящ единичен тест.
Няма да обсъждам неща, като например преместване на логика от контролери към модели, тъй като предполагам, че правите това и ви е удобно да използвате Rails (обикновено Skinny Controller и FAT модел).
За да запазя тази статия кратка, няма да обсъждам тестване, но това не означава, че не трябва да тествате.
Напротив, трябва винаги започвайте с тест за да сте сигурни, че нещата вървят добре, преди да продължите напред. Това е нещо задължително, особено когато правите рефакторинг.
След това можем да внедрим промени и да се уверим, че тестовете преминават през съответните части на кода.
Първо, какво е обект на стойност?
Мартин Фаулър Обяснете:
Обектът на стойност е малък обект, например обект на пари или период от време. Тяхната ключова характеристика е, че те следват стойностната семантика, а не референтната семантика.
Понякога можете да попаднете в ситуация, в която една концепция заслужава своя абстракция и когато нейното равенство не се основава на ценности, а на идентичност. Примери за това могат да бъдат: Дата, URI и име на път на Ruby. Извличането на ценен обект (или модел на домейн) е голямо удобство.
Защо да се занимавам?
Едно от големите предимства на стойностния обект е, че те помагат да се получи изразителност във вашия код. Вашият код ще бъде по-ясен или поне може да бъде, ако имате добри практики за именуване. Тъй като Value Object е абстракция, това води до по-ясни кодове и по-малко грешки.
Друга печалба е неизменност . Неизменността на обектите е много важна. Когато съхраняваме определени набори от данни, които могат да се използват в обект на стойност, обикновено не харесвам данните, които се манипулират.
Кога е полезно това?
Няма идеален отговор на този въпрос. Правете това, което е във ваш интерес и което има най-голямо значение в дадена ситуация.
Освен това има някои насоки, които използвам, за да ми помогне да взема това решение.
Ако смятате, че група методи е свързана, добре, с ценностите е по-скъпо. Тази изразителност означава, че обектът на стойност трябва да представлява отличителен набор от данни, който може да бъде изведен от средния ви разработчик само като погледнете името на обекта.
Как се прави това?
Ценностите трябва да следват определени правила:
В нашия пример ще създам обект на стойност EntryStatus
, за да абстрахирам атрибутите Entry#status_weather
и Entry#status_landform
към собствен клас, който изглежда така:
Забележка: Това е само PORO (Plain Old Ruby Object), той не наследява от ActiveRecord::Base
Дефинирали сме методи за четене на нашите атрибути и ги присвояваме при стартиране. Също така използваме сравним микс, за да съпоставим обекти, използвайки метода ().
Можем да модифицираме модела Entry
за да използваме обекта на стойност, който сме създали:
Също така можем да модифицираме метода EntryController#create
за да използвате съответно новия обект на стойност:
Какво е обект на услуга?
Задачата на обект на услуга е да държи кода по време на определено пространство на бизнес логиката. За разлика от стила 'Дебел модел' , където малък брой обекти съдържат много, много методи, за цялата необходима логика, използването на сервизни обекти води до много класове, всеки от които служи за уникална цел.
Защо? Какви са ползите?
Разкъсвам. Сервизните обекти ви помагат да постигнете по-голяма изолация между обектите.
Видимост. Сервизните обекти (ако са правилно именувани) показват какво прави приложението. Мога да разгледам директорията на услугите, за да видя какви възможности предоставя едно приложение.
c корпорациите предлагат по-голяма правна защита на собствениците от корпорациите.
СУХА и Приемете промяната. Поддържам услугите възможно най-прости и малки. Съставям сервизни обекти с други сервизни обекти и ги използвам повторно.
Почистете и ускорете вашия тестов пакет. Услугите са бързи и лесни за тестване, тъй като представляват малки обекти в Ruby с входна точка (наречен метод). Комплексните услуги се състоят от други услуги, така че лесно можете да разделите тестовете си. Също така, използването на сервизни обекти улеснява извличането на свързани обекти, без да се налага да зареждате цялата среда на релсите.
От друга страна, нищо не е идеално. Един недостатък на обектите на услугата е, че те могат да бъдат преувеличени за всяко малко действие. В тези случаи можете в крайна сметка да усложните и да не опростите кода си.
Кога трябва да извлечете сервизни обекти?
Тук също няма фиксирано правило.
Обикновено сервизните обекти са най-подходящи за средни до големи системи: тези с прилично количество логика, извън стандартните CRUD операции.
Така че, когато смятате, че парче код не принадлежи в директорията, на мястото, където сте щяли да го добавите, е добра идея да го преразгледате и да видите дали би било по-добре, ако отиде в обект на услуга.
Ето някои указатели за това кога да се използват обекти на услугата:
Как трябва да проектирате Service Objects?
Проектирането на класа за обект на услуга е сравнително лесно, тъй като нямате нужда скъпоценни камъни не трябва да научавате a DLS ново, но можете, горе-долу, да разчитате на уменията за софтуерен дизайн, които вече притежавате.
Обикновено използвам следните насоки и конвенции, за да проектирам обекта на услугата:
app/services
. Съветвам ви да използвате поддиректории за силни домейни на бизнес логика. Например файлът app/services/report/generate_weekly.rb
ще определи Report::GenerateWeekly
докато app/services/report/publish_monthly.rb
ще определи Report::PublishMonthly
.ApproveTransaction
, SendTestNewsletter
, ImportUsersFromCsv
.Ако погледнете StatisticsController#index
, ще забележите група методи (weeks_to_date_from
, weeks_to_date_to
, avg_distance
и т.н.), групирани в контролера. Това не е добре. Помислете за последствията, ако искате да генерирате седмичния отчет извън statistics_controller
.
В нашия случай ще създадем Report::GenerateWeekly
и извлечете логическия отчет от StatisticsController
:
Така че StatisticsController#index
сега изглежда по-чисто:
Прилагайки шаблона на обект на услугата, ние групираме код около сложно и специфично действие и насърчаваме създаването на по-малки и по-ясни методи.
Домашна работа: помислете за използване Ценен обект за WeeklyReport
вместо Struct
.
Какво е обект Заявка ?
Предмет Заявка е PORE, което представлява база данни за заявки. Може да се използва повторно на различни места в приложението, като в същото време скрива логиката на заявката. Той също така осигурява добра изолирана единица за тестване.
Трябва да извлечете сложни SQL / NoSQL заявки в техните собствени класове.
Всеки обект Заявка отговаря за връщането на набор от резултати въз основа на критериите / бизнес правилата.
В този пример нямаме заявка ( заявка ) сложен, така че използвайте обект Заявка не би било ефективно. За целите на демонстрацията обаче ще извлечем заявката в Report::GenerateWeekly#call
и ние ще създадем generate_entries_query.rb
:
И в Report::GenerateWeekly#call
, нека заменим:
def call @user.entries.group_by(&:week).map do |week, entries| WeeklyReport.new( ... ) end end
с:
def call weekly_grouped_entries = GroupEntriesQuery.new(@user).call weekly_grouped_entries.map do |week, entries| WeeklyReport.new( ... ) end end
Моделът на обекта заявка (заявка) помага да поддържате логиката на модела си строго свързана с поведението на класа, като същевременно държите вашите контролери слаби. Защото те не са нищо друго освен обикновени стари класове Ruby , обектите заявка не е необходимо да наследяват от ActiveRecord::Base
и не трябва да носят отговорност за нищо друго освен за изпълнение на заявката.
Сега ще извлечем логиката на създаване на нов запис към нов обект на услуга. Нека използваме конвенцията и да създадем CreateEntry
:
А сега нашите EntriesController#create
е както следва:
def create begin CreateEntry.new(current_user, entry_params).call flash[:notice] = 'Entry was successfully created.' rescue Exception => e flash[:error] = e.message end redirect_to root_path end
Сега нещата започват да стават по-интересни.
Не забравяйте, че в нашите насоки се съгласихме, че искаме моделите да имат асоциации и константи, но нищо друго (без валидиране или обаждания). Затова нека започнем с премахване на допълнителните описания и вместо това да използваме обект Shape.
Обектът Shape е PORO (Plain Old Ruby Object). Поемете командата на обекта на контролера / услугата, когато трябва да говорите с базата данни.
Защо да използвам Shape обекти?
Когато трябва да рефакторирате приложението си, винаги е добре да имате предвид, основната отговорност ( СЪКЪЛ ).
СЪКЪЛ ви помага да вземате по-добри дизайнерски решения по отношение на отговорността, която класът трябва да носи.
Моделът на вашата таблица на базата данни (модел ActiveRecord в контекста на Rails), например, представлява уникален запис на база данни в код, така че няма причина да се занимавате с каквото и да е, което вашият потребител прави.
Тук влиза обектът Shape.
Обектът Shape е отговорен за представянето на фигура във вашето приложение. Така че всяко поле за въвеждане може да се третира като атрибут в класа. Можете да проверите дали тези атрибути отговарят на някои правила за валидиране и можете да предадете 'чистите' данни там, където трябва да отидат (например вашия модел на база данни или може би вашият конструктор за търсене на заявки).
Кога трябва да използвате обект Shape?
Това ви позволява да поставите цялата логика на формата (конвенции за именуване, проверки и други) на едно място.
Как да създам обект Shape?
ActiveModel::Model
(В Rails 3 вместо това трябва да включите Name, Conversion и Validation).Моля, обърнете внимание, че можете да използвате скъпоценен камък реформа , но продължавайки с PORO, ще създадем entry_form.rb
което изглежда така:
И ние ще модифицираме CreateEntry
за да започнете да използвате обекта Format EntryForm
:
class CreateEntry ...... ...... def call @entry_form = ::EntryForm.new(@params) if @entry_form.valid? .... else .... end end end
Забележка: Някои от вас ще кажат, че няма нужда от достъп до обекта Shape от обекта Service и че можем да извикаме Shape обекта директно от контролера, което е валиден аргумент. Предпочитам обаче да имам ясен поток, затова винаги извиквам Shape object от Service object.
Както се договорихме преди, не искаме нашите модели да съдържат проверки и обаждания. Извличахме валидациите с помощта на Shape обекти. Но все още използваме някои повиквания (after_create
в модел Entry
compare_speed_and_notify_user
).
Защо искаме да премахнем допълнителните описания от моделите?
Разработчици на релси те обикновено започват да забелязват болка при обажданията, по време на тестовете. Ако не тествате вашите модели ActiveRecord, ще започнете да забелязвате болката по-късно, тъй като приложението ви расте и тъй като е необходима повече логика за извикване или избягване на обаждания.
después_*
повикванията се използват предимно във връзка със запазване или продължаване с обекта.
След като обектът бъде запазен, целта на обекта (напр. Отговорност) е изпълнена. Така че, ако все пак видим, че се извикват повиквания, след като обектът е запазен, това вероятно са повиквания, които искат да излязат от зоната на отговорност на обекта и тогава се сблъскваме с проблеми.
В нашия случай изпращаме SMS до потребителя, който не е свързан с входния домейн.
Един прост начин за решаване на проблема е преместването на повикването към свързания обект на услугата. В крайна сметка изпращането на SMS до съответния потребител е свързано с Обекта на услугата CreateEntry
а не моделът Entry като такъв.
Правейки това, вече не трябва да изключваме, compare_speed_and_notify_user
в нашите тестове. Направихме това лесен въпрос, създавайки запис без необходимост от изпращане на SMS и следваме добър обектно-ориентиран дизайн, като се уверим, че нашите класове носят уникална отговорност ( СЪКЪЛ ).
какво можеш да направиш с ruby on rails
Така че сега CreateEntry
това е нещо подобно на това:
Въпреки че можем лесно да използваме колекцията Драпер от оглед на модели и декоратори, оставам с PORO, за тази статия, както правех и досега.
Това, от което се нуждая, е клас, който извиква методи за декорирания обект.
Мога да използвам method_missing
за да приложа това, но ще използвам стандартната Ruby библиотека, SimpleDelegator
. Следващият код показва как да използвате SimpleDelegator
за внедряване на нашия основен декоратор:
% app/decorators/base_decorator.rb require 'delegate' class BaseDecorator Защо методът _h
Този метод действа като прокси за контекста на изгледа. По подразбиране контекстът на изгледа е екземпляр на клас на изглед, който е ActionView::Base
. Можете да получите достъп до помощници на гледните точки, както следва:
_h.content_tag :div, 'my-div', class: 'my-class'
За да бъде по-удобно, добавяме метод decorado
a ApplicationHelper
:
module ApplicationHelper # ..... def decorate(object, klass = nil) klass ||= '#{object.class}Decorator'.constantize decorator = klass.new(object, self) yield decorator if block_given? decorator end # ..... end
Сега можем да преместим помощници EntriesHelper
към декоратори:
# app/decorators/entry_decorator.rb class EntryDecorator И можем да използваме readable_time_period
и readable_speed
както следва:
# app/views/entries/_entry.html.erb - +
- +
Структура след рефакторинг
В крайна сметка получихме повече файлове, но това не е непременно лошо нещо (и помнете това, от самото начало бяхме наясно, че този пример е за демонстрационни цели и не непременно беше добър случай за рефакторинг):
app ├── assets │ └── ... ├── controllers │ ├── application_controller.rb │ ├── entries_controller.rb │ └── statistics_controller.rb ├── decorators │ ├── base_decorator.rb │ └── entry_decorator.rb ├── forms │ └── entry_form.rb ├── helpers │ └── application_helper.rb ├── mailers ├── models │ ├── entry.rb │ ├── entry_status.rb │ └── user.rb ├── queries │ └── group_entries_query.rb ├── services │ ├── create_entry.rb │ └── report │ └── generate_weekly.rb └── views ├── devise │ └── .. ├── entries │ ├── _entry.html.erb │ ├── _form.html.erb │ └── index.html.erb ├── layouts │ └── application.html.erb └── statistics └── index.html.erb
заключение
Въпреки че се фокусираме върху Rails в тази публикация в блога, RoR (Ruby on Rails) не зависи от обекти на услуги или други PORO. Можете да използвате този подход с всеки рамкова мрежа , мобилно или конзолно приложение.
При използване MVC Като архитектура всичко се слепва и забавя, защото повечето промени оказват влияние върху други части на приложението. Също така ви принуждава да помислите къде да поставите някаква бизнес логика - трябва ли да е в модела, контролера или изгледа?
Използвайки просто PORO, сме преместили бизнес логиката към модели или услуги, които не наследяват от ActiveRecord
, което вече е печалба, да не говорим, че имаме по-ясен код, който поддържа СЪКЪЛ и по-бързи модулни тестове.
Изчистената архитектура се опитва да постави полетата за използване в центъра / горната част на вашата структура, така че лесно да можете да видите какво прави вашето приложение. Това също улеснява приемането на промени, тъй като е по-модулно и изолирано. Надявам се да съм показал как да Обикновени стари рубинени предмети и повече абстракции, той разделя опасенията, опростява тестването и помага за създаването на чист, поддържаем код.
Свързани: Какви са предимствата на Ruby on Rails? След две десетилетия програмиране. Използвайте релси