ET新版本,我從2014年10月進入開始著手做,一路做過來有很多收獲,同時也發現很多問題,
其中問題主要集中在以下幾個方面:
- 代碼風格
- 界面端過多使用沒有必要的C++類
- 代碼模塊劃分
- 關于和界面和內核交互有沒有必要全部走GCD并且異步
- 分工問題
下面就逐個描述遇到的問題:
1.代碼風格
代碼風格不只是簡單的寫代碼的“書寫”規范(代碼美化),還有是否遵循蘋果一些 代碼結構模式
、變量命名
、接口設計
問題等等。
我記得趙永奎第一次講座就講到這個問題,我當時只是意識到了簡單的代碼“書寫”規范
問題,而對他講的關于是否遵循蘋果的代碼設計結構(MVC)問題沒有很深的理解。經過這一年多的工作經驗,我深刻的意識到這個問題對:代碼維護
,代碼復用
的巨大影響。
其中下面兩個方面,我認為是最重要的:
a.代碼結構
首先,在ET新的版本中,我能做到經過我寫的功能塊,做到遵守視圖、數據、邏輯控制三部分分離,這樣做的好處就是我拆除了某一部分對另外的兩部分都沒有影響,并且如果某一部分寫的足夠好,是可以拿來復用的,對于View
來說,不混雜業務邏輯和數據的View層,是最具有復用價值的,蘋果最具代表性的就是UITableViewView
,業務邏輯和數據都交給代理和數據源去處理。
而在目前ET的工程中,很多代碼很難遵循這個結構,太多的類明明是繼承與一個視圖類,但是發現業務邏輯也全部混雜在其中;一些類明明是處理業務邏輯的,但是發現這些類中又去處理了視圖的邏輯,真實讓人無法理解。某寫類型或者函數完全沒有做到遵守職責單一的原則,以至于后來用的時候,發現很難理解這個類設計的初衷是什么。
在我看來,一個功能塊,如果要獨立,分成視圖、業務邏輯、數據三部分是必須的,即使一些界面不需要獨立的控制塊,控制邏輯也要放在別的控制類中,而不是視圖中;如果想要做到三個組件共用的功能塊,那么因業務的不同,數據、業務塊可以看需求省去,但是視圖必須完全獨立,不依賴任何數據和外界邏輯,只用提供足夠的業務功能接口和代理、數據源,供控制層根據數據變化操作視圖變化即可。
b.書寫風格
其次,第二個問題就是代碼書寫風格問題(代碼美化)
我個人是要求自己遵循一種風格去寫,也基本遵循近蘋果的風格。其實最終遵循誰的風格去寫都是無所謂的,只要這種風格是大家公認的,就沒問題。
目前在ET,就存在多種編碼風格,奇怪的a式命名法,方法函數肆意的打空格,最不能理解的是無意義的注釋和日志打印。OC的命名規范已經代替大部分注釋,雖然結果是使得代碼變的很長,但是好處在于省去了不必要的注釋,所以在加上無意義的注釋,只能使人讀起來非常累。所以,雖然我向往統一編碼風格,但是絕對不是統一成不遵循蘋果寫法風格。
禪與 Objective-C 編程藝術這篇文所說的條例,ET的項目中很多都是違背的,究竟孰優孰劣,我想大家都有自己的評判。
2.界面端過多使用沒有必要的C++類
ET新版本最開始的時候,峰哥堅持界面的每個功能層次外面都要套一層C++類。
當時針對這個問題和他進行了長久的爭論,最終廢棄了這一層完全沒有必要的東西。
首先峰哥的觀點在于:
1.OC的代碼用C++包裹起來,就有了安全的保證。OC太靈活危險了,靈活到有時候無法控制,所以要用C++將他堵死(這一句是原話)。
2.C++有命名空間,能更好的隔離。OC沒有。
我的觀點在于:
1.我一只沒有明白峰哥所說的OC靈活的危險弊端在哪里?這個問題那段時間和肖斌也討論過,結果也是不明白。動態語言和靜態語言相比,不靈活怎么叫動態語言。OC是有很多hack的方法,但是我想對于我們日常的大部分開發來說,很少有人誰去用那些hack的方法吧,所以包一層C++的作用何在?
并且最關鍵的問題在于:OC有很多語法特性,C++是不具有的,本身如果是寫界面時純OC去寫,KOV
block
delegate
等等在oc代碼之間銜結的非常好,但是中間夾雜了C++的一層,著實讓人無語。
2.關于命名空間問題,OC類沉長的命名法為的效果就是達到防止命名沖突,只不過隔絕的方式不是命名空間那樣隔絕,這一點OC確實做不到。
3.關于C++那一層的職責定位問題。
雖然我在外面寫的界面部分沒有再包一層C++的類,但是在etios模塊仍然使用這種規范。我看了很多包的C++的那一層,我沒有理解那一層的職責在哪里?有的那一層C++的類只是傳接口,完全沒有別的功能,只是在傳遞函數;有的又是混雜了業務邏輯,在起初,我以為那一層C++類是用來處理業務邏輯,即代替C層的,但是最終發現完全不是那個定位,所以關于那一層的職責,我不太理解。
3.代碼模塊劃分
這個問題主要集中在et4ios那個模塊中。
說et4ios是一個模塊,其實根本不好定位這個模塊到底是干嘛的。
新架構初期,et4ios的定位是真正內核外部的一層映射,算是靠近內核層的中間層,銜結界面和內核。
但后來發現并沒有那么單一,目前et4ios中混有以下幾個部分:
- 1.銜結內核的中間層。
- 2.編輯框的界面模塊
- 3.表格區(手勢,界面等)
這就違背了最開始設計的初衷,也導致一個問題:這個et4ios到底是干什么的,有內核?有界面?什么都有?
其中把原本同屬于界面的東西放在了另外的一個模塊,導致的結果就是界面的創建沒有層級結構。本來編輯框 和 表格區 應該由界面端去創建,現在完全不是這樣,而是由內核中間層去創建。導致真正調用的時候需要走從內核單例中去一步一步取到編輯框的對象,然后進行操作。這樣合理嗎?我實在想不出內核中間層去創建界面的依據是什么。
而且編輯框也是通過C++包裹起來,那么我真正想操作編輯框時,其實這層C++起到作用就是重新寫一遍OC對象的接口,完全沒有別的意義。這么冗余,為什么不直接調用呢?(參考2.界面端過多使用沒有必要的C++類)
本文提到的前5點問題,編輯框中全部都存在
4.關于和界面和內核交互有沒有必要全部走GCD并且異步
目前ET幾乎所有的和內核數據的交互都走得GCD
簡單點說,就是不管 讀
或者 寫
內核數據都是跑在 異步在串行的子線程上
目前有以下幾個問題需要討論:
a.被迫所有內核數據讀寫使用異步GCD
一旦有一個對內核的 讀
或者 寫
的操作走的 異步串行子線程
,那么之后所有的對內核的 讀
或者 寫
都要走 異步串行子線程
,原因在于只有這樣才能讓所有對內核的操作在一條隊列上保證先進先執行的時序。所以時常讀取一個非常簡單的數據也要異步,等待回調,這樣給功能實現上增加了不少的麻煩。
b.如何保證時序性?
因為對內核的讀寫是異步子線程操作,內核在子線程跑完之后同步回調主線程,所以如果存在異步套異步的現象發生,仍舊不能保證對內核操作的時序。(這種情況在在目前ET中是存在的)
c.一個操作,需要多次異步時怎么辦?
回調問題。例如 操作A
在執行之前需要請求一個 數據X
,然后拿到 數據X
后再做相應的 操作A
。因為對 數據X
的請求也是異步的,所以要在請求 數據X
的回調代理中去執行 操作A
。這樣一來就顯得有些問題了,原因在于為什么要在請求到 數據X
的回調去執行 操作A
?這兩個事件并沒有什么必然聯系。
所以后來我在解決這個問題時用的方法就是設置 completionBlock
閉包塊。即在請求執行操作A
的函數中寫請求 數據X
并且設置 completionBlock
為執行操作A
,在 數據X
回調時執行這個 completionBlock
,這樣以來就顯得不是突兀了,因為 數據X
回調不用關心具體要干什么,只用執行 completionBlock
即可, completionBlock
在之前就已經設置好了。
當然這并不是最好的解決方案,最好的方法是仿照網絡請求回調,Block
+ delegate
共同支持,以場景需求選擇 Block
或者 delegate
才能寫出最優雅的代碼,畢竟 Block
和 delegate
使用場景還是有很大區別的。
d.究竟有沒有性能的提升?
1.從目前這個GCD設計模型上來看,只是把讀寫操作放在了另外一條 串行子線程
上去跑,既然讀寫操作依舊串行,那么必然效率是不可能提升的。唯一的不同是,子線程讀寫內核時主線程不再卡頓了,但是回過頭來想:既然子線程讀寫內核都已經卡主,那么主線程不卡有什么實際意義嗎?ET大部分操作都是建立在和內核的交互,還是要跑在 串行子線程
上的,所以子線程卡主時主線程不卡并沒有什么實際意義。
2.既然沒有效率提升,那么有沒有效率降低呢?
因為目前幾乎每個讀寫內核都要經過兩次線程切換,即 主 ->(異步) 子 ->(同步) 主,大量線程切換是有損耗的,這個損耗我具體沒有研究過,但是就目前ET這個GCD使用密集度,損耗應該還是有一定影響的。
5.工作效率問題
ET之所以拖這么長時間,問題就是重復性工作導致的效率低下。
最典型的就是編輯框,從去年的11月就開說這個東西屬于比較中樞性的東西,很多東西的交互都跟它有關系,并且本身也是個有些復雜的東西。
當時如果按照原本的東西去做,不要去追求微軟的樣子,我相信早已完成了。這個東西最起初峰哥對很多細節和業務都不了解,我相信至少做過一邊的肖斌是更有發言權的。只是他覺得能做出和微軟一模一樣的。結果呢?從峰哥轉到肖斌,峰哥不滿進度,又要自己重新搞,最后又拋給文強和榮華去做。從一開始的要重寫編輯框那個基礎控件,我們就告訴他沒有那個必要,并且不好寫,結果導致浪費了很多時間,最后編輯框依舊是老樣子。
分工問題導致效率低下的一個表現是:某些功能是A寫的,最后這些東西又交給B去處理,首先在我們組,我和文強對OC代碼結構和寫法的理解有偏差,說句實話,讓我去看他寫的代碼,有些地方的寫法我是無法接受的,所以看起來也比較沒有耐心,這點是我的問題。我深知工作中這種交叉debug事情是不可避免的,但這個問題應當做到影響面最小,即盡量避免工作內容倒手。所有這也是后期可以改善的一個方面。當然這一點對于實際的項目工程來說是很難完美實現的,所以后期只能盡量避免過多的發生此類事情。
寫在最后
以上的5點是我對這將近一年的新版本開發過程中遇到問題的總結,可能些許帶有一些個人情感,如果有哪些寫的欠妥,我們可以提出來一起進行討論。
希望今后的工作中針對這些問題進行改善。
感謝閱讀。