[請益] 如何有效益的維護data loader

看板Soft_Job (軟體人)作者 (Tina)時間1年前 (2022/11/22 01:03), 編輯推噓17(18176)
留言95則, 19人參與, 1年前最新討論串1/1
如題 目前做的project架構長這樣 Loader1 Loader2 Loader3 ........... Loader30 Area 1 Area 2 Area 3 .... .... Area 10 就是同一個Loader 會算出結果給不同Area的人 有分成前端跟後端,前後端都是我維護 (前端 .Net Framework java script MVC,會 用到一點 jquery,其他大多套套件用現成的物件再加工,後端就純C# query DB用的工具是公版的不用自己寫,就負責input 要打的SQL跟DB,然 後output datatable或是對DB做insert/delete/update....) Loader每支老闆認知都不算很大所以也是一人包辦XD Loader每支的邏輯也類似: Start--->會記錄log表示loader開始 Initial setting----> query一些接下來SQL會用到的config QueryRawData---->把上一個initial function的config帶下來在這裡組成SQL string 並且query進data table ProcessData--->對上一步的data 做運算然後轉換成可能只有一個kpi值的結果 或是pre-sum過後的結果 (舉例來說query hourly的資料轉換成daily的資料) End---->只是記錄log表示上面的function都執行完了 看似很穩定 但loader卻需要不斷的更版 原因是因為SQL全部都是寫死的,接水其他系統的資料 https://imgur.com/a/xjTfPfG 以這個圖為例,USER只看的到最終的TABLE,沒有太多空間可以彈性修改query的條件 也沒有像左上角有彈性調整query資料的方法 (有config但是很少) 所以需求常常長得像這樣: "tinasfishs 啊你幫我改一下,我發現今天的KPI有錯,因為 今天開始要加採計'AA' 這種類別,麻煩再幫我改" 原始SQL通常長這樣 SELECT COUNT(1) CNT FROM STORE_SALES WHERE 1=1 SELECT * FROM STOR_SALES WHERE 1=1 ( AND TYPE IN ('A','AB','BC',....'DZ','AA') AND SALE_DATE BETWEEN SYSDATE-3/24 AND SYSDATE-1/24 AND MT_CODE IN ('2','5') AND...... CASE WHEN .... )A, ( SELECT EMPLOYEE_DEG,EMPLOYEE_NAME FROM EMPLOYE_L WHERE AREA='AREA1' AND RES_PRODUCT NOT LIKE '%AAZc' .... .... ... )B, ( SELECT EMPLOYE_ID,EMPLOYEE_SHIFT FROM SHIFT_ARRANGE_LIST WHERE RECTIME>SYSDATE-5 AND AREA='AREA1' if (AREA=='AREA1' or AREA=='AREA2') { RECTIME<SYSDATE-1 } )C WHERE A.SALE_EMPLOYEE=B.EMPLOYEE_NAME AND B.EMPLOYEE_ID=C. EMPLOYEE_ID SQL通常都很長而且用sub-query,會把商業邏輯埋在hard-code的SQL裡面 不能用SQL處理的邏輯則是在ProcessData那步處理 假設綠色的地方是config,黃色的地方則是這次修改的部分 重點是改後端的SQL都需要重新上code,雖然有提供公版的工具把SQL另外儲存 只要呼叫那個外部工具就可以把SQL取得 但前人為了開發方便 當然全部都把SQL直接擺在程式裡 然後複雜的是,同樣算這個KPI,各個AREA 的條件是不盡相同的 用藍色字的地方就是舉例,沒有使用config而是用C# 的code 直接hard code 這兩個 area 需要加此條件 所以也會衍生像是 "我們是AREA3,AREA1 跟 AREA2 看的那個條件我們從下禮拜開始也想跟著採計 ,你們可以重新上code嗎" 有爬文像是Stored procedure 之類的做法,歹勢對於這個架構完全不適用 理論上像這樣各個area的條件有不少差異的情況下,應該是個別維護各area的loader 但這整套是寫在一起的...,每次上code為了維護版控也會在各area同步上同一套 也就會發生改A壞B,假設area1跟area2 共用同一段SQL條件,答應area1刪掉 其中一句之後,area2 就跑來說他們的KPI異常 這個專案負責接水30幾支上游的TABLE,就有30幾支LOADER..而且還在逐漸增加中 所以談需求跟開發的時候,根本也不是從 "為什麼要新增AA這個條件,除了改SQL有什麼更好的方式" 去切入 因為那要去詢問上游以及user為什麼要新增這個條件太花時間 而是 "幫我改SQL吧比較快"---> 所以從來都只在做改SQL這種很末端的工作 一個禮拜大概有4-5個這樣的"假需求"---->我定義為只是改SQL,請user驗驗看是否 符合他們期望 user有時候也不確定改了條件是否就會對,改了也不能上code 總是改了再測測了再改 這樣的需求都做完了,才有時間去處理可能真的是loader本身的問題 ----->效能的問題啊、要新增一支新loader 與user談規格之類的....orz 談規格也是我一人,頂多再加0.5個PM PM也跟我想像會把規格談到不會讓日後充滿這些維護 剛好相反 最後規格談一談還是常常訴諸短解 能夠hard code SQL就hard code,理想性的應該要跟上游負責系統的人看資料 怎麼接軌的溝通過程完全沒有= = 我有堅持過想先看清資料流再做新需求也因為求時效性被打槍 有被訓練得比較有警覺性,但一個SQL 至少20行,下面又有條件讓user高興改就改 實在很難用很大的框架去處理這樣的事,SQL有記得拔出來放在另外存的地方 不用重新上code就很不錯了 BTW SQL邏輯跟要接水什麼報表通常都是由USER提供 ----------- 有跟老闆溝通過像這樣接水別人資料的匯總型AP 應該要重構,或者是一支一支 拿出來看有什麼可以enhance的 但user常常會認知KPI錯誤就來說是系統問題,久而久之老闆也好像覺得是我的問題 而沒有深究之所以KPI會錯誤,就是因為SQL在上code流程的不彈性,還有讓user在 不能彈性重上CODE的情況下還是一再想修改SQL (不能彈性的原因是要重上code老闆都會看,跟他解釋這個是要改SQL就會被 question,但老闆也不看CODE也不會負責建議有建設性的方法,只會打高空問 說可不可以不要改SQL--->問我的格局只能做到這樣...整個黑人問號) 私以為想修改SQL或是想改變KPI的算法,都應該是大家坐下來看data flow是什麼 是不是只是加了一句SQL就可以改變 但文化上大家也不太有耐心這樣梳理問題 不太清楚老闆是否了解目前系統的設計是長這樣,總之在溝通上也覺得不太有救 想問問有沒有維護或是開發過這種DATA LOADER的前輩 可以分享一下心得的QQ -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.25.93.94 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1669050189.A.15C.html

11/22 01:29, 1年前 , 1F
我看到1=1了耶...
11/22 01:29, 1F

11/22 01:30, 1年前 , 2F
也不要用*
11/22 01:30, 2F

11/22 01:32, 1年前 , 3F
把條件弄成dynamic 不要hardcoded 設定好權限 讓個別
11/22 01:32, 3F

11/22 01:33, 1年前 , 4F
user可以選要加甚麼條件在filter裡 我做過這個 很難寫
11/22 01:33, 4F

11/22 01:33, 1年前 , 5F
難在一堆無聊人士搞audit 設定權限他們也不懂
11/22 01:33, 5F

11/22 01:34, 1年前 , 6F
辛苦啦,我是建議你讓sql參數化單純一點,把條件的東西搬去
11/22 01:34, 6F

11/22 01:34, 1年前 , 7F
c#用策略模式做
11/22 01:34, 7F

11/22 01:35, 1年前 , 8F
然後多使用虛擬類別,多的kpi用介面去加
11/22 01:35, 8F

11/22 01:35, 1年前 , 9F
這樣你sql就相對單純
11/22 01:35, 9F

11/22 01:36, 1年前 , 10F
現在這樣筆數多撈起來會很慢吧...
11/22 01:36, 10F

11/22 01:49, 1年前 , 11F
然後你sql要板控的話可以加一個sql,專案在方案裡
11/22 01:49, 11F

11/22 01:49, 1年前 , 12F
最終還是sp化接參數再透過策略選擇呼叫那一種就好
11/22 01:49, 12F

11/22 01:50, 1年前 , 13F
好維護,改起來也快,而且會好閱讀很多吧
11/22 01:50, 13F

11/22 06:52, 1年前 , 14F
1=1是為了 後面串條件方便吧 應該是後面可能不會出現
11/22 06:52, 14F

11/22 06:52, 1年前 , 15F
條件
11/22 06:52, 15F

11/22 08:39, 1年前 , 16F
不太懂分那麼多支loader 的原因為何?
11/22 08:39, 16F

11/22 09:22, 1年前 , 17F
先把上游資料轉成同樣格式,query 的部分再跟著 area 版控
11/22 09:22, 17F

11/22 09:23, 1年前 , 18F
現在這樣維護成本就是 loader 與 area 數量乘開
11/22 09:23, 18F

11/22 09:24, 1年前 , 19F
把東西拆到讓維護成本變成加法是唯一的活路
11/22 09:24, 19F

11/22 09:32, 1年前 , 20F

11/22 09:32, 1年前 , 21F
Game Live patch:做多種MOD讓使用者自行訂閱
11/22 09:32, 21F

11/22 11:41, 1年前 , 22F
Loader1.GetSQLText(Area1), Loader2.GetSQLText(Area1)
11/22 11:41, 22F

11/22 12:08, 1年前 , 23F
query可以獨立分開放在檔案裡讀吧?
11/22 12:08, 23F

11/22 12:35, 1年前 , 24F
JavaScript 為什麼你要分開寫
11/22 12:35, 24F

11/22 17:12, 1年前 , 25F
你做好一版 馬上把所有可能被影響的loader/area重跑 比
11/22 17:12, 25F

11/22 17:12, 1年前 , 26F
對實際被影響的資料是否符合你預期 先建立這樣的系統避免
11/22 17:12, 26F

11/22 17:12, 1年前 , 27F
改A壞B沒發現 再來談重構
11/22 17:12, 27F

11/22 17:14, 1年前 , 28F
會發生改a壞b表示你有共用的code卻允許共用的其中一個需
11/22 17:14, 28F

11/22 17:14, 1年前 , 29F
求端任意更改 這當然不正常, 如果一種東西會被多個需求
11/22 17:14, 29F

11/22 17:14, 1年前 , 30F
端各自提需求修改 那這種東西不論有多相似 都應該建立單
11/22 17:14, 30F

11/22 17:14, 1年前 , 31F
獨的class
11/22 17:14, 31F

11/22 17:15, 1年前 , 32F
你的整個重構會很複雜不是你一人一兩個月就能完成 一定要
11/22 17:15, 32F

11/22 17:15, 1年前 , 33F
先建立確保不會改A壞B的機制
11/22 17:15, 33F

11/22 17:16, 1年前 , 34F
你這正常的架構就是要先定義原始資料類別有哪些, 聚合資
11/22 17:16, 34F

11/22 17:16, 1年前 , 35F
料的filter有哪些
11/22 17:16, 35F

11/22 17:19, 1年前 , 36F
你的loader程式應該要給每個最終報表有適當的命名 同時
11/22 17:19, 36F

11/22 17:19, 1年前 , 37F
有文件紀錄每個報表會有哪些單位查看
11/22 17:19, 37F

11/22 17:25, 1年前 , 38F
每一支報表由哪些資料源以及哪些filter算出中間的結果以
11/22 17:25, 38F

11/22 17:25, 1年前 , 39F
及最終報表 要有文件
11/22 17:25, 39F

11/22 17:30, 1年前 , 40F
當有人跟你說 他要增加採計AA類別 你就去查程式 採計AA
11/22 17:30, 40F

11/22 17:30, 1年前 , 41F
類別這個行為是哪一支filter在處理, 有其他單位用到嗎?
11/22 17:30, 41F

11/22 17:30, 1年前 , 42F
如果沒有 那大概就是直接修改這支filter 最終報表就會是
11/22 17:30, 42F

11/22 17:30, 1年前 , 43F
他要的結果 也不影響別的單位. 如果有其他單位用到 你可
11/22 17:30, 43F

11/22 17:30, 1年前 , 44F
能需要拆分成兩支filter給兩個單位使用 或是你的這個filt
11/22 17:30, 44F

11/22 17:30, 1年前 , 45F
er可以吃參數 那就是兩個area吃不同config即可. 最重要是
11/22 17:30, 45F

11/22 17:30, 1年前 , 46F
不管你的架構如何 改完就是要測試確保沒有動到不該動的
11/22 17:30, 46F

11/22 17:30, 1年前 , 47F
東西 這就是測試的覆蓋率的重要性
11/22 17:30, 47F

11/22 17:31, 1年前 , 48F
最後建議 直接換工作
11/22 17:31, 48F

11/22 17:58, 1年前 , 49F
不太懂 老闆聽你這樣解釋之後還是認為是你的問題嗎
11/22 17:58, 49F

11/22 17:58, 1年前 , 50F
通常這樣看你敘述下來就知道是架構問題了吧?
11/22 17:58, 50F

11/22 18:43, 1年前 , 51F
SQL WHERE 用 python 的 f-string 把 list 傳進去,這樣
11/22 18:43, 51F

11/22 18:43, 1年前 , 52F
只要更新這個list就好
11/22 18:43, 52F

11/22 21:02, 1年前 , 53F
像是水流一樣,資料一站一站往下流,就很好追蹤!可能會
11/22 21:02, 53F

11/22 21:02, 1年前 , 54F
變動的地方可以另開TABLE存放參考物件AA ,BB...後續就
11/22 21:02, 54F

11/22 21:02, 1年前 , 55F
算新增參考,也只需更動參考TABLE內容,MAIN SQL部分只
11/22 21:02, 55F

11/22 21:02, 1年前 , 56F
要寫好關聯,後續就不用一直改
11/22 21:02, 56F

11/22 23:58, 1年前 , 57F
已經有參數化,loader唯一有設計的就是把同一支loade
11/22 23:58, 57F

11/22 23:58, 1年前 , 58F
r的可能10幾、20幾支SQL擺在同一個class,然後用retu
11/22 23:58, 58F

11/22 23:58, 1年前 , 59F
rn string的方式去return SQL,只是除了用class的殼
11/22 23:58, 59F

11/22 23:58, 1年前 , 60F
包住&部分用參數之外就沒做其他的了。參數有的帶了6-
11/22 23:58, 60F

11/22 23:58, 1年前 , 61F
7個結果還是沒辦法把SQL拆到自由度完全釋放
11/22 23:58, 61F

11/23 00:06, 1年前 , 62F
我的確很想by Area去把SQL list拆出來,但是可能和其
11/23 00:06, 62F

11/23 00:06, 1年前 , 63F
他公司不同,SQL除了擺在公司共用的SQL池以外就是只
11/23 00:06, 63F

11/23 00:06, 1年前 , 64F
有hard code一法,SQL池只是儲存string跟參數位置,
11/23 00:06, 64F

11/23 00:06, 1年前 , 65F
假設要把本來是hard code的條件改成帶參數,就是原本
11/23 00:06, 65F

11/23 00:06, 1年前 , 66F
C#裡面call SQL池的地方要改。例如string SQL=sql po
11/23 00:06, 66F

11/23 00:06, 1年前 , 67F
ol(type,gender)要改成SQL=sqlpool(type,gender,age)
11/23 00:06, 67F

11/23 00:06, 1年前 , 68F
就要重新上code,不能自行維護一份txt檔就好
11/23 00:06, 68F

11/23 00:10, 1年前 , 69F
感覺前人在這樣的infra環境下,選擇hard code或是擺S
11/23 00:10, 69F

11/23 00:10, 1年前 , 70F
QL pool需要的effort是差不多的,為了快速完成,也不
11/23 00:10, 70F

11/23 00:10, 1年前 , 71F
會去選擇把TABLE裡每個欄位都拆出來寫成class…table
11/23 00:10, 71F

11/23 00:10, 1年前 , 72F
跟table我覺得關聯性很差,常常出現10幾個column的ta
11/23 00:10, 72F

11/23 00:10, 1年前 , 73F
ble,我資料庫不強不知道這算不算是架構不好的象徵QQ
11/23 00:10, 73F

11/23 00:12, 1年前 , 74F
但大家的建議都很棒,我會多尋找機會點的!謝謝
11/23 00:12, 74F

11/23 00:55, 1年前 , 75F
sql = "" +
11/23 00:55, 75F

11/23 00:55, 1年前 , 76F
(age != null ? "" +
11/23 00:55, 76F

11/23 00:55, 1年前 , 77F
"\n and age = @age" +
11/23 00:55, 77F

11/23 00:55, 1年前 , 78F
"" : "") +
11/23 00:55, 78F

11/23 00:56, 1年前 , 79F
"";
11/23 00:56, 79F

11/23 00:59, 1年前 , 80F
藍色的if可以寫成上面哪樣, 字串一直串
11/23 00:59, 80F

11/23 01:04, 1年前 , 81F
不想整個Code重上, 可以拆成不同project (dll)
11/23 01:04, 81F

11/23 01:14, 1年前 , 82F
若你將所有C# Code都寫在一個cs檔,就可以實現維護一份text
11/23 01:14, 82F

11/23 01:21, 1年前 , 83F
參數太多可以考慮用一個物件來放
11/23 01:21, 83F

11/23 01:21, 1年前 , 84F
(type, class or Dictionary<string, object> args)
11/23 01:21, 84F

11/23 11:16, 1年前 , 85F
c# call sqlpool interface 改成傳 object 就可以解決改
11/23 11:16, 85F

11/23 11:16, 1年前 , 86F
來改去的問題?
11/23 11:16, 86F

11/23 11:28, 1年前 , 87F
樓上是講我嗎? "實現維護一份text"那一行只是玩笑話
11/23 11:28, 87F

11/23 11:40, 1年前 , 88F
不太懂樓上的意思
11/23 11:40, 88F

11/23 12:10, 1年前 , 89F
另外花點時間寫一支自己理解後的模組?
11/23 12:10, 89F

11/23 12:10, 1年前 , 90F
然後兩邊比較結果,久了沒問題就能把舊的取代
11/23 12:10, 90F

11/24 22:53, 1年前 , 91F
如果你會很常異動邏輯,通常會把核心做成view有需要再篩選
11/24 22:53, 91F

11/24 22:53, 1年前 , 92F
吧,這樣就從資料庫改就好,子查詢也可以做成function放在
11/24 22:53, 92F

11/24 22:53, 1年前 , 93F
資料庫
11/24 22:53, 93F

11/25 01:09, 1年前 , 94F
這個架構也太神奇了吧?
11/25 01:09, 94F

11/26 09:11, 1年前 , 95F
為啥不從程式去處理要用SQL去處理?
11/26 09:11, 95F
文章代碼(AID): #1ZUwzD5S (Soft_Job)
文章代碼(AID): #1ZUwzD5S (Soft_Job)