主頁 > 軟體設計 > 從一個 SAP CRM 軟體實際的故障處理出發,談談企業管理軟體領域內那些很難穩定重現故障的處理技巧

從一個 SAP CRM 軟體實際的故障處理出發,談談企業管理軟體領域內那些很難穩定重現故障的處理技巧

2021-10-25 16:48:45 軟體設計

目錄

企業管理軟體領域內棘手故障的一些表現形式

1. 需要復雜的流程才能重現

2. 故障橫跨企業管理軟體的多個模塊

3. 故障只能在客戶生產系統重現

4. 故障只能在后臺作業模式下重現,在 online 模式運行時一切正常

5. 故障只能在軟體正常運行模式時才能重現,單步除錯時,軟體作業一切正常

一個實際故障排查程序的案例分享

1. 試圖找到穩定重現故障的辦法

2. 縮小可能引起故障的代碼排查范圍

3. 利用除錯器鎖定問題

故障排查程序總結


筆者從2007年大學畢業加入 SAP 成都研究院至今,一直從事企業管理軟體領域的開發作業,

企業管理軟體面向的是企業級用戶,如果軟體出現故障(bug),在某些極端情況下,可能會讓企業蒙受巨大的經濟損失,故而對軟體開發人員在編程規范,軟體測驗和軟體交付之前的驗證等各方面都提出了更高的要求,同時,由于企業管理軟體自身高度的復雜性,有些故障很難重現或者只能在運行了客戶特定業務流程的生產系統上才能重現,這些都給企業管理軟體分析和故障處理帶來了巨大的挑戰,

本文從筆者處理過的一個實際軟體故障出發,談談自己對企業管理軟體里一些棘手故障的處理體會,

在筆者看來,這些棘手故障,可以分為以下幾類,

企業管理軟體領域內棘手故障的一些表現形式

筆者在 SAP成都研究院處理過很多曾讓我頭痛的軟體故障,它們具有下列一項或幾項特征,

1. 需要復雜的流程才能重現

例如我處理過的一個客戶發票(Customer Invoice)相關的故障,這個故障只有在每次 release 發票時才能重現,為了 release 發票,我們必須先創建一個銷售訂單(Sales Order),基于該訂單創建 Customer Demand,然后創建撿貨任務(Pick Task),生成交貨單(Delivery Note),最后才能生成一張新的客戶發票,

這些復雜的流程往往也需要系統事先維護好對應的主資料(Master Data)和事務資料(Transaction Data)才能順利執行,復雜的業務流程增添了故障重現的難度,

2. 故障橫跨企業管理軟體的多個模塊

由于企業管理軟體自身的復雜度,終端用戶眼中看到的貌似簡單的一個故障,背后可能橫跨了軟體實作的多個模塊,

以上述形式1描述的故障為例,假設軟體幫助檔案上描述的支持功能為:客戶在銷售訂單界面上添加了一個新的自定義欄位并維護了對應值,該值能夠從銷售訂單,經撿貨任務,交貨單,最后傳遞到客戶發票上,我們稱這種欄位值從多個檔案間的傳遞稱為 data flow.


那么如果客戶在發票頁面上,看到這個欄位的值為空,客戶可能認為是發票模塊出了故障,然而,在 data flow 的每個節點對應的模塊處理,可能都是造成該故障的罪魁禍首,銷售訂單和客戶發票屬于 CRM 模塊,而撿貨任務和發貨單則歸屬 SCM 的范疇,

在實際開發作業中,這意味著分析該故障往往需要跨團隊間協作,因為 CRM 和 SCM 模塊往往分屬不同的開發團隊負責,

3. 故障只能在客戶生產系統重現

在企業管理軟體交付之前,必定在內部開發,測驗和驗證系統(validation system)進行過不同層次的測驗,即便如此,由于種種客觀原因,比如當應用運行在客戶生產系統上,基于某些只有該客戶才會用到的特定業務流程的配置時,故障才會暴露,而這些配置并沒有被企業管理軟體供應商的內部系統測驗所涵蓋到,

這類故障因為只能在客戶生產系統重現,在分析和定位問題時更加困難重重,尤其當重現步驟會在客戶生產系統進行寫操作時,通常只能聯系客戶相關人員,采用遠程桌面+電話會議的方式,讓客戶相關人員進行操作,然后軟體供應商的支持人員在線除錯,

4. 故障只能在后臺作業模式下重現,在 online 模式運行時一切正常

在企業管理軟體領域特別是 ERP 領域,后臺作業常常被用來執行一些費時的批處理作業,比如訂單批量處理,報表資料分析和聚合匯總等等,后臺作業模式不同于掛接了用戶界面的 online 模式,給單步除錯也帶來了困難,

5. 故障只能在軟體正常運行模式時才能重現,單步除錯時,軟體作業一切正常

當故障出現這種特征時,實際給支持人員傳遞了一個信號:該故障可能與程式特定的執行時序相關,因為程式正常運行,與處于單步除錯模式下運行,執行時序顯然不同,比如在除錯器單步除錯時,可能會破壞多執行緒程式正常的執行時序,


因為缺少了除錯器這一強有力的武器,分析該類故障,需要支持人員具有更強的理論分析能力和問題抽象能力,

由于篇幅限制,本文僅舉一個實際例子,對上述第五類故障的分析處理流程做一個分享,

一個實際故障排查程序的案例分享

筆者曾經負責 SAP CRM IBASE(Installed Base) 模塊,IBase 是一個抽象模型,用于描述已在客戶位置安裝的資源物件,例如設備、機器,服務或軟體,IBase 模型以樹形結構,描述了這些物件的層級結構和它們的各個組件,是服務模塊的參考基礎,

有一天,我收到一個故障報告,另一個團隊的同事,使用我所在團隊負責的 IBASE API,在同一會話程序內創建 IBASE 組件,修改,隨后洗掉,然后保存,會遇到運行時錯誤(Runtime Error).

在故障描述里提到的運行時錯誤的截圖如上圖所示,

這位同事發現,這個錯誤只能在后臺作業模式下重現,并且不一定每次都能夠重現,該故障也無法在單步除錯模式下重現,

并不總是能夠重現 != 不能重現,

1. 試圖找到穩定重現故障的辦法

為了分析這個問題,我得先找到能夠穩定重現的辦法,因為該故障對單步除錯大法免疫,我只能另想他法,

逐字逐句死扣故障報告里的描述,發生故障之前的操作流程為:

(1) 創建 IBASE
(2) 修改 IBASE
(3) 洗掉 IBASE
(4) 保存事務,

出現運行時錯誤,

因為我就是 IBASE 模塊的負責人,所以我三下五除二就寫好了一個不到 200 行的程式,在程式里依次呼叫 IBASE 的創建,修改和洗掉 API,再保存事務,

程式源代碼如下:

REPORT zibase_create_delete.

PARAMETERS: txt TYPE char40 OBLIGATORY DEFAULT 'description test',
            eid TYPE char30 OBLIGATORY DEFAULT 'PROGRAM',
            oid TYPE comm_product-product_id OBLIGATORY DEFAULT 'CHILDOBJ8',
            fam TYPE comm_product-object_family OBLIGATORY DEFAULT '0401',
            cat TYPE COMT_CATEGORY_ID OBLIGATORY DEFAULT 'OBJ_0401'.

DATA: lt_param  TYPE crmt_name_value_pair_tab,
      ls_param  TYPE crmt_name_value_pair,
      lr_core   TYPE REF TO cl_crm_bol_core,
      ls_object TYPE comm_product,
      lr_root   TYPE REF TO if_bol_entity_col,
      entity    TYPE REF TO cl_crm_bol_entity.

CHECK zcl_object_generator=>create_object( iv_id = oid iv_family = fam iv_catid = cat ) = abap_true.

ls_param-name  = cl_crm_ibase_il_constant=>createparam.
ls_param-value = '01'.
APPEND ls_param TO lt_param.

lr_core = cl_crm_bol_core=>get_instance( ).
lr_core->load_component_set('IBASE_ONLY').

CALL METHOD lr_core->root_create
  EXPORTING
    iv_object_name  = cl_crm_ibase_il_constant=>root_object
    iv_create_param = lt_param
    iv_number       = 1
  RECEIVING
    rv_result       = lr_root.

CHECK lr_root IS BOUND.
entity ?= lr_root->get_current( ).

CHECK entity IS BOUND.
IF entity->lock( ) = abap_true.
  entity->switch_to_change_mode( ).
ENDIF.

entity->set_property_as_string( iv_attr_name = 'DESCR' iv_value = CONV #( txt ) ).
entity->set_property_as_string( iv_attr_name = 'EXTID' iv_value = CONV #( eid ) ).
"entity->set_property_as_string( iv_attr_name = 'IBTYP' iv_value = '01' ).
lr_core->modify( ).
DATA(lv_ibase_id) = entity->get_property_as_string( 'IBASE' ).

DATA(component) = entity->create_related_entity( 'FirstLevelComponent' ).

CHECK component IS NOT INITIAL.

DATA(obj_comp) = component->create_related_entity( 'IBCompObj').

CHECK obj_comp IS NOT INITIAL.

obj_comp->set_property_as_string( iv_attr_name = 'OBJECT_ID' iv_value = CONV #( oid ) ).

SELECT SINGLE * INTO ls_object FROM comm_product WHERE product_id = oid.
ASSERT sy-subrc = 0.

obj_comp->set_property_as_string( iv_attr_name = 'OBJECT_GUID' iv_value = CONV #( ls_object-product_guid ) ).
obj_comp->set_property_as_string( iv_attr_name = 'OBJECT_FAMILY' iv_value = CONV #( ls_object-product_guid ) ).
lr_core->modify( ).

DATA(lo_message_container) = entity->get_message_container( ).
CALL METHOD lo_message_container->get_messages
  EXPORTING
    iv_message_type = if_genil_message_container=>mt_all
  IMPORTING
    et_messages     = DATA(lt_msg1).
LOOP AT lt_msg1 ASSIGNING FIELD-SYMBOL(<msg1>).
  WRITE:/ <msg1>-message COLOR COL_NEGATIVE.
ENDLOOP.

CHECK lt_msg1 IS INITIAL.

DATA: ls_header      TYPE ibap_head1,
      lt_struc_tab   TYPE ibap_struc1_tab,
      ls_comp TYPE IBAP_DAT1.
"delete component"

ls_header-ibase = lv_ibase_id.
CALL FUNCTION 'CRM_IBASE_GET_DETAIL'
  EXPORTING
    i_ibase_head      = ls_header
  IMPORTING
    e_struc_ibase_tab = lt_struc_tab
  EXCEPTIONS
    not_specified     = 1
    doesnt_exist      = 2
    no_authority      = 3.

CHECK sy-subrc = 0.

READ TABLE lt_struc_tab ASSIGNING FIELD-SYMBOL(<line>) INDEX 1.
ls_comp-instance = <line>-instance.

CALL FUNCTION 'CRM_IBASE_COMP_DELETE'
  EXPORTING
     i_comp = ls_comp
  EXCEPTIONS
      DATA_NOT_CONSISTENT = 1
      IBASE_LOCKED = 2
      NOT_SUCCESFUL = 3
      NO_AUTHORITY = 4.

CASE sy-subrc.
   WHEN 1.
      WRITE: / 'data not consistent' COLOR COL_NEGATIVE.
   WHEN 2.
      WRITE: / 'cannot delete locked component' COLOR COL_NEGATIVE.
   WHEN 3.
      WRITE: / 'deletion not successful' COLOR COL_NEGATIVE.
   WHEN 4.
      WRITE: / 'no deletion authorization' COLOR COL_NEGATIVE.
 ENDCASE.

DATA(lo_transaction) = lr_core->get_transaction( ).
DATA(lv_changed) = lo_transaction->check_save_needed( ).

CHECK lv_changed EQ abap_true.

DATA(lv_success) = lo_transaction->save( ).

DATA(lo_glb_msg_cont) = lr_core->get_global_message_cont( ).
CALL METHOD lo_glb_msg_cont->if_genil_message_container~get_messages
  EXPORTING
    iv_message_type = if_genil_message_container=>mt_all
  IMPORTING
    et_messages     = DATA(lt_msg).
LOOP AT lt_msg ASSIGNING FIELD-SYMBOL(<msg>).
  WRITE:/ <msg>-message.
ENDLOOP.

IF lv_success = abap_true.
  lo_transaction->commit( ).
  WRITE:/ 'IBASE Created Successfully: ', lv_ibase_id COLOR COL_NEGATIVE.
ELSE.
  lo_transaction->rollback( ).
ENDIF.

執行這個報表,遇到了期望中的運行時錯誤,這是一個好兆頭,因為我現在找到了穩定重現問題的辦法,下一步,我需要縮小問題的范圍,找出我這 200 行代碼里,到底哪一行代碼的執行,引起了運行時錯誤,

筆者喜歡稱自己開發的這種專門用于分析故障,重現錯誤的程式,為“腳手架程式”或者“故障觸發器”,

2. 縮小可能引起故障的代碼排查范圍

因為這 200 行代碼是我自己撰寫的,所以我可以任意修改,首先把所有代碼全部注釋掉,只留下 IBASE 創建 API 的呼叫,執行程式,一切正常,

再解除 IBASE 修改 API 呼叫代碼的注釋,讓其參與到程式執行中,一切正常,

再反注釋 IBASE 洗掉 API 呼叫代碼,執行程式,出現了運行時錯誤!

由此說明,這個運行時錯誤和 IBASE 洗掉的場景相關,

回到故障提交報告里的運行時錯誤截圖:第 103 行拋出了一個型別為 X 的錯誤,因為呼叫函式 CRM_IBASE_COMP_GET_DETAIL, 并沒有讀取到通過輸入引數 i_date 和 i_time 指定的時間戳對應的 IBASE 資料,因此程式決定通過拋出錯誤的方式來終止執行,

通過運行時錯誤的背景關系呼叫堆疊,我找到了 CRM_IBASE_COMP_GET_DETAIL API 沒有回傳任何 IBASE 資料的原因:下圖第 53 行高亮代碼的 CHECK 陳述句,檢查當前傳入的時間戳(默認為 IBASE 創建時的時間戳)是否小于待讀取 IBASE 抬頭的 valto(即 valid to,指 IBASE 有效截止日期的時間戳)欄位,如果小于,則順序執行 CHECK 下一條即 54 行,如果大于或等于,則退出資料讀取邏輯所在的回圈體,


在后臺作業運行模式,以及我的腳手架程式執行時,第 53 行時間戳判斷條件沒有滿足,因此退出了回圈,導致 CRM_IBASE_COMP_GET_DETAIL 讀取失敗,所以引發了故障,

要想滿足 53 行的判斷條件,只有兩種可能:

  • 當前時間戳 > IBASE valto 欄位值
  • 當前時間戳 = IBASE valto 欄位值

需要強調的是,ABAP 編程語言里的時間戳欄位,精確到秒,比如 20211024102424 代表 2021年10月24日10點24分24秒,

3. 利用除錯器鎖定問題

雖然我的腳手架應用在單步除錯模式下也無法重現故障,但是直接執行可以重現,因此,執行執行腳手架應用,在運行時故障頁面點擊工具列的 Debugger 按鈕,能彈出除錯器,查看應用程式拋出運行時錯誤的各種資訊:


這一回,在除錯器里,所有的謎題都揭曉了:當前時間戳 = IBASE valto 欄位值,因此導致 API CRM_IBASE_COMP_GET_DETAIL 讀取失敗,拋出運行時錯誤,

  • 在呼叫 IBASE 創建 API 時,會把待創建的 IBASE 抬頭的 valfr 欄位,賦以系統的當前時間戳,
  • 在呼叫 IBASE 洗掉 API 時,會把該待洗掉 IBASE 抬頭的 valto 欄位,賦以系統的當前時間戳,

為什么在單步除錯模式下,無法重現這個錯誤呢?我們來看一張簡單的時序圖,

橫軸代表時間戳,t3 代表代碼 53 行判斷陳述句里的 <ibinadm>-valto 欄位值, t1 代表代碼 53 行判斷陳述句里的 lv_timestamp 欄位值,

在單步除錯模式下,假設我們從 IBASE 創建 API 開始依次單步執行,則由于按鍵手速原因,t3 必定大于 t1.

而在后臺作業模式以及腳手架程式正常運行情況下,如果 IBASE 創建,修改和洗掉的 API 執行得足夠快速,能夠在一秒鐘之內完成,則 t3 與 t1 之差小于 1 秒,故 CHECK 陳述句執行失敗,直接回傳,

換言之,這個故障提交時,CRM IBASE API 的開發人員,并沒有考慮到 IBASE 的創建和洗掉會在`同一秒之內`完成的場景,畢竟正常情況下,客戶不可能在 1 秒鐘之內,在 UI 完成 IBASE 先創建再洗掉的操作,這種場景只可能在客戶使用 IBASE API 進行一些二次開發場景下才有可能出現,

當然,最后這個問題,也絕非僅僅是把 53 行 CHECK 陳述句的 < 符號,改成小于等于操作那么簡單,我們仔細評估了改動可能帶來的其他副作用,并和提交該故障的團隊開發人員進行了討論,最后采取了其他的方式來避免這個故障的發生,

故障排查程序總結

回到這個故障分析程序本身,最開始接到故障時,因為單步除錯無法重現,因此筆者很是一籌莫展了一陣,后來想到撰寫腳手架程式來穩定重現該故障,這一步是問題分析的突破口

有了腳手架程式之后,先注釋掉所有的 API 呼叫,再逐步開放 IBASE 創建,修改和洗掉的代碼,最終把問題范圍縮小到 IBASE 洗掉程序,

通過腳手架應用的直接執行觸發的運行時錯誤,利用除錯器查看程式拋出錯誤時的變數值,將問題鎖定到時間戳的處理邏輯上,進而找出根源,

這一分析步驟有點像上世紀末本世紀初電腦 DIY 發燒友們遇到組裝機無法啟動時的排查措施,當組裝機無法啟動時,只保留電源,主板和 CPU,嘗試啟動,如果成功,再逐一添加顯卡,硬碟等其他設備,當新添加的設備導致系統重新回到無法啟動狀態,說明該設備有問題,當時發燒友們把這種方式稱為“最小系統法”,

而整個分析程序的重中之重,就是把故障報告中無法穩定重現故障的后臺作業里執行的內容,抽象成一個不到 200 行的腳手架程式,

《編程珠璣》第五章曾經分享過一個關于故障除錯的有趣故事:IBM 研究中心一位程式員,新安裝了一臺作業站,發現一個故障:他只能采取坐著的姿勢登錄系統;一旦站起來,就無法登陸系統了,大家知道這個故障最后怎么定位的嗎?去讀讀原書吧!

希望本文能給大家在企業管理軟體領域內的故障排除方法帶來一些啟發,感謝閱讀,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/335806.html

標籤:其他

上一篇:python中的梯形規則

下一篇:將INSERTINTO與VALUES一起使用失敗,并顯示運行時錯誤“3078”

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more