SwiftUI 時代に向けた 2 スペースインデントのすゝめ

## なぜ今 2 スペースインデントなのか

![Xcode_Editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178830/7a9d3428-731b-d3a6-a8ee-27095c178f8e.png)

**コードを書くスペースが狭い😭**

<br>
<br>

というわけで、最近新規で立ち上げる SwiftUI プロジェクトでは 2 スペース幅のインデントを採用しています。

これが中々良さそうな感じなので、 2 スペースインデントをおすすめしていく記事となります。


- 5K2K モニタで解決
- Preview は言うほど使わなくなるので、 Canvas 非表示 + 必要に応じて ⌥⌘↩ で表示
- そもそもネストが深いなら別に切り出すべき

等々言いたいことはあるかもしれませんが、興味があればお付き合いください。

## 2 スペースインデントのメリット・デメリット

### 😀 コード幅の節約

これが最大のメリットです。

冒頭でも触れたように SwiftUI での Preview 表示はコードエディタ部分とで Side-by-Side 表示される[^1]ため、横幅が貴重になってきます。

[^1]:一応 `Canvas on Bottom` で上下表示も可能です

インデント量が 4 スペース → 2 スペースとなるため、単純な効果としてはインデント部分で横幅 50% の削減になるのですが、 SwiftUI においては宣言的 UI の宿命なのかネストが深くなる傾向があるため、その効果も大きくなってきます。

実際、宣言的 UI の先行者である React や Flutter では、 2 スペースインデントの採用が主流です。

### 😀 コードが追いやすい

こちらは感覚的な話になってしまうのですが 、SwiftUI においては 2 スペースインデントの方がコードを追いやすいと感じています。

というのも、 SwiftUI については行数あたりのインデント・ディデントの頻度が高くなりやすく、コードに沿って目線を上から下に落としていく際に左右に目線を振る動作が増えて負担になると思っています。

具体的には以下のようなコードです。

```swift
HStack {
    Image(systemName: "person.circle")
    VStack {
        Text("John Doe")
        if isVerified {
            Label {
                Text("Verified")
            } icon: {
                Image(systemName: "checkmark.seal")
            }
            .foregroundColor(.green)
        } else {
            Button {
                verify()
            } label: {
                Label {
                    Text("Verify")
                } icon: {
                    Image(systemName: "arrow.clockwise")
                }
                .foregroundColor(.blue)
            }
        }
    }
}
```

これを 2 スペースインデント化すると以下のようになり、多少なりとも追いやすくなった感触があります。

```swift
HStack {
  Image(systemName: "person.circle")
  VStack {
    Text("John Doe")
    if isVerified {
      Label {
        Text("Verified")
      } icon: {
        Image(systemName: "checkmark.seal")
      }
      .foregroundColor(.green)
    } else {
      Button {
        verify()
      } label: {
        Label {
          Text("Verify")
        } icon: {
          Image(systemName: "arrow.clockwise")
        }
        .foregroundColor(.blue)
      }
    }
  }
}
```



### 😡 階層判断が曖昧になる

なぜコードにインデントをかけるかというと、階層構造を見える化するためで、インデント量が減ると当然これが曖昧になってきます。

これに対しては、現代的な開発環境だと IDE 側のサポートが優秀で、例えば VSCode では

- インデントレベルごとに縦に補助線
- ペアとなる Bracket を同じ色で表示

といったようなサポート機能が標準的に入っています。

Xcode でも~~微妙ですが~~ Code folding ribbon といった視覚的にサポートしてくれる機能が存在します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178830/59dec00e-8934-693a-2fda-d928e053cc60.png)


### 😡 標準的には 4 スペースインデント

- Xcode のデフォルト設定
- Apple 公式のサンプルプロジェクト

等を見ると、まず 4 スペースインデントが採用されているため、標準的な設定は何か？と聞かれたら 4 スペースインデントにはなってしまうと思います。

#### ❗️ 2022/09/28 追記

@yusuga さんから教えてもらったのですが、 OSS として Apple 主導で開発が進められている [apple/swift-format](https://github.com/apple/swift-format) だとデフォルトで 2 スペースインデントになっていました。

```sh:設定確認
$ swift-format dump-configuration | head -n 10
{
  "fileScopedDeclarationPrivacy" : {
    "accessLevel" : "private"
  },
  "indentation" : {
    "spaces" : 2
  },
  "indentConditionalCompilationBlocks" : true,
  "indentSwitchCaseLabels" : false,
  "lineBreakAroundMultilineExpressionChainComponents" : false,
```

```swift:該当コード
  /// A value representing a single level of indentation.
  ///
  /// All indentation will be conducted in multiples of this configuration.
  public var indentation: Indent = .spaces(2)
```
https://github.com/apple/swift-format/blob/e23f8ebd1cec244078fa64551f4ddd43f657716b/Sources/SwiftFormatConfiguration/Configuration.swift#L60-L63

Apple も一枚岩というわけではなさそうです。

## 2 スペースインデントの導入方法

ここからは実際に 2 スペースインデントを導入してみるとなった場合の対応方法について記載していきます。

### Xcode プロジェクト

EditorConfig に未対応な代わりに、 Xcode では以下の 3 パターンでインデント設定を変えることができます。
(`.xcodeproj` で管理される)

- Xcode 自体の設定
- プロジェクトごとの設定
- ファイルごとの設定

優先度は具象なほうが優先で、ファイルごと > プロジェクトごと > Xcode 自体という順で優先されます。

ファイルごとにインデント幅を変えることができるため、部分的に 2 スペースインデントを導入してみるといったことも可能です。

#### Xcode自体の設定

Preferences → Text Editing → Indentation から設定可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178830/cab5df54-02f3-81bb-c384-a8cfa6926f8f.png)

プロジェクトごとの設定、ファイルごとの設定で上書きされない限りはグローバルで効いてくるため、ここで設定することはあまりないかもしれません。

#### プロジェクトごとの設定

プロジェクトを開いた状態で、右側の Inspectors View → Text Editing で設定可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178830/1c35c2d6-0262-9552-5d07-d79c07cba8cf.png)

コーディング規約として、プロジェクトとして管理するのが自然だとは思うので、 2 スペースインデントで決め打ちで行くとなった場合は、ここで設定することになると思います。

_※　Xcode 自体の設定とプロジェクトごとの設定が同一だった場合は、 `.xcodeproj` 側に書き出されないことがあるので注意_

#### ファイルごとの設定

プロジェクトごとの設定と同様に、指定したファイルを開いた状態で右側の Inspectors View →　Text Editing から設定可能です。

この場合、対象のファイルのみインデント設定が反映されるため、とりあえず SwiftUI 関連のファイルのみ 2 スペースインデント化したいといった細かいスコープにも対応できます。

### XcodeGen を利用している場合

「`.xodeproj` は直接管理してなくて [XcodeGen](https://github.com/yonaskolb/XcodeGen) で生成しちゃってるよ😞」という方も安心してください。

XcodeGen でもインデント幅 (+ タブ幅) 設定用の[オプション](https://github.com/yonaskolb/XcodeGen/blob/master/Docs/ProjectSpec.md#options)が存在します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178830/b2464329-e912-e387-50c6-cfd0d1f556eb.png)

yaml ファイル上では以下のような記述で、インデント幅 (+ タブ幅) が 2 となっている `.xcodeproj` を生成できます。

```yaml:project.yml
name: ProjectName
options:
  indentWidth: 2
  tabWidth: 2
```

### SwiftFormat を利用している場合

「[SwiftFormat](https://github.com/nicklockwood/SwiftFormat) を掛けているので結局 4 スペースに戻ってしまう😢」

大丈夫です。 SwiftFormat にもインデント幅設定用の[オプション](https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md#indent)があります。

2 スペースを指定する場合は、以下を CLI で直接指定するか、 `.swiftformat` への追記で対応できます。

```
--indent 2
```

むしろ SwiftFormat がインデント幅指定に対応してくれているため、一括で移行するとなった場合は SwiftFormat での一括置換を検討してもいいかもしれません。

## やっぱり周囲の説得が難しい

- 前述の通り Apple が 4 スペースインデント志向
- 不毛な宗教論争になりやすい

といった理由から、実際に 2 スペースインデントを導入するとなると色々と障害があるかと思います。

最後に 2 スペースインデント採用に向けた強力な説得材料を一つ紹介します。

### Google の Swift コーディング規約は 2 スペースインデント

https://google.github.io/swift/

明確に `indentation width` が 2 という記載はないのですが、 `"+2"` で検索してもらえれば近い記述があるかと思います。

実際、 Firebase iOS SDK は 2 スペースインデントになっていたりします。

https://github.com/firebase/firebase-ios-sdk/blob/master/FirebaseAnalyticsSwift/Sources/Analytics%2BSwiftUI.swift

## おわりに

正直、インデント幅については、実際に試してみての感覚的な部分も大きいとは思います。
その是非も含めて、 2 スペースインデントを一度体験してみるだけでもいかがでしょうか？