Swiftでクリーンアーキテクチャーの仕組みとTDDの作り方の実験
今回はGTDのアプリを作ります。パート1は基本のモデルエンティティまで作ります。
GTDについて
GTDは仕事の進め方の手法です。特に複数のプロジェクトを同時にやる程忙しい方にはオススメです。GTDについての情報はこちら:
TDDについて
TDDは英語で言うと「Test driven development」です。日本語だと「テスト駆動開発」です。コードを書く前にそのコードの結果を証明できるテストを書くことです。そうすると以下のメリットがあります:
- コードを変更するときに、他のところに影響があればテストが失敗するのですぐわかります。
- 随分後からコードを見ると、テストが説明書になります。コードを書いたときに何を考えてたかはわかりやすくなります。
- 守ってくれるテストがあれば、変更の影響の心配なくリファクタリングができます。
TDDのやり方
簡単にいうと、TDDの作り方はこんな感じです:
- 一つだけの失敗するテストを作る。
- テストが成功するまで実装する。
- 繰り返しを除く(リファクタリング)。
- 1-3を繰り返す。
まずはアプリの機能が依存する条件から始めましょう。その条件を見て、先に一つずつ条件が満たされたかどうかを自動で確かめるテストを作ります。実装はまだ書いていないため、テストは失敗することを確認する。
アプリの条件:
ホーム画面では5つの項目があります:
- Inbox(未処理項目)
- Current Actions(現在行動可能項目)
- Projects(プロジェクト一覧)
- Waiting On(〇〇待ち項目)
- Someday / Maybe(いつか・かもしれない項目)
このアプリの基本のエンティティはItem(項目)です。つまりまだやっていない一つのやる事です。
もう一つの基本のエンティティはProject(プロジェクト)です。Projectは複数のやることがあって、具体的に決められた結果も設定されてることです。一つ以上のやることをつけることが可能ですが、できれば次の一つだけのやることを決めた方がオススメです。計画しないとうまくいかないときは複数のやることを入れるのがオススメです。
Inboxは新しく思い付いたやることを入れるところです。まだ処理する暇はないけど、忘れたくないためとりあえず入れるという感じです。
Current Actionsは処理されたいつでもやれる項目の一覧です。優先度は順番で変えられます。
Waiting On(〇〇待ち項目)は誰かもしくは何かが終わらないと行動不可能の状態であるやることです。
Someday / Maybe(いつか・かもしれない項目)は現在やることが無理とか、優先低いとか、次は何をすればいいか全くわからないことなどのプロジェクトややりたいことの一覧です。いつかやれる時期が来たり、やれる方法を思い付いたりことがあるときのために取っておきたいことです。
Xcodeの準備
Xcode 9とSwift 4でやりましょう。
新しいプロジェクトを作成
- (
⌘+shift+N)を打つ -
Single View Appを選択し、Nextをクリックする -
Product Nameに「CleanGTD」を入力(好きなタイトルでいいですが、これ以後の説明でCleanGTDで説明します。) -
LanguageにSwiftを選択する -
Use Core Dataのチェックを外す -
Include Unit Testsをチェックする -
Include UI Testsをチェックする -
Nextをクリックする - 場所を設定する
- Gitはオススメですが、不要です
掃除
-
ViewController.swiftを削除 -
CleanGTDTests.swiftを削除 - (
⌘+shift+,)を打つとスキーム編集画面が表示する -
Testを選択して、CleanGTDUITestsのチェックを外す
失敗するテスト
今回のアプリのモデルエンティティの中心にあるItemから始めましょう。
まずはItemを作ることができるかどうかのテストです。
Testクラス作成
- (
⌘+N)でUnit Test Case Classを選択する -
Nextをクリックする - ファイル名のところに「ItemTests」を入力する
-
Nextをクリックする - ターゲットは
CleanGTDTestsだけがチェックされてるのを確認する -
Createをクリックする
ItemTests.swiftで以下のコードを入力してください。
import XCTest
@testable import CleanGTD
class ItemTests: XCTestCase {
func testItemCanBeCreated() {
let _ = Item()
}
}
(⌘ + U)(テストを実行する)を打つとテストターゲットがビルドできません。
テストが成功するため、空のstructを作るだけで最初のテストが成功できます。
CleanGTDのターゲットにItem.swiftを作成して、以下を入力してください。
import Foundation
struct Item {}
Itemには三つの項目があります:
- text
- notes
- lastModifiedDate
何かを変更する際に先に失敗するテストを作るか作ってあるテストを変更するのです。
class ItemTests: XCTestCase {
func testItemCanBeCreated() {
let _ = Item(text:"", notes:[], lastModifiedDate:Date())
}
}
また失敗しました。
さあ、直しましょう。notesはノートの一覧です。いつかノートに項目をつけることになりそうなので、Note.swiftでNoteエンティティも作りましょう。
まずはItemの変更です。
import Foundation
struct Item {
let text:String
let notes:[Note]
let lastModifiedDate:Date
}
そうしてNoteのstructですね。
import Foundation
struct Note {}
また(⌘ + U)を打つと成功ができました。
Noteの項目はとりあえずtextだけでいいので追加しよう。
import XCTest
@testable import CleanGTD
class NoteTest: XCTestCase {
func testNoteHasText() {
_ = Note(text:"test note.")
}
}
(⌘ + U)、また失敗。
struct Note {
text:String
}
textを追加すると(⌘ + U)で成功。
Projectは五つの項目があります。
- title
- lastModifiedDate
- expectedOutcome
- items
- notes
Project作成テスト
import XCTest
@testable import CleanGTD
class ProjectTests: XCTestCase {
func testProjectCreation() {
let _ = Project(title:"Project Title", lastModifiedDate:Date(), expectedOutcome:"Expected outcome.", items:[Item], notes: [])
}
}
(⌘ + U)でビルドできない。よし。
とりあえずのProject実装
import Foundation
struct Project {
let title:String
let expectedOutcome:String
let lastModifiedDate:Date
let items:[Item]
let notes:[Note]
}
(⌘ + U)で成功。
これで基本のエンティティの全部ができました。
次回のパート2はホーム画面のビジネスロジックの作り方を解説します。