目前項目開發中, 后端主要使用Spring Data Rest, 前端嘗試過基于Vue和Bulma的單頁模板vue-admin, 由于Bulma相對比較新, 成熟的組件庫少. 后來引入了開源模板renren-security, 包含了用戶, 組織和權限管理的基本功能, 代碼結構較為簡單, 前端使用了Vue, 也保留了傳統組件, 便于模塊間解耦和兼容舊頁面. 為便于開發, 把前端改為前后端分離的多頁應用, 參考了renren-fastplus和jeefast, 原項目前端與后端耦合并不多, 改動之處主要是使用了token認證替換了session認證, 并且把權限字符串發送到前端判斷.(因此在后端需要認證權限, 否則可能會有偽造的請求) 另外使用了通用組件處理CRUD的公共功能d2-crud. 該組件最初取自D2項目團隊D2 Projects, 開始關注該項目是由于在飛冰上看到他們發布的Vue項目腳手架, 有一套相關的項目, 形成了自己的小生態. 我一直認為有潛力的項目會重視生態建設, 但是他們的整體項目仍是單頁模板, 難于和舊代碼集成, 所以只用了CRUD組件. 當時該組件還處于開發初期, 代碼較簡單, 但作者是個人開發, 需要的一些功能等不及, 所以自己做了表格和表單組件的拆分, 引入了spring-data-rest-js與后端通信, 使用了AlaSQL在前端進行數據緩存和導入導出. 對于數據表之間的關聯也在前端實現.
這一套工具組合起來, 簡單的增刪改查頁面開發效率還可以, 基本不需要寫代碼, 每個模塊只需要后端寫好實體類, 前端建立數據配置, 建好相應的頁面, 配好菜單路徑和權限, 就可以使用了. 特定的需求可以在前端添加按鈕和函數, 原則上不需要在后端修改.
目前感覺到開發中存在的問題:
Spring Data Rest功能較弱, 不能方便的實現復雜查詢. 目前是通過把數據一次全部加載到前端, 在前端進行查詢處理. 后期還是要考慮通過后端接口查詢, 需要引入新的實現方式.
前端組件標準化不夠. 通過不同場景下的使用需求可以提煉出一些前端通用的需求, 為了避免代碼重復做了一些組件封裝, 但是只是粗略實現了基本功能, 不夠清晰簡潔.
需要手工對接的地方還是較多, 需要按照前端和后端的技術需要去適配同一個業務需求. 未來需要整理業務中通用的需求, 模式, 形成通用的聲明化配置化的代碼基礎, 方便后續的開發.
所以接下來, 準備使用PostgreSql數據庫替換Mysql, 經調查測試, 其在性能和功能方面都更優秀. 然后可以使用PostgREST提供Http接口, 避免了手工維護后端接口, 前端在權限范圍內可按需操作后端數據. 權限判斷等必須在后端完成的功能通過在數據庫中聲明, 簡化了開發, 也保證了數據的完整性. 關于這種后端自動生成接口的技術, 其實一直在關注. 原則上后端的很多工作就是把數據庫的訪問轉成HTTP的接口, 這種工作應該自動完成更好. 如果數據庫沒法直接提供HTTP形式的接口(比如像CouchDB那樣), 那么最好是只通過一層簡單的封裝, 對外暴露Web接口. 這方面目前感覺做的最成熟的就是PostgREST. 以前一直使用的是Spring Data Rest, 只提供了最簡單的CRUD和分頁功能, 并且需要Spring環境. 在后端只提供數據接口的情況下, 顯得結構復雜, 功能單薄. github上有人建了一個列表automatic-api, 總體來看這方面的技術多數是小規模的探索, 沒有形成整體的開發架構. 最近看到國內也有人在做這種嘗試APIJSON. 這種思想和實現并不是很難, 和所有的ORM或數據訪問框架一樣, 都是拼SQL語句. 關鍵是要形成完整的開發模型, 需要一套相關項目和工具組成的生態系統. 其中首先要解決的是權限控制問題. 很多人說, 前端直接傳SQL語句到后端執行最簡單了, 但是不解決授權驗證的問題, 就只能作為原型技術來用. PostgREST利用了PostgreSql數據庫本身強大的權限管理和編程功能, 利用JWT傳遞權限角色到數據庫, 所有的授權判斷直接利用數據庫本身的管理功能. 最大化的減少了代碼的冗余, 也保證了用于生產環境的規范化. 原則上, 只要是權限范圍內的操作都可以在前端執行, 后端不需要寫業務相關代碼. 當然, 如果需要寫的話, 可以在數據庫中寫存儲過程(函數), 前端通過Web接口調用. 這樣的技術架構實際上把項目整體簡化成了最為本質的兩層: 數據 和 界面. 這是軟件的本質功能, 其余所有的環節都屬于中間步驟, 可以被簡化, 規范化和通用化. 這是最初和最終的目標, 參見第一篇文章.
至于這種模式存在的問題, 首先是最好把數據協議和傳輸協議分開, 雖然現在HTTP是Web標準, 但是面向未來, 最好不要捆綁在特定的傳輸協議上, 只做好Web可用的數據訪問接口, 底層使用websocket, 或者HTTP2, HTTP3, 或者別的什么協議都可以. 這個問題其實是由于TCP/IP協議簡化的應用層造成的, OSI模型中的會話層和表示層是有必要的, 而且并不需要特殊硬件, 應該是在軟件中分層. 把所有功能都簡化到應用層的后果就是HTTP承擔了太多角色, 沒有一個清晰的層次, 導致了Web開發需要后端寫很多難以復用的接口. 所以REST和GraphQL都在填這個坑, 我覺得最根本的方式還是重視OSI模型, 在軟件架構中分離出會話和表示層, 建立起通用規范的實現和接口調用方式, 這樣不僅對于Web, 對于更底層直接基于socket的調用都是大有好處的, 現在的情況下是這些功能分布于通訊框架和業務代碼中, 沒有一個清晰的結構, 增加了復雜性. 當然, 這是從長遠和理想角度考慮, 目前HTTP接口還是夠用的, 前端通過對應的客戶端庫轉接相應格式的接口, 后續切換應該也問題不大.
其次是綁定了特定數據庫的問題, 這個問題目前看來并沒有太好的解決方式. 數據庫領域的分裂割據跟操作系統, 瀏覽器, 編程語言一樣, 由來已久, 短期難以消除. 如果我們想只用標準SQL, 使用各個數據庫通用的部分, 那么最好能像在前端一樣, 用jQuery這樣的庫處理瀏覽器差異, 但是目前看來沒有哪個項目能承擔起這個重任. 從中小企業的需求和現狀來看, 大部分使用數據庫只是簡單的數據存儲, MySQL也能滿足要求. 但是MySQL也有很多歷史遺留的和現實的問題, 功能偏弱, 不能統一. 目前看分裂有可能越來越大, 官方的MySQL8加入了角色管理, 但是社區很多已經轉向了MariaDB, 未來發展方向并不明朗. 而PostgreSql雖然顯得相對低調, 近幾年卻也呈現一路上升之勢. 加上一大批相關項目的支持, 未來成為數據庫領域的Chrome也未可知. 畢竟, 如果開源軟件功能足夠強大, 生態足夠豐富, 大部分企業也不會錯過壓縮成本的好機會.
另外, 關于數據庫內置的權限系統能不能很好的滿足業務特定的需求, 需要實踐驗證. 個人感覺確實是存在強耦合的風險. 目前的想法是, 讓業務角色和數據庫角色關聯, 發揮合力.
前端方面, 通用組件還需要繼續優化整理, 保證通用功能不出現重復代碼, 特定功能可以用簡潔的聲明式代碼實現. 在此基礎上加強前后端的整合, 屏蔽技術實現細節帶來的差異, 提煉出業務常用類型和流程, 比如人員, 機構, 日期時間, 貨幣, 任務, 單據. 更多的建立起基于業務的抽象, 業務類型決定了數據庫類型和前端組件類型. 對于簡單通用的需求, 只要聲明一次, 前后端都能夠以統一的方式成功運行. 對于特定的需求, 能夠在實際需要的地方(一般原則是權限范圍內的在前端, 需要控制權限的在后端)插入聲明代碼, 即可運行. 并且爭取做到用戶可以簡單的理解和配置, 在無需改動代碼和開發人員不參與的情況下實現系統按需修改.
最終的目標是希望真正能實現業務和技術的解耦. 業務規則應該是數據化, 聲明化的. 框架解析業務規則, 并產生能夠在計算機上運行的程序. 業務的變化不需要修改技術實現代碼, 技術的迭代也不會影響業務的正確運行. 這是軟件開發的長遠目標, 也是降低軟件復雜性和開發維護成本的根本方式. 結合當前的技術情況, 具體形式采用DSL, 還是SQL, XML或LISP, 或者干脆用規則表, 現在不能確定, 但總的思路是業務是數據, 就像函數是數據一樣. 聲明式的業務規則在底層框架的支持下自動轉換成程序在計算機上運行. 技術和業務的復雜性相互獨立. 開發人員的主要精力應該是理解業務需求, 設計合適的數據庫和界面, 并以聲明的方式直白的翻譯業務需求. 開發的難度大大降低, 無經驗的人員, 甚至客戶企業工作人員簡單熟悉后都可以參與開發, 把軟件的控制權交給用戶. 而專業技術人員更多的是負責保證底層環境的穩定運行, 實際上就是現在的云模式.
希望在不遠的將來, 碼農, 996, 軟件培訓這些概念會像舊時的黃包車, 西洋景, 大哥大, BP機一樣, 成為一種模糊的回憶. 生活在一個改變的年代, 我們都在努力奔跑的同時, 也享受著別人的努力所帶來的便捷.