Prinċipju ta' Responsabbiltà Uniku. Mhux sempliċi kemm jidher

Prinċipju ta' Responsabbiltà Uniku. Mhux sempliċi kemm jidher Il-prinċipju tar-responsabbiltà unika, magħruf ukoll bħala l-prinċipju tar-responsabbiltà unika,
magħruf ukoll bħala l-prinċipju tal-varjabbiltà uniformi - raġel estremament jiżloq biex jifhem u mistoqsija nervuża bħal din f'intervista ta 'programmatur.

L-ewwel familjarità serja tiegħi ma 'dan il-prinċipju seħħet fil-bidu tal-ewwel sena, meta dawk żgħar u ħodor ttieħdu fil-foresta biex jagħmlu studenti minn larva - studenti reali.

Fil-foresta, konna maqsuma fi gruppi ta '8-9 persuni kull wieħed u kellna kompetizzjoni - liema grupp kien jixorbu flixkun vodka l-aktar mgħaġġel, sakemm l-ewwel persuna mill-grupp tferra vodka ġo tazza, it-tieni tixrobha, u t-tielet għandu snack. L-unità li temmet l-operat tagħha timxi lejn l-aħħar tal-kju tal-grupp.

Il-każ fejn id-daqs tal-kju kien multiplu ta' tlieta kien implimentazzjoni tajba ta' SRP.

Definizzjoni 1. Responsabbiltà unika.

Id-definizzjoni uffiċjali tal-Prinċipju ta’ Responsabbiltà Unika (SRP) tiddikjara li kull entità għandha r-responsabbiltà u r-raġuni għall-eżistenza tagħha, u għandha responsabbiltà waħda biss.

Ikkunsidra l-oġġett "Drinker" (Tippler).
Biex nimplimentaw il-prinċipju SRP, aħna se naqsmu r-responsabbiltajiet fi tlieta:

  • Wieħed iferra (PourOperation)
  • Wieħed jixrob (DrinkUpOperation)
  • Wieħed għandu snack (TakeBiteOperation)

Kull wieħed mill-parteċipanti fil-proċess huwa responsabbli għal komponent wieħed tal-proċess, jiġifieri, għandu responsabbiltà atomika waħda - li tixrob, tferra jew ikla.

It-toqba tax-xorb, min-naħa tagħha, hija faċċata għal dawn l-operazzjonijiet:

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

Prinċipju ta' Responsabbiltà Uniku. Mhux sempliċi kemm jidher

Għaliex?

Il-programmatur tal-bniedem jikteb kodiċi għall-ape-man, u l-ape-bniedem huwa inattenti, stupidu u dejjem bil-għaġla. Huwa jista 'jżomm u jifhem madwar 3 - 7 termini f'ħin wieħed.
Fil-każ ta 'sakra, hemm tlieta minn dawn it-termini. Madankollu, jekk niktbu l-kodiċi b'folja waħda, allura jkun fih idejn, nuċċalijiet, ġlied u argumenti bla tarf dwar il-politika. U dan kollu se jkun fil-korp ta 'metodu wieħed. Jien ċert li rajt kodiċi bħal dan fil-prattika tiegħek. Mhux l-aktar test uman għall-psyche.

Min-naħa l-oħra, ir-raġel tax-xadini huwa ddisinjat biex jissimula oġġetti tad-dinja reali f'rasu. Fl-immaġinazzjoni tiegħu, jista 'jimbottahom flimkien, jiġbor oġġetti ġodda minnhom, u jiżarmahom bl-istess mod. Immaġina mudell ta’ karozza antik. Fl-immaġinazzjoni tiegħek, tista 'tiftaħ il-bieb, ħoll it-trim tal-bieb u tara hemm il-mekkaniżmi tal-lift tat-tieqa, li ġewwa fihom se jkun hemm gerijiet. Imma ma tistax tara l-komponenti kollha tal-magna fl-istess ħin, f'"elenkar" wieħed. Mill-inqas il-"bniedem xadina" ma jistax.

Għalhekk, programmaturi umani jiddekomponu mekkaniżmi kumplessi f'sett ta 'elementi inqas kumplessi u ta' ħidma. Madankollu, jista 'jiġi dekompost b'modi differenti: f'ħafna karozzi qodma, il-kanal tal-arja jidħol fil-bieb, u fil-karozzi moderni, ħsara fl-elettronika tal-illokkjar ma tħallix li l-magna tibda, li tista' tkun problema waqt it-tiswijiet.

Issa, SRP huwa prinċipju li jispjega KIF tiddekomponi, jiġifieri, fejn tiġbed il-linja diviżorja.

Jgħid li huwa meħtieġ li jiddekomponi skond il-prinċipju ta 'diviżjoni ta' "responsabbiltà", jiġifieri, skond il-kompiti ta 'ċerti oġġetti.

Prinċipju ta' Responsabbiltà Uniku. Mhux sempliċi kemm jidher

Ejja nerġgħu lura għax-xorb u l-vantaġġi li jirċievi r-raġel xadina waqt id-dekompożizzjoni:

  • Il-kodiċi sar estremament ċar f'kull livell
  • Il-kodiċi jista 'jinkiteb minn diversi programmaturi f'daqqa (kull wieħed jikteb element separat)
  • L-ittestjar awtomatizzat huwa ssimplifikat - aktar ma jkun sempliċi l-element, iktar ikun faċli li jiġi ttestjat
  • Il-kompożizzjoni tal-kodiċi tidher - tista 'tissostitwixxi DrinkUpOperation għal operazzjoni li fiha drunkard iferra likwidu taħt il-mejda. Jew ibdel l-operazzjoni tat-tferrigħ b'operazzjoni li fiha tħallat l-inbid u l-ilma jew il-vodka u l-birra. Skont ir-rekwiżiti tan-negozju, tista 'tagħmel kollox mingħajr ma tmiss il-kodiċi tal-metodu Tippler.Att.
  • Minn dawn l-operazzjonijiet tista 'titwi l-glutton (bl-użu biss TakeBitOperation), Alkoħoliku (bl-użu biss DrinkUpOperation dritta mill-flixkun) u jissodisfaw ħafna rekwiżiti oħra tan-negozju.

(Oh, jidher li dan huwa diġà prinċipju OCP, u jien kisret ir-responsabbiltà ta 'din il-kariga)

U, ovvjament, l-iżvantaġġi:

  • Ikollna noħolqu aktar tipi.
  • Sakra jixrob għall-ewwel darba ftit sigħat wara milli kieku kien ikollu.

Definizzjoni 2. Varjabilità unifikata.

Ippermettuli, rġulija! Il-klassi tax-xorb għandha wkoll responsabbiltà waħda - tixrob! U b'mod ġenerali, il-kelma "responsabbiltà" hija kunċett estremament vag. Xi ħadd huwa responsabbli għad-destin tal-umanità, u xi ħadd huwa responsabbli biex jgħolli l-pingwini li nqalbu mal-arblu.

Ejja nikkunsidraw żewġ implimentazzjonijiet tal-ħwat. L-ewwel waħda, imsemmija hawn fuq, fiha tliet klassijiet - ferra, tixrob u snack.

It-tieni huwa miktub permezz tal-metodoloġija "Forward and Only Forward" u fih il-loġika kollha fil-metodu Att:

//Не тратьте время  на изучение этого класса. Лучше съешьте печеньку
с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);
    }
   }
}

Dawn iż-żewġ klassijiet, mil-lat ta’ osservatur minn barra, jidhru eżattament l-istess u jaqsmu l-istess responsabbiltà ta’ “xorb”.

Konfużjoni!

Imbagħad immorru onlajn u nsiru nafu definizzjoni oħra ta' SRP - il-Prinċipju Uniku tal-Bidla.

SCP jgħid li "Modulu għandu raġuni waħda u waħda biss biex jinbidel". Jiġifieri, "Ir-responsabbiltà hija raġuni għall-bidla."

(Jidher li l-ġuvini li ħarġu bid-definizzjoni oriġinali kienu kunfidenti fil-kapaċitajiet telepatiċi tar-raġel tax-xadini)

Issa kollox jaqa’ f’postu. Separatament, nistgħu nibdlu l-proċeduri ta 'tferrigħ, xorb u snacking, iżda fil-ħwat innifsu nistgħu nibdlu biss is-sekwenza u l-kompożizzjoni tal-operazzjonijiet, pereżempju, billi nimxu l-ikla ħafifa qabel tixrob jew inżidu l-qari ta' toast.

Fl-approċċ "Forward and Only Forward", dak kollu li jista 'jinbidel jinbidel biss fil-metodu Att. Dan jista 'jinqara u effettiv meta jkun hemm ftit loġika u rari tinbidel, iżda ħafna drabi jispiċċa f'metodi terribbli ta' 500 linja kull wieħed, b'aktar if-dikjarazzjonijiet milli meħtieġ biex ir-Russja tissieħeb fin-NATO.

Definizzjoni 3. Lokalizzazzjoni tal-bidliet.

Ħafna drabi dawk li jixorbu ma jifhmux għaliex qamu fl-appartament ta’ xi ħadd ieħor, jew fejn ikun il-mowbajl tagħhom. Wasal iż-żmien li żżid logging dettaljat.

Ejja nibdew niilloggjaw bil-proċess tat-tferrigħ:

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}");
    }
}

Billi tinkapsulha fil PourOperation, aġixxejna bil-għaqal mil-lat tar-responsabbiltà u l-inkapsulament, iżda issa aħna konfużi mal-prinċipju tal-varjabbiltà. Minbarra l-operazzjoni nnifisha, li tista 'tinbidel, il-qtugħ innifsu jsir ukoll jinbidlu. Int ser ikollok tissepara u toħloq logger speċjali għall-operazzjoni tat-tferrigħ:

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)
        }
    }
}

Il-qarrej metikoluż jinduna b’dan LogAfter, LogBefore и OnError tista 'wkoll tinbidel individwalment, u, b'analoġija mal-passi preċedenti, se toħloq tliet klassijiet: PourLoggerBefore, PourLoggerAfter и PourErrorLogger.

U niftakru li hemm tliet operazzjonijiet għal min jixorbu, aħna jkollna disa 'klassijiet ta' qtugħ. Bħala riżultat, iċ-ċirku kollu tax-xorb jikkonsisti minn 14 (!!!) klassi.

Iperbola? Bilkemm! Raġel xadina b'granata ta 'dekompożizzjoni se jaqsam il-"pourer" f'decanter, ħġieġ, operaturi tat-tferrigħ, servizz ta' provvista ta 'ilma, mudell fiżiku tal-ħabta tal-molekuli, u għat-trimestru li jmiss se jipprova jħoll id-dipendenzi mingħajr varjabbli globali. U emminni, mhux se jieqaf.

Huwa f'dan il-punt li ħafna jaslu għall-konklużjoni li SRP huma ħrejjef minn renji roża, u jmorru jilagħbu noodles...

... mingħajr qatt ma tgħallimt dwar l-eżistenza tat-tielet definizzjoni ta' Srp:

“Il-Prinċipju ta’ Responsabbiltà Unika jgħid li affarijiet li huma simili għall-bidla għandhom jinħażnu f'post wieħed". jew "Dak li jinbidel flimkien għandu jinżamm f'post wieħed"

Jiġifieri, jekk nibdlu l-qtugħ ta 'operazzjoni, allura rridu nibdluha f'post wieħed.

Dan huwa punt importanti ħafna - peress li l-ispjegazzjonijiet kollha ta 'SRP li kienu hawn fuq qalu li kien meħtieġ li tfarrak it-tipi waqt li kienu qed jiġu mgħaffġa, jiġifieri, imponew "limitu ta' fuq" fuq id-daqs tal-oġġett, u issa diġà qed nitkellmu dwar "limitu aktar baxx". Fi kliem ieħor, L-SRP mhux biss jeħtieġ "tgħaffiġ waqt it-tgħaffiġ", iżda wkoll li ma żżejjed - "tgħaffiġx affarijiet interlocking". Din hi l-battalja kbira bejn il-leħja ta’ Occam u r-raġel tax-xadini!

Prinċipju ta' Responsabbiltà Uniku. Mhux sempliċi kemm jidher

Issa min jixorbu għandu jħossu aħjar. Minbarra l-fatt li m'hemmx għalfejn naqsmu l-logger IPourLogger fi tliet klassijiet, nistgħu wkoll ngħaqqdu l-loggers kollha f'tip wieħed:

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

U jekk inżidu r-raba 'tip ta' operazzjoni, allura l-qtugħ għalih huwa diġà lest. U l-kodiċi tal-operazzjonijiet infushom huwa nadif u ħieles mill-istorbju tal-infrastruttura.

Bħala riżultat, għandna 5 klassijiet biex insolvu l-problema tax-xorb:

  • Operazzjoni tat-tferrigħ
  • Operazzjoni tax-xorb
  • Operazzjoni tal-imblukkar
  • Logger
  • Faċċata tax-xorb

Kull wieħed minnhom huwa responsabbli strettament għal funzjonalità waħda u għandu raġuni waħda għall-bidla. Ir-regoli kollha simili għall-bidla jinsabu fil-qrib.

Eżempju tal-ħajja reali

Darba ktibna servizz biex nirreġistraw awtomatikament klijent b2b. U metodu ALLA deher għal 200 linja ta 'kontenut simili:

  • Mur f'1C u oħloq kont
  • B'dan il-kont, mur fil-modulu tal-ħlas u oħloq hemmhekk
  • Iċċekkja li kont b'tali kont ma jkunx inħoloq fuq is-server prinċipali
  • Oħloq kont ġdid
  • Żid ir-riżultati tar-reġistrazzjoni fil-modulu tal-ħlas u n-numru 1c mas-servizz tar-riżultati tar-reġistrazzjoni
  • Żid l-informazzjoni tal-kont ma' din it-tabella
  • Oħloq numru tal-punt għal dan il-klijent fis-servizz tal-punt. Għaddi n-numru tal-kont 1c tiegħek għal dan is-servizz.

U kien hemm madwar 10 operazzjonijiet kummerċjali oħra f'din il-lista b'konnettività terribbli. Kważi kulħadd kellu bżonn l-oġġett tal-kont. L-ID tal-punt u l-isem tal-klijent kienu meħtieġa f'nofs is-sejħiet.

Wara siegħa ta 'refactoring, stajna nisseparaw il-kodiċi tal-infrastruttura u xi wħud mill-sfumaturi ta' ħidma b'kont f'metodi/klassijiet separati. Il-metodu ta 'Alla għamilha eħfef, iżda kien fadal 100 linja ta' kodiċi li sempliċement ma ridux jinħall.

Wara ftit jiem biss deher ċar li l-essenza ta 'dan il-metodu "ħfief" hija algoritmu tan-negozju. U li d-deskrizzjoni oriġinali tal-ispeċifikazzjonijiet tekniċi kienet pjuttost kumplessa. U huwa l-attentat biex dan il-metodu jinqasam f'biċċiet li jiksru l-SRP, u mhux viċi versa.

Formaliżmu.

Wasal iż-żmien li nħallu s-sakra tagħna waħdu. Nixxef id-dmugħ tiegħek – żgur li se nirritornaw għaliha xi darba. Issa ejja nifformalizzaw l-għarfien minn dan l-artikolu.

Formaliżmu 1. Definizzjoni ta' SRP

  1. Separa l-elementi sabiex kull wieħed minnhom ikun responsabbli għal ħaġa waħda.
  2. Ir-responsabbiltà tirreferi għal "raġuni għall-bidla." Jiġifieri, kull element għandu raġuni waħda biss għall-bidla, f'termini ta 'loġika tan-negozju.
  3. Bidliet potenzjali fil-loġika tan-negozju. għandhom ikunu lokalizzati. Elementi li jinbidlu b'mod sinkroniku għandhom ikunu fil-qrib.

Formaliżmu 2. Kriterji meħtieġa għall-awtotest.

Ma rajtx kriterji suffiċjenti biex nissodisfa l-SRP. Iżda hemm kundizzjonijiet meħtieġa:

1) Staqsi lilek innifsek x'tagħmel din il-klassi/metodu/modulu/servizz. trid twieġebha b'definizzjoni sempliċi. ( Grazzi Brightori )

spjegazzjonijiet

Madankollu, xi drabi huwa diffiċli ħafna li ssib definizzjoni sempliċi

2) L-iffissar ta 'bug jew iż-żieda ta' karatteristika ġdida taffettwa numru minimu ta 'fajls/klassijiet. Idealment - wieħed.

spjegazzjonijiet

Peress li r-responsabbiltà (għal karatteristika jew bug) hija inkapsulata f'fajl/klassi waħda, taf eżattament fejn tfittex u x'għandek teditja. Per eżempju: il-karatteristika li tinbidel l-output ta 'operazzjonijiet ta' qtugħ se teħtieġ li tinbidel biss il-logger. M'hemmx għalfejn tgħaddi mill-bqija tal-kodiċi.

Eżempju ieħor huwa li żżid kontroll UI ġdid, simili għal dawk ta 'qabel. Jekk dan iġiegħlek iżżid 10 entitajiet differenti u 15-il konvertitur differenti, jidher li qed tegħleb.

3) Jekk diversi żviluppaturi qed jaħdmu fuq karatteristiċi differenti tal-proġett tiegħek, allura l-probabbiltà ta 'kunflitt ta' amalgamazzjoni, jiġifieri, il-probabbiltà li l-istess fajl/klassi tinbidel minn diversi żviluppaturi fl-istess ħin, hija minima.

spjegazzjonijiet

Jekk, meta żżid operazzjoni ġdida "Pour vodka taħt il-mejda", għandek bżonn taffettwa l-logger, l-operazzjoni tax-xorb u t-tferrigħ, allura jidher li r-responsabbiltajiet huma maqsuma b'mod mgħawweġ. Naturalment, dan mhux dejjem huwa possibbli, iżda għandna nippruvaw innaqqsu din iċ-ċifra.

4) Meta mistoqsija mistoqsija ta 'kjarifika dwar il-loġika tan-negozju (minn żviluppatur jew maniġer), tmur strettament f'klassi/fajl wieħed u tirċievi informazzjoni minn hemm biss.

spjegazzjonijiet

Il-karatteristiċi, ir-regoli jew l-algoritmi jinkitbu b'mod kompatt, kull wieħed f'post wieħed, u mhux imxerrda bi bnadar fl-ispazju tal-kodiċi.

5) L-ismijiet huwa ċar.

spjegazzjonijiet

Il-klassi jew il-metodu tagħna huwa responsabbli għal ħaġa waħda, u r-responsabbiltà hija riflessa f'isimha

AllManagersManagerService - x'aktarx klassi ta 'Alla
LocalPayment - probabbilment le

Formaliżmu 3. Metodoloġija ta' żvilupp Occam-first.

Fil-bidu tad-disinn, il-bniedem xadina ma jafx u ma jħossx l-irqaq kollha tal-problema li qed tiġi solvuta u jista 'jagħmel żball. Tista' tagħmel żbalji b'modi differenti:

  • Agħmel oġġetti kbar wisq billi tgħaqqad responsabbiltajiet differenti
  • Reframing billi taqsam responsabbiltà waħda f'ħafna tipi differenti
  • Iddefinixxi b'mod żbaljat il-konfini tar-responsabbiltà

Huwa importanti li tiftakar ir-regola: "aħjar li tagħmel żball kbir," jew "jekk m'intix ċert, taqsamx." Jekk, pereżempju, il-klassi tiegħek fiha żewġ responsabbiltajiet, allura xorta waħda tinftiehem u tista 'tinqasam fi tnejn b'bidliet minimi fil-kodiċi tal-klijent. L-assemblaġġ ta 'ħġieġ minn frak ta' ħġieġ huwa ġeneralment aktar diffiċli minħabba l-kuntest li qed jinfirex fuq diversi fajls u n-nuqqas ta 'dipendenzi meħtieġa fil-kodiċi tal-klijent.

Wasal iż-żmien li nsejħulha kuljum

L-ambitu tal-SRP mhuwiex limitat għal OOP u SOLID. Japplika għal metodi, funzjonijiet, klassijiet, moduli, mikroservizzi u servizzi. Japplika kemm għall-iżvilupp "figax-figax-and-prod" kif ukoll "rocket-science", li jagħmel id-dinja ftit aħjar kullimkien. Jekk taħseb dwarha, dan huwa kważi l-prinċipju fundamentali tal-inġinerija kollha. L-inġinerija mekkanika, is-sistemi ta 'kontroll, u tabilħaqq is-sistemi kumplessi kollha huma mibnija minn komponenti, u "sottoframmentazzjoni" ċċaħħad lid-disinjaturi mill-flessibilità, "frammentazzjoni żejda" iċaħħad lid-disinjaturi mill-effiċjenza, u l-konfini mhux korretti jċaħħduhom mir-raġuni u l-paċi tal-moħħ.

Prinċipju ta' Responsabbiltà Uniku. Mhux sempliċi kemm jidher

SRP mhuwiex ivvintat min-natura u mhuwiex parti mix-xjenza eżatta. Tifqa mil-limitazzjonijiet bijoloġiċi u psikoloġiċi tagħna.Hija biss mod kif tikkontrolla u tiżviluppa sistemi kumplessi bl-użu tal-moħħ tar-raġel tax-xadini. Jgħidilna kif niddekomponu sistema. Il-formulazzjoni oriġinali kienet teħtieġ ammont ġust ta 'telepatija, imma nittama li dan l-artikolu jneħħi xi wħud mill-iskrin tad-duħħan.

Sors: www.habr.com

Żid kumment