BPM ቅጥ ውህደት

BPM ቅጥ ውህደት

ታዲያስ, ሀብር!

ኩባንያችን የኢአርፒ-ክፍል የሶፍትዌር መፍትሄዎችን በማዘጋጀት ላይ ያተኮረ ሲሆን ከእነዚህ ውስጥ የአንበሳውን ድርሻ የሚይዘው በከፍተኛ የንግድ አመክንዮ እና የሰነድ ፍሰት በ ላ EDMS ነው። አሁን ያሉት የምርቶቻችን ስሪቶች በJavaEE ቴክኖሎጂዎች ላይ የተመሰረቱ ናቸው፣ ነገር ግን በማይክሮ ሰርቪስ ላይ በንቃት እየሞከርን ነው። የእንደዚህ አይነት መፍትሄዎች በጣም ችግር ካለባቸው አካባቢዎች አንዱ ከጎን ያሉት ጎራዎች የሆኑ የተለያዩ ንዑስ ስርዓቶችን ማቀናጀት ነው። የምንጠቀመው የስነ-ህንፃ ስታይል፣ የቴክኖሎጂ ቁልል እና ማዕቀፎች ምንም ቢሆኑም የውህደት ችግሮች ሁሌም ትልቅ ራስ ምታት ይሰጡናል፣ነገር ግን በቅርብ ጊዜ እንደዚህ አይነት ችግሮችን በመፍታት ረገድ መሻሻል ታይቷል።

ወደ እርስዎ ትኩረት ባመጣሁት ጽሑፍ ውስጥ NPO "Krista" በተሰየመው ቦታ ስላለው ልምድ እና የስነ-ህንፃ ጥናት እናገራለሁ. እንዲሁም ለውህደት ችግር ቀላል መፍትሄን ከመተግበሪያ ገንቢ እይታ አንጻር እንመለከታለን እና ከዚህ ቀላልነት በስተጀርባ ምን እንደተደበቀ ለማወቅ እንሞክራለን.

ማስተባበያ

በአንቀጹ ውስጥ የተገለጹት የስነ-ህንፃ እና ቴክኒካል መፍትሄዎች በተወሰኑ ስራዎች አውድ ውስጥ በግል ልምድ ላይ በመመርኮዝ በእኔ ቀርበዋል. እነዚህ መፍትሄዎች ሁለንተናዊ ናቸው ብለው አይናገሩም እና በሌሎች የአጠቃቀም ሁኔታዎች ውስጥ ጥሩ ላይሆኑ ይችላሉ።

BPM ከእሱ ጋር ምን ግንኙነት አለው?

ይህንን ጥያቄ ለመመለስ፣ የመፍትሄዎቻችንን ተግባራዊ ችግሮች በዝርዝር በጥልቀት መመርመር አለብን። በእኛ የተለመደው የግብይት ስርዓት ውስጥ ያለው የንግድ አመክንዮ ዋና አካል መረጃን በተጠቃሚ በይነገጽ ፣በእጅ እና በራስ-ሰር በማጣራት ይህንን ውሂብ ወደ ዳታቤዝ ውስጥ በማስገባት በአንዳንድ የስራ ሂደቶች በማከናወን ፣ ወደ ሌላ ስርዓት / የትንታኔ ዳታቤዝ / ማህደር በማተም ፣ ሪፖርቶችን በማመንጨት ነው። . ስለዚህ ለደንበኞች የስርዓቱ ቁልፍ ተግባር ውስጣዊ የንግድ ሂደታቸውን አውቶማቲክ ማድረግ ነው.

ለምቾት ሲባል “ሰነድ” የሚለውን ቃል በግንኙነት ውስጥ የምንጠቀመው የተወሰነ የስራ ፍሰት “ሊያያዝ” በሚችል የጋራ ቁልፍ የተዋሃደ የውሂብ ስብስብ እንደ ማጠቃለያ ነው።
ግን ስለ ውህደት አመክንዮስ? ከሁሉም በላይ ፣ የውህደት ተግባሩ የተፈጠረው በስርዓቱ አርክቴክቸር ነው ፣ በደንበኛው ጥያቄ ሳይሆን ወደ ክፍሎች “የተቆረጠ” ፣ ግን ሙሉ በሙሉ በተለያዩ ምክንያቶች ተጽዕኖ ስር ነው ።

  • በኮንዌይ ህግ ተገዢ;
  • ቀደም ሲል ለሌሎች ምርቶች የተገነቡ ንዑስ ስርዓቶችን እንደገና ጥቅም ላይ በማዋል ምክንያት;
  • ተግባራዊ ባልሆኑ መስፈርቶች ላይ በመመስረት በአርክቴክቱ ውሳኔ.

የንግድ አመክንዮ በውህደት ቅርሶች እንዳይበክል እና የአፕሊኬሽኑን ገንቢ የስርዓቱን የስነ-ህንፃ መልከአምድር ገፅታዎች በጥልቀት የመመልከት አስፈላጊነትን ለማስታገስ የውህደት ሎጂክን ከዋናው የስራ ሂደት የንግድ አመክንዮ ለመለየት ትልቅ ፈተና አለ። ይህ አካሄድ በርካታ ጥቅሞች አሉት ፣ ግን ልምምድ ውጤታማነቱን ያሳያል ።

  • የውህደት ችግሮችን መፍታት ብዙውን ጊዜ በዋናው የስራ ሂደት አፈፃፀም ላይ ባለው ውስን የኤክስቴንሽን ነጥቦች ምክንያት በተመሳሰለ ጥሪ መልክ ወደ ቀላሉ አማራጮች ይመለሳል (የተመሳሰለ ውህደት ጉዳቶች ከዚህ በታች ተብራርተዋል)።
  • ከሌላ ንዑስ ስርዓት ግብረመልስ በሚያስፈልግበት ጊዜ የመዋሃድ ቅርሶች አሁንም ወደ ዋና የንግድ ሎጂክ ውስጥ ይገባሉ ።
  • የመተግበሪያው ገንቢ ውህደቱን ችላ በማለት እና የስራ ሂደቱን በመለወጥ በቀላሉ ሊሰብረው ይችላል;
  • ስርዓቱ ከተጠቃሚው እይታ አንድ ሙሉ መሆን ያቆማል ፣ በንዑስ ስርዓቶች መካከል “ስፌት” ይስተዋላል ፣ እና ብዙ የተጠቃሚ ክዋኔዎች ይታያሉ ፣ ይህም ውሂብ ከአንድ ንዑስ ስርዓት ወደ ሌላ ማስተላለፍ ይጀምራል።

ሌላው አቀራረብ የውህደት ግንኙነቶችን እንደ ዋናው የንግድ ሎጂክ እና የስራ ሂደት ዋና አካል አድርጎ መቁጠር ነው። የአፕሊኬሽን ገንቢ ብቃቶች ወደ ሰማይ እንዳይሄዱ ለመከላከል፣ አዲስ የውህደት መስተጋብር መፍጠር ቀላል እና ጥረት የለሽ መሆን አለበት፣ መፍትሄን ለመምረጥ አነስተኛ አማራጮች። ይህን ለማድረግ ከሚመስለው በላይ ከባድ ነው፡ መሳሪያው ለተጠቃሚው “ራሱን በእግሩ ላይ እንዲተኩስ” ሳይፈቅድለት ለተጠቃሚው የሚፈለጉትን የተለያዩ አማራጮችን ለማቅረብ የሚያስችል ሃይለኛ መሆን አለበት። አንድ መሐንዲስ በውህደት ተግባራት አውድ ውስጥ ሊመልሳቸው የሚገባቸው ብዙ ጥያቄዎች አሉ ነገር ግን አፕሊኬሽኑ ገንቢ በእለት ተዕለት ስራው ሊያስብባቸው የማይገባባቸው፡ የግብይት ወሰን፣ ወጥነት፣ ተውኔትነት፣ ደህንነት፣ ሚዛን፣ ጭነት እና የሃብት ስርጭት፣ መስመር፣ ማርሻል፣ የስርጭት እና የመቀያየር አውዶች ወዘተ. የመተግበሪያ ገንቢዎች በትክክል ቀላል የመፍትሄ አብነቶችን ማቅረብ አስፈላጊ ነው, ለእንደዚህ አይነት ጥያቄዎች ሁሉ መልሶች ቀድሞውኑ ተደብቀዋል. እነዚህ አብነቶች በትክክል ደህና መሆን አለባቸው፡ የንግድ አመክንዮ በጣም ብዙ ጊዜ ይለወጣል፣ ይህም ስህተቶችን የማስተዋወቅ አደጋን ይጨምራል፣ የስህተቶች ዋጋ በዝቅተኛ ደረጃ ላይ መቆየት አለበት።

ግን BPM ከእሱ ጋር ምን ግንኙነት አለው? የስራ ሂደትን ለመተግበር ብዙ አማራጮች አሉ።
በእውነቱ ፣ ሌላ የንግድ ሥራ ሂደቶች ትግበራ በእኛ መፍትሄዎች ውስጥ በጣም ታዋቂ ነው - በግዛት ሽግግር ዲያግራም መግለጫ መግለጫ እና ለሽግግሮች የንግድ አመክንዮ ተቆጣጣሪዎች ግንኙነት። በዚህ ጉዳይ ላይ የ "ሰነዱ" በንግድ ሥራ ሂደት ውስጥ ያለውን ወቅታዊ አቋም የሚወስነው ግዛት የ "ሰነዱ" የራሱ ባህሪ ነው.

BPM ቅጥ ውህደት
በፕሮጀክት ጅምር ላይ ሂደቱ ይህን ይመስላል

የዚህ ትግበራ ተወዳጅነት ቀጥተኛ የንግድ ሂደቶችን በመፍጠር አንጻራዊ ቀላልነት እና ፍጥነት ምክንያት ነው. ሆኖም፣ የሶፍትዌር ሲስተሞች ይበልጥ ውስብስብ ሲሆኑ፣ አውቶሜትድ የሆነው የንግዱ ሂደት አካል ያድጋል እና የበለጠ ውስብስብ ይሆናል። እያንዳንዱ ቅርንጫፍ በትይዩ እንዲፈፀም የመበስበስ, የሂደቶችን ክፍሎች እንደገና ጥቅም ላይ ማዋል, እንዲሁም የቅርንጫፎችን ሂደቶች ያስፈልጉታል. በእንደዚህ ዓይነት ሁኔታዎች ውስጥ መሳሪያው የማይመች ይሆናል, እና የስቴት ሽግግር ዲያግራም የመረጃ ይዘቱን ያጣል (የውህደት ግንኙነቶች በስዕሉ ውስጥ በጭራሽ አይታዩም).

BPM ቅጥ ውህደት
ከብዙ ተደጋጋሚ መስፈርቶች ማብራሪያ በኋላ ሂደቱ ይህን ይመስላል።

ከዚህ ሁኔታ መውጣት የሞተርን ውህደት ነበር jBPM በጣም ውስብስብ ከሆኑ የንግድ ሂደቶች ጋር ወደ አንዳንድ ምርቶች። በአጭር ጊዜ ውስጥ ይህ መፍትሔ የተወሰነ ስኬት ነበረው-በማስታወሻው ውስጥ በትክክል መረጃ ሰጭ እና ተዛማጅ ዲያግራምን እየጠበቁ ውስብስብ የንግድ ሂደቶችን ተግባራዊ ማድረግ ተችሏል. BPMN2.

BPM ቅጥ ውህደት
ውስብስብ የንግድ ሂደት ትንሽ ክፍል

በረጅም ጊዜ ውስጥ, መፍትሔው የሚጠበቀውን ያህል አልኖረም: በምስላዊ መሳሪያዎች አማካኝነት የንግድ ሂደቶችን ለመፍጠር ያለው ከፍተኛ የጉልበት ሥራ ተቀባይነት ያለው የምርታማነት አመልካቾችን ለማግኘት አልፈቀደም, እና መሳሪያው ራሱ በገንቢዎች መካከል በጣም የማይወደዱ ናቸው. በተጨማሪም ስለ ሞተሩ ውስጣዊ መዋቅር ቅሬታዎች ነበሩ, ይህም ብዙ "ፕላቶች" እና "ክራች" እንዲታዩ አድርጓል.

jBPMን የመጠቀም ዋናው አወንታዊ ገጽታ የንግድ ሥራ ሂደት ምሳሌ የራሱ የሆነ ቋሚ ሁኔታ መኖሩን ጥቅሙን እና ጉዳቱን ማወቅ ነው። በተለያዩ አፕሊኬሽኖች መካከል ውስብስብ ውህደት ፕሮቶኮሎችን በምልክቶች እና በመልእክቶች በመጠቀም ያልተመሳሰሉ ግንኙነቶችን ለመተግበር የሂደት አቀራረብን የመጠቀም እድልን አይተናል። በዚህ ውስጥ የማያቋርጥ ሁኔታ መኖሩ ወሳኝ ሚና ይጫወታል.

ከላይ በተጠቀሰው መሠረት መደምደም እንችላለን- በ BPM ዘይቤ ውስጥ ያለው የሂደት አቀራረብ ከጊዜ ወደ ጊዜ ውስብስብ የንግድ ሥራ ሂደቶችን በራስ-ሰር ለማሠራት ፣ የውህደት እንቅስቃሴዎችን ወደ እነዚህ ሂደቶች ለማስማማት እና የተተገበረውን ሂደት በተመጣጣኝ ማስታወሻ የማሳየት ችሎታን ለመጠበቅ ሰፊ ሥራዎችን ለመፍታት ያስችለናል።

የተመሳሰለ ጥሪዎች ጉዳቶች እንደ የውህደት ንድፍ

የተመሳሰለ ውህደት ቀላሉን የማገድ ጥሪን ያመለክታል። አንድ ንዑስ ስርዓት እንደ አገልጋይ ጎን ሆኖ የሚሰራ እና ኤፒአይን በሚፈለገው ዘዴ ያጋልጣል። ሌላ ንዑስ ስርዓት ከደንበኛው ጎን ሆኖ ይሠራል እና በትክክለኛው ጊዜ ጥሪ ያደርጋል እና ውጤቱን ይጠብቃል። በስርዓቱ አርክቴክቸር ላይ በመመስረት የደንበኛው እና የአገልጋይ ጎኖች በአንድ መተግበሪያ እና ሂደት ውስጥ ወይም በተለያዩ ውስጥ ሊገኙ ይችላሉ። በሁለተኛው ጉዳይ ላይ አንዳንድ የ RPC አተገባበርን መተግበር እና የመለኪያዎችን እና የጥሪውን ውጤት ማርሻል መስጠት ያስፈልግዎታል.

BPM ቅጥ ውህደት

ይህ የመዋሃድ ንድፍ በጣም ትልቅ የድክመቶች ስብስብ አለው, ነገር ግን በቀላልነቱ ምክንያት በተግባር በሰፊው ጥቅም ላይ ይውላል. የአተገባበሩ ፍጥነት ይማርካል እና የግዜ ገደቦችን በሚገጥሙበት ጊዜ ደጋግመው እንዲጠቀሙበት ያስገድድዎታል, መፍትሄውን እንደ ቴክኒካል ዕዳ ይመዘግባል. ነገር ግን ልምድ የሌላቸው ገንቢዎች ሳያውቁት ሲጠቀሙበት ይከሰታል, በቀላሉ አሉታዊ መዘዞችን አይገነዘቡም.

በንዑስ ስርዓት ግንኙነት ውስጥ በጣም ግልጽ ከሚሆነው ጭማሪ በተጨማሪ፣ “በማደግ” እና “በመለጠጥ” ግብይቶች ላይ ብዙም ግልጽ ያልሆኑ ችግሮችም አሉ። በእርግጥ, የቢዝነስ አመክንዮ አንዳንድ ለውጦችን ካደረገ, ግብይቶችን ማስቀረት አይቻልም, እና ግብይቶች, በተራው, በእነዚህ ለውጦች የተጎዱ የተወሰኑ የመተግበሪያ ሃብቶችን ያግዱ. ማለትም አንዱ ንዑስ ስርዓት ከሌላው ምላሽ እስኪጠብቅ ድረስ ግብይቱን ማጠናቀቅ እና መቆለፊያዎቹን ማስወገድ አይችልም። ይህም የተለያዩ ተፅዕኖዎችን የመጋለጥ እድልን በእጅጉ ይጨምራል.

  • የስርዓቱ ምላሽ ሰጪነት ጠፍቷል, ተጠቃሚዎች ለጥያቄዎች መልስ ለማግኘት ረጅም ጊዜ ይጠብቃሉ;
  • በተጨናነቀ የክር ገንዳ ምክንያት አገልጋዩ በአጠቃላይ ለተጠቃሚ ጥያቄዎች ምላሽ መስጠት ያቆማል፡ አብዛኛው ክሮች በግብይት በተያዘ ግብአት ላይ ተቆልፈዋል።
  • Deadlocks መታየት ይጀምራል: ያላቸውን ክስተት እድላቸው በጥብቅ ግብይቶች ቆይታ ላይ, የንግድ ሎጂክ እና ግብይቱ ውስጥ ተሳታፊ መቆለፊያዎች መጠን ላይ ይወሰናል;
  • የግብይት ጊዜ ማብቂያ ስህተቶች ይታያሉ;
  • ስራው ከፍተኛ መጠን ያለው ውሂብን ማቀናበር እና መለወጥ የሚፈልግ ከሆነ አገልጋዩ ከ OutOfMemory ጋር “ይወድቃል” እና የተመሳሰለ ውህደቶች መኖራቸው ሂደቱን ወደ “ቀላል” ግብይቶች ለመከፋፈል በጣም ከባድ ያደርገዋል።

ከሥነ ሕንፃ እይታ አንፃር ፣ በውህደት ወቅት ጥሪዎችን ማገድ የግለሰቦችን ንዑስ ስርዓቶች ጥራት ላይ ቁጥጥርን ወደ ማጣት ያመራል-የአንድ ንዑስ ስርዓት ከሌላ ንዑስ ስርዓት የጥራት አመልካቾች ተነጥሎ የአንድን ንዑስ ስርዓት ዒላማ የጥራት አመልካቾችን ማረጋገጥ አይቻልም። ንዑስ ስርዓቶች በተለያዩ ቡድኖች የተገነቡ ከሆነ, ይህ ትልቅ ችግር ነው.

እየተዋሃዱ ያሉት ንዑስ ስርዓቶች በተለያዩ አፕሊኬሽኖች ውስጥ ከሆኑ እና በሁለቱም በኩል ተመሳሳይ ለውጦችን ማድረግ ካለብዎት ነገሮች የበለጠ አስደሳች ይሆናሉ። የእነዚህን ለውጦች ግብይት እንዴት ማረጋገጥ ይቻላል?

በተለዩ ግብይቶች ውስጥ ለውጦች ከተደረጉ ፣ ከዚያ አስተማማኝ ልዩ አያያዝ እና ማካካሻ ማቅረብ ያስፈልግዎታል ፣ እና ይህ የተመሳሰለ ውህደት ዋና ጥቅሞችን ሙሉ በሙሉ ያስወግዳል - ቀላልነት።

የተከፋፈሉ ግብይቶችም ወደ አእምሯቸው ይመጣሉ, ነገር ግን በመፍትሄዎቻችን ውስጥ አንጠቀምባቸውም: አስተማማኝነትን ማረጋገጥ አስቸጋሪ ነው.

"ሳጋ" ለግብይት ችግር መፍትሄ ሆኖ

በማይክሮ አገልግሎቶች ተወዳጅነት እየጨመረ በመምጣቱ ፍላጎት የሳጋ ንድፍ.

ይህ ንድፍ ከላይ የተጠቀሱትን የረጅም ጊዜ ግብይቶች ችግሮች በትክክል ይፈታል ፣ እንዲሁም የስርዓቱን ሁኔታ ከንግድ አመክንዮ ጎን የመምራት አቅሞችን ያሰፋዋል-ከተሳካ ግብይት በኋላ የሚከፈለው ማካካሻ ስርዓቱን ወደ ቀድሞው ሁኔታ መመለስ አይችልም ፣ ግን ያቅርቡ። አማራጭ የውሂብ ሂደት መንገድ. ይህ ደግሞ ሂደቱን ወደ "ጥሩ" መጨረሻ ለማምጣት በሚሞክርበት ጊዜ በተሳካ ሁኔታ የተጠናቀቁ የውሂብ ሂደት ደረጃዎችን ከመድገም እንዲቆጠቡ ያስችልዎታል.

የሚገርመው ነገር፣ በሞኖሊቲክ ሲስተም ውስጥ ይህ ስርዓተ-ጥለት እንዲሁ ልቅ የተጣመሩ ንዑስ ስርዓቶችን ወደ ውህደት ሲመጣ ጠቃሚ ነው እና ለረጅም ጊዜ በሚቆዩ ግብይቶች ምክንያት የሚመጡ አሉታዊ ተፅእኖዎች እና ተዛማጅ የንብረት መቆለፊያዎች ይስተዋላሉ።

ከቢዝነስ ሂደታችን ጋር በተያያዘ በBPM ዘይቤ፣ “ሳጋስ”ን መተግበር በጣም ቀላል ሆኖ ተገኝቷል፡ የ“ሳጋ” ግለሰባዊ እርምጃዎች በንግድ ሂደቱ ውስጥ እንደ እንቅስቃሴዎች ሊገለጹ ይችላሉ ፣ እና የንግድ ሥራው ቀጣይነት ያለው ሁኔታ እንዲሁ። የ "ሳጋ" ውስጣዊ ሁኔታን ይወስናል. ማለትም፣ ምንም ተጨማሪ የማስተባበር ዘዴ አንፈልግም። የሚያስፈልግህ እንደ መጓጓዣ "ቢያንስ አንድ ጊዜ" ዋስትናዎችን የሚደግፍ የመልዕክት ደላላ ብቻ ነው.

ግን ይህ መፍትሔ የራሱ “ዋጋ” አለው፡-

  • የንግድ ሼል አመክንዮ የበለጠ የተወሳሰበ ይሆናል: ማካካሻ መስራት ያስፈልጋል;
  • በተለይ ለሞኖሊቲክ ስርዓቶች ስሜታዊ ሊሆን የሚችል ሙሉ ወጥነትን መተው አስፈላጊ ይሆናል ።
  • አርክቴክቱ ትንሽ የተወሳሰበ ይሆናል፣ እና ተጨማሪ የመልእክት ደላላ ፍላጎት ይታያል።
  • ተጨማሪ የክትትል እና የአስተዳደር መሳሪያዎች ያስፈልጋሉ (ምንም እንኳን በአጠቃላይ ይህ ጥሩ ቢሆንም የስርዓት አገልግሎት ጥራት ይጨምራል).

ለሞኖሊቲክ ስርዓቶች, "Sag" ለመጠቀም ማረጋገጫው በጣም ግልጽ አይደለም. ለማይክሮ ሰርቪስ እና ሌሎች SOA ፣ ምናልባት ቀድሞውኑ ደላላ አለ ፣ እና በፕሮጀክቱ መጀመሪያ ላይ ሙሉ ወጥነት የሚሠዋበት ፣ ይህንን ንድፍ የመጠቀም ጥቅሞቹ ከጉዳቱ በእጅጉ ሊበልጡ ይችላሉ ፣ በተለይም በንግድ አመክንዮ ውስጥ ምቹ ኤፒአይ ካለ። ደረጃ.

በማይክሮ አገልግሎቶች ውስጥ የንግድ ሎጂክን ማጠናቀር

በማይክሮ ሰርቪስ መሞከር ስንጀምር ምክንያታዊ ጥያቄ ተነሳ፡ የጎራ ውሂብን ዘላቂነት ከሚያረጋግጥ አገልግሎት ጋር በተያያዘ የጎራ ንግድ አመክንዮ የት ነው ማስቀመጥ ያለበት?

የተለያዩ ቢፒኤምኤስዎችን አርክቴክቸር ስንመለከት፣ የንግድ ሎጂክን ከፅናት መለየት ምክንያታዊ ሊመስል ይችላል፡ የመድረክ ንብርብር እና ከጎራ ነፃ የሆኑ ማይክሮ አገልገሎቶች የጎራ ቢዝነስ ሎጂክን ለማስፈጸም አካባቢ እና መያዣ ይፍጠሩ፣ እና የጎራ ውሂብን ጽናት እንደ በጣም ቀላል እና ቀላል ክብደት ያላቸው ማይክሮ ሰርቪስ የተለየ ንብርብር. በዚህ ጉዳይ ላይ የንግድ ሥራ ሂደቶች የቋሚነት ንብርብር አገልግሎቶችን ኦርኬስትራ ያከናውናሉ.

BPM ቅጥ ውህደት

ይህ አቀራረብ በጣም ትልቅ ጥቅም አለው: የፈለጉትን ያህል የመድረክን ተግባራዊነት ማሳደግ ይችላሉ, እና ተጓዳኝ የመድረክ ማይክሮ ሰርቪስ ሽፋን ብቻ ከዚህ "ስብ" ይሆናል. ከየትኛውም ጎራ የሚመጡ የንግድ ሂደቶች ልክ እንደዘመነ የመሳሪያ ስርዓቱን አዲሱን ተግባር መጠቀም ይችላሉ።

የበለጠ ዝርዝር ጥናት የዚህ ዘዴ ጉልህ ጉዳቶችን አሳይቷል-

  • የብዙ ጎራዎችን የንግድ አመክንዮ በአንድ ጊዜ የሚያስፈጽም የመድረክ አገልግሎት እንደ አንድ የውድቀት ነጥብ ትልቅ አደጋዎችን ያስከትላል። በቢዝነስ አመክንዮ ላይ ተደጋጋሚ ለውጦች ወደ ስርአተ-ሰፊ ውድቀቶች የሚያመሩ ስህተቶችን የመጋለጥ እድልን ይጨምራሉ;
  • የአፈጻጸም ጉዳዮች፡ የንግድ አመክንዮ ከውሂቡ ጋር በጠባብ እና ቀርፋፋ በይነገጽ ይሰራል፡
    • ውሂቡ እንደገና ይጣበቃል እና በአውታረመረብ ቁልል ውስጥ ይወጣል ፣
    • በአገልግሎቱ ውጫዊ ኤፒአይ ደረጃ ላይ ያሉ ጥያቄዎችን ለመለካት በቂ አቅም ባለመኖሩ የጎራ አገልግሎት ለንግድ አመክንዮ ሂደት ከሚያስፈልገው በላይ ብዙ መረጃዎችን ይሰጣል።
    • በርካታ ገለልተኛ የንግድ ሼል አመክንዮዎች ተመሳሳይ ውሂብን ለማስኬድ ደጋግመው ሊጠይቁ ይችላሉ (ይህ ችግር የሚሸጎጥ የክፍለ-ጊዜ ክፍሎችን በመጨመር ሊቀንስ ይችላል ፣ ግን ይህ የበለጠ አርክቴክቸርን ያወሳስበዋል እና የውሂብ ተዛማጅነት እና የመሸጎጫ ውድቅነት ችግሮች ይፈጥራል)
  • የግብይት ችግሮች፡-
    • በመድረክ አገልግሎት የተከማቸ ቀጣይነት ያለው የንግድ ሼል ሂደቶች ከጎራ መረጃ ጋር የማይጣጣሙ ናቸው ፣ እና ይህንን ችግር ለመፍታት ቀላል መንገዶች የሉም ።
    • የጎራ መረጃን ከግብይቱ ውጭ ማገድ፡- የጎራ ንግድ አመክንዮ መጀመሪያ የአሁኑን ውሂብ ትክክለኛነት ካጣራ በኋላ ለውጦችን ማድረግ ከፈለገ በተሰራው ውሂብ ላይ የውድድር ለውጥ ሊኖር እንደሚችል ማስቀረት ያስፈልጋል። የውጭ መረጃን ማገድ ችግሩን ለመፍታት ይረዳል, ነገር ግን እንዲህ ዓይነቱ መፍትሔ ተጨማሪ አደጋዎችን ያስከትላል እና የስርዓቱን አጠቃላይ አስተማማኝነት ይቀንሳል;
  • በሚዘምንበት ጊዜ ተጨማሪ ችግሮች፡ በአንዳንድ ሁኔታዎች የጽናት አገልግሎት እና የንግድ አመክንዮ በተመሳሳይ ጊዜ ወይም በጥብቅ ቅደም ተከተል መዘመን አለባቸው።

በመጨረሻ፣ ወደ መሰረታዊ ነገሮች መመለስ ነበረብን፡ የጎራ መረጃን እና የዶሜይን ንግድ አመክንዮ ወደ አንድ ማይክሮ አገልግሎት መሸፈን። ይህ አካሄድ ማይክሮ ሰርቪስ እንደ የስርዓቱ ዋና አካል ያለውን ግንዛቤ ቀላል ያደርገዋል እና ከላይ የተጠቀሱትን ችግሮች አያመጣም. ይህ እንዲሁ በነጻ አይሰጥም፡-

  • ከንግድ አመክንዮ (በተለይ የተጠቃሚ እንቅስቃሴዎችን እንደ የንግድ ሂደቶች አካል ለማቅረብ) እና የኤፒአይ መድረክ አገልግሎቶችን ለግንኙነት የኤፒአይ ደረጃ ማበጀት ያስፈልጋል። ለኤፒአይ ለውጦች፣ ወደ ፊት እና ወደ ኋላ ተኳሃኝነት የበለጠ ጥንቃቄ ይጠይቃል።
  • የቢዝነስ አመክንዮ አሠራር እንደ እያንዳንዱ የጥቃቅን አገልግሎት አካል ለማረጋገጥ ተጨማሪ የሩጫ ጊዜ ቤተ-መጻሕፍት መጨመር አስፈላጊ ነው, እና ይህ ለእንደዚህ ዓይነቶቹ ቤተ-መጻሕፍት አዳዲስ መስፈርቶችን ያመጣል: ቀላልነት እና አነስተኛ የመሸጋገሪያ ጥገኛዎች;
  • የንግድ አመክንዮ ገንቢዎች የቤተ-መጻህፍት ስሪቶችን መከታተል አለባቸው-ማይክሮ አገልግሎት ለረጅም ጊዜ ካልተጠናቀቀ ምናልባት ብዙ ጊዜ ያለፈበት የቤተ-መጻሕፍት ሥሪት ይይዛል። ይህ አዲስ ባህሪን ለመጨመር ያልተጠበቀ እንቅፋት ሊሆን ይችላል እና በስሪቶች መካከል የማይጣጣሙ ለውጦች ካሉ የድሮውን የቢዝነስ አመክንዮ ወደ አዲስ የቤተ-መጽሐፍት ስሪቶች ማዛወርን ሊጠይቅ ይችላል።

BPM ቅጥ ውህደት

የመድረክ አገልግሎቶች ንብርብር በእንደዚህ ዓይነት አርክቴክቸር ውስጥም አለ ፣ ግን ይህ ንብርብር ከአሁን በኋላ የጎራ የንግድ ሥራ አመክንዮ ለማስፈጸሚያ መያዣ አይፈጥርም ፣ ግን አካባቢው ብቻ ነው ፣ ረዳት “የመሣሪያ ስርዓት” ተግባራትን ይሰጣል። እንዲህ ዓይነቱ ንብርብር የሚያስፈልገው የጎራ ማይክሮ አገልግሎትን ቀላል ክብደት ለመጠበቅ ብቻ ሳይሆን አስተዳደርን ለማማለልም ጭምር ነው.

ለምሳሌ, በንግድ ሂደቶች ውስጥ የተጠቃሚ እንቅስቃሴዎች ተግባራትን ያመነጫሉ. ነገር ግን፣ ከተግባሮች ጋር ሲሰራ ተጠቃሚው በአጠቃላይ ዝርዝሩ ውስጥ ከሁሉም ጎራዎች የተውጣጡ ተግባራትን ማየት አለበት፣ ይህ ማለት ከጎራ ቢዝነስ አመክንዮ የጸዳ ተዛማጅ የመሳሪያ ስርዓት ተግባር ምዝገባ አገልግሎት መኖር አለበት። በእንደዚህ ዓይነት አውድ ውስጥ የንግድ ሥራ አመክንዮዎችን ማቆየት በጣም ችግር ያለበት ነው ፣ እና ይህ የዚህ አርክቴክቸር ሌላ ስምምነት ነው።

በመተግበሪያ ገንቢ ዓይኖች በኩል የንግድ ሂደቶችን ማቀናጀት

ከላይ እንደተገለፀው አንድ ሰው በጥሩ ልማት ምርታማነት ላይ እንዲተማመን የመተግበሪያ ገንቢ ከብዙ አፕሊኬሽኖች መስተጋብር ከመተግበሩ ቴክኒካል እና ምህንድስና ባህሪያት መገለል አለበት።

በተለይ ለጽሑፉ የተፈለሰፈውን በጣም አስቸጋሪ የሆነ የውህደት ችግር ለመፍታት እንሞክር። ይህ ሶስት መተግበሪያዎችን የሚያካትት የ"ጨዋታ" ተግባር ይሆናል፣እያንዳንዳቸው የተወሰነውን የጎራ ስም የሚገልጹበት፡ "app1", "app2", "app3".

በእያንዳንዱ መተግበሪያ ውስጥ በውህደት አውቶቡስ በኩል "ኳስ መጫወት" የሚጀምሩ የንግድ ሂደቶች ተጀምረዋል. "ኳስ" የሚል ስም ያላቸው መልዕክቶች እንደ ኳስ ይሠራሉ.

የጨዋታው ህግጋት:

  • የመጀመሪያው ተጫዋች አስጀማሪ ነው። ሌሎች ተጫዋቾችን ወደ ጨዋታው ይጋብዛል, ጨዋታውን ይጀምራል እና በማንኛውም ጊዜ ሊያጠናቅቀው ይችላል;
  • ሌሎች ተጫዋቾች በጨዋታው ውስጥ ያላቸውን ተሳትፎ ያውጃሉ, እርስ በእርስ እና የመጀመሪያውን ተጫዋች "መተዋወቅ";
  • ኳሱን ከተቀበለ በኋላ ተጫዋቹ ሌላ ተሳታፊ ተጫዋች ይመርጣል እና ኳሱን ለእሱ ያስተላልፋል። አጠቃላይ የማስተላለፊያዎች ብዛት ይቆጠራል;
  • እያንዳንዱ ተጫዋች በእያንዳንዱ የኳስ ቅብብል የሚቀንስ “ጉልበት” አለው። ኃይሉ ሲያልቅ ተጫዋቹ ጨዋታውን ለቅቆ መውጣቱን በማስታወቅ;
  • ተጫዋቹ ብቻውን ከተተወ ወዲያውኑ መውጣቱን ያስታውቃል;
  • ሁሉም ተጫዋቾች ሲወገዱ የመጀመሪያው ተጫዋች ጨዋታው መጠናቀቁን ያውጃል። ጨዋታውን ቀደም ብሎ ከተተወ ጨዋታውን ለማጠናቀቅ ጨዋታውን ለመከታተል ይቀራል።

ይህንን ችግር ለመፍታት የእኛን DSL ለንግድ ሂደቶች እጠቀማለሁ, ይህም በኮትሊን ውስጥ ያለውን አመክንዮ በትንሹ በትንሹ ቦይለር ለመግለጽ ያስችለናል.

የመጀመሪያው ተጫዋች (የጨዋታው ጀማሪ በመባል የሚታወቀው) የንግድ ሂደት በመተግበሪያ1 መተግበሪያ ውስጥ ይሰራል፡-

ክፍል የመጀመሪያ ተጫዋች

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

የንግድ ሥራ አመክንዮ ከማስፈጸም በተጨማሪ፣ ከላይ ያለው ኮድ የንግድ ሥራ ሂደትን ሞዴል ሊያወጣ ይችላል፣ ይህም በሥዕላዊ መግለጫ መልክ ይታያል። ምስላዊ ማድረጊያውን እስካሁን አልተተገበርነውም፣ ስለዚህ እሱን ለመሳል ትንሽ ጊዜ ማሳለፍ ነበረብን (እዚህ ላይ የዲያግራሙን ወጥነት ከተሰጠው ኮድ ጋር ለማሻሻል የበር አጠቃቀምን በተመለከተ የ BPMN ማስታወሻን በትንሹ ቀለል አድርጌዋለሁ)

BPM ቅጥ ውህደት

app2 የሌላውን ተጫዋች የንግድ ሂደት ያካትታል፡-

ክፍል 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}")
}

ሥዕል

BPM ቅጥ ውህደት

በመተግበሪያ 3 አፕሊኬሽን ውስጥ ትንሽ ለየት ያለ ባህሪ ያለው ተጫዋች እንሰራለን፡ በአጋጣሚ የሚቀጥለውን ተጫዋች ከመምረጥ ይልቅ በክብ ሮቢን ስልተ ቀመር መሰረት ይሰራል፡

ክፍል 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}")
}

አለበለዚያ የተጫዋቹ ባህሪ ከቀዳሚው አይለይም, ስለዚህ ስዕሉ አይለወጥም.

አሁን ይህንን ሁሉ ለማስኬድ ፈተና ያስፈልገናል. የፈተናውን ኮድ ብቻ እሰጣለሁ ፣ ጽሑፉን በቦይለር ሳህኖች እንዳያደናቅፍ (በእርግጥ ፣ የሌሎችን የንግድ ሂደቶች ውህደት ለመፈተሽ ቀደም ሲል የተፈጠረውን የሙከራ አካባቢ ተጠቀምኩ)

የሙከራ ጨዋታ()

@Test
public void testGame() throws InterruptedException {
    String pl2 = startProcess(app2, "RandomPlayer", playerParams("Player2", 20));
    String pl3 = startProcess(app2, "RandomPlayer", playerParams("Player3", 40));
    String pl4 = startProcess(app3, "RoundRobinPlayer", playerParams("Player4", 25));
    String pl5 = startProcess(app3, "RoundRobinPlayer", playerParams("Player5", 35));
    String pl1 = startProcess(app1, "InitialPlayer");
    // Теперь нужно немного подождать, пока игроки "познакомятся" друг с другом.
    // Ждать через sleep - плохое решение, зато самое простое. 
    // Не делайте так в серьезных тестах!
    Thread.sleep(1000);
    // Запускаем игру, закрывая пользовательскую активность
    assertTrue(closeTask(app1, pl1, "Start"));
    app1.getWaiting().waitProcessFinished(pl1);
    app2.getWaiting().waitProcessFinished(pl2);
    app2.getWaiting().waitProcessFinished(pl3);
    app3.getWaiting().waitProcessFinished(pl4);
    app3.getWaiting().waitProcessFinished(pl5);
}

private Map<String, Object> playerParams(String name, int energy) {
    Map<String, Object> params = new HashMap<>();
    params.put("playerName", name);
    params.put("energy", energy);
    return params;
}

ፈተናውን እናካሂድና መዝገቡን እንመልከት፡-

የኮንሶል ውፅዓት

Взята блокировка ключа lock://app1/process/InitialPlayer
Let's play!
Снята блокировка ключа lock://app1/process/InitialPlayer
Player2: I'm here!
Player3: I'm here!
Player4: I'm here!
Player5: I'm here!
... join player Player2 ...
... join player Player4 ...
... join player Player3 ...
... join player Player5 ...
Step 1: Player1 >>> Player3
Step 2: Player3 >>> Player5
Step 3: Player5 >>> Player3
Step 4: Player3 >>> Player4
Step 5: Player4 >>> Player3
Step 6: Player3 >>> Player4
Step 7: Player4 >>> Player5
Step 8: Player5 >>> Player2
Step 9: Player2 >>> Player5
Step 10: Player5 >>> Player4
Step 11: Player4 >>> Player2
Step 12: Player2 >>> Player4
Step 13: Player4 >>> Player1
Step 14: Player1 >>> Player4
Step 15: Player4 >>> Player3
Step 16: Player3 >>> Player1
Step 17: Player1 >>> Player2
Step 18: Player2 >>> Player3
Step 19: Player3 >>> Player1
Step 20: Player1 >>> Player5
Step 21: Player5 >>> Player1
Step 22: Player1 >>> Player2
Step 23: Player2 >>> Player4
Step 24: Player4 >>> Player5
Step 25: Player5 >>> Player3
Step 26: Player3 >>> Player4
Step 27: Player4 >>> Player2
Step 28: Player2 >>> Player5
Step 29: Player5 >>> Player2
Step 30: Player2 >>> Player1
Step 31: Player1 >>> Player3
Step 32: Player3 >>> Player4
Step 33: Player4 >>> Player1
Step 34: Player1 >>> Player3
Step 35: Player3 >>> Player4
Step 36: Player4 >>> Player3
Step 37: Player3 >>> Player2
Step 38: Player2 >>> Player5
Step 39: Player5 >>> Player4
Step 40: Player4 >>> Player5
Step 41: Player5 >>> Player1
Step 42: Player1 >>> Player5
Step 43: Player5 >>> Player3
Step 44: Player3 >>> Player5
Step 45: Player5 >>> Player2
Step 46: Player2 >>> Player3
Step 47: Player3 >>> Player2
Step 48: Player2 >>> Player5
Step 49: Player5 >>> Player4
Step 50: Player4 >>> Player2
Step 51: Player2 >>> Player5
Step 52: Player5 >>> Player1
Step 53: Player1 >>> Player5
Step 54: Player5 >>> Player3
Step 55: Player3 >>> Player5
Step 56: Player5 >>> Player2
Step 57: Player2 >>> Player1
Step 58: Player1 >>> Player4
Step 59: Player4 >>> Player1
Step 60: Player1 >>> Player4
Step 61: Player4 >>> Player3
Step 62: Player3 >>> Player2
Step 63: Player2 >>> Player5
Step 64: Player5 >>> Player4
Step 65: Player4 >>> Player5
Step 66: Player5 >>> Player1
Step 67: Player1 >>> Player5
Step 68: Player5 >>> Player3
Step 69: Player3 >>> Player4
Step 70: Player4 >>> Player2
Step 71: Player2 >>> Player5
Step 72: Player5 >>> Player2
Step 73: Player2 >>> Player1
Step 74: Player1 >>> Player4
Step 75: Player4 >>> Player1
Step 76: Player1 >>> Player2
Step 77: Player2 >>> Player5
Step 78: Player5 >>> Player4
Step 79: Player4 >>> Player3
Step 80: Player3 >>> Player1
Step 81: Player1 >>> Player5
Step 82: Player5 >>> Player1
Step 83: Player1 >>> Player4
Step 84: Player4 >>> Player5
Step 85: Player5 >>> Player3
Step 86: Player3 >>> Player5
Step 87: Player5 >>> Player2
Step 88: Player2 >>> Player3
Player2: I'm out!
Step 89: Player3 >>> Player4
... player Player2 is out ...
Step 90: Player4 >>> Player1
Step 91: Player1 >>> Player3
Step 92: Player3 >>> Player1
Step 93: Player1 >>> Player4
Step 94: Player4 >>> Player3
Step 95: Player3 >>> Player5
Step 96: Player5 >>> Player1
Step 97: Player1 >>> Player5
Step 98: Player5 >>> Player3
Step 99: Player3 >>> Player5
Step 100: Player5 >>> Player4
Step 101: Player4 >>> Player5
Player4: I'm out!
... player Player4 is out ...
Step 102: Player5 >>> Player1
Step 103: Player1 >>> Player3
Step 104: Player3 >>> Player1
Step 105: Player1 >>> Player3
Step 106: Player3 >>> Player5
Step 107: Player5 >>> Player3
Step 108: Player3 >>> Player1
Step 109: Player1 >>> Player3
Step 110: Player3 >>> Player5
Step 111: Player5 >>> Player1
Step 112: Player1 >>> Player3
Step 113: Player3 >>> Player5
Step 114: Player5 >>> Player3
Step 115: Player3 >>> Player1
Step 116: Player1 >>> Player3
Step 117: Player3 >>> Player5
Step 118: Player5 >>> Player1
Step 119: Player1 >>> Player3
Step 120: Player3 >>> Player5
Step 121: Player5 >>> Player3
Player5: I'm out!
... player Player5 is out ...
Step 122: Player3 >>> Player5
Step 123: Player5 >>> Player1
Player5: I'm out!
Step 124: Player1 >>> Player3
... player Player5 is out ...
Step 125: Player3 >>> Player1
Step 126: Player1 >>> Player3
Player1: I'm out!
... player Player1 is out ...
Step 127: Player3 >>> Player3
Player3: I'm out!
Step 128: Player3 >>> Player3
... player Player3 is out ...
Player3: I'm out!
Stop!
Step 129: Player3 >>> Player3
Player3: I'm out!

ከዚህ ሁሉ ብዙ ጠቃሚ መደምደሚያዎችን ማድረግ እንችላለን-

  • አስፈላጊ ከሆኑ መሳሪያዎች ጋር የመተግበሪያ ገንቢዎች የንግድ አመክንዮ ሳያቋርጡ በመተግበሪያዎች መካከል የውህደት ግንኙነቶችን መፍጠር ይችላሉ ።
  • የኢንጂነሪንግ ብቃቶችን የሚያስፈልገው የውህደት ተግባር ውስብስብነት በማዕቀፉ ውስጥ ይህ በመጀመሪያ በህንፃው ውስጥ ከተካተተ ሊደበቅ ይችላል። የችግር ችግር ሊደበቅ አይችልም, ስለዚህ በኮድ ውስጥ ላለ አስቸጋሪ ችግር መፍትሄው ይህን ይመስላል;
  • የውህደት አመክንዮ ሲዳብር፣ ውሎ አድሮ ወጥነት ያለው እና በሁሉም የውህደት ተሳታፊዎች ሁኔታ ላይ ያሉ ለውጦች የመስመር አለመቻልን ግምት ውስጥ ማስገባት አስፈላጊ ነው። ይህ ውጫዊ ክስተቶች በሚፈጠሩበት ቅደም ተከተል ላይ ግድየለሽ ለማድረግ አመክንዮ ውስብስብ እንድንሆን ያስገድደናል። በእኛ ምሳሌ, ተጫዋቹ ከጨዋታው መውጣቱን ካወጀ በኋላ በጨዋታው ውስጥ ለመሳተፍ ይገደዳል: ሌሎች ተጫዋቾች ሾለ መውጣቱ መረጃው እስኪደርስ እና በሁሉም ተሳታፊዎች እስኪሰራ ድረስ ኳሱን ማስተላለፋቸውን ይቀጥላሉ. ይህ አመክንዮ ከጨዋታው ህግጋት የተከተለ አይደለም እና በተመረጠው አርክቴክቸር ማዕቀፍ ውስጥ የስምምነት መፍትሄ ነው።

በመቀጠል ስለ የመፍትሄያችን የተለያዩ ውስብስብ ነገሮች, ስምምነቶች እና ሌሎች ነጥቦች እንነጋገራለን.

ሁሉም መልዕክቶች በአንድ ወረፋ ውስጥ ናቸው።

ሁሉም የተቀናጁ አፕሊኬሽኖች ከአንድ የውህደት አውቶቡስ ጋር ይሰራሉ፣ እሱም በውጪ ደላላ መልክ፣ አንድ BPMQueue ለመልእክቶች እና አንድ BPMTopic ርዕስ ለሲግናሎች (ዝግጅቶች)። ሁሉንም መልእክቶች በአንድ ወረፋ ውስጥ ማስቀመጥ በራሱ ስምምነት ነው። በቢዝነስ አመክንዮ ደረጃ፣ አሁን በስርዓቱ መዋቅር ላይ ለውጦችን ሳያደርጉ የፈለጉትን ያህል አዳዲስ የመልእክት አይነቶችን ማስተዋወቅ ይችላሉ። ይህ ጉልህ የሆነ ማቅለል ነው, ነገር ግን የተወሰኑ አደጋዎችን ይይዛል, ይህም በተለመደው ተግባሮቻችን አውድ ውስጥ ለእኛ ያን ያህል አስፈላጊ አይመስልም ነበር.

BPM ቅጥ ውህደት

ነገር ግን፣ እዚህ አንድ ረቂቅ ነገር አለ፡ እያንዳንዱ መተግበሪያ በመግቢያው ላይ ካለው ወረፋ “የሱን” መልዕክቶችን በጎራው ስም ያጣራል። ምልክቱን "የታይነት ወሰን" ወደ አንድ ነጠላ መተግበሪያ መገደብ ካስፈለገዎ ጎራ በሲግናሎች ውስጥ ሊገለጽ ይችላል። ይህ የአውቶቡስ ፍሰት መጨመር አለበት, ነገር ግን የንግድ አመክንዮ አሁን በጎራ ስሞች መስራት አለበት: መልዕክቶችን ለማስተናገድ - አስገዳጅ, ለሲግናሎች - ተፈላጊ.

የውህደት አውቶቡስ አስተማማኝነትን ማረጋገጥ

አስተማማኝነት ብዙ ነጥቦችን ያቀፈ ነው-

  • የተመረጠው መልእክት ደላላ የሕንፃው ወሳኝ አካል እና አንድ የውድቀት ነጥብ ነው፡ በበቂ ሁኔታ ስህተትን የሚቋቋም መሆን አለበት። በጥሩ ድጋፍ እና ትልቅ ማህበረሰብ በጊዜ የተሞከሩ አተገባበርዎችን ብቻ መጠቀም አለብዎት;
  • የመልእክት ደላላ ከፍተኛ ተገኝነትን ማረጋገጥ አስፈላጊ ነው ፣ ለዚህም በአካል ከተዋሃዱ አፕሊኬሽኖች መለየት አለበት (በተግባራዊ የንግድ ሎጂክ ከፍተኛ የመተግበሪያዎች መገኘት ማረጋገጥ የበለጠ ከባድ እና ውድ ነው);
  • ደላላው "ቢያንስ አንድ ጊዜ" የመላኪያ ዋስትናዎችን የመስጠት ግዴታ አለበት. ይህ የውህደት አውቶቡሱ አስተማማኝ ሾል ለመስራት የግዴታ መስፈርት ነው። "በትክክል አንድ ጊዜ" ደረጃ ዋስትናዎች አያስፈልጉም: የንግድ ሂደቶች እንደ አንድ ደንብ, ለመልእክቶች ወይም ለዝግጅቶች ተደጋጋሚ መምጣት ስሜታዊ አይደሉም, እና ይህ አስፈላጊ በሚሆንበት ልዩ ተግባራት ውስጥ, ተጨማሪ ቼኮችን ወደ ንግዱ ለመጨመር ቀላል ነው. በጣም ውድ የሆኑ ዋስትናዎችን ያለማቋረጥ ከመጠቀም ይልቅ አመክንዮ;
  • መልዕክቶችን እና ምልክቶችን መላክ በንግድ ሂደቶች ሁኔታ እና የጎራ ውሂብ ለውጦች ጋር በአጠቃላይ ግብይት ውስጥ መሳተፍ አለበት። የሚመረጠው አማራጭ ስርዓተ-ጥለት መጠቀም ነው የግብይት ሳጥን, ነገር ግን በመረጃ ቋቱ ውስጥ ተጨማሪ ሰንጠረዥ እና ተደጋጋሚ ያስፈልገዋል. በጄኢ አፕሊኬሽኖች ውስጥ፣ ይህ በአካባቢያዊ የጄቲኤ ሾል አስኪያጅ በመጠቀም ማቅለል ይቻላል፣ ነገር ግን ከተመረጠው ደላላ ጋር ያለው ግንኙነት መስራት መቻል አለበት። XA;
  • የገቢ መልዕክቶች እና ክስተቶች ተቆጣጣሪዎች እንዲሁ የንግድ ሂደቱን ሁኔታ ከሚለውጥ ግብይት ጋር መሥራት አለባቸው-እንዲህ ዓይነቱ ግብይት ተመልሶ ከተመለሰ የመልእክቱ ደረሰኝ መሰረዝ አለበት ፣
  • በስህተቶች ምክንያት ሊደርሱ የማይችሉ መልዕክቶች በተለየ ማከማቻ ውስጥ መቀመጥ አለባቸው ዲ.ኤል.ቁ. (የሞተ ደብዳቤ ወረፋ)። ለዚሁ ዓላማ፣ እንደዚህ ያሉ መልዕክቶችን በማከማቻው ውስጥ የሚያከማች፣ በባህሪያት (ለፈጣን ስብስብ እና ፍለጋ) የሚጠቁም እና ኤፒአይን ለማየት፣ ወደ መድረሻ አድራሻ የሚላክ እና መልዕክቶችን የሚሰርዝ የተለየ የመሣሪያ ስርዓት ማይክሮ ሰርቪስ ፈጥረናል። የስርዓት አስተዳዳሪዎች ከዚህ አገልግሎት ጋር በድር በይነገጽ ሊሰሩ ይችላሉ;
  • በደላላ ቅንጅቶች ውስጥ ወደ DLQ የመግባት እድልን ለመቀነስ የመላኪያ ሙከራዎችን እና በመላኪያዎች መካከል መዘግየቶችን ማስተካከል ያስፈልግዎታል (ምርጥ መለኪያዎችን ለማስላት ፈጽሞ የማይቻል ነው ፣ ግን በተግባራዊ ሁኔታ መሥራት እና በሚሠራበት ጊዜ እነሱን ማስተካከል ይችላሉ) );
  • የዲኤልኪው ማከማቻ ያለማቋረጥ ክትትል ሊደረግበት ይገባል፣ እና የክትትል ስርዓቱ የስርዓት አስተዳዳሪዎችን ማሳወቅ አለበት ስለዚህ ያልተላኩ መልእክቶች ሲከሰቱ በተቻለ ፍጥነት ምላሽ መስጠት ይችላሉ። ይህ ውድቀት ወይም የንግድ ሎጂክ ስህተት "የተጎዳውን አካባቢ" ይቀንሳል;
  • የውህደት አውቶቡሱ ለጊዜያዊ የመተግበሪያዎች መቅረት ግድየለሽ መሆን አለበት፡ ለአንድ ርዕስ መመዝገብ ዘላቂ መሆን አለበት እና የመተግበሪያው ስም ልዩ መሆን አለበት ስለዚህ አፕሊኬሽኑ በማይኖርበት ጊዜ ሌላ ሰው መልእክቶቹን ለማስኬድ አይሞክርም። ወረፋ

የንግድ ሎጂክ ክር ደህንነት ማረጋገጥ

የንግድ ሥራ ሂደት ተመሳሳይ ምሳሌ በአንድ ጊዜ ብዙ መልዕክቶችን እና ክስተቶችን ሊቀበል ይችላል ፣ ይህም ሂደት በትይዩ ይጀምራል። በተመሳሳይ ጊዜ, ለመተግበሪያ ገንቢ, ሁሉም ነገር ቀላል እና ክር-አስተማማኝ መሆን አለበት.

የሂደቱ የንግድ አመክንዮ ያንን የንግድ ሂደት በተናጥል የሚጎዳውን እያንዳንዱን ውጫዊ ክስተት ያስኬዳል። እንደዚህ ያሉ ክስተቶች ሊሆኑ ይችላሉ-

  • የንግድ ሼል ሂደት ምሳሌ መጀመር;
  • በንግድ ሂደት ውስጥ ካለው እንቅስቃሴ ጋር የተያያዘ የተጠቃሚ እርምጃ;
  • የንግድ ሼል ሂደት ምሳሌ የተመዘገበበት መልእክት ወይም ምልክት መቀበል;
  • በንግድ ሂደት ምሳሌ የተቀመጠ ሰዓት ቆጣሪ መቀስቀስ;
  • በኤፒአይ በኩል እርምጃን ይቆጣጠሩ (ለምሳሌ የሂደቱ መቋረጥ)።

እያንዳንዱ እንደዚህ ያለ ክስተት የንግድ ሥራ ሂደት ሁኔታን ሊለውጥ ይችላል-አንዳንድ እንቅስቃሴዎች ሊያበቁ እና ሌሎች ሊጀምሩ ይችላሉ እና የቋሚ ንብረቶች እሴቶች ሊለወጡ ይችላሉ። ማንኛውንም እንቅስቃሴ መዝጋት ከሚከተሉት ተግባራት ውስጥ አንዱን ወይም ከዚያ በላይ እንዲነቃ ሊያደርግ ይችላል። እነዚያ, በተራው, ሌሎች ክስተቶችን መጠበቅ ማቆም ይችላሉ ወይም ምንም ተጨማሪ ውሂብ የማያስፈልጋቸው ከሆነ, በተመሳሳይ ግብይት ውስጥ ማጠናቀቅ ይችላሉ. ግብይቱን ከመዘጋቱ በፊት, የንግድ ሥራው አዲስ ሁኔታ በመረጃ ቋቱ ውስጥ ተቀምጧል, የሚቀጥለው የውጭ ክስተት እስኪከሰት ድረስ ይጠብቃል.

በግንኙነት ዳታቤዝ ውስጥ የተከማቸ ቀጣይነት ያለው የንግድ ሥራ ሂደት ውሂብ ለማዘመን ምረጥ ከተጠቀሙ ሂደትን ለማመሳሰል በጣም ምቹ ነጥብ ነው። አንድ ግብይት ለመለወጥ ከመሠረቱ የንግድ ሥራ ሂደትን ሁኔታ ማግኘት ከቻለ ፣ በትይዩ ምንም ዓይነት ግብይት ለሌላ ለውጥ ተመሳሳይ ሁኔታ ማግኘት አይችልም ፣ እና የመጀመሪያው ግብይት ከተጠናቀቀ በኋላ ፣ ሁለተኛው - ቀድሞውኑ የተለወጠውን ሁኔታ ለመቀበል ዋስትና ተሰጥቶታል.

በዲቢኤምኤስ በኩል አፍራሽ መቆለፊያዎችን በመጠቀም ሁሉንም አስፈላጊ መስፈርቶች እናሟላለን። አሲድእንዲሁም የሩጫ አጋጣሚዎችን ቁጥር በመጨመር አፕሊኬሽኑን ከቢዝነስ አመክንዮ ጋር የማመዛዘን ችሎታን ያቆይ።

ነገር ግን፣ ተስፋ አስቆራጭ መቆለፊያዎች የመዝጊያ መቆለፊያዎችን ያስፈራሩናል፣ ይህ ማለት በቢዝነስ አመክንዮ ውስጥ በአንዳንድ ከባድ ጉዳዮች ላይ የሞት መቆለፊያዎች ከተከሰቱ ለዝማኔ ምረጥ አሁንም ለተወሰነ ምክንያታዊ ጊዜ ማብቃት አለበት።

ሌላው ችግር የንግድ ሥራ ጅምር ማመሳሰል ነው. የንግድ ሥራ ሂደት ምንም ዓይነት ሁኔታ ባይኖርም, በውሂብ ጎታ ውስጥ ምንም ግዛት የለም, ስለዚህ የተገለጸው ዘዴ አይሰራም. በአንድ የተወሰነ ወሰን ውስጥ የንግድ ሥራ ሂደት ምሳሌን ልዩነት ማረጋገጥ ከፈለጉ ከሂደቱ ክፍል እና ከተዛማጅ ወሰን ጋር የተያያዘ አንድ ዓይነት የማመሳሰል ነገር ያስፈልግዎታል። ይህንን ችግር ለመፍታት በውጫዊ አገልግሎት በኩል በዩአርአይ ቅርጸት በተገለፀው የዘፈቀደ ግብዓት ላይ መቆለፊያ እንድንወስድ የሚያስችለንን የተለየ የመቆለፍ ዘዴ እንጠቀማለን።

በምሳሌአችን ውስጥ የInitialPlayer የንግድ ሂደት መግለጫ ይዟል

uniqueConstraint = UniqueConstraints.singleton

ስለዚህ, ምዝግብ ማስታወሻው የተዛማጁን ቁልፍ ስለመውሰድ እና ስለ መልቀቅ መልእክቶችን ይዟል. ለሌሎች የንግድ ሂደቶች እንደዚህ አይነት መልዕክቶች የሉም፡ specialConstraint አልተዘጋጀም።

ከቋሚ ሁኔታ ጋር የንግድ ሥራ ሂደቶች ችግሮች

አንዳንድ ጊዜ የማያቋርጥ ሁኔታ መኖሩ ይረዳል, ነገር ግን በእውነቱ እድገትን ያግዳል.
ችግሮች የሚጀምሩት በቢዝነስ አመክንዮ እና/ወይም በቢዝነስ ሂደት ሞዴል ላይ ለውጥ ማድረግ ሲያስፈልግ ነው። ሁሉም እንደዚህ ያሉ ለውጦች ከቀድሞው የንግድ ሥራ ሂደቶች ጋር ተኳሃኝ አይደሉም። በመረጃ ቋቱ ውስጥ ብዙ የቀጥታ ሁኔታዎች ካሉ፣ ተኳሃኝ ያልሆኑ ለውጦችን ማድረግ ብዙ ችግር ሊፈጥር ይችላል፣ ይህም jBPM ስንጠቀም ብዙ ጊዜ ያጋጥመናል።

በለውጦቹ ጥልቀት ላይ በመመስረት በሁለት መንገዶች እርምጃ መውሰድ ይችላሉ-

  1. በአሮጌው ላይ የማይጣጣሙ ለውጦችን ላለማድረግ አዲስ የንግድ ሥራ ሂደት አይነት ይፍጠሩ እና አዲስ አጋጣሚዎችን ሲጀምሩ ከአሮጌው ይልቅ ይጠቀሙበት። የድሮ ቅጂዎች "እንደ ቀድሞው" መስራታቸውን ይቀጥላሉ;
  2. የንግድ ሥራ አመክንዮ በሚያዘምንበት ጊዜ የማያቋርጥ የንግድ ሥራ ሁኔታን ማዛወር።

የመጀመሪያው መንገድ ቀላል ነው, ግን ውሱንነቶች እና ጉዳቶች አሉት, ለምሳሌ:

  • በብዙ የንግድ ሼል ሂደት ሞዴሎች ውስጥ የንግድ ሼል አመክንዮ ማባዛት, የንግድ ሼል አመክንዮ መጨመር;
  • ብዙውን ጊዜ ወደ አዲስ የንግድ ሼል አመክንዮ አፋጣኝ ሽግግር ያስፈልጋል (በመዋሃድ ተግባራት - ሁልጊዜ ማለት ይቻላል);
  • ገንቢው ጊዜ ያለፈባቸው ሞዴሎች በየትኛው ነጥብ ሊሰረዙ እንደሚችሉ አያውቅም።

በተግባር ሁለቱንም አካሄዶች እንጠቀማለን፣ነገር ግን ህይወታችንን ቀላል ለማድረግ በርካታ ውሳኔዎችን ወስነናል፡-

  • በመረጃ ቋቱ ውስጥ፣ የንግዱ ሂደት ቀጣይነት ያለው ሁኔታ በቀላሉ ሊነበብ በሚችል እና በቀላሉ በተሰራ ቅጽ ውስጥ ይከማቻል፡ በJSON ቅርጸት ህብረቁምፊ። ይህ ፍልሰት በመተግበሪያው ውስጥም ሆነ በውጪ እንዲከናወን ያስችላል። እንደ የመጨረሻ አማራጭ, እራስዎ ማረም ይችላሉ (በተለይ በማረም ጊዜ በልማት ውስጥ ጠቃሚ ነው);
  • የውህደት ንግድ አመክንዮ የንግድ ሼል ሂደቶችን ስም አይጠቀምም ፣ ስለሆነም በማንኛውም ጊዜ የአንዱ ተሳታፊ ሂደቶችን ትግበራ በአዲስ ስም በአዲስ መተካት ይቻላል (ለምሳሌ ፣ “InitialPlayerV2”)። ማሰሪያው በመልእክት እና በምልክት ስሞች ይከሰታል;
  • የሂደቱ ሞዴል የስሪት ቁጥር አለው, በዚህ ሞዴል ላይ የማይጣጣሙ ለውጦችን ካደረግን እንጨምራለን, እና ይህ ቁጥር ከሂደቱ ሁኔታ ጋር ተቀምጧል;
  • የሂደቱ ቀጣይነት ያለው ሁኔታ ከመረጃ ቋቱ መጀመሪያ ወደ ምቹ የነገሮች ሞዴል ይነበባል ፣ ይህም የአምሳያው ሥሪት ቁጥር ከተለወጠ የፍልሰት አሰራር ሊሠራ ይችላል ።
  • የፍልሰት ሂደቱ ከንግዱ ሎጂክ ቀጥሎ ተቀምጧል እና ከውሂብ ጎታው በሚታደስበት ጊዜ ለእያንዳንዱ የንግድ ሼል ሂደት “ሰነፍ” ይባላል።
  • የሁሉንም የሂደት ምሳሌዎች ሁኔታ በፍጥነት እና በተመሳሳይ መልኩ ማዛወር ከፈለጉ፣ የበለጠ ክላሲክ የውሂብ ጎታ ፍልሰት መፍትሄዎች ጥቅም ላይ ይውላሉ፣ ግን ከJSON ጋር መስራት አለቦት።

ለንግድ ሥራ ሂደቶች ሌላ ማዕቀፍ ይፈልጋሉ?

በአንቀጹ ውስጥ የተገለጹት መፍትሄዎች ህይወታችንን በከፍተኛ ሁኔታ ለማቃለል, በመተግበሪያው የእድገት ደረጃ ላይ የተፈቱትን ጉዳዮችን ለማስፋት እና የንግድ ሥራ አመክንዮ ወደ ማይክሮ ሰርቪስ የመለየት ሀሳብ የበለጠ ማራኪ እንዲሆን አስችሎናል. ይህንንም ለማሳካት ብዙ ስራዎች ተሰርተዋል, ለንግድ ስራ ሂደቶች በጣም "ቀላል ክብደት" ማዕቀፍ ተፈጥሯል, እንዲሁም ከተለያዩ የመተግበሪያዎች ችግሮች አንፃር ተለይተው የሚታወቁትን ችግሮች ለመፍታት የአገልግሎት ክፍሎች ተፈጥሯል. እነዚህን ውጤቶች ለመጋራት እና የጋራ ክፍሎችን መገንባት በነጻ ፈቃድ ስር ክፍት መዳረሻ ለማድረግ ፍላጎት አለን. ይህ የተወሰነ ጊዜ እና ጥረት ይጠይቃል። የእንደዚህ አይነት መፍትሄዎችን ፍላጎት መረዳታችን ተጨማሪ ማበረታቻ ሊሆን ይችላል። በታቀደው ጽሁፍ ውስጥ, ለእራሱ ማዕቀፍ ችሎታዎች የሚሰጠው ትኩረት በጣም ትንሽ ነው, ነገር ግን አንዳንዶቹ ከቀረቡት ምሳሌዎች ውስጥ ይታያሉ. ማዕቀፋችንን ካተምን, የተለየ ጽሑፍ ለእሱ ተሰጥቷል. እስከዚያው ድረስ፣ ለሚለው ጥያቄ መልስ በመስጠት ትንሽ አስተያየት ብትተውልን እናመሰግናለን።

በዳሰሳ ጥናቱ ውስጥ የተመዘገቡ ተጠቃሚዎች ብቻ መሳተፍ ይችላሉ። ስግን እንእባክህን።

ለንግድ ሥራ ሂደቶች ሌላ ማዕቀፍ ይፈልጋሉ?

  • 18,8%አዎ፣ ይህን የመሰለ ነገር ለረጅም ጊዜ ፈልጌ ነበር።

  • 12,5%ሾለ እርስዎ አተገባበር የበለጠ ለማወቅ ፍላጎት አለኝ፣ ጠቃሚ ሊሆን ይችላል2

  • 6,2%አሁን ካሉት ማዕቀፎች አንዱን እንጠቀማለን፣ ነገር ግን ስለመተካት እያሰብን ነው1

  • 18,8%አሁን ካሉት ማዕቀፎች ውስጥ አንዱን እንጠቀማለን, ሁሉም ነገር ጥሩ ነው3

  • 18,8%ያለ ማዕቀፍ እናስተዳድራለን3

  • 25,0%የአንተን ጻፍ 4

16 ተጠቃሚዎች ድምጽ ሰጥተዋል። 7 ተጠቃሚዎች ድምፀ ተአቅቦ አድርገዋል።

ምንጭ: hab.com

አስተያየት ያክሉ