如何开发高度可定制的产品
您是否聽說過:“我們非常喜歡您的產品……除了一些小細節”。 然后,CIO推出了一系列其他“必備”要求的清單,其中有數百個要求添加到您的驚人產品中。 您是否聽說過,甚至說過:“團隊,我們即將簽署一份利潤豐厚的合同,但是……”? 然后,客戶對附加功能的愿望清單使開發人員感到頭疼。
那么,如何使產品遠離客戶的潛在危險想法,同時又使他們滿意呢? 對于專門設計為以特定方式運行但現在具有大量附加組件的產品,如何保持最高性能水平呢? 為已開發的解決方案提供不間斷且出色的支持的基本需求將帶來多少挑戰?
在商業世界中,產品定制已成為越來越令人期望的要求,并且響應于這種客戶需求,已經發展了許多通用實踐。 您可以在下面找到典型方法的概述。 如果您已經熟悉它們,那么歡迎您直接滾動至“ 擴展方法 ”部分,并了解我們如何以我們認為更有效的方式解決這些挑戰。
一體
定制的最直接,最明顯的解決方案是實施一個核心產品所需的所有內容,然后采用“ 功能切換 ”技術來滿足每個特定客戶的需求。
多合一方法的主要優點是保留了整體產品,這對于某些類型的產品似乎是一種很好的方式,這些產品通常可以滿足業務需求,而無需進行廣泛的定制。
這種方法的自然局限性隱藏在“不需要太多定制”的假設中。 通常,產品開發就是從這種信念開始的,但是經過多次交付,您才真正意識到需要多少特定于客戶的功能。 陷入困境的情況并不少見。 拒絕定制開發并可能失去客戶,或者將源代碼轉換為具有針對單個客戶的功能的垃圾箱 ,這些功能對于大多數最終用戶而言可能是無用的。
您會選擇哪個選項? 顯然,在艱難和艱難的地方之間進行選擇并不是成功的方法。
簡介:僅當您確定需要罕見且有限的定制時,“多合一”方法才是合適的選擇。 否則,您將面臨可管理和可支持產品與客戶滿意度之間的選擇。 讓我引用杰里·加西亞(Jerry Garcia)的話:“不斷選擇兩種邪惡中的較小者仍然是選擇邪惡”。
分枝
如果重大定制是交付的“必不可少”部分,則不能采用“多合一”技術。 還有另一種簡單的方法- 分支 。 您只需分支產品代碼庫,然后單獨進行更改即可。
將分支與“多合一”進行比較,最大的優點是,沒有適用于自定義范圍的限制。 您使用單獨的分支來滿足不同客戶的特定要求,并避免在同一代碼庫中混合使用所有功能。
但是,它的另一面可能會在產品發展方面變成死胡同。 顯然,產品分支是主要的開發空間:大多數錯誤修正,改進和新功能都首先被應用到產品中。 因此,需要頻繁合并以使所有定制分支與核心產品保持同步。 只要原始產品源代碼不受定制分支的影響,合并是一項簡單的操作,否則,合并將變得非常耗時,并可能導致不可避免的回歸錯誤。
如果您僅限于很少的自定義分支,則此方法仍然可以使用。 但是,隨著交付實例數量的增加,面臨“通過合并實施酷刑”的可能性迫在眉睫。
簡介: 分支方法無疑是非常靈活和直接的-產品的任何部分都可以修改。 但是,交付后階段可能非常費力,隨著時間的推移變得更加困難,并且不太可能導致交付大量可管理的定制分支。
實體-屬性-價值模型
實體-屬性-價值模型 (又名對象-屬性-價值模型,垂直數據庫模型和開放式架構)是眾所周知的且被廣泛使用的數據模型。 EAV支持動態實體屬性,通常與標準關系模型并行使用。
從產品化的角度來看,使用EAV的主要優點是您可以“按原樣”交付產品,然后通過在運行時添加所需的屬性來調整數據模型,從而保持源代碼的整潔。
與以往一樣,還有一個缺點:
- 有限的適用性–僅通過允許向實體添加屬性來限制EAV模型,然后根據預編程的邏輯將其自動嵌入到UI中。
- 額外的數據庫服務器負載–垂直數據庫設計通常成為企業應用程序的瓶頸,企業應用程序通常使用大量與它們相關的實體和屬性進行操作。
- 最后,如果沒有復雜的報告引擎,就無法想象企業系統。 EAV模型具有“垂直”數據庫結構,因此有可能帶來許多麻煩。
簡介: 實體-屬性-價值模型在某些情況下具有很大的價值,例如當需要提供通過具有附加信息性數據而實現的靈活性時,該信息性數據未在業務邏輯中明確使用。 換句話說,EAV具有良好的適度性,例如,除了標準的關系模型和插件體系結構之外 。
插件架構
插件體系結構是最流行且功能最強大的方法之一,其中功能邏輯作為單獨的工件(稱為插件)保存。 要覆蓋現有的開箱即用行為并運行插件,必須在產品源代碼中定義“定制點”(即擴展點)。 “定制點”是源代碼中的某個位置,應用程序在該位置上瀏覽附加的插件,以檢查插件是否包含要在此處運行的替代實現。 插件體系結構的一種變化是外部腳本。 在實現功能實現并將其作為腳本存儲在外部時。 腳本調用也由預定義的“定制點”控制。
使用這種插件方法,可以使產品“清潔”特定的客戶要求,“按原樣”交付核心產品,并根據插件或腳本的要求自定義行為。 這種方法的另一個優點是管理完善的更新過程。 產品和插件功能的完全分離使彼此之間可以獨立更新。
當然存在限制:主要限制是不可能完全知道將來可能會提出哪些自定義要求。 因此,只能猜測應該在何處嵌入“定制點”。 當然,這些可以作為緩解“防萬一”計劃的零星散布在各處,但這將導致代碼可讀性差,硬調試以及復雜的支持。
簡介:如果易于預測“定制點”,那么插件架構確實可以工作,但是請注意,“定制點”之間的定制是不可能的。
擴展方法
我們在企業軟件開發平臺CUBA中實施了獨特的方法。 正如我們上一篇文章所述 ,CUBA是一種非常實用的活生物體,它是通過開發人員驅動的演變過程創建的。 因此,根據我們在現成產品上的豐富經驗,我們提出了兩個最終要求:
- 客戶特定的代碼應與核心產品代碼完全分開
- 產品代碼的每個部分都應該可以修改
我們設法滿足了這些要求,并通過我們的“擴展”機制實現了更多目標。
CUBA擴展
擴展是一個單獨的CUBA項目,它繼承了基礎項目(即您的核心產品)的所有功能,并將其用作庫。 顯然,這使開發人員可以實現全新的功能而不會影響父項目,但是由于使用了“ 開放繼承”模式和特殊的CUBA工具,您還可以覆蓋父項目的任何部分。 總之,擴展是實現本文開頭討論的數百個“少量次要細節”的地方。
實際上,每個CUBA項目都是CUBA平臺本身的擴展-因此它可以覆蓋任何平臺功能。 我們自己采用了這種方法,以從核心平臺中分離出一些現成的功能(全文搜索,報告,圖表等)。 因此,如果您在項目中需要它們,則只需將它們添加為父項目-就是這樣,是多重繼承!
您可以用相同的方式構建分層的定制模型 。 這聽上去很復雜,但是很合理。 讓我舉一個真實的例子: Sherlock –是Haulmont完整的出租車管理解決方案,支持從預定,派遣到應用程序和計費的出租車業務的方方面面。 該解決方案涵蓋了客戶業務的許多不同方面,其中許多是與位置相關的。 例如,所有英國出租車公司都具有相同的法律法規,但是其中許多法規不適用于美國,反之亦然。 顯然,我們不想在核心產品中實施所有這些規定,因為:
- 這是“特定于操作區域”的功能
- 當地法規可能會對不同國家的出租車隊運營產生完全不同的影響
- 一些客戶根本不需要監管控制
因此,我們組織了多級擴展層次結構:
干凈利落。
如您所見,通過使用擴展,您既不需要分支也不需要在核心產品中集成所有需求 ,因此代碼保持簡潔且易于管理。 聽起來真是太好了,所以讓我們看看它是如何工作的!
向現有實體添加新屬性
假定我們具有用戶實體的產品定義,該產品定義由兩個字段組成:登錄名和密碼:
@Entity(name = "product$User") @Table(name = "PRODUCT_USER") public class User extends StandardEntity {@Column(name = "LOGIN")protected String login;@Column(name = "PASSWORD")protected String password;//getters and setters }現在,我們的一些客戶提出了一項附加要求,即向用戶添加“家庭住址”字段。 為此,我們在擴展中擴展User實體:
@Entity(name = "ext$User") @Extends(User.class) public class ExtUser extends User {@Column(name = "ADDRESS", length = 100)private String address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;} }您可能已經注意到,除@Extends以外的所有注釋都是通用的JPA注釋。 @Extends屬性是CUBA引擎的一部分,它甚至在整個產品功能上都將User實體全局替換為ExtUser 。
使用@Extends屬性,我們強制平臺執行以下操作:
換句話說,如果聲明了擴展實體,則基礎實體將在整個解決方案(產品和擴展)中被放棄,并且被擴展實體全局覆蓋。
屏幕定制
因此,我們通過添加地址屬性擴展了User實體,現在希望更改能夠反映在用戶界面中。 首先,讓我們看一下原始(產品)屏幕聲明:
<windowdatasource="userDs"caption="msg://caption"class="com.haulmont.cuba.gui.app.security.user.edit.UserEditor"messagesPack="com.haulmont.cuba.gui.app.security.user.edit"><dsContext><datasourceid="userDs"class="com.haulmont.cuba.security.entity.User"view="user.edit"></datasource></dsContext><layout><fieldGroup id="fieldGroup" datasource="userDs"><column><field id="login"/><field id="password"/></column></fieldGroup><iframe id="windowActions" screen="editWindowActions"/></layout></window>如您所見,CUBA屏幕描述符表示為普通XML。 顯然,我們可以簡單地在擴展名中重新聲明整個屏幕描述符,但這意味著要復制粘貼其中的大部分內容。 因此,如果將來產品屏幕中發生某些更改,我們將必須手動將這些更改復制到擴展屏幕中。 為避免這種情況,CUBA引入了屏幕繼承機制,您所需要的只是描述對屏幕的更改:
<window extends="/com/haulmont/cuba/gui/app/security/user/edit/user-edit.xml"><layout><fieldGroup id="fieldGroup"><column><field id="address"/></column></fieldGroup></layout></window>您可以使用extends屬性定義祖先屏幕,并且僅描述要更改的主題。
這個給你! 最后,讓我們看一下結果:
修改業務邏輯
為了實現業務邏輯修改,CUBA平臺使用Spring框架,該框架構成了平臺基礎結構的核心部分。
例如,您有一個中間件組件來執行價格計算過程:
@ManagedBean("product_PriceCalculator") public class PriceCalculator {public void BigDecimal calculatePrice() { //price calculation} }要覆蓋價格計算實現,我們只需要執行兩個簡單的操作。
首先,擴展產品類并覆蓋相應的過程:
public class ExtPriceCalculator extends PriceCalcuator {@Overridepublic void BigDecimal calculatePrice() { //modified logic goes here} }最后,使用產品Bean標識符在Spring配置中注冊新類:
<bean id="product_PriceCalculator" class="com.sample.extension.core.ExtPriceCalculator"/>現在, PriceCalculator注入將始終返回擴展類實例。 因此,修改后的實現將在整個產品中使用。
擴展基礎產品版本
隨著核心產品的發展和新版本的發布,您最終將決定將擴展程序升級到最新的產品版本。 過程非常簡單:
大多數情況下,產品API在每次更新之間都不會發生重大變化,尤其是在次要版本中。 但是,即使API發生了“大爆炸”,產品通常也至少保持幾個未來版本的向下兼容性,并且舊的實現被標記為“已棄用”,從而允許將所有擴展遷移到最新的API。
結論
作為一個簡短的摘要,我想以表格形式說明比較分析的結果:
| 一體 | 分枝 | 電動汽車 | 外掛程式 | CUBA擴展 | |
| 獨立于架構 | + | + | – | – | – |
| 動態定制 | – | – | + | +/- | – |
| 業務邏輯定制 | + | + | – | +/- | + |
| 數據模型定制 | + | + | + | +/- | + |
| 用戶界面定制 | + | + | +/- | +/- | + |
| 代碼質量和可讀性 | – | +/- | +/- | +/- | + |
| 不影響性能 | + | + | – | + | + |
| 軟件回歸的風險 | 高 | 高 | 低 | 介質 | 介質 |
| 長期支持的復雜性 | 極端的 | 極端的 | 低 | 介質 | 介質 |
| 可擴展性 | 低 | 低 | 高 | 高 | 高 |
如您所見,擴展方法功能強大,但是它缺少的一件事就是能夠動態地微調系統(動態定制)。 為了克服這個問題,CUBA還提供了對實體屬性值模型和插件/腳本方法的全面支持。
我希望您會發現此概述很有用,當然您的反饋意見也將受到贊賞。
翻譯自: https://www.javacodegeeks.com/2015/07/how-to-develop-a-highly-customizable-product.html
總結
以上是生活随笔為你收集整理的如何开发高度可定制的产品的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WildFly管理控制台已更新–请求反馈
- 下一篇: 苹果手机怎么辨别真假