Ганц хариуцлагын зарчим. Энэ мэт санагдаж байгаа шиг энгийн биш

Ганц хариуцлагын зарчим. Энэ мэт санагдаж байгаа шиг энгийн биш Нэг хариуцлагын зарчим гэж нэрлэгддэг нэг хариуцлагын зарчим,
Нэгдмэл хувьсах зарчим гэдэг нь маш гулгамтгай хүн бөгөөд програмист ярилцлага хийх үед ийм сандарсан асуулт юм.

Энэ зарчимтай миний анхны нухацтай танилцсан нь нэгдүгээр курсын эхэнд залуу, ногоон хүүхдүүдийг авгалдайгаар сурагчид болгохоор ой руу аваачсан - жинхэнэ оюутнууд.

Ойд бид тус бүр 8-9 хүнтэй багуудад хуваагдан, аль бүлэг нь нэг шил архи хамгийн хурдан уух вэ, хэрэв бүлгийн эхний хүн аяганд архи хийнэ, хоёр дахь нь архи ууна. гурав дахь нь зууштай. Үйл ажиллагаагаа дуусгасан нэгж нь бүлгийн дарааллын төгсгөлд шилжинэ.

Дарааллын хэмжээ гурвын үржвэртэй байсан тохиолдол нь SRP-ийн сайн хэрэгжилт байсан.

Тодорхойлолт 1. Нэг хариуцлага.

Ганц хариуцлагын зарчим (SRP)-ийн албан ёсны тодорхойлолтод байгууллага бүр өөрийн гэсэн хариуцлага, оршин тогтнох шалтгаантай бөгөөд зөвхөн нэг үүрэг хариуцлагатай гэж заасан байдаг.

"Архичин" объектыг авч үзье (Типплер).
SRP зарчмыг хэрэгжүүлэхийн тулд бид хариуцлагыг гурван хэсэгт хуваана.

  • Нэг цутгах (PourOperation)
  • Нэг уудаг (DrinkUpOperation)
  • Нэг нь зууштай (TakeBiteOperation)

Уг процесст оролцогч бүр үйл явцын нэг бүрэлдэхүүн хэсгийг хариуцдаг, өөрөөр хэлбэл нэг атомын үүрэг хариуцлага хүлээдэг - уух, асгах эсвэл зуушаар хооллох.

Ундны нүх нь эргээд эдгээр үйлдлүүдийн фасад юм.

сlass Tippler {
    //...
    void Act(){
        _pourOperation.Do() // налить
        _drinkUpOperation.Do() // выпить
        _takeBiteOperation.Do() // закусить
    }
}

Ганц хариуцлагын зарчим. Энэ мэт санагдаж байгаа шиг энгийн биш

Яагаад?

Хүний програмист хүн мич хүнд зориулж код бичдэг бөгөөд мич хүн хайхрамжгүй, тэнэг, үргэлж яарч байдаг. Тэрээр нэг дор 3-7 нэр томъёог барьж, ойлгож чадна.
Согтуу хүний ​​тухайд энэ гурван нэр томъёо байдаг. Гэсэн хэдий ч кодыг нэг хуудсан дээр бичвэл гар, шил, зодоон, улс төрийн талаар эцэс төгсгөлгүй маргаанууд орно. Мөн энэ бүхэн нэг аргын биед байх болно. Та практик дээрээ ийм кодыг харсан гэдэгт итгэлтэй байна. Сэтгэцийн хувьд хамгийн хүмүүнлэг тест биш.

Нөгөөтэйгүүр, сармагчин хүн толгойдоо бодит ертөнцийн объектуудыг дуурайлган дүрслэх зорилготой юм. Төсөөлөлдөө тэрээр тэдгээрийг хооронд нь түлхэж, тэдгээрээс шинэ объектуудыг угсарч, ижил аргаар задалж чаддаг. Хуучин загварын машиныг төсөөлөөд үз дээ. Төсөөлөлдөө та хаалгыг онгойлгож, хаалганы обудыг тайлж, цонхны өргөх механизмуудыг харж болно, тэдгээрийн дотор араа байх болно. Гэхдээ та машины бүх эд ангиудыг нэгэн зэрэг, нэг "жагсаалт"-аас харж чадахгүй. Наад зах нь "сармагчин хүн" чадахгүй.

Тиймээс хүний ​​программистууд нарийн төвөгтэй механизмуудыг бага төвөгтэй, ажиллах элементүүдийн багц болгон задалдаг. Гэсэн хэдий ч энэ нь янз бүрийн аргаар задарч болно: олон хуучин машинуудад агаарын суваг хаалга руу ордог бөгөөд орчин үеийн машинуудад түгжээний электроникийн эвдрэл нь хөдөлгүүрийг эхлүүлэхээс сэргийлдэг бөгөөд энэ нь засварын явцад асуудал үүсгэдэг.

Одоо, SRP нь ХЭРХЭН задрах, өөрөөр хэлбэл хуваах шугамыг хаана зурахыг тайлбарладаг зарчим юм..

"Хариуцлагыг" хуваах зарчмын дагуу, өөрөөр хэлбэл тодорхой объектуудын үүрэг даалгаврын дагуу задлах шаардлагатай гэж тэр хэллээ.

Ганц хариуцлагын зарчим. Энэ мэт санагдаж байгаа шиг энгийн биш

Архи ууж, задралын үед сармагчин хүний ​​олж авдаг давуу талууд руу буцаж орцгооё.

  • Код нь бүх түвшинд маш тодорхой болсон
  • Кодыг хэд хэдэн программист нэгэн зэрэг бичиж болно (тус бүр тусдаа элемент бичдэг)
  • Автомат туршилтыг хялбаршуулсан - элемент нь энгийн байх тусмаа тест хийхэд хялбар байдаг
  • Кодын найрлага гарч ирнэ - та сольж болно DrinkUpOperation согтуу хүн ширээн доогуур шингэн асгах мэс засалд. Эсвэл цутгах ажиллагааг дарс, ус эсвэл архи, шар айраг холих үйлдлээр солих хэрэгтэй. Бизнесийн шаардлагаас хамааран та аргын кодонд хүрэлгүйгээр бүгдийг хийх боломжтой Tippler.Act.
  • Эдгээр үйлдлүүдээс та өлөн зэлмүүнийг нугалж болно (зөвхөн TakeBitOperation), Согтууруулах ундаа (зөвхөн хэрэглэх DrinkUpOperation савнаас шууд) болон бусад олон бизнесийн шаардлагыг хангана.

(Өө, энэ нь аль хэдийн OCP зарчим юм шиг санагдаж байна, би энэ нийтлэлийн хариуцлагыг зөрчсөн)

Мөн мэдээжийн хэрэг сул талууд:

  • Бид илүү олон төрлийг бий болгох хэрэгтэй болно.
  • Согтуу хүн анх удаа ууж байснаас хэдхэн цагийн дараа уудаг.

Тодорхойлолт 2. Нэгдсэн хувьсах чанар.

Намайг зөвшөөрнө үү, ноёд оо! Архины анги бас нэг үүрэг хариуцлага хүлээдэг - энэ нь уудаг! Тэгээд ер нь “хариуцлага” гэдэг бол туйлын бүрхэг ойлголт. Хэн нэгэн хүн төрөлхтний хувь заяаг хариуцаж, хэн нэгэн нь туйлд хөмөрсөн оцон шувууг өсгөх үүрэгтэй.

Архичдын хоёр хэрэгжилтийг авч үзье. Дээр дурдсан эхнийх нь цутгах, уух, зууш гэсэн гурван ангиллыг агуулдаг.

Хоёр дахь нь "Урагшаа ба Зөвхөн урагшлах" аргачлалаар бичигдсэн бөгөөд аргын бүх логикийг агуулдаг Хууль:

//Не тратьте время  на изучение этого класса. Лучше съешьте печеньку
сlass BrutTippler {
   //...
   void Act(){
        // наливаем
    if(!_hand.TryDischarge(from:_bottle, to:_glass, size:_glass.Capacity))
        throw new OverdrunkException();

    // выпиваем
    if(!_hand.TryDrink(from: _glass,  size: _glass.Capacity))
        throw new OverdrunkException();

    //Закусываем
    for(int i = 0; i< 3; i++){
        var food = _foodStore.TakeOrDefault();
        if(food==null)
            throw new FoodIsOverException();

        _hand.TryEat(food);
    }
   }
}

Энэ хоёр анги хоёулаа хөндлөнгийн ажиглагчийн байр сууринаас харахад яг адилхан харагддаг бөгөөд “архи уух” үүрэг хариуцлагыг хуваалцдаг.

Төөрөгдөл!

Дараа нь бид интернетэд орж, SRP-ийн өөр тодорхойлолтыг олж мэдье - Нэг өөрчлөлтийн зарчим.

SCP хэлэхдээ "Модуль нь өөрчлөх цорын ганц шалтгаантай байдаг". “Хариуцлага бол өөрчлөлтийн шалтгаан” гэсэн үг.

(Анхны тодорхойлолтыг гаргасан залуус мич хүний ​​телепатик чадварт итгэлтэй байсан бололтой)

Одоо бүх зүйл байрандаа орж байна. Бид цутгах, уух, зуушлах журмыг тусад нь өөрчилж болно, гэхдээ архичин өөрөө зөвхөн үйл ажиллагааны дараалал, найрлагыг өөрчлөх боломжтой, жишээлбэл, уухаасаа өмнө зуушаа хөдөлгөх эсвэл шарсан талхны уншлага нэмэх замаар л өөрчилж болно.

"Урагшаа, зөвхөн урагшлах" аргад өөрчлөх боломжтой бүх зүйл зөвхөн аргад л өөрчлөгддөг Хууль. Энэ нь логик багатай, бараг өөрчлөгддөггүй үед уншиж болохуйц бөгөөд үр дүнтэй байж болох ч ихэнхдээ Орос НАТО-д элсэхэд шаардагдахаас илүү 500 мөртэй аймшигтай аргуудаар төгсдөг.

Тодорхойлолт 3. Өөрчлөлтийг нутагшуулах.

Архи уудаг хүмүүс яагаад хэн нэгний байранд сэрсэн, гар утас нь хаана байгааг ойлгодоггүй. Нарийвчилсан бүртгэлийг нэмэх цаг болжээ.

Цутгах процессоор бүртгэлээ эхлүүлцгээе:

class PourOperation: IOperation{
    PourOperation(ILogger log /*....*/){/*...*/}
    //...
    void Do(){
        _log.Log($"Before pour with {_hand} and {_bottle}");
        //Pour business logic ...
        _log.Log($"After pour with {_hand} and {_bottle}");
    }
}

Үүнийг дотор нь багтаах замаар PourOperation, хариуцлагын үүднээс ухаалаг ажиллаж байсан бол одоо бид хувьсах зарчимтай андуурч байна. Өөрчлөгдөж болох үйлдлээс гадна бүртгэл нь өөрөө өөрчлөгддөг. Та цутгах үйл ажиллагаанд зориулж тусгай мод бэлтгэгчийг салгаж, үүсгэх хэрэгтэй болно.

interface IPourLogger{
    void LogBefore(IHand, IBottle){}
    void LogAfter(IHand, IBottle){}
    void OnError(IHand, IBottle, Exception){}
}

class PourOperation: IOperation{
    PourOperation(IPourLogger log /*....*/){/*...*/}
    //...
    void Do(){
        _log.LogBefore(_hand, _bottle);
        try{
             //... business logic
             _log.LogAfter(_hand, _bottle");
        }
        catch(exception e){
            _log.OnError(_hand, _bottle, e)
        }
    }
}

Үүнийг нягт нямбай уншигч анзаарах байх LogAfter, Бүртгэлийн өмнө и OnError Мөн дангаар нь өөрчилж болох бөгөөд өмнөх алхмуудтай ижил төстэй байдлаар гурван анги үүсгэнэ. PourLoggerBefore, PourLoggerAfter и PourErrorLogger.

Тэгээд архичинд гурван хагалгаа байдгийг санаж мод бэлтгэх есөн ангид ордог. Үүний үр дүнд архины тойрог бүхэлдээ 14 (!!!) ангиас бүрддэг.

Гипербола? Бараг! Задаргааны гранаттай сармагчин эр "цутгагч" -ыг декантер, шил, цутгах оператор, усан хангамжийн үйлчилгээ, молекулуудын мөргөлдөөний физик загвар болгон хувааж, дараагийн улиралд тэрээр хамаарлыг арилгахыг хичээх болно. глобал хувьсагчид. Надад итгээрэй, тэр зогсохгүй.

Яг энэ мөчид олон хүн SRP-г ягаан хаант улсын үлгэр гэж дүгнэж, гоймон тоглохоор явна...

... Srp гэсэн гуравдахь тодорхойлолт байгаа талаар хэзээ ч сураагүй:

“Нэг хариуцлагын зарчимд ингэж заасан өөрчлөлттэй төстэй зүйлсийг нэг газар хадгалах ёстой". эсвэл "Хамтдаа гарсан өөрчлөлтүүдийг нэг дор хадгалах ёстой"

Өөрөөр хэлбэл, хэрэв бид үйл ажиллагааны бүртгэлийг өөрчилбөл үүнийг нэг газар өөрчлөх ёстой.

Энэ бол маш чухал зүйл юм - учир нь дээр дурдсан SRP-ийн бүх тайлбарууд нь тэдгээрийг бутлах үед тэдгээрийг бутлах шаардлагатай гэж хэлсэн, өөрөөр хэлбэл объектын хэмжээнд "дээд хязгаар" тогтоосон бөгөөд одоо Бид "доод хязгаар" -ын талаар аль хэдийн ярьж байна. Өөрөөр хэлбэл, SRP нь зөвхөн "бутлах үед бутлах" шаарддаг төдийгүй хэтрүүлж болохгүй - "хоорондоо баригдсан зүйлсийг бүү бутлаарай". Энэ бол Оккамын сахлын хутга болон сармагчин хүний ​​хоорондох агуу тулаан юм!

Ганц хариуцлагын зарчим. Энэ мэт санагдаж байгаа шиг энгийн биш

Одоо архичин илүү сайн мэдрэх ёстой. IPourLogger бүртгэлийг гурван ангилалд хуваах шаардлагагүйгээс гадна бид бүх логгерийг нэг төрөлд нэгтгэж болно.

class OperationLogger{
    public OperationLogger(string operationName){/*..*/}
    public void LogBefore(object[] args){/*...*/}       
    public void LogAfter(object[] args){/*..*/}
    public void LogError(object[] args, exception e){/*..*/}
}

Хэрэв бид дөрөв дэх төрлийн үйлдлийг нэмбэл түүний бүртгэл аль хэдийн бэлэн болсон байна. Мөн үйл ажиллагааны код нь өөрөө цэвэр, дэд бүтцийн чимээ шуугиангүй байдаг.

Үүний үр дүнд бид архины асуудлыг шийдэх 5 ангитай болсон.

  • Цутгах ажиллагаа
  • Архи уух үйл ажиллагаа
  • Түгжих ажиллагаа
  • Мод бэлтгэгч
  • Архины фасад

Тэд тус бүр нь нэг функцийг хатуу хариуцдаг бөгөөд өөрчлөх нэг шалтгаантай байдаг. Өөрчлөлттэй төстэй бүх дүрмүүд ойролцоо байрладаг.

Бодит амьдралын жишээ

Бид нэг удаа b2b үйлчлүүлэгчийг автоматаар бүртгэх үйлчилгээг бичсэн. Мөн ижил төстэй агуулгын 200 мөрийн хувьд БУРХАН арга гарч ирэв:

  • 1С руу очоод данс үүсгэ
  • Энэ дансны тусламжтайгаар төлбөрийн модуль руу очоод тэнд үүсгэнэ үү
  • Үндсэн сервер дээр ийм данстай данс үүсгээгүй эсэхийг шалгана уу
  • Шинэ данс үүсгэх
  • Төлбөрийн модулийн бүртгэлийн үр дүн болон бүртгэлийн үр дүнгийн үйлчилгээнд 1c дугаарыг нэмнэ үү
  • Энэ хүснэгтэд дансны мэдээллийг нэмнэ үү
  • Энэ үйлчлүүлэгчийн цэгийн үйлчилгээнд онооны дугаар үүсгэнэ үү. 1c дансны дугаараа энэ үйлчилгээнд шилжүүлээрэй.

Мөн энэ жагсаалтад аймшигтай холболттой 10 орчим бизнесийн үйл ажиллагаа байсан. Бараг бүх хүнд дансны объект хэрэгтэй байсан. Дуудлагын тал хувь нь цэгийн ID болон үйлчлүүлэгчийн нэр шаардлагатай байсан.

Нэг цагийн рефакторинг хийсний дараа бид дэд бүтцийн код болон данстай ажиллах зарим нарийн ширийн зүйлийг тусад нь арга/анги болгон салгаж чадсан. Бурханы арга нь үүнийг илүү хялбар болгосон боловч тайлахыг хүсээгүй 100 мөр код үлдсэн.

Хэдхэн хоногийн дараа л энэхүү "хөнгөн" аргын мөн чанар нь бизнесийн алгоритм гэдэг нь тодорхой болсон. Мөн техникийн үзүүлэлтүүдийн анхны тайлбар нь нэлээд төвөгтэй байсан. Мөн энэ аргыг хэсэг болгон хуваах оролдлого нь SRP-г зөрчих болно, харин эсрэгээрээ биш юм.

Формализм.

Согтуудаа ганцааранг нь орхих цаг болжээ. Нулимсаа хатаа - бид хэзээ нэгэн цагт түүнд буцаж ирэх нь гарцаагүй. Одоо энэ нийтлэлээс олж авсан мэдлэгээ албан ёсоор болгоё.

Формализм 1. SRP-ийн тодорхойлолт

  1. Элементүүдийг тусад нь салгаж, тус бүр нь нэг зүйлийг хариуцдаг.
  2. Хариуцлага гэдэг нь "өөрчлөх шалтгаан" гэсэн үг юм. Өөрөөр хэлбэл, элемент бүр нь бизнесийн логикийн хувьд өөрчлөгдөх цорын ганц шалтгаантай байдаг.
  3. Бизнесийн логикт гарч болзошгүй өөрчлөлтүүд. нутагшуулсан байх ёстой. Синхроноор өөрчлөгддөг элементүүд ойролцоо байх ёстой.

Албан ёсны байдал 2. Өөрийгөө шалгах шаардлагатай шалгуурууд.

Би SRP-ийг биелүүлэх хангалттай шалгуурыг олж хараагүй. Гэхдээ шаардлагатай нөхцөлүүд байдаг:

1) Энэ анги/арга/модуль/үйлчилгээ юу хийдэг талаар өөрөөсөө асуу. Та үүнийг энгийн тодорхойлолтоор хариулах ёстой. ( Баярлалаа Брайтори )

тайлбарууд

Гэсэн хэдий ч заримдаа энгийн тодорхойлолтыг олоход маш хэцүү байдаг

2) Алдаа засах эсвэл шинэ функц нэмэх нь хамгийн бага тооны файл/ангид нөлөөлдөг. Хамгийн тохиромжтой - нэг.

тайлбарууд

Хариуцлага (онцлог эсвэл алдаа) нэг файл/ангид багтсан тул та хаанаас хайх, юуг засахаа мэддэг. Жишээлбэл: Бүртгэлийн үйл ажиллагааны гаралтыг өөрчлөх онцлог нь зөвхөн бүртгэл хөтлөгчийг өөрчлөх шаардлагатай болно. Кодын үлдсэн хэсгийг давах шаардлагагүй.

Өөр нэг жишээ бол өмнөхтэй адил шинэ UI хяналтыг нэмэх явдал юм. Хэрэв энэ нь таныг 10 өөр нэгж, 15 өөр хөрвүүлэгч нэмэхийг албадвал та үүнийг хэтрүүлж байгаа бололтой.

3) Хэрэв хэд хэдэн хөгжүүлэгчид таны төслийн өөр өөр функцууд дээр ажиллаж байгаа бол нэгтгэх зөрчилдөөн үүсэх магадлал, өөрөөр хэлбэл нэг файл/ангиллыг хэд хэдэн хөгжүүлэгч нэгэн зэрэг өөрчлөх магадлал хамгийн бага байна.

тайлбарууд

“Ширээн дор архи хийнэ” гэсэн шинэ үйлдлийг нэмэхдээ мод бэлтгэгч, уух, цутгах үйл ажиллагаанд нөлөөлөх шаардлагатай бол үүрэг хариуцлага нь мушгин хуваагдсан мэт харагдаж байна. Мэдээжийн хэрэг, энэ нь үргэлж боломжтой байдаггүй, гэхдээ бид энэ тоог багасгахыг хичээх хэрэгтэй.

4) Бизнесийн логикийн талаар тодруулах асуултыг (хөгжүүлэгч эсвэл менежерээс) асуухад та нэг анги/файл руу орж, зөвхөн тэндээс мэдээлэл авдаг.

тайлбарууд

Онцлогууд, дүрэм эсвэл алгоритмууд нь тус бүрийг нэг газар авсаархан бичсэн бөгөөд кодын орон зайд тугнуудаар тараагдахгүй.

5) Нэршил нь тодорхой байна.

тайлбарууд

Манай анги, арга барил нэг зүйлийг хариуцаж, хариуцлага нь нэрэндээ тусгагдсан байдаг

AllManagersManagerService - хамгийн их магадлалтай нь Бурханы анги юм
LocalPayment - магадгүй үгүй

Формализм 3. Оккам-анхны хөгжлийн арга зүй.

Дизайны эхэн үед сармагчин хүн шийдэгдэж буй асуудлын бүх нарийн ширийн зүйлийг мэддэггүй, мэдэрдэггүй бөгөөд алдаа гаргаж болно. Та янз бүрийн аргаар алдаа гаргаж болно:

  • Өөр өөр үүрэг хариуцлагыг нэгтгэх замаар объектыг хэт том болгох
  • Нэг үүрэг хариуцлагыг олон төрөлд хуваах замаар дахин боловсруулах
  • Хариуцлагын хил хязгаарыг буруу тодорхойлсон

"Том алдаа гаргасан нь дээр" эсвэл "Хэрэв та итгэлгүй байгаа бол үүнийг салгаж болохгүй" гэсэн дүрмийг санах нь чухал. Жишээлбэл, танай ангид хоёр үүрэг хариуцлага байгаа бол энэ нь ойлгомжтой хэвээр байгаа бөгөөд үйлчлүүлэгчийн кодыг хамгийн бага өөрчлөлтөөр хоёр болгон хувааж болно. Контекст хэд хэдэн файлд тархсан, үйлчлүүлэгчийн кодонд шаардлагатай хамаарал байхгүй тул шилний хэлтэрхийнээс шил угсрах нь ихэвчлэн илүү хэцүү байдаг.

Үүнийг өдөр гэж нэрлэх цаг болжээ

SRP-ийн хамрах хүрээ нь OOP болон SOLID-ээр хязгаарлагдахгүй. Энэ нь арга, функц, анги, модуль, микро үйлчилгээ, үйлчилгээнд хамаарна. Энэ нь "figax-figax-and-prod" болон "rocket-science"-ийн хөгжилд хоёуланд нь хамаатай бөгөөд дэлхийг хаа сайгүй арай дээрдүүлдэг. Хэрэв та бодож байгаа бол энэ нь бараг бүх инженерчлэлийн үндсэн зарчим юм. Механик инженерчлэл, удирдлагын системүүд, үнэхээр бүх нарийн төвөгтэй системүүд нь бүрэлдэхүүн хэсгүүдээс бүтээгдсэн бөгөөд "дутуу хуваагдал" нь дизайнеруудын уян хатан байдлыг, "хэт хуваагдал" нь дизайнеруудын үр ашгийг, буруу хил хязгаар нь тэднийг оюун ухаан, сэтгэлийн амар амгалангаас нь салгадаг.

Ганц хариуцлагын зарчим. Энэ мэт санагдаж байгаа шиг энгийн биш

SRP нь байгалиасаа зохион бүтээгдээгүй бөгөөд нарийн шинжлэх ухааны нэг хэсэг биш юм. Энэ нь бидний биологийн болон сэтгэл зүйн хязгаарлагдмал байдлаас гарч байна.Энэ бол зүгээр л сармагчин хүний ​​тархийг ашиглан нарийн төвөгтэй системийг хянах, хөгжүүлэх арга зам юм. Тэрээр системийг хэрхэн задлахыг бидэнд хэлдэг. Анхны найруулга нь хангалттай хэмжээний телепати шаарддаг боловч энэ нийтлэл нь утааны хөшигний зарим хэсгийг арилгана гэж найдаж байна.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх