8人/天,小記一次 JAVA(APP後台) 項目改造 .NET 過程(後台代碼已完整開源於 Github)

來源:互聯網
上載者:User

標籤:containe   如何   存在   inf   劃線   靈活   統一   image   實現   

Github: https://github.com/iccb1013/Jade.Net

我們只消耗了8/人天的時間,完成了全部工作,基於我們 Jade.Net 的開源後台代碼,任何小規模的後台管理系統,都可以在極短的時間內完成。


這是我們在 2017 年早些時候開發的一個項目,甲方是一家工藝美術品企業,需要開發一款 APP 展示產品,並引入會員(多級代理),線上下單,返點等功能。 在立項後由於一些原因,選擇了使用 Java 來開發後台管理部分,面向 IOS 和 Android 版用戶端提供服務。

項目的前期調研、分析、設計工作,及推進過程這裡不作過多討論,本文主要圍繞改造工作中的技術問題進行記錄和分析。

先簡單看一下,瞭解這是怎麼樣的一個項目,終端 APP 






後台管理端,有兩個職責:
一)向 APP 端提供功能介面,如商品介面,會員介面等;
二)純後台管理功能,如商品管理,會員管理等;

Java 版後台做出的效果如下:





其它管理類功能後台效果與之類似,總體而言並不複雜。除開商務邏輯之外,是很普通的管理後台。

下面我對這次改造工作的過程進行回顧與說明。
這次改造重構的痛點是要保持 APP 介面的絕對相容,不能影響生產環境的正常運行。


首先我們分析原 Java 版項目:

Java 版後台開發人員把其公司曆史項目也摻雜在內,並且新項目內有多處引用(這個嚴重點都會涉及法律問題),代碼結構參考關聯性比較混亂,背景基本許可權、菜單、字典散落分布在各處:







原後台使用的是 MySql 資料庫,我們這次改造要將資料庫換為 SQL Server ,並使用 Entity Framework 作為我們的資料庫訪問層。

由於 Java 版開發人員使用了原公司的系統,很多表可能僅僅只是改了下表名,裡面有大量無關的欄位,並且保留了原項目的所有表設計,包括一些公用組件需要用到的表,參考關聯性比較混亂,沒有表結構說明書,我們需要重新核對整個資料庫表結構的設計:




資料表欄位名與類屬性名稱的不合理,讓我們的核對工作不是很樂觀:






使用了 mybatis 做為資料訪問層,我們在改造過程中,需要逐一核對資料庫操作,以便在改造過程中保持百分之百的相容:





下面開始我們的改造工作:

第一步:使用 SQL Server 重建資料庫

遷移資料庫分為兩個步驟,一是建庫,二是遷移資料。
理論上來說建庫工作可以匯出原 MySQL 的建庫指令碼調整後在 SQL Server 執行來建立資料庫,但是為了後續工作更穩妥的開展,我們採購了人工核對,手工建立的方式,重新梳理表結構。
我們根據 Java 代碼和原 MySQL 資料庫,分析出了詳細的的表結構設計:



在這一過程中,也對原表結構進行了修訂與細節調整,主要修訂以下存在的問題:
1)欄位命名模糊,比如欄位 modify_person ,或 person_id 。系統中存在 後台使用者 和 客戶 兩個概念,一個用表 user 儲存,一個用表 customer 儲存,所以一些表中的 person_id 指向很模糊。
2)欄位命名不統一,比如同樣是備忘,有些表使用 description ,有些表則使用 remark諸如此類,我們在重構中進行了完全的統一。
3)去除了原系統中不使用的表和欄位,重新設計部分基礎結構方面的表,去除了原開發人員複用的不知名項目相關的欄位關聯關係。
4)一些單詞拼字錯誤。

此外,最佳化了一些表關連接構及業務:
1)商品與商品分類的關係,由一個商品只能屬於一個分類,最佳化為允許屬於多個分類,變為類似標籤的概念。
2)商品的圖片儲存,由關聯表的一對多儲存,最佳化為在商品表通過一個欄位儲存 json 數組來儲存圖片URL,這一最佳化可以使後台相關代碼簡化許多。
3)若干欄位儲存不合理的問題,可能是由於開發過程中的需求調整,開發人員對增加的欄位儲存欠考慮,儲存的位置和結構存在問題,我們在重構中進行了修正。

表和欄位的命名方式,不管合不合理,畢竟我們是重構,不是推倒重做,所以沒有太大變化,繼承了過去的規則和方式,但是去掉了“jade_” 的表名首碼。
梳理資料庫之後,我們為資料庫建立了完整的外部索引鍵關聯關係,使用 Entity Framework 產生了實體模型:




第二步:遷移資料

在改造之後,需要將原資料庫中的資料完全遷移過來,考慮到表結構發生了一定的變化,已無法簡單的資料匯出匯入,我們專門編寫了一系列的遷移指令碼在上線前完成資料移轉工作。


第三步:.NET 版本後台架構的搭建

首先我們確立重構所要達到的目標:

1)完全相容 Java 版本向 APP 端提供的 API 介面,不影響線上 APP 的正常使用。
2)針對後台管理功能所提供的 API 介面,使用更規範的方式獨立實現,不繼承 Java 版的後台 API 介面。
3)背景全部重新實現,包括全部 UI,Java 版本的 UI 有很多缺陷一直被客戶詬病,體驗不佳。
4)以最小的代價完成此次重構,計劃 2 個人,2個周末,共 8 人天的時間完成全部工作。

對以上問題,我們在開工前進行了簡要的分析,難度並不大,但是工作量不小。介面的問題,我們定義兩套,一套後台使用,一套 APP 使用,給 APP 使用的介面,只需參照 Java 版代碼定義 DTO 對象,實現與資料庫實體物件的映射關係即可,後台介面和整個後台管理端UI部分,在過去我做的 .NET Web 項目上進行大幅簡化複用即可。

為了便於說明,我畫了一張簡要的結構圖來說明兩套 Api :



項目的實際規模並不大,且由於我們力求最小成本,所以所見,項目的結構也同樣簡單,本次改造工作無需追求技術體系的先進性,能夠滿足項目的要求即可。
左邊後台到 Api ,再到 Core 有現成的代碼可以複用,實現了出入參協議、鑒權等準系統,只需要實現商務邏輯即可,右側 AppApi 部分,則需要多一層協議轉換工作,將原 Java 版本的出入參協議轉換為 Core 要求的協議格式,而原 Java 版的 Api 介面協議並不統一,需要一個一個介面核查複刻。 

後台解決方案結構如下:



CCPRestSDK
    我們使用的簡訊平台的 SDK。
Jade.Core
    商務邏輯層
Jade.Model
    資料庫實體模型
Jade.Model.Dto
    用於前後台資料轉送的對象定義,包括針對 Model 的傳輸對象定義和其它需要傳遞的對象定義。
Sheng.Kernal
    基礎類庫,提供了如反射,HTTP請求,對象映射等等基礎功能。在複用到本項目時經過了簡化。
Sheng.Web.Infrastructure
    用於 Web 項目的基礎類庫,提供了通用 Api 協議定義,控制器、DTO等共通的基礎功能,在複用到本項目時經過了簡化。
    這裡包括一個專門為此項目寫的友盟推送實現,友盟官方沒有提供 C# 版 SDK。


考慮到這個項目比較簡單,我在這裡不再對基本技術體系做太多贅述,而是通過兩個簡單的請求過程進行闡述,代碼已經開源在了 Github 上,可以下載代碼後根據下文進行查看。

Github: https://github.com/iccb1013/Jade.Net


Api 的請求過程




在 Areas 下提供了 Api 和 AppApi 兩個地區提供介面,我們以 Api 下的 ProductController 為例,它向後台 UI 提供產品相關的介面:



以 UpdateProduct 介面進行說明,此介面用於更新產品,此介面接收前端傳入的商品資訊,並更新資料庫中的商品資訊:



此介面的 RequestArgs 方法是介面 Controller 的基礎 ApiBaseController 所提供的,用於把前端 Post  過來的內容還原序列化成指定的對象。

Product_Info product = Mapper.Map<Product_Info>(args); 

作用是將 Dto 對象映射為資料庫實體物件,這裡我們使用了開源組件 AutoMapper。

有關 AutoMapper  可以訪問:http://automapper.org/

引用 AutoMapper 組件後,只需定義不同對象間的映射規則即可,可適用於絕大多數情況,Product_Info 的映射規則如下:



介面在完成對象映射後,調用 Core 中的方法來實現業務:



基本的 Entity Framework 操作,不作贅述。

這裡有一個細節,是圖中標出的  ShengMapper.SetValuesWithoutProperties 部分,這個方法把 傳入的 product 中資料拷貝到從資料庫取出來的 dbProduct 中,但是跳過2個指定的屬性和所有的虛屬性。
AutoMapper 不能定義同一個物件類型的映射規則,也不能靈活的在不同情境使用不同的規則,所以我寫了 ShengMapper 用於處理這種情況。

ShengMapper 也是開源的:Github: https://github.com/iccb1013/Sheng.Mapper

此外可以留意到方法的返回對象是 NormalResult,這是一個 Core 層使用的一般返回對象:



相當於一個邏輯上不需要傳回值的方法,但我們需要知道它的執行狀態,如:



有一些開發人員愛用 Exception 來返回業務結果,這樣做是非常不合適的,比如這裡的 商品編碼重複,他是一個業務操作的結果,並且這個結果是在我們的預期之內的,不是一個 程式異常。
用異常來返回業務操作結果有兩個非常大的弊端,一是拋異常時非常影響效能,二是要區別對待真的程式異常和業務結果,也是十分麻煩的事情。總之,沒有理由這麼做。

NormalResult 還提供了一個重載,可以返回指定類型的對象結果:



當 Core 層完成業務操作時,Controller 層的 API 會通過一個 ApiResult 對象來封裝 Api 介面的返回結果:



此處的 return ApiResult() 方法,是 Sheng.Web.Infrastructure 中的 BaseController 所提供的,可以處理大多數 Api 返回結果:

 

如果都不能滿足,也可以手工 new 一個 ApiResult 返回:



Hint 只在部分特殊情況下使用,並不會為每種操作結果安排一個錯誤碼,對於我們的項目來說,多傳一些位元組回去沒有問題,但有些特殊情境,前端需要知道具體的情況針對性處理,這時我們才使用錯誤碼。


Sheng.Web.Infrastructure 還提供了對於請求分頁列表資料的通用協議:






GetListDataArgs 對象使用一個 ParametersContainer 來儲存查詢條件,它其實是一個索引值對。避免為每一個查詢定義強型別的查詢入參對象,實在是太過麻煩了,也沒有必要。

我們通過這樣的方式來處理查詢條件即可:




下面我們再看一個 AppApi 的說明,我們還以產品資訊為例,它的 Api 定義:



在 AppApi 中,為了相容既有的介面約定,做了許多轉換工作:



把原 APP 介面的查詢條件,轉換為上文提到的 ParametersContainer:



這裡把 APP 介面的列表查詢入參,轉換為我們過去定義好的 GetListDataArgs:



這裡做一些欄位轉換時的特殊標記:




此外,原 Java 版在向 APP 提供介面時,提供給 APP 的 DTO 對象,十分詭異的和資料庫模型不一致,比如資料庫欄位名有底線,但是 DTO 傳輸模型沒有,還有一些欄位的命名則是完全不一樣,我們利用 AutoMapper 來逐一映射:



至此,項目的結構已經完全清楚,剩下的全部是商務邏輯層的業務操作。 

重構工作的完成的效果:






前端 UI 的實現方法:

前端 UI 及指令碼庫複用了我之前寫過的 Web 項目, Asp.net MVC,結合使用了前後端分離和 Razor 兩種方式。

Razor 引擎具有極高的開發效率,在做頁面資料展示時非常的方便,藉助 Razor 和 Asp.net MVC 的布局頁和分布頁技術,可以快速而有效搭建頁面架構。

如,定義了一個用於一般列表頁面的布局頁(模版):



可以輕鬆的看出頁面定義了大體結構:標題,副標題,按鈕,查詢區,表格容器和分頁容器。表格容器和分頁容器並沒有使用 Razor,而是在具體視圖頁通過一般前後端分離的方式用指令碼進行處理。

這是一個一般列表頁視圖實現的例子,基於上面的布局頁,代碼量就只有不到100行,就實現了一個普通列表頁面。



只需要初始化table,主要是定義這個頁面中表格所具備的列,查詢參數即可,另外在定義一個查詢條件區,這個列表頁面就完成了。所有共通的功能都寫在了布局頁和共用的指令檔中。

編輯和查看頁面也使用了同樣的處理方式,不再贅述。 

基於開發效率和實際項目需要考慮,我們這裡沒有使用重量級的前端開發架構,而是複用了過去我寫的 js 指令碼,這些指令碼基於 jQuery 完成一些共通的功能來提高開發效率,如處理資料載入綁定,發起 Api 請求等操作。

common.js:



這裡的 __getDto 和 _setDto 方法,搭配頁面 HTML 的特殊標記,可以實現前端對象的自動產生和綁定:





在 HTML 標籤中用 dtoproperty 屬性標記出 DTO 對象的屬性名稱後,使用 __getDto 方法即可自動產生前端對象。



使用 __setDto 方法,則可以快速把 Api 返回的對象,載入到前端控制項中。

如所示,前端畫面簡單的儲存,載入資料就完成了。


listViewCommon2.js,這是用於一般表頁的指令碼,基於這裡的共通指令碼,加上Razor 引擎的布局頁功能,實現了不到 100 行 HTML 和 JS 代碼即可完成一個列表頁面,當然,如果追求技術上的更加完美,可以繼續抽象,繼續封裝達到更好的效果:




editViewCommon.js ,這是用於一般編輯頁面的指令碼:




你可以從 Github 上下載代碼之後在 Jade.Shell 的 Scripts 目前下查閱這些指令碼。

整個項目從純技術角度來說還有許多提高改進的空間,但我們現在是做項目,不是做研究做架構產品,我們可以在未來的項目中通過項目推進的方式一步一步的提煉和完善我們的開發模式和技術體系。

最終,2個人,2個周末,在大量複用過去代碼的基礎上,只消耗了8人天完成了本次改造工作。

Github: https://github.com/iccb1013/Jade.Net


本次工作之後的一點心得體會,主要是幾個失誤的地方:

1)前期將項目交給過去的同事來做,沒有過多關注,導致了項目上線前遭遇許多問題,卻得不到妥善解決,我個人秉承誠以待人的原則,用人不疑,疑人不用,這一點我想沒有錯,錯的是我完全放手沒有投入精力把控工程,除了報銷吃喝費用外基本不參與,這是一個教訓,無論何種情況,應該一定程度的參與並把控好各項主要工作。

2)立項時預估後台工作量只需1個人月,為了分擔人員風險,我還是多付了一個人的費用安排2個人來做,但在人員使用上,沒有做到風險規避。

3)過早的結清了人員費用,導致工作無法順利推進,對於外包項目,費用結算一定要有計劃性,包括預留尾款。

最後我想談一談技術人員的“人設”問題,這是我從此項目上深刻認識到的一個問題。

我做了超過十年的技術研發工作,但同時許多朋友說我不像一個程式員,我並不認為程式員一定要雙肩包,開口只談技術,相反隨著年齡和閱曆的增長,我一天比一天認識到業務、行業的重要性,我很早就知道做技術是為了什麼,做技術不是為了做技術,而是為了服務我們的客戶,服務社會,服務一切需要的人,我更關心的是我要做什麼事情,我的目標是什麼。一直以來我認為這是一個技術人員轉變和提高的核心觀念。

但是最近一到兩年,我慢慢意識到,有時我們需要讓自己契合對方心理上的某種“人設”,就這個玉雕工作室的項目來說,我和客戶談需求和業務比較多,吃飯喝酒比較多,加上不那麼技術的形象(長頭髮,紮辮子),導致客戶始終不認為我是一個技術人員,當然我也不太在意這一點,但是,後來我意識到一些問題。

對於這種小型外包項目,特別是還沒有接下來之前,客戶最在意的還是我們有沒有技術實力做好,能不能給我們做,這裡有一個角色帶入的問題,這時我不是供職於大公司的專案經理服務於既有客戶,紮辮子花衣服做需求也不是不可以,但是當時我是一個要接項目的人,在互相不瞭解的情況下,如何快速建立信任?最簡單的辦法是讓自己契合對方心理上的“人設”:我就是你要找的人。

許多客戶包括企業領導層,對技術人員都有自己所理解的“人設”,客戶不懂技術,領導也許也不那麼懂技術,他們要找有技術實力的人,怎麼辦呢,說白了,憑感覺。

玉雕這個項目直到原來 Java 版背景兩個開發人員撂挑子,客戶都感歎他們技術好,客戶是做工藝品的,和IT技術八杆子打不著邊,為什嗎?這件事讓我反思了很久,就是“人設”。

於是我剪了頭髮,換上襯衫,買一個瑞士軍刀電腦包(笑)。以便於我在不同的時候有不同的人設。

當然更重要的是對於技術和業務的種種理念,在和不同的人表達的時候,要特別注意表達的方式和技巧,以及表達到什麼度。對於水平比自己高的人,可以隨意表達自己的想法,不要怕,但是遇到經驗或能力不如自己的人時,要特別小心,因為對方可能無法體悟你的意思。

比如和同樣一個做過十年項目的老鳥說一句:技術不是那麼重要,也許雙方可以會心一笑,重要的是彼此知道我們所說的技術不重要的點,技術不重要的度在哪裡。但是如果和一個沒有太多各種項目經驗的人說這樣的話,可能是不合適的,對方會不能理解,進行主觀的判斷你不行,因為你不技術。

唯一的辦法是不要太個性,要契合別人的人設,不管他有沒有道理。"木秀於林風必摧之",瑞士軍刀電腦包該背還是要背(笑)。



本文聯合

曹旭升
QQ:279060597
Email:[email protected]
http://blog.shengxunwei.com

範大宏
QQ:237194340
Email:[email protected]

8人/天,小記一次 JAVA(APP後台) 項目改造 .NET 過程(後台代碼已完整開源於 Github)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.