176
155

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Swift リファクタリング実践 Tips1

Last updated at Posted at 2016-07-12

Twitter (@eduraaa)gist (ezura) でちょくちょくコードの考察のようなものを書いています。
今回はその中で、特に反応をいただいた、リファクタリング関係の Tips の一部を紹介します。

この記事のおすすめの読み方

  1. before の例を見て、その処理が何をしたいのか概要を読み取る
  2. after を見て before との印象の違いをみてみる

例 1

before
if /* condition */ {
    label.text = "a"
} else if /* condition */ {
    label.text = "b"
} else {
    label.text = nil
}
after
label.text = {
    if /* condition */ {
        return "a"
    } else if /* condition */ {
        return "b"
    } else {
        return nil
    }
}()

この処理の意味するところは「label.text の値を条件に応じて設定している」なのですが、before の場合、「何か条件分岐してるな」などの伝えたいことの本質とは少し外れたステップを読み手に"最初"に考えさせてしまいがちです。

「ぞれぞれの条件のとき、何がおきるのかな」→「なるほど。label.text の値を設定しているのだろう。いや、もしかして、label.text ではないものに対しての処理も紛れてないか?」→「紛れもなく、label.text の値を設定しているのだ」と、心配させてしまうかもしれません。
一方、after のようにすると、その処理群が何をしたいのか、その本質を一目見るだけでわかります。また、何か処理を付け足したとしても、本来の意図を大きく崩すような処理を書き難いです。

例 2

before
if /* condition */ {
    labelA.text = "a"
    labelB.text = "A"
    labelC.text = "A"
} else if /* condition */ {
    labelC.text = "B"
    labelB.text = "B"
    labelA.text = "b"
} else {
    labelA.text = "c"
    labelC.text = "C"
    labelB.text = "C"
}
after1
(labelA.text, labelB.text, labelC.text) = {
    if /* condition */ {
        return ("a", "b", "c")
    } else if /* condition */ {
        return ("b", "B", "B")
    } else {
        return ("c", "C", "C")
    }
}()
after2
(labelA.text, labelB.text, labelC.text) = {
    if /* condition */ {
        return (labelA: "a", labelB: "b", labelC: "c")
    } else if /* condition */ {
        return (labelA: "b", labelB: "B", labelC: "B")
    } else {
        return (labelA: "c", labelB: "C", labelC: "C")
    }
}()
after3
(labelA: labelA.text, labelB: labelB.text, labelC: labelC.text) = {
    if /* condition */ {
        return (labelA: "a", labelB: "b", labelC: "c")
    } else if /* condition */ {
        return (labelA: "b", labelB: "B", labelC: "B")
    } else {
        return (labelA: "c", labelB: "C", labelC: "C")
    }
}()

before では、例 1 のときよりも更に全体を注意深く見なければ、正確に意図を掴みにくいのではないでしょうか。
パッと見て何をやりたいのか察しはつくと思うのですが、それでも、「それぞれの条件下の処理の中で labelA, B, C が全て揃っているのかどうか」不安になりそうです。
一方、after1, 2, 3 では、例 1 の after と同様に、意図がはっきりと読み取れます。書き足した場合も指定漏れの心配もありません。
after1, 2, 3 のどの記述が良いかは、好みと状況によりますが、返り値の tuple の要素にラベルをつけてあげると、それぞれの値が何なのか受取先の tuple を見に行かなくて良いので読む人に優しいと思います。ただ、冗長に感じる場合も多々あるので、使い分けていくことも必要です。

最後に

第一回はここまでにします。

176
155
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
176
155

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?