回想起來,我在目前的團隊(金融科技領域)待了有很長一段時間了,一直在做SDK研發,平時工作中經歷過大刀闊斧一蹴而就的喜悅,也經歷過被一個問題按在地上摩擦,無奈「廢寢忘食」的不堪,日復一日年復一年,如果硬要吐露一下內心的感受,就一個字「難!」。
為什麼說難呢?總結下來有兩方面原因,一方面原因是所處行業為金融行業,金融行業相對其它行業,更加註重產品合規、功能穩定、資料安全、使用者隱私等,所以在產品方面的要求非常嚴格甚至苛刻,嚴格到必須做各種眼花繚亂的測試報告,苛刻到不允許呼叫任何一個有可能存在風險的API。另一方面原因就是所研發的產品是SDK,SDK和APP一樣,是程式碼、程式、軟體,但和APP又不一樣,SDK(Software Development Kit)被定義為軟體開發套件,具備工具的屬性,是一種會被整合到其它軟體裡面的軟體包,在開發SDK的時候,需要處理好SDK和宿主程式之間的關係,需要比開發APP考慮更多的問題,例如:SDK怎樣設計才能更方便地被整合和使用,SDK怎樣避免和宿主程式之間發生衝突,SDK如何保證前後相容、SDK如何控制包體積等。
下面我們就來具體說說給金融科技領域編寫使用者端SDK,需要思考哪些方面的問題。
一款SDK之所以能作為產品誕生並不斷髮展,一定有它的社會價值,這種價值可能體現在它能給行業面臨的一些問題帶來解決方案,或者是能夠降低生產成本,又或者是能夠提升生產效率等,如果SDK不具備實用價值,不能為他人、為社會所需要,即使程式碼質量再高,也不可能在市場上取得成功,甚至都無法生存下去。
所以,思考千萬條,實用第一條!
正所謂「無規矩不成方圓」,人類從原始時期開始,一直到現在的文明社會,每個階段都會在種群內部建立一套規章制度,用以約束個體行為,促進成員間的合作,保障社會活動有序進行,這種規章制度不斷演進,不斷合理化,就逐漸形成了法律法規體系,法律法規體系是一套邏輯嚴謹且高度完備的系統,從基本法到一般法律,涉及社會中的方方面面,這裡面就包含對各行各業的法律規定,金融行業作為關係民生的基礎行業,涵蓋銀行業、證券業、保險業、基金業、信託業等眾多子行業,這麼重要且龐大體系要能正常運轉,自然離不開行業法律法規的支撐,國家不僅為金融行業頒佈了各種法律條文,還建立了專門的監管機構來監督金融活動的開展過程,旨在建立合規合法的金融市場,保證金融行業的穩定可持續發展。
軟體作為金融企業從傳統服務行業到數位化高科技行業轉型的基礎設施,而SDK又作為眾多軟體的零部件,自然而然必須符合法律規範,接受國家的監督管理。軟體是人類新時代文明的產物,大大解放了生產力,能用來做很多事情,如果利用得好,可以帶來巨大收益,如果遭到濫用,則會帶來嚴重損失甚至危害,所以必須對軟體制定各種約束規則,時刻監督軟體的運作過程,保證軟體是用來提供優質服務的,而不是破壞社會正常秩序的。
安全可以看作是合規的進一步延伸,如果說合規是通過技術之外的手段來約束軟體的自由,而安全則是通過對技術內部的審查來判斷軟體是否達到安全標準,並決定是否允許使用軟體。
任何一個軟體都不是絕對安全的,是軟體總會有漏洞,有漏洞就會存在被破解、被攻擊、被非法利用的風險,一旦這種風險變為事故,損失可大可小,但對於金融行業而言,再小的事故都會導致口碑和客戶信任感的急劇下降,所以金融行業在軟體安全性方面是極度重視的。
金融企業通常會採取各種方式加強軟體的安全性,例如:
程式碼掃描
金融企業會通過多種程式碼檢測工具對程式碼進行安全掃描,掃描完成之後會形成書面檢測報告,我們拿到檢測報告之後要做的事情就是分析其中每個風險項產生的原因,思考解決辦法,然後逐個清理掉。
軟體加固
金融企業會藉助專業的加固平臺對軟體進行加固,包括APP加固、二級制包加固等,加固是為了增加軟體被破解的難度,最大程度防止軟體被反編譯,被他人竊取關鍵資訊和軟體勞動成果。
資料加密
網際網路時代,最有價值的往往不是各種層出不窮的軟體本身,而是隱藏在軟體背後的資料,因為資料是記錄系統中各角色資訊以及使用者行為的第一手資料,通過這些資料我們可以洞察整個行業的現狀,並且分析預測出發展趨勢,因此資料就是機密,對資料的保護至關重要。金融企業通常都會對資料進行各種加密處理,如資料傳輸加密、資料儲存加密等。
軟體安全認證
金融企業在軟體類庫方面有嚴格的管理機制,只有經過安全認證的軟體類庫才會被允許使用。部分企業會建立私有軟體倉庫,並把經過安全認證的軟體類庫同步到倉庫裡面,開發過程中,只允許依賴自己軟體倉庫裡面的類庫,不能隨便參照外部的類庫。
漏洞跟蹤
金融企業對軟體漏洞方面的關注程度是非常高的,每當有權威機構釋出漏洞說明時,他們都會第一時間檢查自己的產品裡面是否有用到漏洞涉及到相關軟體,如果有就必須及時處理。
以上只是列舉了金融企業在軟體安全性工作方面的一些常規操作,實際情況會複雜得多。我們在給金融企業編寫SDK的過程當中,需要配合金融企業完成各種安全檢測,並及時處理各種安全性方面的問題。
軟體的穩定性也是影響到軟體是否可用的重要指標,只有穩定執行的軟體才能保證業務的正常開展。試想一下,如果一個軟體bug層出不窮,經常用著用著就卡死了或者崩潰了,會有什麼後果?可能會收到客戶的反饋和投訴,導致客戶受到損失,口碑日趨下滑,逐漸失去使用者群體……這些都是作為乙方的我們最害怕,最不願意看到的。因此,保證軟體的穩定性是我們在軟體開發過程中極為重要的一環。
SDK作為第三方庫,會被整合到不同的宿主程式裡面去,這就使得SDK面臨的業務場景複雜多樣,一些邊緣場景更是無法預知,也許SDK在一個APP中表現「完美」,但到了到另一個APP中就開始「抽風」了,如何保證SDK在各種場景下都能穩定執行,成了一個不折不扣的難題,但是我們仍然可以通過努力來減少不穩定因素。
SDK要保證穩定性,需要產品、研發、測試三管齊下,團隊成員齊心協力、緊密配合。
SDK要保證穩定性,在版本控制方面也需要做好管理,例如SDK可以分不同的版本發行,提供諸如穩定版、開發版、體驗版之類的各種版本,用於滿足不同使用者的需求,穩定版可以很長時間更新一次,追求穩定的客戶可以使用穩定版,開發版可以在開發過程中有更新的時候釋出,用於內部測試等,體驗版可以每個迭代或幾個迭代釋出一次,用於及時對外發布更新,一些熱衷嚐鮮的使用者可以提前拿來體驗。這樣穩定版的更新頻率不會太頻繁,可以在一定程度上避免穩定性問題。
何為友好?人與人之間的友好體現在大家相互尊重,能夠禮貌、和諧、融洽地相處,那麼SDK的友好又體現在哪些方面呢?和SDK直接打交道的是整合SDK的宿主程式,所以SDK的友好性也是直接體現在SDK和宿主程式之間的,要思考SDK友好性的問題,就需要思考SDK如何才能和宿主程式和諧共處。
宿主程式要使用SDK,第一步要做的便是整合SDK,因此,體現SDK友好性的第一點就是SDK整合起來簡單方便。以Android工程為例,在build.gradle檔案中僅新增一行程式碼,就把SDK依賴到了工程裡面,除此之外,不需要改動工程原有的任何設定,不需要處理任何編譯報錯,便能成功把工程執行起來,這就說明SDK在整合方面非常友好。
宿主程式要使用SDK,需要SDK提供各種介面給外部呼叫,例如初始化SDK的介面、呼叫SDK內部各種能力的介面、監聽SDK內部事件的介面等等,因此,體現SDK友好性的第二點就是SDK提供的介面很完善,介面命名合理,引數含義準確,註釋清晰,呼叫起來很容易很方便。
不管是整合SDK還是使用介面,如果有一份清晰完善的檔案拿來參考,那便是再好不過的了,這樣能大大降低開發者的學習門檻,因此,SDK的友好性也體現在提供了高質量的使用檔案。
除了檔案,開發者們往往也希望有範例可以參考,畢竟有一份現成的程式碼學習起來會更加直觀,範例能幫助開發者更加快速地掌握SDK使用方法。因此,SDK的友好性還體現在有完善的範例可供參考、學習。
在做行動端開發的時候,我們經常面臨的一項優化內容就是APP瘦身,APP為什麼要瘦身?因為如果APP體量太大,就意味著下載APP需要耗費更多的流量,網路不好的話下載耗時也會增加,安裝APP也需要佔據更大的儲存空間,使用者使用APP的成本就增大了,體驗也大打折扣,這就是為什麼當下小程式如此流行的原因,因為小程式足夠輕量,安裝解除安裝都非常方便,使得大眾在平時工作和生活中往往更傾向於使用小程式,而不是到手機應用市場裡面去獲取一個笨重的APP。
雖然小程式對原生應用產生了很大沖擊,但並不意味著小程式能夠完全替代原生應用,因為小程式畢竟還是一種介於原生和前端之間的技術,它支援垮端,能夠呼叫很多原生的能力,擁有比純Web應用更好的UI互動體驗,但是比起原生應用,還是不如原生應用那麼流暢,渲染出來的控制元件還是不如原生應用那麼精美,原生應用的優勢是小程式無法替代的。
不過小程式等優秀前端技術的出現,還是給原生應用開發敲響了警鐘——原生應用也需要更加註重輕量化。其實不僅僅是金融企業,很多網際網路企業在開發APP的時候,都會盡可能地縮減應用體積,有的APP對體積大小非常敏感,例如當SDK的體積超過1MB時就會猶豫要不要使用SDK了。所以,SDK開發者們不得不面對這樣一個問題,那就是SDK必須「小而美」。小,要求SDK佔用的體積小,美,要求SDK小的同時還必須功能強大,要能滿足使用者的各種需求。
俗話說「魚與熊掌不可兼得」,我們如何實現SDK的小而美?這裡簡單羅列一下可以採取的措施:
保證程式碼的簡潔、清爽、優雅
架構合理,邏輯清晰,乾淨整潔的程式碼,閱讀起來會更加容易,開發人員維護起來也會簡單許多,出現程式碼冗餘,「屎山」堆積的情況也會大大減少,反之如果程式碼邏輯混亂,程式設計師A今天這麼寫,程式設計師B明天那麼改,久而久之,程式碼不僅可能BUG叢生,而且會變得越來月臃腫,臃腫的程式碼自然而然無法做到輕量。
對資原始檔進行處理
SDK中佔體積最大的可能不是程式碼,而是各種資原始檔,包括圖片、音訊、視訊等,我們可以對這些檔案進行處理,例如:
對程式碼進行壓縮
例如,在Java裡面我們可以藉助ProGuard工具對程式碼進行混淆,混淆過程中會移除程式碼中無用的類、欄位、方法,並且用簡短無意義的名稱對類、欄位、方法重新命名,這樣在保護程式碼的同時也能夠減小程式碼佔據的空間。
減少對第三方庫的依賴
在實現一些複雜功能的時候,我們往往傾向於找現成的輪子直接套用,但是直接依賴第三方庫會帶來一些問題,其中一個問題就是可能會增加程式碼體積,因為有的庫雖然功能很強大,但是體積也很大,實際上,有時候我們只需要其中一部分功能,這個時候我們最好不要直接依賴第三方庫,我們可以對其進行裁剪,只保留我們所需要的程式碼,或者借鑑其思路自己編碼實現,在實現過程中也許還能夠對程式碼進一步做精簡。
元件化
把SDK按照功能模組拆分為多個小的SDK,每個小的SDK作為單獨的元件進行維護和釋出,使用者在整合SDK的時候就只需要依賴要用到的SDK就可以了,這樣就避免了一下子引入整個SDK帶來的體積問題。
外掛化
把SDK按照功能模組拆分為多個小的SDK,每個小的SDK作為單獨的外掛進行維護,使用者只需要整合核心SDK,其它SDK可以在執行過程中通過核心SDK動態下載並載入,這樣SDK的體積也會大大減小。
同一套程式碼,在不同的機型上面,或不同版本的作業系統中,或不同的場景下,表現可能會不一致,有的不一致屬於正常現象(例如某個二次開發的作業系統更改了UI樣式,和原生作業系統不一樣了),但也有一些不一致是因為沒做好適配導致的。其實,適配一直是需要投入大量精力且讓人頭疼的工作,因為移動裝置型別太多,有全面屏的也有非全面屏的,有記憶體大的也有記憶體小的,有系統魔改的好的也有被改的亂七八糟面目全非的,碎片化很嚴重,只能說開發者們太難了!
一個好的產品,在適配方面一定是做得還不錯的,所以要想把產品做好,也一定要做好適配工作,想辦法讓自己的程式碼相容更多的機型、相容不同版本的系統、相容各種複雜的場景。
做好適配工作,一方面需要研發人員瞭解基本的適配規則,例如螢幕適配原則,在研發過程中嚴格遵循這些規則,同時主動跟進系統版本變化情況,及時做好版本適配,有時候還要深入挖掘不同機型之間的差異,以彌補手機廠商們改造系統時帶來的問題。另一方面,測試人員需要做大量測試,以及時發現一些適配問題,交給研發人員修復。
SDK研發是一個不斷迭代升級的過程,每隔一段時間就會對外發布新的版本,在這個過程當中,我們必須做好前後相容,不然會出現各種問題,例如:
業務邏輯異常
SDK需要請求後端介面獲取資料,從某個版本開始,後端因為某些原因對介面進行了調整,返回的資料和之前的不一樣了,SDK也跟著調整了處理介面返回資料的邏輯,不過沒有對舊介面返回的資料進行相容,SDK改造完畢釋出了一個新版本,使用者拿到新版本SDK進行了升級,但是忘了升級後端服務,這個時候就出現了新版本SDK+舊版本後端介面的情況,舊的後端介面返回舊的資料,而新版本SDK已經不再相容舊的資料了,於是介面返回的資料沒能在SDK這邊被正常處理,出現了資料載入異常的情況。
使用者端SDK和伺服器端不能保證每次都是配套升級的,有可能只升級了SDK或者只升級了伺服器端,因此,我們需要考慮新舊版本SDK搭配新舊版本伺服器端是否會有相容問題,如果有則應該想辦法做好相容處理。
使用者需要改動現有程式碼,不能平滑升級
SDK對外提供了一個介面,宿主程式會呼叫這個介面來完成某些功能,某次升級SDK版本之後,突然發現這個介面找不到了,查了一圈檔案,又問了SDK這邊的工作人員,才發現原來舊介面已經被去掉了,需要使用新的介面來替換舊介面。這種情況下,使用者改改自己的程式碼,呼叫新介面也是可以的,不過這種直接強行讓使用者改程式碼的行為還是不那麼友好,改動小倒還好,如果改動較大,使用者調整程式碼的成本就增大了,使用者不一定情願,結果可能還是要SDK這邊把舊介面加回來。
在開發SDK時,應該儘可能保證對外的介面不頻繁變動,如果要更改,也應該在相容舊版本介面的基礎庫上改,例如增加一個新介面,同時保留舊介面,舊介面的實現改為和新介面一致,並且把舊介面標註為已過時,提示使用者舊介面在未來的某個版本會徹底廢棄,建議改為呼叫新介面。
資料丟失
舊版本SDK在某個檔案目錄下儲存了一些資料,新版本SDK調整了儲存資料的目錄位置,如果在SDK升級過程中,沒有將舊目錄下的檔案資料匯入到新目錄的檔案中,那麼這部分資料就會丟失。
如果舊的資料不重要,影響會比較小,反之影響就比較大了,我們應該在升級過程中將舊的資料遷移到新的資料檔案中,保證新版本SDK仍能讀取到儲存下來的資料。
不管是我們自己使用別人的庫,還是別人開發的時候整合我們的SDK,我們經常會遇到一類問題,就是SDK和宿主程式之間不相容,也就是我們常說的「衝突了」,當然,衝突包含很多種,例如依賴庫衝突、工程設定衝突、資源衝突等,舉一些例子:
依賴庫衝突
依賴庫衝突是指SDK和宿主依賴了同一個庫的不同版本,不同版本之間相互不相容,而且不同版本不能同時共存,這種情況下,到底是選擇SDK依賴的版本,還是宿主依賴的版本呢?好像都不合適,因為不管依賴哪個版本,都會對SDK或宿主其中一方造成影響。
那麼要如何解決這個問題呢?站在SDK的角度,如果宿主能夠把依賴庫的版本改為和SDK依賴的版本一致,然後做一下適配,問題就解決了,但現實情況往往是宿主方不願意自己做改動,而是希望SDK能夠單方面處理掉這個問題。客觀來講,確實是由SDK來處理才能從根本上解決問題,因為SDK面對的是眾內送流量備援容錯機制程式,出現依賴庫衝突的可能不止是個別宿主程式,總不能要求出現問題的宿主程式都來適配SDK。因此,SDK只能從自身出發來解決問題,那麼,SD應該怎麼處理呢?我想到的有以下幾種方式:
依賴庫衝突是一個典型且麻煩的問題,建議開發SDK的時候,儘可能少依賴第三方庫,特別是版本相容做得不好的第三方庫。
工程設定衝突
如果SDK和宿主的編譯指令碼設定不一致,可能會導致宿主在編譯構建時發生報錯不能正常通過,或者在執行時發生異常,例如Android工程裡面:
minSdkVersion
比宿主指定的minSdkVersion
大,編譯階段報錯;為了避免工程設定衝突,在開發SDK的過程中,應該避免使用容易對宿主造成侵入的設定,如果必須使用,則應該讓設定在最大程度上能相容更多的宿主應用程式。
資源衝突
如果SDK和宿主使用了同名的資源,會出現宿主資源覆蓋SDK資源的問題,這樣SDK中參照資源的地方就會出現問題。為了避免資源衝突,可以採取的做法是對資源命名時加上能夠避免重名的字首或字尾。
衝突並不可怕,因為衝突總是能夠被解決的,但是作為SDK開發者,我們要做的應該是主動出擊,做到儘可能避免和宿主發生衝突。
因為作業系統、程式語言種類較多,所以同一套SDK可能會用不同的程式語言去實現,例如有在iOS上執行的Objective-C、Swift版本,有在Android上執行的Java、Kotlin版本,也有在鴻蒙上執行的JS、Java、C/C++版本,當然還有支援垮端的Flutter版本等等,但不管是什麼語言開發的,既然是同一套SDK,那就應該保持一致,這裡的一致不光是指表現上的一致,還包括實現上的一致,以及檔案上的一致,一致程度的高低不僅在一定程度上體現了SDK的質量,也反映了SDK研發團隊內部協同工作的水平。
表現一致
表現一致是指SDK在UI、功能、互動、體驗等外在表現形式上的一致。
實現一致
實現一致是指SDK在架構設計、資料模型、介面設計、編碼邏輯等內部實現上的一致。
檔案一致
檔案一致是指SDK整合檔案、介面檔案等關鍵性檔案內容和風格上的一致。
SDK研發是一個從0到1,再從1到100的過程。當SDK基於某個最初的想法誕生之後,就需要結合更多的想法讓自己走得更遠,這些更多的想法來自於哪裡呢?可能來自於團隊成員們天馬行空的創意,但更多更有價值的還是來自於使用者的實際需求,只有能解決實際問題的產品才是好產品。
然而,使用者的需求永遠是五花八門,讓人意想不到,捉摸不透的,因為每個使用者在意的點不一樣,需要解決的問題也不一樣,因此,SDK面臨的實際業務場景是非常複雜的,SDK必須要能滿足多樣化的需求,這就對SDK的設計、SDK的靈活性、可延伸性提出了更高的要求。
SDK要想做到足夠靈活,應該怎麼做呢?我認為可以採取以下方式:
通用性原則
SDK在設計和實現上應該做到儘可能通用,即核心部分能夠滿足絕大多數使用場景而無需做任何客製化化開發。
抽象介面
SDK可以把具體的業務邏輯抽象化,通過介面或抽象類的形式暴露給外部,允許外部自定義具體實現並替換SDK內部的預設實現。
豐富設定
SDK可以提供足夠豐富的設定項,外部通過設定設定項來控制SDK內部的狀態。
豐富元件
把具備通用性的使用者需求提煉出來並進行分類,然後按照類別開發不同的元件,這樣就能逐漸形成一套功能完善,不同功能之間又相互解耦的SDK,使用者根據自己的需要自由組合這些元件即可。
客製化化開發
實際上,考慮到多種因素,我們並不能保證SDK不做任何客製化化開發,如果確實需要做客製化化開發,那也還是得做,不過在做的過程當中,可以思考如何從產品設計或者技術架構上入手,讓客製化化內容最終也變得通用。
成功的產品除了產品本身質量過硬之外,還必須要有高質量的服務與之配套,SDK作為服務於企業、服務於廣大開發者的產品,自然要做好服務工作。站在SDK研發人員的角度,我認為好的服務至少包括以下方面:
及時響應客戶
客戶在使用SDK的整個過程當中,包括前期試用階段、後期正式使用階段,不可避免的會遇到各種各樣的問題,當客戶反饋問題之後,我們必須第一時間響應客戶,協助客戶定位問題原因,給予解決辦法,有的問題可能是目前尚未解決有待處理的,這類問題也應該向客戶說明當前的情況和後續處理計劃,讓客戶心裡有底。
及時且高質量地交付產品
正常情況下,SDK都會按照迭代節奏定期釋出新版本,但有時候客戶的一些要求可能會打亂我們正常發版的節奏,比如說客戶使用了比較舊的穩定版,但是發現該版本有一些bug需要修復,或者是要在該版本的基礎上增加一些功能,客戶把訴求傳達給了我們,並且給了交付時間截止日期,秉承客戶至上的理念,只要客戶的要求還在合理範圍之內,我們還是要做好服務工作的,所以即使是加班加點,也得想辦法按時交付。
雖然說按時交付,時間上可能會很緊張,但這並不意味著可以降低交付標準,需求檔案、產品設計、技術檔案、測試用例、研發自測、測試驗收等等,該有的環節還是一個都不能少,而且不能敷衍了事,必須保證最終交付到客戶手裡的是完全符合交付標準的產品。
維護好檔案及範例
在前面也提到過檔案和範例,但這裡還是要重申一下檔案和範例的重要性,因為檔案和範例關係到使用者能否順利地使用SDK,其重要性並不亞於SDK本身。
不管是檔案還是範例,一定要做到及時更新。
到此,我們說了這麼多,更多是從使用者的立場出發來思考問題的,現在我們來站在SDK廠商權益的角度來說一說還需要做些什麼事情。
申請軟著和專利
軟著和專利關係到SDK廠商的核心利益,例如:法律維權、稅收減免、高企申報、投融資等,其重要性不言而喻,因此,必須在第一時間申請SDK軟著和專利。
原始碼安全
出於技術智慧財產權的考慮,SDK廠商不會對外開放核心原始碼,對於這部分閉原始碼,有必要採取嚴格的保護措施,例如程式碼混淆、程式碼加固、程式碼倉庫許可權限制等,以防原始碼洩露。
Key校驗
我們在整合使用SDK的時候,經常會需要先在開發者平臺上面申請一個Key(SDK Key、API Key等),然後把Key設定到工程裡面,才能正常使用SDK,這是因為SDK廠商需要通過Key來校驗、限制開發者的SDK使用許可權,否則開發者可以無限制地使用SDK,廠商利益就得不到保障了。
以上便是我對研發金融科技類使用者端SDK的一點點體會,思考不一定全面,其中每一點也僅是粗略地闡述,沒有深入挖掘,後續有機會我會在專門的文章裡面就其中某些方面進一步探討。
研發SDK其實就是造輪子,要把輪子造得又圓又結實,必須經過長期打磨,需要自上而下的頂層設計,也需要每一位成員發揮自己的工匠精神,不畏艱難險阻,精心雕琢每一個細節。
尊重原創,轉載請註明出處:
關於如何編寫好金融科技使用者端SDK的思考