主頁 > 軟體設計 > 一款可以讓大型iOS工程編譯速度提升50%的工具

一款可以讓大型iOS工程編譯速度提升50%的工具

2021-03-04 09:52:51 軟體設計

cocoapods-hmap-prebuilt 是什么?

cocoapods-hmap-prebuilt 是美團平臺迭代組自研的一款 cocoapods 插件,以 Header Map 技術 為基礎,進一步提升代碼的編譯速度,完善頭檔案的搜索機制,

雖然以二進制組件的方式構建 App 是 HPX (美團移動端統一持續集成/交付平臺)的主流解決方案,但在某些場景下(Profile、Address/Thread/UB/Coverage Sanitizer、App 級別靜態檢查、ObjC 方法呼叫兼容性檢查等等),我們的構建作業還是需要以全原始碼編譯的方式進行;而且在實際開發程序中,大多是以原始碼的方式進行開發,所以我們將實驗物件設定為基于全原始碼編譯的流程,

廢話不多說,我們來看看它的實際使用效果!

總的來說,以美團和大眾點評的全原始碼編譯流程為實驗物件的前提下,cocoapods-hmap-prebuilt 插件能將總鏈路提升 45% 以上的速度,在 Xcode 打包環節上能提升 50% 以上的速度,是不是有點動心了?

為了更好的理解這個插件的價值和功能,我們不妨先看一下當前的工程中存在的問題,

為什么現有的專案不夠好?

目前,美團內的 App 都是基于 CocoaPods 做包管理方面的作業,所以在實際的開發程序中,CocoaPods 會在 Pods/Header/ 目錄下添加組件名目錄和頭檔案軟鏈,類似于下面的形式:

/Users/sketchk/Desktop/MyApp/Pods
└── Headers
    ├── Private
    │   └── AFNetworking
    │       ├── AFHTTPRequestOperation.h -> ./XXX/AFHTTPRequestOperation.h
    │       ├── AFHTTPRequestOperationManager.h -> ./XXX/AFHTTPRequestOperationManager.h
    │       ├── ...
    │       └── UIRefreshControl+AFNetworking.h -> ./XXX/UIRefreshControl+AFNetworking.h
    └── Public
        └── AFNetworking
            ├── AFHTTPRequestOperation.h -> ./XXX/AFHTTPRequestOperation.h
            ├── AFHTTPRequestOperationManager.h -> ./XXX/AFHTTPRequestOperationManager.h
            ├── ...
            └── UIRefreshControl+AFNetworking.h -> ./XXX/UIRefreshControl+AFNetworking.h

也正是通過這樣的目錄結構和軟鏈,CocoaPods 得以在 Header Search Path 中添加如下的引數,使得預編譯環節順利進行,

$(inherited)
${PODS_ROOT}/Headers/Private
${PODS_ROOT}/Headers/Private/AFNetworking
${PODS_ROOT}/Headers/Public
${PODS_ROOT}/Headers/Public/AFNetworking

雖然這種構建 Search Path 的方式解決了預編譯的問題,但在某些專案中,例如多達 400+ 組件的巨型專案中,會造成以下幾點問題:

  1. 大量的 Header Search Path 路徑,會造成編譯引數中的 -I 選項極速膨脹,在達到一定長度后,甚至會造成無法編譯的情況
  2. 目前美團的工程中,已經有近 5W 個頭檔案,這意味著不論是頭檔案的搜索程序,還是軟鏈的創建程序,都會引起大量的檔案 IO 操作,進而會產生一些耗時操作,
  3. 編譯時間會隨著組件數量急劇增長,以美團和大眾點評有 400+ 個組件的體量為參考,全原始碼打包耗時均在 1 小時以上,
  4. 基于路徑順序查找頭檔案的方式有潛在的風險,例如重名頭檔案的情況,排在后面的頭檔案永遠無法參與編譯,
  5. 由于 ${PODS_ROOT}/Headers/Private 路徑的存在,讓參考其他組件的私有頭檔案變為了可能,

想解決上述的問題,好一點的情況下,可能會浪費 1 個小時,而不好的情況,就是讓有風險的代碼上線了,你說工程師會不會因此而感到頭疼?

Header Map 是個啥?

還好 cocoapods-hmap-prebuilt 的出現,讓這些問題變成了歷史,不過要想理解它為什么能解決這些問題,我們得先理解一下什么是 Header Map,

Header Map 其實是一組頭檔案資訊映射表!

為了更直觀的理解 Header Map,我們可以在 Build Setting 中開啟 Use Header Map 選項,真實的體驗一下它,

然后在 Build Log 里獲取相應組件里對應檔案的編譯命令,并在最后加上 -v 引數,來查看其運行的秘密:

$ clang <list of arguments> -c some-file.m -o some-file.o -v

在 console 的輸出內容中,我們會發現一段有意思的內容:

通過上面的圖,我們可以看到編譯器將尋找頭檔案的順序和對應路徑展示出來了,而在這些路徑中,我們看到了一些陌生的東西,即后綴名為 .hmap 的檔案,后面還有個括號寫著 headermap,

沒錯!它就是 Header Map 的物體,

此時 Clang 已經在剛才提到的 hmap 檔案里塞入了一份頭檔案名和頭檔案路徑的映射表,不過它是一種二進制格式的檔案,為了驗證這個的說法,我們可以通過 milend 撰寫的hmap 工具來查其內容,

在執行相關命令(即 hmap print)后,我們可以發現這些 hmap 里保存的資訊結構大致如下, 類似于一個 Key-Value 的形式,Key 值是頭檔案的名稱,Value 是頭檔案的實際物理路徑:

需要注意,映射表的鍵值內容會隨著使用場景產生不同的變化,例如頭檔案參考是在 "..." 的形式下,還是 <...> 的形式下,又或是在 Build Phase 里 Header 的配置情況,例如,你將頭檔案設定為 Public 的時候,在某些 hmap 中,它的 Key 值就為 PodA/ClassA,而將其設定為 project 的時候,它的 Key 值可能就是 ClassA,而配置這些資訊的地方,如下圖所示:

至此我想你應該了解到 Header Map 到底是個什么東西了,

當然這種技術也不是一個什么新鮮事兒,在 Facebook 的 buck 工具中也提供了類似的東西,只不過檔案型別變成了 HeaderMap.java 的樣子,

此時,我估計你可能并不會對 buck 產生太多的興趣,而是開始思考上一張圖中 Headers 的 Public、Private、Project 到底代表著什么意思,好像很多同學從來沒怎么關注過,以及為什么它會影響 hmap 里的內容?

Public,Private,Project 是個啥?

在 Apple 官方的 Xcode Help - What are build phases? 檔案中,我們可以看到如下的一段解釋:

Associates public, private, or project header files with the target. Public and private headers define API intended for use by other clients, and are copied into a product for installation. For example, public and private headers in a framework target are copied into Headers and PrivateHeaders subfolders within a product. Project headers define API used and built by a target, but not copied into a product. This phase can be used once per target.

總的來說,我們可以知道一點,就是 Build Phases - Headers 中提到 Public 和 Private 是指可以供外界使用的頭檔案,而 Project 中的頭檔案是不對外使用的,也不會放在最終的產物中,

如果你繼續翻閱一些資料,例如 StackOverflow - Xcode: Copy Headers: Public vs. Private vs. Project? 和 StackOverflow - Understanding Xcode’s Copy Headers phase,你會發現在早期 Xcode Help 的 Project Editor 章節里,有一段名為 Setting the Role of a Header File 的段落,里面詳細記載了三個型別的區別,

Public: The interface is finalized and meant to be used by your product’s clients. A public header is included in the product as readable source code without restriction.
Private: The interface isn’t intended for your clients or it’s in early stages of development. A private header is included in the product, but it’s marked “private”. Thus the symbols are visible to all clients, but clients should understand that they’re not supposed to use them.
Project: The interface is for use only by implementation files in the current project. A project header is not included in the target, except in object code. The symbols are not visible to clients at all, only to you.

至此,我們應該能夠徹底了解了 Public、Private、Project 的區別,簡而言之,Public 還是通常意義上的 Public,Private 則代表 In Progress 的含義,至于 Project 才是通常意義上的 Private 含義,

此時,你會不會聯想到 CocoaPods 中 Podspec 的 Syntax 里還有 public_header_filesprivate_header_files 兩個欄位,它們的真實含義是否和 Xcode 里的概念沖突呢?

這里我們仔細閱讀一下官方檔案的解釋,尤其是 private_header_files 欄位,

我們可以看到,private_header_files 在這里的含義是說,它本身是相對于 Public 而言的,這些頭檔案本義是不希望暴露給用戶使用的,而且也不會產生相關檔案,但是在構建的時候,會出現在最終產物中,只有既沒有被 Public 和 Private 標注的頭檔案,才會被認為是真正的私有頭檔案,且不出現在最終的產物里,

看起來,CocoaPods 對于 Public 和 Private 的官方解釋是和 Xcode 中的描述一致的,兩處的 Private 并非我們通常理解的 Private,它的本意更應該是開發者準備對外開放,但又沒完全 Ready 的頭檔案,更像一個 In Progress 的含義,

這一塊是不是讓你有點大跌眼鏡?那么,在現實世界中,我們是否正確的使用了它們呢?

為什么用原生的 hmap 不能改善編譯速度?

前面我們介紹了 hmap 是什么,以及怎么開啟它(啟用 Build Setting 中的 Use Header Map 選項),也介紹了一些影響生成 hmap 的因素(Public、Private、Project),

那是不是我只要開啟 Xcode 提供的 Use Header Map 就可以提升編譯速度了呢?

很可惜,答案是否定的!

至于原因,我們就從下面的例子開始說起,假設我們有一個基于 CocoaPods 構建的全原始碼工程專案,它的整體結構如下:

  • 首先,Host 和 Pod 是我們的兩個 Project,Pods 下的 Target 的產物型別為 Static Library,
  • 其次,Host 底下會有一個同名的 Target,而 Pods 目錄下會有 n+1 個 Target,其中 n 取決于你依賴的組件數量,而 1 是一個名為 Pods-XXX 的 Target,最后,Pods-XXX 這個 Target 的產物會被 Host 里的 Target 所依賴,

整個結構看起來如下所示:

當構建的產物型別為 Static Library 的時候,CocoaPods 在創建頭檔案產物程序中,它的邏輯大致如下:

  • 不論 podspec 里如何設定 public_header_filesprivate_header_files,相應的頭檔案都會被設定為 Project 型別,
  • Pods/Headers/Public 中會保存所有被宣告為 public_header_files 的頭檔案,
  • Pods/Headers/Private 中會保存所有頭檔案,不論是 public_header_files 或者 private_header_files 描述到,還是那些未被描述的,這個目錄下是當前組件的所有頭檔案全集,
  • 如果 podspec 里未標注 Public 和 Private 的時候,Pods/Headers/PublicPods/Headers/Private 的內容一樣且會包含所有頭檔案,

正是由于這種機制,會導致一些有意思的問題發生,

  • 首先,由于所有頭檔案都被當做最終產物保留下來,在結合 Header Search Path 里 Pods/Headers/Private 路徑的存在,我們完全可以參考到其他組件里的私有頭檔案,例如我只要使用 #import <SomePod/Private_Header.h> 的方式,就會命中私有檔案的匹配路徑,
  • 其次,就是在 Static Library 的狀況下,一旦我們開啟了 Use Header Map,結合組件里所有頭檔案的型別為 Project 的情況,這個 hmap 里只會包含 #import "ClassA.h" 的鍵值參考,也就是說只有 #import "ClassA.h" 的方式才會命中 hmap 的策略,否則都將通過 Header Search Path 尋找其相關路徑,例如下圖中的 PodB,在其 build 的程序中,Xcode 會為 PodB 生成 5 個 hmap 檔案,也就是說這 5 個檔案只會在編譯 PodB 中使用,其中 PodB 會依賴 PodA 的一些頭檔案,但由于 PodA 中的頭檔案都是 Project 型別的,所以其在 hmap 里的 Key 全部為 ClassA.h ,也就是說我們只能以 #import "ClassA.h" 的方式引入,

而我們也知道,在參考其他組件的時候,通常都會采用 #import <A/A.h> 的方式引入,至于為什么會用這種方式,一方面是這種寫法會明確頭檔案的由來,避免問題,另一方面也是這種方式可以讓我們在是否開啟 clang module 中隨意切換,當然,還有一點就是Apple 在 WWDC 里曾經不止一次建議開發者使用這種方式來引入頭檔案,

接著上面的話題來說,所以說在 Static Library 的情況下且以 #import <A/A.h> 這種標準方式引入頭檔案時,開啟 Use Header Map 選項并不會幫我們提升編譯速度,

但真的就沒有辦法使用 Header Map 了么?

cocoapods-hmap-prebuilt 誕生了

當然,總是有辦法解決的,我們完全可以自己動手做一個基于 CocoaPods 規則下的 hmap 檔案,正是基于這個想法,美團自研的 cocoapods-hmap-prebuilt 插件誕生了!

它的核心功能并不多,大概有以下幾點:

  • 借助 CocodPods 處理 Header Search Path 和創建頭檔案 soft link 的時機,構建了頭檔案索引表并以此生成 n+1 個 hmap 檔案(n 是每個組件自己的 Private Header 資訊,1 是所有組件公共的 Public Header 資訊),
  • 重寫 xcconfig 檔案里的 Header Search Path 到對應的 hmap 檔案上,一條指向組件自己的 private hmap,一條指向所有組件共用的 public hmap,
  • 針對 public hmap 里的重名頭檔案進行了特殊處理,只允許保存組件名/頭檔案名方式的 Key-Value,排查重名頭檔案帶來的例外行為,
  • 將組件自身的 Ues Header Map 功能關閉,減少不必要的檔案創建和讀取,

聽起來可能有點繞,內容也有點多,不過這些你都不用關心,你只需要通過以下 2 個步驟就能將其使用起來:

  1. 在 Gemfile 里宣告插件,
  2. 在 Podfile 里使用插件,
// this is part of Gemfile
source 'http://sakgems.sankuai.com/' do
  gem 'cocoapods-hmap-prebuilt'
  gem 'XXX'
  ...
end

// this is part of Podfile
target 'XXX' do
  plugin 'cocoapods-hmap-prebuilt'
  pod 'XXX'
  ...
end

除此之外,為了拓展其實用性,我們還提供了頭檔案補丁(解決重名頭檔案的定向選取)和環境變數注入(無侵入的在其他系統中使用)的能力,便于其在不同場景下的使用,

總結

至此,關于 cocoapods-hmap-prebuilt 的介紹就要結束了,

回看整個故事的開始,Header Map 是我在研究 Swift 和 Objective-C 混編程序中發現的一個很小的知識點,而且 Xcode 自身就實作了一套基于 Header Map 的功能,在實際的使用程序中,它的表現并不理想,

但幸運的是,在后續的探索的程序中,我們發現了為什么 Xcode 的 Header Map 沒有生效,以及為什么它與 CocoaPods 出現了不兼容的情況,雖然它的原理并不復雜,核心點就是將檔案查找和讀取等 IO 操作編變成了記憶體讀取操作,但結合實際的業務場景,我們發現它的收益是十分可觀的,

或許這是在提醒我們,要永遠對技術保持一顆好奇的心!

其實,利用 Clang Module 技術也可以解決本文一開始提到的幾個問題,但它并不在這篇文章的討論范圍中,如果你對 Clang Module 或者對 Swift 與 Objective-C 混編感興趣,歡迎閱讀參考檔案中的 《從預編譯的角度理解 Swift 與 Objective-C 及混編機制》一文,以了解更多的詳細資訊,

參考檔案

  • Apple - WWDC 2018 Behind the Scenes of the Xcode Build Process
  • Apple 的 HeaderMap.cpp 原始碼
  • 美團技術學院- 從預編譯的角度理解 Swift 與 Objective-C 及混編機制

作者

  • 思琦,筆名 SketchK,美團 iOS 工程師,目前負責移動端 CI/CD 方面的作業及平臺內 Swift 技術相關的事宜,
  • 旭陶,美團 iOS 工程師,目前負責 iOS 端開發提效相關事宜,
  • 霜葉,2015 年加入美團,先后從事過 Hybrid 容器、iOS 基礎組件、iOS 開發工具鏈和客戶端持續集成門戶系統等作業,

| 想閱讀更多技術文章,請關注美團技術團隊(meituantech)官方微信公眾號,

| 在公眾號選單欄回復【2020年貨】、【2019年貨】、【2018年貨】、【2017年貨】、【演算法】等關鍵詞,可查看美團技術團隊歷年技術文章合集,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/265832.html

標籤:其他

上一篇:Spring Cloud 學習筆記五:搭建微服務工程之Hystrix 的實時監控功能

下一篇:前端構架模式MVC與MVVM

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more