CotEditor を Swift に移行する

本稿は [Swift Tweets 2017 Summer](https://swift-tweets.github.io/2017-summer) で発表（ツイート）したものをまとめ、Qiita 用に追記・再構成[^1]したものです。


### 発表概要

[CotEditor](https://coteditor.com) プロジェクトの現主催者 [1024jp](https://twitter.com/1024jp) です。CotEditor は昨年 2016 年に Objective-C から Swift に移行しました。今日はその話をします。


本発表は、事前に以下のような概要を開示していました。

> 2004 年から脈々と受け継がれる総 Cocoa 製の macOS 用テキストエディタ [CotEditor](https://coteditor.com) は、昨年 2016 年に Objective-C から Swift に 100% 移行しました。
> 
> Swift は魅力的な言語ですが、すでに Objective-C で 10 年超動いてるアプリケーションを誰に頼まれたわけでもないのにわざわざ Swift で書き直す意味は果たしてあるのでしょうか？
> 
> そこそこの規模の GUI アプリケーションを OSS 活動として実際にひとりで Swift に書き換えること、またコードが Swift になったことによる開発上の変化についてを、CotEditor の現開発者としてお話しします。




## 自己紹介


まずは自己紹介。

![slide.002.png](https://qiita-image-store.s3.amazonaws.com/0/6520/478cc686-c3f9-386f-ff14-fbce7604e128.png)


- [Gapplin](http://gapplin.wolfrosch.com)
- [BathyScaphe](https://bathyscaphe.bitbucket.io) [^2]
- [GzipSwift](https://github.com/1024jp/GzipSwift)


## CotEditor 紹介

CotEditor は macOS 専用の汎用プレーンテキストエディタです。

https://coteditor.com

![slide.003.png](https://qiita-image-store.s3.amazonaws.com/0/6520/a64291af-e863-cfc0-8558-b057f6e76370.png)


オープンソースで開発が進められていますが、OSS とは言うものの 2014 年頭に開発を引き継いでからは実質的に私 1024jp がひとりで開発[^3]しています。

macOS に特化しているので、技術的には document-based、Text Kit（NSTextView たち）と Cocoa をフル活用した実装であり、機能としても AppleScript や Services を始め Mac の機能を最大限利用しています。

ソースはすべてGitHubで入手できます。皆様も実際に一度ご覧になってみると良いかと思います。
https://github.com/coteditor/CotEditor/


### プロジェクト規模

プロジェクトの規模を表現するのは難しいですが、目安としては、188 枚の Swift ファイルと 40 枚強の Storyboard/xib ファイルで構成されています。

![slide.004.png](https://qiita-image-store.s3.amazonaws.com/0/6520/93ccda2a-0efd-1bbc-6d81-f341b3054d38.png)



## Swift 化への道のり

### Swift 移行

CotEditor の Swift 化はちょうど1年前頃、6月後半から7月いっぱいにかけて行われました。実際にコードを Objective-C から Swift に書き換えていたのは1ヶ月半くらいです。その後機能追加や調整を経て、10月頭にリリースがされました。

![slide.005.png](https://qiita-image-store.s3.amazonaws.com/0/6520/16f1d489-871b-d6a1-4225-0b6060fae5f4.png)



### あと始末

しかし、そう甘くはないので、その後1週間おきくらいのバグフィックスリリースが続きました（つらい！）。

![slide.006.png](https://qiita-image-store.s3.amazonaws.com/0/6520/9af5a2b1-c16b-180d-1fc3-7c0a2fc6eb44.png)



### 移行の下準備

なお、コードの移行は6月から始めていますが、下準備で色々仕込んではいます。また、それ以前に Gapplin  などいくつか小ぶりな macOS アプリケーションをすでに Swift 化していたので、基本的な Swift 知識はすでに携えていました。

下準備としては、

- Objective-C のすべてのヘッダファイルに nullability と generics を仕込んでおく
- テストはすべて Swift で書いておく
- ほか Objective-C コードを書く時点で「Swift にした時どうなるか」を想像しておく

をやってました。
テストを Swift で書いておくことは移行のときのミス軽減に超助かりました。


## Objective-C から Swift への翻訳作業

改めて見ると、せいぜい1ヶ月半なので「移行自体はわりとすぐ終わったんだね」という印象を抱かれるかと思いますが、Objective-C 版から分岐してから Swift 化した CotEditor 3.0.0 が完成するまで、だいたい 1,000 コミット積んでいます（※他の機能追加も含みます）。


Swift 化を進めているときの私は "Swift 翻訳マシーン" と化していたので、使える時間はすべて Swift への書き換えに費やしていました。具体的に言うと、お風呂に入りながら iPad で Swift 関連記事やリファレンスを読み、山手線のホームで並んでる時とか電車の中で座れずに立っている時も移行作業をしてました。
左手で MacBook Pro の底をを持ち右手でキーボードを打つと、人は立っていてもコーディングができます。皆さんもお試しください。電車の走行中は揺れるので、両足でバランスをとることにもわりと意識を割く必要があるのがポイントです。
ちなみに片手で打ってると Xcode の補完の便利さを痛感します。

Objective-C から Swift への移行というのは、一部の困難（困難！）を除けば比較的単純な作業なので、頭をフル回転させなくても粛々と進めることができました。


ひとりでこの規模のプロジェクトの移行を一気にやることはとても体力がいりますが、同時に、ひとりで全部おもりしてたからこそ、プロジェクト全体すべてのコードが頭に入っており適切に移行を進めることができたのではないかと思います。

とはいえ移行中は、ファイルを Objective-C から Swift に書き換えても書き換えても終わらないので「今私が移行半ばに力尽きて情熱が薄れプロジェクトを放置したらどうなるんだろう...」と常に思っていました。尽きないでよかったです。




## Swift 化の利点

### Swift 化 = つらい (?)

ということで、既存アプリケーションの Swift 化は、

- どう頑張っても移行時にバグが埋め込まれる
- たいへん！（≒時間がかかる）

というデメリットでできています。

### モチベーション

ではなぜ Swift化 をしたのか。それは以下のようにまとめることができるでしょう。すなわち：

① コード量が減る
② struct/enum、extnsion などを利用した構造的なコード構成にできる
③ プロジェクト全体のモダンさが保てる
④ Swift 化そのものがたのしい

順に話します。


### ① コード量が減る

コード量が少なければ少ないほどいいと思っているので、これは私にとってとても魅力的でした。


### ② struct/enum、extnsion などを利用した構造的なコード構成にできる

これは Swift Tweets 聴講者の皆様ならば、私がいうまでもなく体感していることでしょう。新しく機能を足していくには現状がクリーンでなければいつか破綻します。

最後の Objective-C コードの CotEditor 2.5.6 で117枚あった .m ファイルは、最新の CotEditor 3.2.0 では188枚の .swift ファイルになっています。これは機能の分離が進んだ結果で、大変良いことだと受け止めてます。

![slide.007.png](https://qiita-image-store.s3.amazonaws.com/0/6520/79014bf9-ae63-8ee1-6711-c4553eca5e91.png)



ちなみに、私が CotEditor の開発を引き取った CotEditor 1.3.1 当時は、.m ファイルはたった39枚でした（思えば遠くにきたものだ）。

![slide.008.png](https://qiita-image-store.s3.amazonaws.com/0/6520/09453c9e-088e-0e5e-812f-e1d633fc20a7.png)





### ③ プロジェクト全体のモダンさが保てる

モダンさは今後何年もプロジェクトを続けていく上では重要な視点です。

Apple は 現在は Objective-C も Swift も受け入れていますが、将来はわかったものではありません。それにビルト自体はできても Apple が提供する新しい機能 / API が Swift でなければ使えない可能性も十分あります。
つまり、Swift 移行は CotEditor プロジェクトを今後何年も続けていくという決意表明でもあります。

ちなみに、Swift 化に伴いフレームワークの管理を [CocoaPods](https://cocoapods.org) から [Carthage](https://github.com/Carthage/Carthage) に変えたり、[swiftlint](https://github.com/realm/SwiftLint) を導入したりもしており、この辺もモダン化に一役買っています。



### ④ Swift化そのものがたのしい

そして「たのしい」です。バカみたいですが、一番重要なモチベーションです。そもそも CotEditor は無料の OSS で私は趣味で開発を行っており、これをやることによる金銭的なインセンティブはゼロです。本業もプログラマではないので転職に有利とかもありません。
たのしい以外のなんのモチベーションでやればいいのでしょう。Swift 化するということ自体が私の趣味活動でした。開発者であれば新しいことへのチャレンジと自分のコードがどんどんモダンになっていく姿に興奮を覚えない人はいないでしょう。


以上4つが私がCotEditorをSwift化することに決めた要素です。


### 移行に対するユーザの反応

あともうひとつ面白かったのが、この CotEditor の Swift 化をけっこうユーザが喜んでくれたことです。Swift を実際に書く macOS/iOS 開発界隈の方々が話題にしてくれるというのは予想ができたのですが、一般ユーザの方々も。
私からすると「内部コードが変わったからって使う側として嬉しいことなどなにもないのでは？」という気もするのですが、国内外のネットや App Store のレビューなどを読んでおりますと、CotEditor が現在 100% Swift であることを好意的に受け止めています。

たぶんブランディング的には、

　Swift は Apple 製の（なんかすごい）新しいプログラミング言語
　→ CotEditor が Swift になった
　→ CotEditor はApple の最新技術を貪欲に取り入れている

というロジックなのではないかと思います。

私としては「CotEditor は最も Mac らしいテキストエディタである」というのが開発の一番目指すところなので、このような受け止められ方は願ったり叶ったりで「しめしめ」といったところです。


## Swift 開発の困難

ということで、現在はCotEditorはすべてSwiftで書いています。が、困難もあります。


### macOS の困難

macOS アプリケーション の Swift 開発特有の困難としては、この辺でしょうか。

#### macOS 界隈は iOS に比べて Swift 移行が遅いので Swift 情報が少ない

macOS のアプリケーションは iOS に比べて開発ペースがゆっくりしたものが多く、またサポートする OS も iOS より広範囲（ユーザがなかなかバージョンを上げてくれない）なので、Swift が使えないバージョンを切るタイミングが遅いです。あと、人口が少ない上に粛々と開発を進める開発者/企業が多く、あまりナレッジが表（ネット・書籍）に出てきません。


#### Cocoa Bindings の仕組みが Swift と相性が悪い

macOS での開発には Cocoa Bindings という大変便利な機能があり、GUI の macOS アプリケーションの開発となると、これを多用することになるのですが、これが Swift と相性が悪いです。Cocoa Binding を行うには NSObject を継承したものでないといけなく、一番 Struct 化してキャッキャしたいようなモデルオブジェクトが軒並み NSObject に縛られることになります。
んで iOS にはない機能なのでこれに関する情報も少ない。

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">モデルオブジェクト<br>↓<br>structにするチャンス<br>↓<br>table (NSTableView)とかに流し込みたい<br>↓<br>NSArrayControllerさんのお世話になりたい<br>↓<br>NSArrayController「NSObject派生でお願いします」<a href="https://twitter.com/hashtag/swtws?src=hash">#swtws</a></p>&mdash; 1024 (@1024jp) <a href="https://twitter.com/1024jp/status/888761458640658432">July 22, 2017</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>



### テキスト処理の困難

あとテキストエディタ的には、TextKit 系の NSString (NSRange) と Swift.String の狭間でいつもジレンマを感じています。Swift の型ベースの String は魅力的ですが、TextKit を使うと結局 NSString を意識する必要があります。
どこで NSString (NSRange) と Swift.String (String.Range) の計算コストを吸収するかも悩みどころだし、NSString では大丈夫だった String へのサロゲートペア片割れ差し込みとかも、Swift だと即エラーになるなんて罠もあったり。


## Sum-Up

しかしそれらは些細なことで、結果としては、このタイミングで Swift 移行をとても良かったと感じています。私は Objective-C の `[]` が大好きだったのですが、でもやっぱり Swift のモダンでクリーンなコードは読みやすく快適で作業もはかどります。


私からは以上です。最高にMacらしいアプリケーションを作るには常に Apple の示す最前線に立っている必要があり、そのためには Swift 化は必然だった、というお話でした。
皆様も Swift でたのしい開発ライフがおくれることを願っています。あと CotEditor をよろしくニャン🐍。自分で言うのもなんですが、よくできた Mac アプリケーション[^4]だと思います。



---

[^1]: 当日のツイート全体像は [2017/7/22 #swtws Swift Tweets 2017 Summer - Togetterまとめ](https://togetter.com/li/1132511) を見ると良いかと思います。
[^2]: BathyScaphe に関しては私は補助的なサブ開発者であり、主にデザインや Web サイト、コードのリファクタリングを担当しています。
[^3]: GUI アプリケーションの開発というのは多岐にわたり、コーディングはもちろん、アプリケーション全体のデザインと舵取り、ユーザサポート、アイコンなどのGUIパーツ画像を描いたり、Webサイトを整備したり、ローカライズをしたり、Store の Apple チームとやりとりしたり...。
[^4]: これに関しては、私が引き継ぐ前の、オリジナル開発者のもともとの CotEditor のデザインが大変よくできていたのも大きいです。当初から思想がしっかりしてました。