搜尋此網誌

2014/01/17

開發 SAP RFC 專案的架構技巧

開發 SAP RFC 專案的架構技巧

情境:使用 DotNET Client + SAP RFC 進行庫存管理

要測試 SAP RFC (Remote Function Call) 似乎真的要有 SAP 系統以及其 SAPGui 工具(很龐大),
就算把 SAP 架起來了也不是隨時有環境可進行測試,這一定會影響功能面的開發進度
因為大部分的功能看來都與 SAP RFC 無關,所以被此卡住就不划算了。

先介紹一個常見的 SA/SD 技巧:虛擬倉 + 虛擬儲位
  • 仔細想想就會發現所有的庫存交易都是Movement(移動)
  • Movement 一定要有的資料是:品項、來源、目的、與數量。
  • 若把系統範圍之外的地方想像成虛擬倉/虛擬儲位的話,
    所有的
    庫存交易都可用一致的的 Movement 邏輯處理掉,不必再裡廠內或廠外的問題

舒緩此類系統邊界問題的架構技巧如下(此技巧也常用於 module 邊界):
  • 建立一個 SapRfc 父類別並定義出要使用的函式介面。
  • 定義兩個 SapRfc 的子類別例如:SapRfcMock 與 SapRfcReal:
    • SapRfcMock 是模擬介面,裡頭要用一般 DB 或 只用 Collection 隨你的便,這部分很單純。
    • SapRfcReal 是真正去做 RFC 呼叫的類別,將 RFC 的 code 都放在這裡。
    • 這樣功能面與 RFC 的工作就可平行地進展
  • 若使用 DotNET,建議不要再用 DataTable 之類的東西(因為也不會有DB),
    因為靈活的 DataSource 屬性
    才是 DotNET的強項
    • 最好是建立 Model 物件(EX: Warehouse, Locator, Inventory, Product,...)
    • 將上述的 Model 物件放到 List 之類的東西就可與控制項 binding 了。
    • 若一鄧要用 DataTable 將面臨更多的轉換動作
事實上 Model + SapRfcMock 定義完成後,一至三天內馬上就可開始功能面的開發。
而且這個定義可以用遞增的方式進行,不用一次全部做完,所以只需要很短的時間就做可出第一版。

UI(client端) 必須使用 SapRfc 呼叫以read/write需要的資料。
千萬不要一開始就去想真正的 RFC 呼叫,因為研究 RFC 會卡住功能的開發
只需用一個 flag 決定傳回 SapRfcMock 或 SapRfcReal 即可,整個感覺如下:
C# 檔案見:
https://drive.google.com/file/d/0B9exai2F1cufMHRPLWlpVUVXWGs/edit?usp=sharing

01 public sealed class SapRfcFactory {
02     private static SapRfc singleton = null;
03 
04     public static SapRfc GetInstance() {
05         // 在此處決定要使用 real 或 mock 物件
06         if (singleton = null)
07             singleton = new SapRfcMock();
08         //singleton = new SapRfcReal();
09 
10         return singleton;
11     }
12 
13     private SapRfcFactory() {}
14 
15     // other codes...
16 }
17 
18 // 定義 RFC 呼叫介面
19 public abstract class SapRfc {
20     // 可以在此成員存放共用參數
21     Dictionary<string, object> dicParams = new Dictionary<string, object>();
22 
23     public abstract bool Logon();
24     public abstract void Logout();
25 }
26 
27 public class SapRfcMock: SapRfc {
28     public override bool Logon() {
29         // 直接回傳 true
30         return true;
31     }
32 
33     public override void Logout() {
34         // do nothing.
35     }
36 }
37 
38 public class SapRfcReal: SapRfc {
39     public override bool Logon() {
40         // 進行實際的 RFC 登入...
41     }
42 
43     public override void Logout() {
44         // 進行實際的 RFC 登出...
45     }
46 }