MÅ«su uzÅÄmums specializÄjas ERP klases programmatÅ«ras risinÄjumu izstrÄdÄ, kuru lauvas tiesu aizÅem transakciju sistÄmas ar milzÄ«gu biznesa loÄ£ikas un dokumentu plÅ«smas apjomu a la EDMS. MÅ«su produktu paÅ”reizÄjÄs versijas ir balstÄ«tas uz JavaEE tehnoloÄ£ijÄm, taÄu mÄs arÄ« aktÄ«vi eksperimentÄjam ar mikropakalpojumiem. Viena no problemÄtiskÄkajÄm Å”Ädu risinÄjumu jomÄm ir dažÄdu blakus domÄnu apakÅ”sistÄmu integrÄcija. IntegrÄcijas problÄmas mums vienmÄr ir sagÄdÄjuÅ”as milzÄ«gas galvassÄpes neatkarÄ«gi no izmantotajiem arhitektÅ«ras stiliem, tehnoloÄ£iju skursteÅiem un ietvariem, taÄu pÄdÄjÄ laikÄ ir vÄrojams progress Å”Ädu problÄmu risinÄÅ”anÄ.
RakstÄ, kuru piedÄvÄju jÅ«su uzmanÄ«bai, pastÄstÄ«Å”u par NPO āKristaā pieredzi un arhitektÅ«ras izpÄti norÄdÄ«tajÄ teritorijÄ. ApskatÄ«sim arÄ« vienkÄrÅ”a integrÄcijas problÄmas risinÄjuma piemÄru no lietojumprogrammu izstrÄdÄtÄja viedokļa un uzzinÄsim, kas slÄpjas aiz Ŕīs vienkÄrŔības.
Atruna
RakstÄ aprakstÄ«tos arhitektoniskos un tehniskos risinÄjumus esmu piedÄvÄjis, balstoties uz personÄ«go pieredzi konkrÄtu uzdevumu kontekstÄ. Å ie risinÄjumi nepretendÄ uz universÄliem un var nebÅ«t optimÄli citos lietoÅ”anas apstÄkļos.
KÄds BPM sakars ar to?
Lai atbildÄtu uz Å”o jautÄjumu, mums ir nedaudz dziļÄk jÄiedziļinÄs mÅ«su risinÄjumu pielietoto problÄmu specifikÄ. GalvenÄ biznesa loÄ£ikas daļa mÅ«su tipiskajÄ darÄ«jumu sistÄmÄ ir datu ievadÄ«Å”ana datu bÄzÄ, izmantojot lietotÄja saskarnes, Å”o datu manuÄla un automatizÄta pÄrbaude, to veikÅ”ana, izmantojot kÄdu darbplÅ«smu, publicÄÅ”ana citÄ sistÄmÄ / analÄ«tiskÄ datu bÄzÄ / arhÄ«vÄ, atskaiÅ”u Ä£enerÄÅ”ana. . TÄdÄjÄdi sistÄmas galvenÄ funkcija klientiem ir viÅu iekÅ”Äjo biznesa procesu automatizÄcija.
ÄrtÄ«bas labad mÄs saziÅÄ lietojam terminu ādokumentsā kÄ abstrakciju no datu kopas, ko vieno kopÄja atslÄga, ar kuru var āsaistÄ«tā noteiktu darbplÅ«smu.
Bet kÄ ar integrÄcijas loÄ£iku? Galu galÄ integrÄcijas uzdevumu Ä£enerÄ sistÄmas arhitektÅ«ra, kas tiek āsagrieztaā daļÄs NEVIS pÄc klienta pieprasÄ«juma, bet gan pilnÄ«gi atŔķirÄ«gu faktoru ietekmÄ:
pakļauts Konveja likumam;
iepriekÅ” citiem produktiem izstrÄdÄtu apakÅ”sistÄmu atkÄrtotas izmantoÅ”anas rezultÄtÄ;
pÄc arhitekta ieskatiem, pamatojoties uz nefunkcionÄlÄm prasÄ«bÄm.
PastÄv liels kÄrdinÄjums atdalÄ«t integrÄcijas loÄ£iku no galvenÄs darbplÅ«smas biznesa loÄ£ikas, lai nepiesÄrÅotu biznesa loÄ£iku ar integrÄcijas artefaktiem un glÄbtu lietojumprogrammu izstrÄdÄtÄju no nepiecieÅ”amÄ«bas iedziļinÄties sistÄmas arhitektÅ«ras ainavas iezÄ«mÄs. Å ai pieejai ir vairÄkas priekÅ”rocÄ«bas, taÄu prakse parÄda tÄs neefektivitÄti:
integrÄcijas problÄmu risinÄÅ”ana parasti atgriežas pie vienkÄrÅ”ÄkajÄm iespÄjÄm sinhrono zvanu veidÄ, jo galvenÄs darbplÅ«smas Ä«stenoÅ”anÄ ir ierobežoti paplaÅ”inÄjuma punkti (sinhronÄs integrÄcijas trÅ«kumi ir apskatÄ«ti tÄlÄk);
integrÄcijas artefakti joprojÄm iekļūst biznesa pamatloÄ£ikÄ, ja ir nepiecieÅ”ama atgriezeniskÄ saite no citas apakÅ”sistÄmas;
lietojumprogrammas izstrÄdÄtÄjs ignorÄ integrÄciju un var viegli to pÄrtraukt, mainot darbplÅ«smu;
sistÄma pÄrstÄj bÅ«t vienots veselums no lietotÄja viedokļa, kļūst pamanÄmas āÅ”uvesā starp apakÅ”sistÄmÄm un parÄdÄs liekas lietotÄja darbÄ«bas, kas iniciÄ datu pÄrsÅ«tÄ«Å”anu no vienas apakÅ”sistÄmas uz otru.
VÄl viena pieeja ir uzskatÄ«t integrÄcijas mijiedarbÄ«bu par galvenÄs biznesa loÄ£ikas un darbplÅ«smas neatÅemamu sastÄvdaļu. Lai nepieļautu lietojumprogrammu izstrÄdÄtÄju kvalifikÄcijas strauju pieaugumu, jaunu integrÄcijas mijiedarbÄ«bu izveidei jÄbÅ«t vienkÄrÅ”ai un bez piepÅ«les, ar minimÄlÄm risinÄjuma izvÄles iespÄjÄm. To izdarÄ«t ir grÅ«tÄk, nekÄ Å”Ä·iet: instrumentam ir jÄbÅ«t pietiekami jaudÄ«gam, lai nodroÅ”inÄtu lietotÄjam nepiecieÅ”amÄs dažÄdas tÄ izmantoÅ”anas iespÄjas, neļaujot viÅam āieÅ”aut sev kÄjÄā. Ir daudzi jautÄjumi, uz kuriem inženierim ir jÄatbild integrÄcijas uzdevumu kontekstÄ, bet par kuriem lietojumprogrammu izstrÄdÄtÄjam nevajadzÄtu domÄt savÄ ikdienas darbÄ: darÄ«jumu robežas, konsekvence, atomitÄte, droŔība, mÄrogoÅ”ana, slodzes un resursu sadale, marÅ”rutÄÅ”ana, ŔķiroÅ”ana, izplatÄ«Å”anas un komutÄcijas konteksti utt. NepiecieÅ”ams piedÄvÄt lietojumprogrammu izstrÄdÄtÄjiem diezgan vienkÄrÅ”as risinÄjumu veidnes, kurÄs atbildes uz visiem Å”Ädiem jautÄjumiem jau ir paslÄptas. Å Ä«m veidnÄm jÄbÅ«t diezgan droÅ”Äm: biznesa loÄ£ika mainÄs ļoti bieži, kas palielina kļūdu raÅ”anÄs risku, kļūdu izmaksÄm jÄpaliek diezgan zemÄ lÄ«menÄ«.
Bet kÄds BPM sakars ar to? Ir daudz iespÄju darbplÅ«smas ievieÅ”anai...
PatieÅ”Äm, mÅ«su risinÄjumos ļoti populÄra ir cita biznesa procesu realizÄcija - ar deklaratÄ«vu stÄvokļa pÄrejas diagrammas definÄ«ciju un apstrÄdÄtÄju savienoÅ”anu ar biznesa loÄ£iku pÄrejÄm. Å ajÄ gadÄ«jumÄ stÄvoklis, kas nosaka ādokumentaā paÅ”reizÄjo pozÄ«ciju biznesa procesÄ, ir paÅ”a ādokumentaā atribÅ«ts.
Å Ädi izskatÄs process projekta sÄkumÄ
Å Ä«s ievieÅ”anas popularitÄte ir saistÄ«ta ar lineÄro biznesa procesu izveides relatÄ«vo vienkÄrŔību un Ätrumu. TomÄr, tÄ kÄ programmatÅ«ras sistÄmas nemitÄ«gi kļūst sarežģītÄkas, biznesa procesa automatizÄtÄ daļa aug un kļūst sarežģītÄka. Ir nepiecieÅ”ama dekompozÄ«cija, procesu daļu atkÄrtota izmantoÅ”ana, kÄ arÄ« procesu sazaroÅ”ana, lai katrs zars tiktu izpildÄ«ts paralÄli. Å Ädos apstÄkļos rÄ«ks kļūst neÄrts, un stÄvokļa pÄrejas diagramma zaudÄ savu informÄcijas saturu (integrÄcijas mijiedarbÄ«ba diagrammÄ vispÄr netiek atspoguļota).
Å Ädi process izskatÄs pÄc vairÄkÄm prasÄ«bu precizÄÅ”anas iterÄcijÄm.
Izeja no Ŕīs situÄcijas bija dzinÄja integrÄcija jBPM dažos produktos ar vissarežģītÄkajiem biznesa procesiem. ÄŖstermiÅÄ Å”im risinÄjumam bija zinÄmi panÄkumi: kļuva iespÄjams Ä«stenot sarežģītus biznesa procesus, saglabÄjot diezgan informatÄ«vu un atbilstoÅ”u diagrammu apzÄ«mÄjumÄ. BPMN2.
Neliela daļa no sarežģīta biznesa procesa
IlgtermiÅÄ risinÄjums neattaisnoja cerÄ«bas: augstÄ darba intensitÄte biznesa procesu veidoÅ”anÄ, izmantojot vizuÄlos rÄ«kus, neļÄva sasniegt pieÅemamus produktivitÄtes rÄdÄ«tÄjus, un pats rÄ«ks kļuva par vienu no visnepatÄ«kamÄkajiem izstrÄdÄtÄju vidÅ«. Bija arÄ« sÅ«dzÄ«bas par dzinÄja iekÅ”Äjo struktÅ«ru, kas izraisÄ«ja daudzu āplÄksteruā un ākruÄ·uā parÄdÄ«Å”anos.
Galvenais pozitÄ«vais jBPM izmantoÅ”anas aspekts bija izpratne par ieguvumiem un kaitÄjumu, ko rada biznesa procesa instances pastÄvÄ«gais stÄvoklis. MÄs arÄ« redzÄjÄm iespÄju izmantot procesa pieeju, lai ieviestu sarežģītus integrÄcijas protokolus starp dažÄdÄm lietojumprogrammÄm, izmantojot asinhronu mijiedarbÄ«bu, izmantojot signÄlus un ziÅojumus. PastÄvÄ«ga stÄvokļa klÄtbÅ«tnei tajÄ ir izŔķiroÅ”a nozÄ«me.
Pamatojoties uz iepriekÅ” minÄto, mÄs varam secinÄt: Procesu pieeja BPM stilÄ Ä¼auj risinÄt visdažÄdÄkos uzdevumus, lai automatizÄtu arvien sarežģītÄkus biznesa procesus, harmoniski iekļautu integrÄcijas darbÄ«bas Å”ajos procesos un saglabÄtu iespÄju vizuÄli attÄlot realizÄto procesu piemÄrotÄ notÄcijÄ.
Sinhrono zvanu kÄ integrÄcijas modeļa trÅ«kumi
SinhronÄ integrÄcija attiecas uz vienkÄrÅ”Äko bloÄ·ÄÅ”anas zvanu. Viena apakÅ”sistÄma darbojas kÄ servera puse un pakļauj API ar nepiecieÅ”amo metodi. Cita apakÅ”sistÄma darbojas kÄ klienta puse un Ä«stajÄ laikÄ veic zvanu un gaida rezultÄtu. AtkarÄ«bÄ no sistÄmas arhitektÅ«ras klienta un servera puses var atrasties vai nu vienÄ lietojumprogrammÄ un procesÄ, vai arÄ« dažÄdÄs. OtrajÄ gadÄ«jumÄ jums ir jÄpiemÄro RPC ievieÅ”ana un jÄnodroÅ”ina parametru un izsaukuma rezultÄtu ŔķiroÅ”ana.
Å im integrÄcijas modelim ir diezgan liels trÅ«kumu kopums, taÄu tÄ vienkÄrŔības dÄļ tas tiek ļoti plaÅ”i izmantots praksÄ. ÄŖstenoÅ”anas Ätrums valdzina un liek to izmantot atkal un atkal, saskaroties ar steidzamiem termiÅiem, ierakstot risinÄjumu kÄ tehnisko parÄdu. Bet gadÄs arÄ«, ka nepieredzÄjuÅ”i izstrÄdÄtÄji to izmanto neapzinÄti, vienkÄrÅ”i neapzinoties negatÄ«vÄs sekas.
Papildus visredzamÄkajam apakÅ”sistÄmas savienojamÄ«bas pieaugumam ir arÄ« mazÄk acÄ«mredzamas problÄmas ar darÄ«jumiem, kas saistÄ«ti ar "pieaugÅ”anu" un "izstiepÅ”anu". PatieÅ”Äm, ja biznesa loÄ£ika veic dažas izmaiÅas, tad no darÄ«jumiem nevar izvairÄ«ties, un darÄ«jumi savukÄrt bloÄ·Ä noteiktus lietojumprogrammu resursus, kurus ietekmÄ Å”Ä«s izmaiÅas. Tas ir, kamÄr viena apakÅ”sistÄma negaida atbildi no otras, tÄ nevarÄs pabeigt darÄ«jumu un noÅemt slÄdzenes. Tas ievÄrojami palielina dažÄdu seku risku:
SistÄmas reaÄ£ÄtspÄja zÅ«d, lietotÄji ilgi gaida atbildes uz pieprasÄ«jumiem;
serveris parasti pÄrstÄj atbildÄt uz lietotÄju pieprasÄ«jumiem pÄrpildÄ«ta pavedienu pÅ«la dÄļ: lielÄkÄ daļa pavedienu ir bloÄ·Äti resursÄ, ko aizÅem darÄ«jums;
SÄk parÄdÄ«ties strupceļi: to raÅ”anÄs iespÄjamÄ«ba ir ļoti atkarÄ«ga no darÄ«jumu ilguma, darÄ«jumu loÄ£ikas un darÄ«jumÄ iesaistÄ«to bloÄ·ÄÅ”anas apjoma;
parÄdÄs darÄ«juma taimauta kļūdas;
serveris āneizdodasā ar OutOfMemory, ja uzdevums prasa apstrÄdÄt un mainÄ«t lielu datu apjomu, un sinhronÄs integrÄcijas klÄtbÅ«tne apgrÅ«tina apstrÄdes sadalÄ«Å”anu āvieglÄkosā darÄ«jumos.
No arhitektÅ«ras viedokļa bloÄ·ÄÅ”anas zvanu izmantoÅ”ana integrÄcijas laikÄ noved pie kontroles zaudÄÅ”anas pÄr atseviŔķu apakÅ”sistÄmu kvalitÄti: nav iespÄjams nodroÅ”inÄt vienas apakÅ”sistÄmas mÄrÄ·a kvalitÄtes rÄdÄ«tÄjus atseviŔķi no citas apakÅ”sistÄmas kvalitÄtes rÄdÄ«tÄjiem. Ja apakÅ”sistÄmas izstrÄdÄ dažÄdas komandas, tÄ ir liela problÄma.
Lietas kļūst vÄl interesantÄkas, ja integrÄtÄs apakÅ”sistÄmas atrodas dažÄdÄs lietojumprogrammÄs un jums ir jÄveic sinhronas izmaiÅas abÄs pusÄs. KÄ nodroÅ”inÄt Å”o izmaiÅu transakciju?
Ja izmaiÅas tiek veiktas atseviŔķos darÄ«jumos, jums bÅ«s jÄnodroÅ”ina uzticama izÅÄmumu apstrÄde un kompensÄcija, un tas pilnÄ«bÄ novÄrÅ” sinhronÄs integrÄcijas galveno ieguvumu - vienkÄrŔību.
PrÄtÄ nÄk arÄ« izplatÄ«tie darÄ«jumi, taÄu mÄs tos neizmantojam savos risinÄjumos: ir grÅ«ti nodroÅ”inÄt uzticamÄ«bu.
Å is modelis lieliski atrisina iepriekÅ” minÄtÄs ilgo darÄ«jumu problÄmas, kÄ arÄ« paplaÅ”ina sistÄmas stÄvokļa pÄrvaldÄ«bas iespÄjas no biznesa loÄ£ikas puses: kompensÄcija pÄc neveiksmÄ«ga darÄ«juma var nevis atgriezt sistÄmu sÄkotnÄjÄ stÄvoklÄ«, bet nodroÅ”inÄt alternatÄ«vs datu apstrÄdes ceļŔ. Tas arÄ« ļauj izvairÄ«ties no veiksmÄ«gi pabeigtu datu apstrÄdes darbÄ«bu atkÄrtoÅ”anas, mÄÄ£inot novest procesu lÄ«dz ālabÄmā beigÄm.
Interesanti, ka monolÄ«tajÄs sistÄmÄs Å”is modelis ir aktuÄls arÄ« tad, kad runa ir par brÄ«vi savienotu apakÅ”sistÄmu integrÄciju, un tiek novÄrota negatÄ«va ietekme, ko izraisa ilgstoÅ”i veikti darÄ«jumi un attiecÄ«gie resursu bloÄ·Äjumi.
SaistÄ«bÄ ar mÅ«su biznesa procesiem BPM stilÄ āSÄgasā ir ļoti viegli ieviest: atseviŔķus āSÄgasā soļus var norÄdÄ«t kÄ darbÄ«bas biznesa procesa ietvaros, kÄ arÄ« biznesa procesa noturÄ«go stÄvokli. nosaka āSÄgasā iekÅ”Äjo stÄvokli. Tas ir, mÄs neprasÄm nekÄdu papildu koordinÄcijas mehÄnismu. Viss, kas Jums nepiecieÅ”ams, ir ziÅojumu brokeris, kas atbalsta "vismaz vienreizÄjÄs" garantijas kÄ transportu.
Bet Å”im risinÄjumam ir arÄ« sava ācenaā:
biznesa loÄ£ika kļūst sarežģītÄka: jÄizstrÄdÄ kompensÄcija;
bÅ«s jÄatsakÄs no pilnÄ«gas konsekvences, kas var bÅ«t Ä«paÅ”i jutÄ«ga monolÄ«tÄm sistÄmÄm;
ArhitektÅ«ra kļūst nedaudz sarežģītÄka, un parÄdÄs papildu nepiecieÅ”amÄ«ba pÄc ziÅojumu brokera;
bÅ«s nepiecieÅ”ami papildu uzraudzÄ«bas un administrÄÅ”anas rÄ«ki (lai gan kopumÄ tas ir labi: sistÄmas apkalpoÅ”anas kvalitÄte paaugstinÄsies).
MonolÄ«tÄm sistÄmÄm "Sag" izmantoÅ”anas pamatojums nav tik acÄ«mredzams. Mikropakalpojumiem un citiem SOA, kur, visticamÄk, jau ir brokeris un projekta sÄkumÄ tiek upurÄta pilnÄ«ga konsekvence, Ŕī modeļa izmantoÅ”anas priekÅ”rocÄ«bas var ievÄrojami atsvÄrt trÅ«kumus, Ä«paÅ”i, ja biznesa loÄ£ikÄ ir Ärta API lÄ«menÄ«.
Biznesa loÄ£ikas iekapsulÄÅ”ana mikropakalpojumos
Kad sÄkÄm eksperimentÄt ar mikropakalpojumiem, radÄs pamatots jautÄjums: kur likt domÄna biznesa loÄ£iku attiecÄ«bÄ pret servisu, kas nodroÅ”ina domÄna datu noturÄ«bu?
AplÅ«kojot dažÄdu BPMS arhitektÅ«ru, var Ŕķist saprÄtÄ«gi noŔķirt biznesa loÄ£iku no noturÄ«bas: izveidot platformu un domÄna neatkarÄ«gu mikropakalpojumu slÄni, kas veido vidi un konteineru domÄna biznesa loÄ£ikas izpildei, un noformÄt domÄna datu noturÄ«bu kÄ atseviŔķs ļoti vienkÄrÅ”u un vieglu mikropakalpojumu slÄnis. Biznesa procesi Å”ajÄ gadÄ«jumÄ veic noturÄ«bas slÄÅa pakalpojumu orÄ·estrÄÅ”anu.
Å ai pieejai ir ļoti liela priekÅ”rocÄ«ba: jÅ«s varat palielinÄt platformas funkcionalitÄti, cik vien vÄlaties, un tikai atbilstoÅ”ais platformas mikropakalpojumu slÄnis no tÄ kļūs āresnsā. Biznesa procesi no jebkura domÄna var nekavÄjoties izmantot jauno platformas funkcionalitÄti, tiklÄ«dz tÄ tiek atjauninÄta.
platformas pakalpojums, kas vienlaikus izpilda daudzu domÄnu biznesa loÄ£iku, rada lielus riskus kÄ vienu neveiksmes punktu. Biežas biznesa loÄ£ikas izmaiÅas palielina kļūdu risku, kas izraisa visas sistÄmas kļūmes;
veiktspÄjas problÄmas: biznesa loÄ£ika strÄdÄ ar saviem datiem, izmantojot Å”auru un lÄnu saskarni:
dati atkal tiks sakÄrtoti un pÄrsÅ«knÄti caur tÄ«kla steku;
domÄna pakalpojums bieži nodroÅ”ina vairÄk datu, nekÄ nepiecieÅ”ams biznesa loÄ£ikas apstrÄdei, jo nav pietiekamu iespÄju parametrizÄt pieprasÄ«jumus pakalpojuma ÄrÄjÄ API lÄ«menÄ«;
vairÄkas neatkarÄ«gas biznesa loÄ£ikas daļas var atkÄrtoti pieprasÄ«t tos paÅ”us datus apstrÄdei (Å”o problÄmu var mazinÄt, pievienojot sesijas komponentus, kas saglabÄ datus keÅ”atmiÅÄ, taÄu tas vÄl vairÄk sarežģī arhitektÅ«ru un rada datu atbilstÄ«bas un keÅ”atmiÅas nederÄ«guma problÄmas);
darÄ«juma problÄmas:
biznesa procesi ar pastÄvÄ«gu stÄvokli, ko glabÄ platformas pakalpojums, neatbilst domÄna datiem, un nav vienkÄrÅ”u veidu, kÄ Å”o problÄmu atrisinÄt;
domÄna datu bloÄ·ÄÅ”anas izvietoÅ”ana Ärpus darÄ«juma: ja domÄna biznesa loÄ£ikÄ ir jÄveic izmaiÅas pÄc kÄrtÄjo datu pareizÄ«bas pirmÄs pÄrbaudes, ir jÄizslÄdz iespÄja veikt konkurÄtspÄjÄ«gas izmaiÅas apstrÄdÄtajos datos. ÄrÄjo datu bloÄ·ÄÅ”ana var palÄ«dzÄt atrisinÄt problÄmu, taÄu Å”Äds risinÄjums rada papildu riskus un samazina sistÄmas kopÄjo uzticamÄ«bu;
papildu grÅ«tÄ«bas atjauninÄÅ”anas laikÄ: dažos gadÄ«jumos pastÄvÄ«bas pakalpojums un biznesa loÄ£ika ir jÄatjaunina sinhroni vai stingrÄ secÄ«bÄ.
Galu galÄ mums bija jÄatgriežas pie pamatiem: jÄiekapsulÄ domÄna dati un domÄna biznesa loÄ£ika vienÄ mikropakalpojumÄ. Å Ä« pieeja vienkÄrÅ”o mikropakalpojuma uztveri kÄ sistÄmas neatÅemamu sastÄvdaļu un nerada iepriekÅ” minÄtÄs problÄmas. Tas arÄ« netiek sniegts bez maksas:
API standartizÄcija ir nepiecieÅ”ama mijiedarbÄ«bai ar biznesa loÄ£iku (jo Ä«paÅ”i, lai nodroÅ”inÄtu lietotÄja darbÄ«bas kÄ daļu no biznesa procesiem) un API platformas pakalpojumiem; prasa rÅ«pÄ«gÄku uzmanÄ«bu API izmaiÅÄm, uz priekÅ”u un atpakaļ saderÄ«bu;
ir nepiecieÅ”ams pievienot papildu izpildlaika bibliotÄkas, lai nodroÅ”inÄtu biznesa loÄ£ikas funkcionÄÅ”anu kÄ daļu no katra Å”Äda mikropakalpojuma, un tas rada jaunas prasÄ«bas Å”ÄdÄm bibliotÄkÄm: vieglums un pÄrejas atkarÄ«bu minimums;
biznesa loÄ£ikas izstrÄdÄtÄjiem ir jÄuzrauga bibliotÄku versijas: ja mikropakalpojums ilgu laiku nav pabeigts, visticamÄk, tas saturÄs novecojuÅ”u bibliotÄku versiju. Tas var bÅ«t negaidÄ«ts ŔķÄrslis jauna lÄ«dzekļa pievienoÅ”anai un var bÅ«t nepiecieÅ”ams migrÄt Å”Äda pakalpojuma veco biznesa loÄ£iku uz jaunÄm bibliotÄku versijÄm, ja starp versijÄm ir notikuÅ”as nesaderÄ«gas izmaiÅas.
Å ÄdÄ arhitektÅ«rÄ ir arÄ« platformas pakalpojumu slÄnis, taÄu Å”is slÄnis vairs neveido konteineru domÄna biznesa loÄ£ikas izpildei, bet tikai tÄ vidi, nodroÅ”inot papildu āplatformasā funkcijas. Å Äds slÄnis ir nepiecieÅ”ams ne tikai, lai saglabÄtu domÄna mikropakalpojumu vieglo raksturu, bet arÄ« lai centralizÄtu pÄrvaldÄ«bu.
PiemÄram, lietotÄju darbÄ«bas biznesa procesos Ä£enerÄ uzdevumus. TomÄr, strÄdÄjot ar uzdevumiem, lietotÄjam uzdevumi no visiem domÄniem ir jÄredz vispÄrÄjÄ sarakstÄ, kas nozÄ«mÄ, ka ir jÄbÅ«t atbilstoÅ”am platformas uzdevumu reÄ£istrÄcijas pakalpojumam, kas atbrÄ«vots no domÄna biznesa loÄ£ikas. UzÅÄmÄjdarbÄ«bas loÄ£ikas iekapsulÄÅ”anas saglabÄÅ”ana Å”ÄdÄ kontekstÄ ir diezgan problemÄtiska, un tas ir vÄl viens Ŕīs arhitektÅ«ras kompromiss.
Biznesa procesu integrÄcija ar lietojumprogrammu izstrÄdÄtÄja acÄ«m
KÄ minÄts iepriekÅ”, lietojumprogrammu izstrÄdÄtÄjam ir jÄbÅ«t abstrahÄtam no vairÄku lietojumprogrammu mijiedarbÄ«bas ievieÅ”anas tehniskajÄm un inženiertehniskajÄm iezÄ«mÄm, lai varÄtu paļauties uz labu izstrÄdes produktivitÄti.
MÄÄ£inÄsim atrisinÄt diezgan sarežģītu integrÄcijas problÄmu, kas Ä«paÅ”i izdomÄta rakstam. Å is bÅ«s āspÄļuā uzdevums, kas ietver trÄ«s lietojumprogrammas, kur katra no tÄm definÄ noteiktu domÄna nosaukumu: āapp1ā, āapp2ā, āapp3ā.
KatrÄ lietojumprogrammÄ tiek palaisti biznesa procesi, kas sÄk āspÄlÄt bumbuā, izmantojot integrÄcijas kopni. ZiÅojumi ar nosaukumu āBumbaā darbosies kÄ bumba.
SpÄles noteikumi:
pirmais spÄlÄtÄjs ir iniciators. ViÅÅ” uzaicina uz spÄli citus spÄlÄtÄjus, sÄk spÄli un var to beigt jebkurÄ laikÄ;
pÄrÄjie spÄlÄtÄji deklarÄ savu dalÄ«bu spÄlÄ, āiepazÄ«stā viens otru un pirmo spÄlÄtÄju;
pÄc bumbas saÅemÅ”anas spÄlÄtÄjs izvÄlas citu dalÄ«bnieku un piespÄlÄ viÅam bumbu. Tiek skaitÄ«ts kopÄjais sÅ«tÄ«jumu skaits;
Katram spÄlÄtÄjam ir "enerÄ£ija", kas samazinÄs ar katru Ŕī spÄlÄtÄja bumbas piespÄli. Kad enerÄ£ija beidzas, spÄlÄtÄjs pamet spÄli, paziÅojot par izstÄÅ”anos;
ja spÄlÄtÄjs paliek viens, viÅÅ” nekavÄjoties paziÅo par savu aizieÅ”anu;
Kad visi spÄlÄtÄji ir izslÄgti, pirmais spÄlÄtÄjs paziÅo, ka spÄle ir beigusies. Ja viÅÅ” pamet spÄli agri, viÅam ir jÄseko spÄlei, lai to pabeigtu.
Lai atrisinÄtu Å”o problÄmu, es izmantoÅ”u mÅ«su DSL biznesa procesiem, kas ļauj mums kompakti aprakstÄ«t Kotlin loÄ£iku, izmantojot minimÄlu plÄksni.
PirmÄ spÄlÄtÄja (jeb spÄles iniciatora) biznesa process darbosies lietotnÄ app1:
klases InitialPlayer
import ru.krista.bpm.ProcessInstance
import ru.krista.bpm.runtime.ProcessImpl
import ru.krista.bpm.runtime.constraint.UniqueConstraints
import ru.krista.bpm.runtime.dsl.processModel
import ru.krista.bpm.runtime.dsl.taskOperation
import ru.krista.bpm.runtime.instance.MessageSendInstance
data class PlayerInfo(val name: String, val domain: String, val id: String)
class PlayersList : ArrayList<PlayerInfo>()
// ŠŃŠ¾ ŠŗŠ»Š°ŃŃ ŃŠŗŠ·ŠµŠ¼ŠæŠ»ŃŃŠ° ŠæŃŠ¾ŃŠµŃŃŠ°: ŠøŠ½ŠŗŠ°ŠæŃŃŠ»ŠøŃŃŠµŃ ŠµŠ³Š¾ Š²Š½ŃŃŃŠµŠ½Š½ŠµŠµ ŃŠ¾ŃŃŠ¾ŃŠ½ŠøŠµ
class InitialPlayer : ProcessImpl<InitialPlayer>(initialPlayerModel) {
var playerName: String by persistent("Player1")
var energy: Int by persistent(30)
var players: PlayersList by persistent(PlayersList())
var shotCounter: Int = 0
}
// ŠŃŠ¾ Š“ŠµŠŗŠ»Š°ŃŠ°ŃŠøŃ Š¼Š¾Š“ŠµŠ»Šø ŠæŃŠ¾ŃŠµŃŃŠ°: ŃŠ¾Š·Š“Š°ŠµŃŃŃ Š¾Š“ŠøŠ½ ŃŠ°Š·, ŠøŃŠæŠ¾Š»ŃŠ·ŃŠµŃŃŃ Š²ŃŠµŠ¼Šø
// ŃŠŗŠ·ŠµŠ¼ŠæŠ»ŃŃŠ°Š¼Šø ŠæŃŠ¾ŃŠµŃŃŠ° ŃŠ¾Š¾ŃŠ²ŠµŃŃŃŠ²ŃŃŃŠµŠ³Š¾ ŠŗŠ»Š°ŃŃŠ°
val initialPlayerModel = processModel<InitialPlayer>(name = "InitialPlayer",
version = 1) {
// ŠŠ¾ ŠæŃŠ°Š²ŠøŠ»Š°Š¼, ŠæŠµŃŠ²ŃŠ¹ ŠøŠ³ŃŠ¾Šŗ ŃŠ²Š»ŃŠµŃŃŃ ŠøŠ½ŠøŃŠøŠ°ŃŠ¾ŃŠ¾Š¼ ŠøŠ³ŃŃ Šø Š“Š¾Š»Š¶ŠµŠ½ Š±ŃŃŃ ŠµŠ“ŠøŠ½ŃŃŠ²ŠµŠ½Š½ŃŠ¼
uniqueConstraint = UniqueConstraints.singleton
// ŠŠ±ŃŃŠ²Š»ŃŠµŠ¼ Š°ŠŗŃŠøŠ²Š½Š¾ŃŃŠø, ŠøŠ· ŠŗŠ¾ŃŠ¾ŃŃŃ ŃŠ¾ŃŃŠ¾ŠøŃ Š±ŠøŠ·Š½ŠµŃ-ŠæŃŠ¾ŃŠµŃŃ
val sendNewGameSignal = signal<String>("NewGame")
val sendStopGameSignal = signal<String>("StopGame")
val startTask = humanTask("Start") {
taskOperation {
processCondition { players.size > 0 }
confirmation { "ŠŠ¾Š“ŠŗŠ»ŃŃŠøŠ»Š¾ŃŃ ${players.size} ŠøŠ³ŃŠ¾ŠŗŠ¾Š². ŠŠ°ŃŠøŠ½Š°ŠµŠ¼?" }
}
}
val stopTask = humanTask("Stop") {
taskOperation {}
}
val waitPlayerJoin = signalWait<String>("PlayerJoin") { signal ->
players.add(PlayerInfo(
signal.data!!,
signal.sender.domain,
signal.sender.processInstanceId))
println("... join player ${signal.data} ...")
}
val waitPlayerOut = signalWait<String>("PlayerOut") { signal ->
players.remove(PlayerInfo(
signal.data!!,
signal.sender.domain,
signal.sender.processInstanceId))
println("... player ${signal.data} is out ...")
}
val sendPlayerOut = signal<String>("PlayerOut") {
signalData = { playerName }
}
val sendHandshake = messageSend<String>("Handshake") {
messageData = { playerName }
activation = {
receiverDomain = process.players.last().domain
receiverProcessInstanceId = process.players.last().id
}
}
val throwStartBall = messageSend<Int>("Ball") {
messageData = { 1 }
activation = { selectNextPlayer() }
}
val throwBall = messageSend<Int>("Ball") {
messageData = { shotCounter + 1 }
activation = { selectNextPlayer() }
onEntry { energy -= 1 }
}
val waitBall = messageWaitData<Int>("Ball") {
shotCounter = it
}
// Š¢ŠµŠæŠµŃŃ ŠŗŠ¾Š½ŃŃŃŃŠøŃŃŠµŠ¼ Š³ŃŠ°Ń ŠæŃŠ¾ŃŠµŃŃŠ° ŠøŠ· Š¾Š±ŃŃŠ²Š»ŠµŠ½Š½ŃŃ Š°ŠŗŃŠøŠ²Š½Š¾ŃŃŠµŠ¹
startFrom(sendNewGameSignal)
.fork("mainFork") {
next(startTask)
next(waitPlayerJoin).next(sendHandshake).next(waitPlayerJoin)
next(waitPlayerOut)
.branch("checkPlayers") {
ifTrue { players.isEmpty() }
.next(sendStopGameSignal)
.terminate()
ifElse().next(waitPlayerOut)
}
}
startTask.fork("afterStart") {
next(throwStartBall)
.branch("mainLoop") {
ifTrue { energy < 5 }.next(sendPlayerOut).next(waitBall)
ifElse().next(waitBall).next(throwBall).loop()
}
next(stopTask).next(sendStopGameSignal)
}
// ŠŠ°Š²ŠµŃŠ°ŠµŠ¼ Š½Š° Š°ŠŗŃŠøŠ²Š½Š¾ŃŃŠø Š“Š¾ŠæŠ¾Š»Š½ŠøŃŠµŠ»ŃŠ½ŃŠµ Š¾Š±ŃŠ°Š±Š¾ŃŃŠøŠŗŠø Š“Š»Ń Š»Š¾Š³ŠøŃŠ¾Š²Š°Š½ŠøŃ
sendNewGameSignal.onExit { println("Let's play!") }
sendStopGameSignal.onExit { println("Stop!") }
sendPlayerOut.onExit { println("$playerName: I'm out!") }
}
private fun MessageSendInstance<InitialPlayer, Int>.selectNextPlayer() {
val player = process.players.random()
receiverDomain = player.domain
receiverProcessInstanceId = player.id
println("Step ${process.shotCounter + 1}: " +
"${process.playerName} >>> ${player.name}")
}
Papildus biznesa loÄ£ikas izpildei iepriekÅ” minÄtais kods var izveidot biznesa procesa objekta modeli, ko var vizualizÄt diagrammas veidÄ. MÄs vÄl neesam ieviesuÅ”i vizualizÄtÄju, tÄpÄc mums bija jÄpavada nedaudz laika zÄ«mÄÅ”anai (Å”eit es nedaudz vienkÄrÅ”oju BPMN apzÄ«mÄjumu attiecÄ«bÄ uz vÄrtu izmantoÅ”anu, lai uzlabotu diagrammas konsekvenci ar zemÄk esoÅ”o kodu):
app2 ietvers otra spÄlÄtÄja biznesa procesu:
klases RandomPlayer
import ru.krista.bpm.ProcessInstance
import ru.krista.bpm.runtime.ProcessImpl
import ru.krista.bpm.runtime.dsl.processModel
import ru.krista.bpm.runtime.instance.MessageSendInstance
data class PlayerInfo(val name: String, val domain: String, val id: String)
class PlayersList: ArrayList<PlayerInfo>()
class RandomPlayer : ProcessImpl<RandomPlayer>(randomPlayerModel) {
var playerName: String by input(persistent = true,
defaultValue = "RandomPlayer")
var energy: Int by input(persistent = true, defaultValue = 30)
var players: PlayersList by persistent(PlayersList())
var allPlayersOut: Boolean by persistent(false)
var shotCounter: Int = 0
val selfPlayer: PlayerInfo
get() = PlayerInfo(playerName, env.eventDispatcher.domainName, id)
}
val randomPlayerModel = processModel<RandomPlayer>(name = "RandomPlayer",
version = 1) {
val waitNewGameSignal = signalWait<String>("NewGame")
val waitStopGameSignal = signalWait<String>("StopGame")
val sendPlayerJoin = signal<String>("PlayerJoin") {
signalData = { playerName }
}
val sendPlayerOut = signal<String>("PlayerOut") {
signalData = { playerName }
}
val waitPlayerJoin = signalWaitCustom<String>("PlayerJoin") {
eventCondition = { signal ->
signal.sender.processInstanceId != process.id
&& !process.players.any { signal.sender.processInstanceId == it.id}
}
handler = { signal ->
players.add(PlayerInfo(
signal.data!!,
signal.sender.domain,
signal.sender.processInstanceId))
}
}
val waitPlayerOut = signalWait<String>("PlayerOut") { signal ->
players.remove(PlayerInfo(
signal.data!!,
signal.sender.domain,
signal.sender.processInstanceId))
allPlayersOut = players.isEmpty()
}
val sendHandshake = messageSend<String>("Handshake") {
messageData = { playerName }
activation = {
receiverDomain = process.players.last().domain
receiverProcessInstanceId = process.players.last().id
}
}
val receiveHandshake = messageWait<String>("Handshake") { message ->
if (!players.any { message.sender.processInstanceId == it.id}) {
players.add(PlayerInfo(
message.data!!,
message.sender.domain,
message.sender.processInstanceId))
}
}
val throwBall = messageSend<Int>("Ball") {
messageData = { shotCounter + 1 }
activation = { selectNextPlayer() }
onEntry { energy -= 1 }
}
val waitBall = messageWaitData<Int>("Ball") {
shotCounter = it
}
startFrom(waitNewGameSignal)
.fork("mainFork") {
next(sendPlayerJoin)
.branch("mainLoop") {
ifTrue { energy < 5 || allPlayersOut }
.next(sendPlayerOut)
.next(waitBall)
ifElse()
.next(waitBall)
.next(throwBall)
.loop()
}
next(waitPlayerJoin).next(sendHandshake).next(waitPlayerJoin)
next(waitPlayerOut).next(waitPlayerOut)
next(receiveHandshake).next(receiveHandshake)
next(waitStopGameSignal).terminate()
}
sendPlayerJoin.onExit { println("$playerName: I'm here!") }
sendPlayerOut.onExit { println("$playerName: I'm out!") }
}
private fun MessageSendInstance<RandomPlayer, Int>.selectNextPlayer() {
val player = if (process.players.isNotEmpty())
process.players.random()
else
process.selfPlayer
receiverDomain = player.domain
receiverProcessInstanceId = player.id
println("Step ${process.shotCounter + 1}: " +
"${process.playerName} >>> ${player.name}")
}
Diagramma:
App3 lietojumprogrammÄ mÄs padarÄ«sim spÄlÄtÄju ar nedaudz atŔķirÄ«gu uzvedÄ«bu: tÄ vietÄ, lai nejauÅ”i izvÄlÄtos nÄkamo spÄlÄtÄju, viÅÅ” rÄ«kosies saskaÅÄ ar apļa algoritmu:
klases RoundRobinPlayer
import ru.krista.bpm.ProcessInstance
import ru.krista.bpm.runtime.ProcessImpl
import ru.krista.bpm.runtime.dsl.processModel
import ru.krista.bpm.runtime.instance.MessageSendInstance
data class PlayerInfo(val name: String, val domain: String, val id: String)
class PlayersList: ArrayList<PlayerInfo>()
class RoundRobinPlayer : ProcessImpl<RoundRobinPlayer>(roundRobinPlayerModel) {
var playerName: String by input(persistent = true,
defaultValue = "RoundRobinPlayer")
var energy: Int by input(persistent = true, defaultValue = 30)
var players: PlayersList by persistent(PlayersList())
var nextPlayerIndex: Int by persistent(-1)
var allPlayersOut: Boolean by persistent(false)
var shotCounter: Int = 0
val selfPlayer: PlayerInfo
get() = PlayerInfo(playerName, env.eventDispatcher.domainName, id)
}
val roundRobinPlayerModel = processModel<RoundRobinPlayer>(
name = "RoundRobinPlayer",
version = 1) {
val waitNewGameSignal = signalWait<String>("NewGame")
val waitStopGameSignal = signalWait<String>("StopGame")
val sendPlayerJoin = signal<String>("PlayerJoin") {
signalData = { playerName }
}
val sendPlayerOut = signal<String>("PlayerOut") {
signalData = { playerName }
}
val waitPlayerJoin = signalWaitCustom<String>("PlayerJoin") {
eventCondition = { signal ->
signal.sender.processInstanceId != process.id
&& !process.players.any { signal.sender.processInstanceId == it.id}
}
handler = { signal ->
players.add(PlayerInfo(
signal.data!!,
signal.sender.domain,
signal.sender.processInstanceId))
}
}
val waitPlayerOut = signalWait<String>("PlayerOut") { signal ->
players.remove(PlayerInfo(
signal.data!!,
signal.sender.domain,
signal.sender.processInstanceId))
allPlayersOut = players.isEmpty()
}
val sendHandshake = messageSend<String>("Handshake") {
messageData = { playerName }
activation = {
receiverDomain = process.players.last().domain
receiverProcessInstanceId = process.players.last().id
}
}
val receiveHandshake = messageWait<String>("Handshake") { message ->
if (!players.any { message.sender.processInstanceId == it.id}) {
players.add(PlayerInfo(
message.data!!,
message.sender.domain,
message.sender.processInstanceId))
}
}
val throwBall = messageSend<Int>("Ball") {
messageData = { shotCounter + 1 }
activation = { selectNextPlayer() }
onEntry { energy -= 1 }
}
val waitBall = messageWaitData<Int>("Ball") {
shotCounter = it
}
startFrom(waitNewGameSignal)
.fork("mainFork") {
next(sendPlayerJoin)
.branch("mainLoop") {
ifTrue { energy < 5 || allPlayersOut }
.next(sendPlayerOut)
.next(waitBall)
ifElse()
.next(waitBall)
.next(throwBall)
.loop()
}
next(waitPlayerJoin).next(sendHandshake).next(waitPlayerJoin)
next(waitPlayerOut).next(waitPlayerOut)
next(receiveHandshake).next(receiveHandshake)
next(waitStopGameSignal).terminate()
}
sendPlayerJoin.onExit { println("$playerName: I'm here!") }
sendPlayerOut.onExit { println("$playerName: I'm out!") }
}
private fun MessageSendInstance<RoundRobinPlayer, Int>.selectNextPlayer() {
var idx = process.nextPlayerIndex + 1
if (idx >= process.players.size) {
idx = 0
}
process.nextPlayerIndex = idx
val player = if (process.players.isNotEmpty())
process.players[idx]
else
process.selfPlayer
receiverDomain = player.domain
receiverProcessInstanceId = player.id
println("Step ${process.shotCounter + 1}: " +
"${process.playerName} >>> ${player.name}")
}
PretÄjÄ gadÄ«jumÄ spÄlÄtÄja uzvedÄ«ba neatŔķiras no iepriekÅ”ÄjÄs, tÄpÄc diagramma nemainÄs.
Tagad mums ir nepiecieÅ”ams tests, lai to visu izpildÄ«tu. Es doÅ”u tikai paÅ”a testa kodu, lai nepÄrblÄ«vÄtu rakstu (patiesÄ«bÄ es izmantoju iepriekÅ” izveidoto testa vidi, lai pÄrbaudÄ«tu citu biznesa procesu integrÄciju):
No tÄ visa mÄs varam izdarÄ«t vairÄkus svarÄ«gus secinÄjumus:
ar nepiecieÅ”amajiem rÄ«kiem lietojumprogrammu izstrÄdÄtÄji var izveidot integrÄcijas mijiedarbÄ«bu starp lietojumprogrammÄm, nepÄrtraucot biznesa loÄ£iku;
integrÄcijas uzdevuma sarežģītÄ«ba, kam nepiecieÅ”amas inženieru kompetences, var tikt paslÄpts ietvarÄ, ja tas sÄkotnÄji ir iekļauts ietvara arhitektÅ«rÄ. ProblÄmas sarežģītÄ«bu nevar noslÄpt, tÄpÄc sarežģītas problÄmas risinÄjums kodÄ izskatÄ«sies tÄ;
IzstrÄdÄjot integrÄcijas loÄ£iku, obligÄti jÄÅem vÄrÄ iespÄjamÄ konsekvence un visu integrÄcijas dalÄ«bnieku stÄvokļa izmaiÅu linearizÄcijas trÅ«kums. Tas liek mums sarežģīt loÄ£iku, lai padarÄ«tu to nejutÄ«gu pret ÄrÄjo notikumu norises kÄrtÄ«bu. MÅ«su piemÄrÄ spÄlÄtÄjs ir spiests piedalÄ«ties spÄlÄ pÄc tam, kad viÅÅ” ir paziÅojis par izstÄÅ”anos no spÄles: citi spÄlÄtÄji turpinÄs viÅam piespÄlÄt bumbu, lÄ«dz informÄcija par viÅa izstÄÅ”anos sasniegs un to apstrÄdÄs visi dalÄ«bnieki. Å Äda loÄ£ika neizriet no spÄles noteikumiem un ir kompromisa risinÄjums izvÄlÄtÄs arhitektÅ«ras ietvaros.
TÄlÄk mÄs runÄsim par mÅ«su risinÄjuma dažÄdajÄm sarežģītÄ«bÄm, kompromisiem un citiem jautÄjumiem.
Visas ziÅas ir vienÄ rindÄ
Visas integrÄtÄs lietojumprogrammas darbojas ar vienu integrÄcijas kopni, kas tiek parÄdÄ«ta ÄrÄjÄ brokera veidÄ, vienu BPMQueue ziÅojumiem un vienu BPMTopic tÄmu signÄliem (notikumiem). Visu ziÅojumu ievietoÅ”ana vienÄ rindÄ ir kompromiss. Biznesa loÄ£ikas lÄ«menÄ« tagad varat ieviest tik daudz jaunu ziÅojumu veidu, cik vÄlaties, neveicot izmaiÅas sistÄmas struktÅ«rÄ. Tas ir bÅ«tisks vienkÄrÅ”ojums, taÄu tas rada zinÄmus riskus, kas mÅ«su tipisko uzdevumu kontekstÄ mums neŔķita tik nozÄ«mÄ«gi.
TomÄr Å”eit ir viens smalkums: katra lietojumprogramma filtrÄ āsavusā ziÅojumus no rindas pie ieejas pÄc sava domÄna nosaukuma. DomÄnu var norÄdÄ«t arÄ« signÄlos, ja ir jÄierobežo signÄla āredzamÄ«bas jomaā tikai vienai lietojumprogrammai. Tam vajadzÄtu palielinÄt kopnes caurlaidspÄju, bet biznesa loÄ£ikai tagad jÄdarbojas ar domÄna nosaukumiem: ziÅojumu adresÄÅ”anai - obligÄti, signÄliem - vÄlams.
IzvÄlÄtais ziÅojumu brokeris ir svarÄ«ga arhitektÅ«ras sastÄvdaļa un viens atteices punkts: tam ir jÄbÅ«t pietiekami izturÄ«gam pret kļūmÄm. Jums vajadzÄtu izmantot tikai laika pÄrbaudÄ«tas implementÄcijas ar labu atbalstu un lielu kopienu;
nepiecieÅ”ams nodroÅ”inÄt augstu ziÅojumu brokera pieejamÄ«bu, kam tas ir fiziski jÄatdala no integrÄtajÄm aplikÄcijÄm (augstu pieejamÄ«bu lietojumprogrammÄm ar pielietoto biznesa loÄ£iku ir daudz grÅ«tÄk un dÄrgÄk nodroÅ”inÄt);
brokerim ir pienÄkums nodroÅ”inÄt āvismaz vienu reiziā piegÄdes garantijas. TÄ ir obligÄta prasÄ«ba uzticamai integrÄcijas kopnes darbÄ«bai. Nav nepiecieÅ”amas "tieÅ”i vienreiz" lÄ«meÅa garantijas: biznesa procesi parasti nav jutÄ«gi pret atkÄrtotu ziÅojumu vai notikumu ieraÅ”anos, un Ä«paÅ”os uzdevumos, kur tas ir svarÄ«gi, ir vieglÄk pievienot biznesam papildu pÄrbaudes. loÄ£ika nekÄ pastÄvÄ«gi izmantot diezgan ādÄrgasā garantijas;
ziÅojumu un signÄlu sÅ«tÄ«Å”anai jÄbÅ«t iesaistÄ«tai kopÄjÄ darÄ«jumÄ ar izmaiÅÄm biznesa procesu un domÄna datu stÄvoklÄ«. VÄlamÄ iespÄja bÅ«tu izmantot modeli DarÄ«jumu izsÅ«tne, bet tam bÅ«s nepiecieÅ”ama papildu tabula datu bÄzÄ un atkÄrtotÄjs. JEE lietojumprogrammÄs to var vienkÄrÅ”ot, izmantojot vietÄjo JTA menedžeri, bet savienojumam ar izvÄlÄto brokeri ir jÄspÄj darboties XA;
ienÄkoÅ”o ziÅojumu un notikumu apstrÄdÄtÄjiem ir jÄstrÄdÄ arÄ« ar darÄ«jumu, kas maina biznesa procesa stÄvokli: ja Å”Äds darÄ«jums tiek atvilkts, tad ziÅojuma saÅemÅ”ana ir jÄatceļ;
ziÅojumi, kurus nevarÄja piegÄdÄt kļūdu dÄļ, ir jÄuzglabÄ atseviÅ”Ä·Ä krÄtuvÄ D.L.Q. (miruÅ”o vÄstuļu rinda). Å im nolÅ«kam mÄs izveidojÄm atseviŔķu platformas mikropakalpojumu, kas glabÄ Å”Ädus ziÅojumus savÄ krÄtuvÄ, indeksÄ tos pÄc atribÅ«tiem (Ätrai grupÄÅ”anai un meklÄÅ”anai) un pakļauj API apskatei, atkÄrtotai nosÅ«tÄ«Å”anai uz mÄrÄ·a adresi un ziÅojumu dzÄÅ”anai. SistÄmas administratori var strÄdÄt ar Å”o pakalpojumu, izmantojot savu tÄ«mekļa saskarni;
brokera iestatÄ«jumos ir jÄpielÄgo piegÄdes atkÄrtojumu skaits un kavÄÅ”anÄs starp piegÄdÄm, lai samazinÄtu iespÄju, ka ziÅojumi nonÄks DLQ (optimÄlos parametrus aprÄÄ·inÄt gandrÄ«z neiespÄjami, taÄu var rÄ«koties empÄ«riski un pielÄgot tos darbÄ«bas laikÄ );
DLQ veikals ir nepÄrtraukti jÄuzrauga, un pÄrraudzÄ«bas sistÄmai ir jÄbrÄ«dina sistÄmas administratori, lai, ja rodas nepiegÄdÄti ziÅojumi, viÅi varÄtu reaÄ£Ät pÄc iespÄjas ÄtrÄk. Tas samazinÄs kļūmes vai biznesa loÄ£ikas kļūdas āietekmÄto zonuā;
integrÄcijas kopnei ir jÄbÅ«t nejutÄ«gai pret Ä«slaicÄ«gu lietojumprogrammu neesamÄ«bu: tÄmas abonementiem ir jÄbÅ«t noturÄ«giem, un lietojumprogrammas domÄna nosaukumam jÄbÅ«t unikÄlam, lai, kamÄr lietojumprogramma nav pieejama, kÄds cits nemÄÄ£inÄtu apstrÄdÄt tÄs ziÅojumus no rindÄ.
Biznesa loÄ£ikas pavedienu droŔības nodroÅ”inÄÅ”ana
Viena un tÄ pati biznesa procesa instance var saÅemt vairÄkus ziÅojumus un notikumus vienlaikus, kuru apstrÄde sÄksies paralÄli. TajÄ paÅ”Ä laikÄ lietojumprogrammu izstrÄdÄtÄjam visam jÄbÅ«t vienkÄrÅ”am un droÅ”am.
Procesa biznesa loÄ£ika apstrÄdÄ katru ÄrÄjo notikumu, kas ietekmÄ Å”o biznesa procesu atseviŔķi. Å Ädi notikumi varÄtu bÅ«t:
biznesa procesa instances palaiŔana;
lietotÄja darbÄ«ba, kas saistÄ«ta ar darbÄ«bu biznesa procesÄ;
ziÅojuma vai signÄla saÅemÅ”ana, kurai ir abonÄta biznesa procesa instance;
biznesa procesa instances iestatÄ«ta taimera iedarbinÄÅ”ana;
kontrolÄt darbÄ«bu, izmantojot API (piemÄram, procesa pÄrtraukums).
Katrs Å”Äds notikums var mainÄ«t biznesa procesa gadÄ«juma stÄvokli: dažas darbÄ«bas var beigties un citas var sÄkties, un pastÄvÄ«go Ä«paŔību vÄrtÄ«bas var mainÄ«ties. Jebkuras darbÄ«bas aizvÄrÅ”ana var izraisÄ«t vienas vai vairÄku tÄlÄk norÄdÄ«to darbÄ«bu aktivizÄÅ”anu. Tie, savukÄrt, var pÄrtraukt gaidÄ«t citus notikumus vai, ja viÅiem nav nepiecieÅ”ami nekÄdi papildu dati, var pabeigt to paÅ”u darÄ«jumu. Pirms darÄ«juma slÄgÅ”anas jaunais biznesa procesa stÄvoklis tiek saglabÄts datu bÄzÄ, kur tas gaidÄ«s nÄkamo ÄrÄjo notikumu.
PastÄvÄ«gi biznesa procesu dati, kas tiek glabÄti relÄciju datu bÄzÄ, ir ļoti Ärts punkts apstrÄdes sinhronizÄÅ”anai, ja izmantojat SELECT FOR UPDATE. Ja vienam darÄ«jumam izdevÄs iegÅ«t biznesa procesa stÄvokli no tÄ maiÅas bÄzes, tad neviens cits paralÄli darÄ«jums nevarÄs iegÅ«t tÄdu paÅ”u stÄvokli citai izmaiÅai, un pÄc pirmÄ darÄ«juma pabeigÅ”anas tiek veikts otrais. garantÄta saÅemt jau mainÄ«to stÄvokli.
Izmantojot pesimistiskÄs slÄdzenes DBVS pusÄ, mÄs izpildÄm visas nepiecieÅ”amÄs prasÄ«bas ACID, kÄ arÄ« saglabÄ iespÄju mÄrogot lietojumprogrammu ar biznesa loÄ£iku, palielinot darbojoÅ”os gadÄ«jumu skaitu.
TomÄr pesimistiskas slÄdzenes mÅ«s draud ar strupceļu, kas nozÄ«mÄ, ka SELECT FOR UPDATE joprojÄm ir jÄierobežo lÄ«dz noteiktam saprÄtÄ«gam taimautam gadÄ«jumam, ja dažos ÄrkÄrtÄ«gos biznesa loÄ£ikas gadÄ«jumos rodas strupceļŔ.
VÄl viena problÄma ir biznesa procesa sÄkuma sinhronizÄcija. KamÄr nav biznesa procesa gadÄ«juma, datu bÄzÄ nav stÄvokļa, tÄpÄc aprakstÄ«tÄ metode nedarbosies. Ja jums ir jÄnodroÅ”ina biznesa procesa instances unikalitÄte noteiktÄ tvÄrumÄ, tad jums bÅ«s nepiecieÅ”ams sava veida sinhronizÄcijas objekts, kas saistÄ«ts ar procesa klasi un atbilstoÅ”o tvÄrumu. Lai atrisinÄtu Å”o problÄmu, mÄs izmantojam citu bloÄ·ÄÅ”anas mehÄnismu, kas ļauj mums bloÄ·Ät patvaļīgu resursu, kas norÄdÄ«ts ar atslÄgu URI formÄtÄ, izmantojot ÄrÄju pakalpojumu.
MÅ«su piemÄros InitialPlayer biznesa process satur deklarÄciju
uniqueConstraint = UniqueConstraints.singleton
TÄpÄc žurnÄlÄ ir ziÅojumi par atbilstoÅ”Äs atslÄgas slÄdzenes paÅemÅ”anu un atlaiÅ”anu. Citiem biznesa procesiem Å”Ädu ziÅojumu nav: unikÄls ierobežojums nav iestatÄ«ts.
Biznesa procesu problÄmas ar pastÄvÄ«gu stÄvokli
Dažreiz pastÄvÄ«gs stÄvoklis ne tikai palÄ«dz, bet arÄ« patieÅ”Äm kavÄ attÄ«stÄ«bu.
ProblÄmas sÄkas tad, kad ir jÄveic izmaiÅas biznesa loÄ£ikÄ un/vai biznesa procesa modelÄ«. Ne visas Å”Ädas izmaiÅas ir savietojamas ar veco biznesa procesu stÄvokli. Ja datu bÄzÄ ir daudz reÄllaika instanÄu, tad nesaderÄ«gu izmaiÅu veikÅ”ana var radÄ«t daudz nepatikÅ”anas, ar kurÄm bieži saskÄrÄmies, lietojot jBPM.
AtkarÄ«bÄ no izmaiÅu dziļuma varat rÄ«koties divos veidos:
izveidojiet jaunu biznesa procesa veidu, lai neveiktu nesaderÄ«gas izmaiÅas vecajÄ, un izmantojiet to vecÄ vietÄ, palaižot jaunas instances. VecÄs kopijas turpinÄs darboties ākÄ lÄ«dz Å”imā;
migrÄjiet pastÄvÄ«go biznesa procesu stÄvokli, atjauninot biznesa loÄ£iku.
Pirmais veids ir vienkÄrÅ”Äks, taÄu tam ir savi ierobežojumi un trÅ«kumi, piemÄram:
biznesa loÄ£ikas dublÄÅ”anÄs daudzos biznesa procesu modeļos, palielinot biznesa loÄ£ikas apjomu;
Bieži vien ir nepiecieÅ”ama tÅ«lÄ«tÄja pÄreja uz jaunu biznesa loÄ£iku (integrÄcijas uzdevumu ziÅÄ - gandrÄ«z vienmÄr);
izstrÄdÄtÄjs nezina, kurÄ brÄ«dÄ« novecojuÅ”os modeļus var izdzÄst.
PraksÄ mÄs izmantojam abas pieejas, taÄu esam pieÅÄmuÅ”i vairÄkus lÄmumus, lai atvieglotu mÅ«su dzÄ«vi:
Datu bÄzÄ biznesa procesa pastÄvÄ«gais stÄvoklis tiek glabÄts viegli lasÄmÄ un viegli apstrÄdÄjamÄ formÄ: JSON formÄta virknÄ. Tas ļauj veikt migrÄciju gan lietojumprogrammÄ, gan ÄrÄji. KÄ pÄdÄjo lÄ«dzekli varat to labot manuÄli (Ä«paÅ”i noderÄ«gi izstrÄdÄ atkļūdoÅ”anas laikÄ);
integrÄcijas biznesa loÄ£ikÄ netiek izmantoti biznesa procesu nosaukumi, lai jebkurÄ brÄ«dÄ« bÅ«tu iespÄja viena iesaistÄ«tÄ procesa ievieÅ”anu aizstÄt ar jaunu ar jaunu nosaukumu (piemÄram, āInitialPlayerV2ā). SaistÄ«Å”ana notiek ar ziÅojumu un signÄlu nosaukumiem;
procesa modelim ir versijas numurs, kuru mÄs palielinÄm, ja Å”ajÄ modelÄ« veicam nesaderÄ«gas izmaiÅas, un Å”is numurs tiek saglabÄts kopÄ ar procesa instances stÄvokli;
procesa noturÄ«gais stÄvoklis vispirms tiek nolasÄ«ts no datu bÄzes ÄrtÄ objekta modelÄ«, ar kuru var strÄdÄt migrÄcijas procedÅ«ra, ja ir mainÄ«jies modeļa versijas numurs;
migrÄcijas procedÅ«ra tiek novietota blakus biznesa loÄ£ikai un tiek saukta par "slinku" katram biznesa procesa gadÄ«jumam tÄ atjaunoÅ”anas laikÄ no datu bÄzes;
ja nepiecieÅ”ams Ätri un sinhroni migrÄt visu procesu gadÄ«jumu stÄvokli, tiek izmantoti klasiskÄki datu bÄzes migrÄcijas risinÄjumi, taÄu jÄstrÄdÄ ar JSON.
Vai jums ir nepiecieŔams cits biznesa procesu ietvars?
RakstÄ aprakstÄ«tie risinÄjumi ļÄva bÅ«tiski vienkÄrÅ”ot mÅ«su dzÄ«vi, paplaÅ”inÄt lietojumprogrammu izstrÄdes lÄ«menÄ« atrisinÄto problÄmu loku un padarÄ«t pievilcÄ«gÄku ideju par biznesa loÄ£ikas nodalÄ«Å”anu mikropakalpojumos. Lai to panÄktu, tika ieguldÄ«ts liels darbs, izveidots ļoti āvieglsā biznesa procesu ietvars, kÄ arÄ« servisa komponenti, lai atrisinÄtu konstatÄtÄs problÄmas visdažÄdÄko aplikÄciju problÄmu kontekstÄ. MÄs vÄlamies dalÄ«ties ar Å”iem rezultÄtiem un padarÄ«t kopÄ«gu komponentu izstrÄdi atvÄrtu piekļuvi saskaÅÄ ar bezmaksas licenci. Tas prasÄ«s zinÄmas pÅ«les un laiku. Izpratne par pieprasÄ«jumu pÄc Å”Ädiem risinÄjumiem mums varÄtu bÅ«t papildu stimuls. PiedÄvÄtajÄ rakstÄ Ä¼oti maz uzmanÄ«bas tiek pievÄrsts paÅ”a ietvara iespÄjÄm, taÄu dažas no tÄm ir redzamas no sniegtajiem piemÄriem. Ja mÄs publicÄsim savu sistÄmu, tam tiks veltÄ«ts atseviŔķs raksts. TikmÄr bÅ«sim pateicÄ«gi, ja atstÄsiet nelielu atsauksmi, atbildot uz jautÄjumu:
AptaujÄ var piedalÄ«ties tikai reÄ£istrÄti lietotÄji. Ielogoties, lÅ«dzu.
Vai jums ir nepiecieŔams cits biznesa procesu ietvars?
18,8%JÄ, es kaut ko tÄdu meklÄju jau ilgu laiku
12,5%Mani interesÄ uzzinÄt vairÄk par jÅ«su ievieÅ”anu, tas varÄtu bÅ«t noderÄ«gi2
6,2%MÄs izmantojam vienu no esoÅ”ajiem ietvariem, bet domÄjam par nomaiÅu1
18,8%Izmantojam vienu no esoÅ”ajiem karkasiem, viss kÄrtÄ«bÄ3