鍍金池/ 教程/ iOS/ Artsy
與四軸無人機(jī)的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動開發(fā)
Collection View 動畫
截圖測試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個(gè)完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動布局工具箱
動畫
為 iOS 7 重新設(shè)計(jì) App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動畫解釋
響應(yīng)式 Android 應(yīng)用
初識 TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計(jì)優(yōu)雅的移動游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動畫
常見的后臺實(shí)踐
糟糕的測試
避免濫用單例
數(shù)據(jù)模型和模型對象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計(jì)的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計(jì)
置換測試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測試
值對象
活動追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場
游戲
調(diào)試核對清單
View Controller 容器
學(xué)無止境
XCTest 測試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫支持
Fetch 請求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過程

Artsy

與 objc.io 這期專題的其他團(tuán)隊(duì)規(guī)模相比,Astsy 的移動團(tuán)隊(duì)很小。盡管如此,我們卻因?yàn)槲覀冊谏鐓^(qū)的影響力而被關(guān)注。我們的 iOS 開發(fā)團(tuán)隊(duì)成員都參加過著名和大型的 Cocoa 社區(qū)開源項(xiàng)目。

Artsy 團(tuán)隊(duì)內(nèi)部充滿了我們稱之為默認(rèn)開源的技術(shù)氛圍。我們不是絕無僅有的一個(gè)。開源一個(gè)項(xiàng)目有時(shí)候聽起來更像獲得了一個(gè)技術(shù)勛章,但是這個(gè)項(xiàng)目所影響到的東西可能會超出你的想象。開源不單單是創(chuàng)建一個(gè) GitHub repository -- 同時(shí)也是我們團(tuán)隊(duì)成員的情感分享。

我們團(tuán)隊(duì)都信奉開源。盡管我們每個(gè)人的動機(jī)各不相同 - 從堅(jiān)信教育的力量到想要幫助其他人站在巨人的肩膀上看得更遠(yuǎn) - 我們都從開源中受益匪淺。

我們團(tuán)隊(duì)的每個(gè)人相信,除非的確有一個(gè)理由需要你保密,否則你就應(yīng)該把它開源。這種精神不單單對于代碼。我們在 Google Hangouts On Air 定期舉辦交流會,邀請其他人參與進(jìn)來和討論問題。我們的團(tuán)隊(duì)也用一個(gè)開源的倉庫來組織活動。


我們這個(gè)小團(tuán)隊(duì)為 Cocoa 開發(fā)者社區(qū)作出了顯著的貢獻(xiàn)。我們以這三種方式貢獻(xiàn)自己的力量:

1.我們經(jīng)常會發(fā)布一些應(yīng)用的組件,這些組件作為開源庫可能會幫助其他開發(fā)者。 2.在使用其他的庫的同時(shí),我們發(fā)送反饋,bug report 和 pull request。 3.我們鼓勵(lì)所有的團(tuán)隊(duì)成員積極參加社區(qū)活動,包括演講,寫博客或者出版書籍。

有幾個(gè)很好理解的原因可以解釋我們?yōu)槭裁聪胍獪p少代碼的規(guī)模和復(fù)雜度。我們通過編寫小而穩(wěn)定的組件來提高應(yīng)用整體的穩(wěn)定性和完整性。另外,通過可重用的庫,我們在編寫多個(gè)應(yīng)用時(shí)也減少了工作量。

Artsy 主要有三個(gè) iOS 應(yīng)用,同時(shí)還維護(hù)著一些小的項(xiàng)目,當(dāng)有新的項(xiàng)目時(shí),可以避免重復(fù)造輪子從而節(jié)省時(shí)間。對于為了一個(gè)應(yīng)用而創(chuàng)造的庫來說,維護(hù)和修復(fù)漏洞是一件很值得分享的事。我們過去在代碼重用的策略做得很好,但是仍然有很大提升的空間。

如果將我們的應(yīng)用拆分成小而且可重用的幾部分的話,會有很多技術(shù)上的優(yōu)點(diǎn),但同時(shí)這些不同的組件也有明確的擁有者。當(dāng)我們這樣做的時(shí)候,我們需要確保我們確實(shí)把知識分享給團(tuán)隊(duì)成員,來保證團(tuán)隊(duì)成員們對我們的代碼盡可能的熟悉。這一點(diǎn)是非常重要的;當(dāng)我們團(tuán)隊(duì)里的某一個(gè)成員突然被法院傳召三個(gè)月,我們不需要苦惱,因?yàn)樗皇俏ㄒ坏膶μ囟ú糠执a熟悉的人。

除了團(tuán)隊(duì)實(shí)際的管理外,鼓勵(lì)開發(fā)者去探索 iOS 開發(fā)的不同的方向,能幫助他們更專業(yè),更全面。我們在 iOS 領(lǐng)域自然已經(jīng)爐火純青,而與此同時(shí)學(xué)習(xí)其他編程語言能幫助我們保持頭腦清醒和情緒放松,并且可以發(fā)現(xiàn)新的思路來解決相似的問題。

我們遠(yuǎn)程工作;我們的團(tuán)隊(duì)到目前為止還沒有同時(shí)呆在一個(gè)屋子里過。通過像一個(gè)開源社區(qū)來工作,團(tuán)隊(duì)結(jié)構(gòu)更加靈活和可伸縮,而不是像傳統(tǒng)的團(tuán)隊(duì)一樣。


2015 年初,我們完成了 Artsy 的 iOS 應(yīng)用 eigen 的開源工作。這是一個(gè)持續(xù)了很多個(gè)月的項(xiàng)目;我們慎重考慮過,并逐漸地證明,開源一個(gè)面向消費(fèi)者的應(yīng)用的確會有它的商業(yè)價(jià)值。這也反駁了那些質(zhì)疑我們的聲音,讓他們看到了這一切是如何發(fā)生的。這對于公司來說并不是一個(gè)艱難的決定,因?yàn)榉窒碇R已然是我們公司的每個(gè)人所信奉的核心價(jià)值。

開源 eigen 的第一步工作已經(jīng)完成得差不多了;我們已經(jīng)盡可能地從我們的應(yīng)用中開源代碼。我們的大部分的準(zhǔn)備工作都是在確保代碼中敏感的細(xì)節(jié)不會通過 git 歷史記錄和 GitHub 的 issue 泄露出去。最后,我們決定用一個(gè)全新的 repository,還有完全空白的歷史記錄以及 issue。

在前面,我說過如果開源則意味著全部對外開放,除非確實(shí)有一個(gè)理由想讓它保密。我們所開源的那些代碼并不是讓 Artsy 獨(dú)具一格或者更有價(jià)值的代碼。Artsy 的有些代碼是需要一直閉源的。其中的例子中包括一個(gè)商業(yè)許可用途的字體,還有 Art Genome Project 所用到的推薦引擎等。

做完前期開源工作的準(zhǔn)備后,接下來就是從基礎(chǔ)開始搭建一個(gè)完整的開源應(yīng)用。這給了我們機(jī)會來審視要如何在開源環(huán)境下進(jìn)行管理項(xiàng)目,處理開發(fā)的問題以及進(jìn)行實(shí)際的開發(fā)。這種體驗(yàn)與維護(hù)社區(qū)的開源項(xiàng)目非常類似。

在開發(fā)前期我們不會設(shè)定嚴(yán)格的的線路圖。這部分程度上歸咎于我們需要準(zhǔn)時(shí)完成項(xiàng)目,另外在我們內(nèi)部的 Slack 頻道里也已經(jīng)有很多交流了。將來,我們會嘗試盡量多地將我們的交流放到公共的倉庫里去。

開發(fā)并開源一個(gè)復(fù)雜的 iOS 應(yīng)用這件事并沒有很多公司嘗試過。在開發(fā)工具方面,我們還有些欠缺,這也是必須努力的方向。最常見莫過于 API tokens 的保密。為了解決這個(gè)問題,我們創(chuàng)造了一個(gè)新的,更加安全的方法來保存這些 keys。

Artsy 是一個(gè)設(shè)計(jì)驅(qū)動型的公司,我們的設(shè)計(jì)師在我們開發(fā)工作進(jìn)行時(shí)經(jīng)常參加進(jìn)來。我們的設(shè)計(jì)師能夠很容易地參加到開源項(xiàng)目中。只需稍加援手,我們的設(shè)計(jì)師們就可以調(diào)整到開放的方式進(jìn)行工作。他們已經(jīng)對如何使用 GitHub 來反饋問題相當(dāng)熟悉,所以他們參加到開源項(xiàng)目的貢獻(xiàn)中是一件再簡單不過的事了。他們都有著關(guān)于回饋設(shè)計(jì)社區(qū)的想法,和像我們對開發(fā)者社區(qū)的態(tài)度一樣。


我們上面說明了一些概念和理論上的東西,接下來說一下我們真實(shí)的日常工作。

開源工作與典型的軟件開發(fā)并沒有那么大的差別。我們打開 issue,提交 pull requests,并在 GitHub 上討論交流。當(dāng)我們有機(jī)會創(chuàng)造一個(gè)新的開源庫的時(shí)候,負(fù)責(zé)這個(gè)庫的開發(fā)者會使用他自己的賬號來創(chuàng)建倉庫,而不是使用 Artsy 的賬號。

這是一種產(chǎn)品歸屬感。如果在六個(gè)月之后某個(gè)團(tuán)隊(duì)成員對這個(gè)庫有什么疑問的話,他可以很快地找到求助的人。同樣地,開發(fā)者也會有歸屬感,并且?guī)椭覀儬I造令人滿足和愉悅的工作環(huán)境。最后,開發(fā)者們了解到這些由他們創(chuàng)造的代碼是屬于他們的,這樣他們可以繼續(xù)使用這些代碼,即使他們離開了 Artsy。

讓我們來看一個(gè)例子吧。

像很多可靠的開發(fā)者一樣,我們在盡可能地嘗試自動化我們的工作。這其中包括使用持續(xù)集成 (CI) 來減少新的 bugs 的產(chǎn)生以及回退。目前,我們使用 Travis 來持續(xù)集成,當(dāng)然,也有很多其他解決方案。

我們很多的測試都是基于 Facebook 的 iOS 截屏測試庫來進(jìn)行的。這個(gè)庫可以構(gòu)造一個(gè) view (或者 ViewController),來模擬交互,然后將視圖層次結(jié)構(gòu)截圖以作參考。之后,當(dāng)我們測試時(shí),我們進(jìn)行相同的操作和截圖,從而與之前的參考截圖作對比。

我們所遇到的一個(gè)問題是關(guān)于 Travis 的使用。雖然截屏測試在本地能夠通過,但它會在 CI 環(huán)境下失敗。究其原因,是因?yàn)榻仄翜y試是由 Kaleidoscope 對提供的參考和不通過的截圖進(jìn)行比對,從而診斷出原因。但是,在 CI 環(huán)境下,我們沒有取得這些截圖的權(quán)限,那我們應(yīng)該怎么辦呢?

在維也納的周末旅行中,Orta 和 Ash 一起討論了可能的解決辦法。最后我們決定構(gòu)建一個(gè)叫 Second Curtain 的工具,它可以解析 xcodebuild 的輸出。如果它檢測到任何測試失敗,那么有關(guān)不通過的截圖和參考文件截圖將會被上傳到一個(gè) S3 bucket 上,并可以比較出不同的地方。這是 Ash 第一次用 Ruby 寫的比較重量級的工具,這給了開發(fā)者一個(gè)機(jī)會來改進(jìn)我們的配置工具,并且拓展了知識。


經(jīng)常有人會問我們?yōu)槭裁窗秧?xiàng)目都開源。我們已經(jīng)討論了我們的技術(shù)上的目的,以及它給予我們團(tuán)體每個(gè)成員的感受,但坦白說,開源其實(shí)是一樁很聰明的交易。例如,我們正在編寫一個(gè)開源庫來處理使用我們的 API 時(shí)所需要進(jìn)行的身份驗(yàn)證。這項(xiàng)工作不單單會讓那些使用我們的 API 進(jìn)行的開發(fā)工作更簡單,同時(shí)它也使每個(gè)人的開發(fā)更輕松。這真是太爽啦。

對于開發(fā)者,經(jīng)常有特意避開第三方依賴庫的傾向,這種現(xiàn)象在 iOS 開發(fā)社區(qū)尤為明顯。他們經(jīng)常受害于重復(fù)制造輪子,并浪費(fèi)很多時(shí)間來調(diào)試,而不是使用那些已經(jīng)為他們解決了相似問題的庫。在我們的移動團(tuán)隊(duì),我們非常反感這種現(xiàn)象,反而,我們更欣賞那種 “自豪地到處搜刮” 的思想 (我們很贊同這個(gè)開發(fā)者說過的話)。

在我們的公司里,我們都會認(rèn)真評估員工的個(gè)人素質(zhì)和技術(shù)水平;但是,這些指標(biāo)不單單是 HR 手里的表格上面的幾個(gè)選項(xiàng)這么簡單。如果你確實(shí)很優(yōu)秀,那么這些東西會潛移默化地融入你的日常生活和工作中。而我們,正是由于待在這么一個(gè)開源項(xiàng)目的團(tuán)隊(duì)里而身體力行。

通過將我們的軟件開源,龐大的開發(fā)者社群能夠?qū)ξ覀兊墓ぷ魈峁┓答仯屛覀冇袡C(jī)會與全世界那些出色的開發(fā)者一起交流。與別人分享知識同時(shí)也幫助我們培養(yǎng)良好的工作氛圍 -- 當(dāng)我們出名以后 -- 反過來會吸引那些好的開發(fā)者加入我們。畢竟,我們從來沒有得到如此多的尊敬和聲望。

我們經(jīng)常整理那些從博客或者會議演講中獲得的技術(shù)知識和技術(shù)筆記。它們不僅會幫助我們將見解和技術(shù)傳給公司外部的開發(fā)者,同時(shí)便利了那些加入我們團(tuán)隊(duì)的新成員,讓他們更加迅速地了解到我們的工作,以及我們所使用的工具。我們甚至分享那些關(guān)于如何分享知識的經(jīng)驗(yàn),這也是其中一件我們正努力去做的事。

開源工作不總是一帆風(fēng)順的,但是我們遇到的困難仍然不值一提。一種普遍的關(guān)于開源的看法是,讓別人看到自己不完美的代碼會很尷尬。但我們認(rèn)為,提高水平最好的辦法就是讓別人看你的代碼,讓別人評論你的代碼。這不應(yīng)該成為讓你尷尬的原因 -- 同時(shí),幾乎,所有開發(fā)者都明白,截止日期快要來的時(shí)候,項(xiàng)目里那些迫不得已的 hacky 代碼必定會缺乏可讀性和優(yōu)雅性。

我們的一些競爭對手在使用我們的代碼,因?yàn)樗麄兎答伭艘恍└倪M(jìn)給我們。我們也一樣。實(shí)際上,開源一個(gè)商業(yè)項(xiàng)目最大的挑戰(zhàn)在于管理。這種責(zé)任關(guān)系是處理人際關(guān)系最重要的部分,也是需要認(rèn)真處理好的 -- 特別是當(dāng)一個(gè)項(xiàng)目得到了足夠多的好名聲。大部分的項(xiàng)目都沒有得到足夠的管理,這使它們最終舉步維艱。

發(fā)布完代碼,將項(xiàng)目拋之腦外,并忽視開發(fā)者的反饋是一件很常見的事情,但是我們卻樂于接受開源項(xiàng)目的責(zé)任,并努力繼續(xù)把項(xiàng)目開源。

那些需要額外花費(fèi)我們時(shí)間來開發(fā)和維護(hù)的開源項(xiàng)目,經(jīng)常能幫助從日常的任務(wù)中解放出來,而且,通過 GitHub 進(jìn)行的交流也能夠幫到我們團(tuán)隊(duì)中遠(yuǎn)程工作的成員。

在一個(gè)擁抱開源的公司里作為一個(gè)小的團(tuán)隊(duì)而工作,可以讓那些由于開源而要承擔(dān)的各種風(fēng)險(xiǎn)微不足道。如果這種風(fēng)險(xiǎn)確實(shí)存在的話,技術(shù)好處,商業(yè)前景以及開源項(xiàng)目所帶來的樂趣要比它們大,并且大得多。

將一個(gè)庫開源和創(chuàng)建一個(gè)開源庫其實(shí)有著本質(zhì)上的不同 - 這種不同和從技術(shù)上開源還是從精神上開源是一樣的。一句話來說,回答這個(gè)問題就可以總結(jié)兩者的差異:

你是為了自己的利益而開源呢,還是為了所有人的利益?