Galapagos Tech Blog

株式会社ガラパゴスのメンバーによる技術ブログです。

Swiftで直感的に書ける範囲比較演算を定義する

こんにちは、iOS開発チームの本柳です。

Pythonなどでは値の範囲チェック(m < x and n > xのような評価)をする時、数学の評価式のようなm < x < nと記述することが出来、大変分かりやすいですよね。

swiftでは、動的に変化する画面の座標が範囲内にあるか?という評価を行うケースがそれなりに多く、このような評価式をつくることが出来ると大変に便利。

便利ならば作ってしまおう!ということで~を使って似たような評価式を書けるようにしてみました。

オペレーターの定義

まずは、<,<=,>,>=に該当するオペレーターを定義します。

Pythonだとm > x > nのようにも書けますが、これはn < x < mと等価であるので、<,<=だけを書ければ良いはずです。

なので、<~!<=~に置き換えて定義出来るようにします。

// `<=`に該当するオペレーター
infix operator ~ { associativity left }
// `<`に該当するオペレーター
infix operator ~! { associativity left }

こうして定義することで、Swiftではm ~ x ~ nのように記述することが可能になります。 これはm <= x <= nと等価になります。

Swiftでは常に左辺の結果を利用したいので、オペレーターにはassociativity leftを指定して左結合するようにしておきます。

オペレーターが利用する処理の実装

実装方針は下記の通りです。

  • 最初の~オペレーターは中間比較オブジェクトを生成する
  • 次の~オペレーターは左辺に比較オブジェクトを取り、右辺にComparableな値をとって真偽値を返す

比較オブジェクト(_Rangeとして定義することにします)は中間状態、完全状態を持ちますが、この状態はファントムタイプで実装することにします。

まずはファントムタイプの定義です。

class _RangeState {}
class _RangeIntermediate: _RangeState {}
class _RangePerfection: _RangeState {}

次に_Rangeオブジェクトの定義を行います。

デフォルトの_Rangeオブジェクトはコンストラクタをプライベートにして、さらに、中間状態をもつインスタンスのファクトリメソッドを定義しておくことで、初回生成は常に中間状態を持つように定義します。

enum _Range_MinOp {
    case less
    case lessOrEq
}

enum _Range_MaxOp {
    case gt
    case gtOrEq
}

struct _Range<T: Comparable, U: _RangeState> {
    typealias MinOp = _Range_MinOp
    typealias MaxOp = _Range_MaxOp
    
    private let value: T
    private let min: T
    private let minOp: MinOp
    private let max: T?
    private let maxOp: MaxOp?

    // コンストラクタはプライベートにして、状態を持たないインスタンスを生成出来ないようにします
    private init(value: T, min: T, minOp: MinOp, max: T?, maxOp: MaxOp?) {
        self.value = value
        self.min = min
        self.minOp = minOp
        self.max = max
        self.maxOp = maxOp
    }

    // 初期状態では中間オブジェクトのみ生成することが出来ます
    static func buildIntermediate(value: T, min: T, minOp: MinOp) -> _Range<T, _RangeIntermediate> {
        return _Range<T, _RangeIntermediate>(value: value,
                                             min:   min,
                                             minOp: minOp,
                                             max:   nil,
                                             maxOp: nil)
    }
}

デフォルトの_Rangeオブジェクトの定義が出来たら、今度は中間状態の_Rangeオブジェクトを拡張して、完全状態の_Rangeオブジェクトを生成出来るようにします。

extension _Range where U: _RangeIntermediate {
    func toPerfection(max max: T, maxOp: MaxOp) -> _Range<T, _RangePerfection> {
        return _Range<T, _RangePerfection>(value: value,
                                           min:   min,
                                           minOp: minOp,
                                           max:   max,
                                           maxOp: maxOp)
    }
}

最後に完全状態の_Rangeインスタンスに値の評価する処理を実装すれば_Rangeオブジェクトは完成です。

extension _Range where U: _RangePerfection {
    var valueInRange: Bool {
        return valueLessThanMinimum && valueGtThanMaximum
    }

    private var valueLessThanMinimum: Bool {
        switch minOp {
        case .less:     return value > min
        case .lessOrEq: return value >= min
        }
    }

    private var valueGtThanMaximum: Bool {
        switch maxOp! {
        case .gt:     return value < max
        case .gtOrEq: return value <= max
        }
    }
}

オペレーターの関数を定義

ここまで出来たら最後に、演算子に適合させたい型とオペレーターを紐付ける処理を書いて完了です。

func ~<T: Comparable>(lhs: T, rhs: T) -> _Range<T, _RangeIntermediate> {
    return _Range<T, _RangeState>.buildIntermediate(rhs, min: lhs, minOp: .lessOrEq)
}

func ~!<T: Comparable>(lhs: T, rhs: T) -> _Range<T, _RangeIntermediate> {
    return _Range<T, _RangeState>.buildIntermediate(rhs, min: lhs, minOp: .less)
}

func ~<T: Comparable>(lhs: _Range<T, _RangeIntermediate>, rhs: T) -> Bool {
    let range = lhs.toPerfection(max: rhs, maxOp: .gtOrEq)
    return range.valueInRange
}

func ~!<T: Comparable>(lhs: _Range<T, _RangeIntermediate>, rhs: T) -> Bool {
    let range = lhs.toPerfection(max: rhs, maxOp: .gt)
    return range.valueInRange
}

これで下記のようにシンプルに範囲を比較する処理が書けるようになりました。

let value1 = 10
print(1 ~ value1 ~ 10)  // -> true
print(1 ~ value1 ~! 10) // -> false

let value2 = 1
print(1 ~ value2 ~ 10)   // -> true
print(1 ~! value2 ~ 10)  // -> false

株式会社ガラパゴスでは、Swiftをつかってプログラミングを楽しみたいエンジニアを絶賛大募集中です!

RECRUIT | 株式会社ガラパゴス iPhone/iPad/Androidのスマートフォンアプリ開発

たくさんのご応募、お待ちしております。

とのの「#QAアーキ 行ってきた〜!」

こんにちは!ガラパゴステストチーム とののです。
わたしは先日、QA勉強会「ここは苦しいところですが、どうか一つ、QAアーキテクチャを。」に参加してきました!
たいへん勉強になりましたので、ここでも振り返って自分に納めていきたいと思います。

参加前のとのの

わたしがこの勉強会に参加しようと思ったのは、単純に
「QAアーキテクチャってなんだ???知りたい!」と思ったからです。
内容が難しいかどうか、話についていけるかが参加前一番気になるところです。今回はイベントの詳細ページをみて、”QAに関わる全ての方”とあったので「とりあえずいける!!!」という勢いでした笑

QAアーキに参加したよ

connpass.com

QA勉強会「ここは苦しいところですが、どうか一つ、QAアーキテクチャを。」
2016/12/20 19:00〜 @電気通信大学
講演1「QAアーキテクチャの話」:勉強会主催者 藤沢 耕助さん
講演2「ここは苦しいところですが、どうか一つ、QAアーキテクチャを。」:電気通信大学 にしさん

大学って落ち着きますね…

講演1「QAアーキテクチャの話」

QAアーキテクチャについて、藤沢さんがどう考えているか、というお話でした。

資料 Qaアーキテクチャの話

■ 「QA」とはなんだろう?
■「アーキテクチャ」とはなんだろう?
■では「QAアーキテクチャ」とは?

(以下ざっくりわたしが理解した内容)

  • 顧客の要求との齟齬が少ないほど「高品質」と言えるのではないか。
  • では品質を保証するためにできることはなんだろう?
    →お客さんに納得してもらうこと?それには何かしらの基準や観点が必要ですね。
    →バグがないこと、は示せないけど、特定の範囲でならバグゼロは示せる→納得してもらえる、のでは?

  • QAとは:何の品質を何の目的で保証しているのかを理解、納得してもらうことなんじゃないだろうか

  • テストにおけるアーキテクチャ設計とは
     何をテストするのか(テスト要求分析)
     そのテストの目的は何か(テスト対象分析)
     どのようにテストするのか(テスト条件分析)
    →テストを分析して、設計していくこと?

  • テストアーキテクチャはQAアーキテクチャの一部で、お客さんに理解、納得してもらうためのいろんなアーキテクチャのまとめがQAアーキテクチャなんじゃないだろうか
    →レビューアーキテクチャ、テストアーキテクチャ、プロセス保証アーキテクチャ、インフラアーキテクチャなど

とのの。。(ふむふむ)
「テスト」がQAの一部、というところにはっとしました。
いままでひたすらアプリを動かして検証して、テストのことばかり考えていましたが、
品質保証にはテスト以外のアプローチもある、ということを教えてもらった気がします。
これからもテストをしてテストを良くして品質保証することに変わりはないですが、講演を聞いて視野が広がりました。

講演2「ここは苦しいところですが、どうか一つ、QAアーキテクチャを。」

QAが機能しないときっていうのは、上手くいっていなくて、なにをすればいいかはわかっているけど、制約とかしがらみで動けない状態が多い。
そんなとき!「QAアーキテクチャを」何卒… という意味だそうです。タイトルにしっくりきました。

資料 Yasuharu Nishi, 電気通信大学 | SlideShare

■テストや品質保証における問題はこういうところです
■QAアーキテクチャに慣れていないので、テストアーキテクチャを設計してみましょう
■レビュー段階で同じように設計することで、テストを楽にすることができる
■では、QAアーキテクチャを設計しましょう

  • まずテスト観点図をかいてみよう
     このテストの意図は何か、というところを考えて書くことがポイント
     テストの意図が明確になり、何をどうするとバグが起きるのか、が図からわかる
     どこで何を保証したのかが図からわかる
  • 開発者が気をつけることもわかってくるので、自然に「レビュー観点」が明らかになってくる
  • なのでまず「レビュー設計」をしましょう
  • レビューには副次的役割もあり、その狙いも含めて考えましょう
  • ではQAアーキテクチャを設計していきましょう
  • ふわふわはっきりしない「品質」をモデリングして、はっきりさせましょう: QA観点モデル
  • 開発工程ごとに、さっき決めたどの観点が保証されているのかを整理しましょう: アシュアランスパイプライン
  • そのパイプラインを支える技術力を整理して持っておきましょう: テックシェルフ

とのの。。(ふむふむ)
質疑応答でにしさんがおっしゃっていた、「初めから全部わかってやるのなんて無理。はじめは40点でいいから試してみよう」
という回答がわたしにとってすごくヒントになりました。
直接QAアーキテクチャを設計する、ということはまだまだできそうにないのですが、
わたしの仕事に置き換えて、力をつけるためにはどんなところに注目して仕事をすればいいかが少しわかった気がします。

さいごに

今回もたいへん勉強になりました!
Twitterでも参加したかったのですが、正直いっぱいいっぱいでした!!!
もっとサクッ!すぱッッ!と文章がかけるようになりたいです。

スピードも含めてスキルアップしていきたいと思います!!
ではまたお会いいたしましょう、とののでした。

www.glpgs.com

第9回Quesに参加してみた話

はじめまして、テストチームの とののです!

テストについては勉強したてほやほやのテストエンジニアです!
今回、エンジニアブログ初参加ということで、先月わたしが生まれて初めて参加したイベントについて 張り切って書きたいと思います!!



ではさっそく… 「会場が渋谷でね、駅にはついたんだけどね、たてものの(泣)」
みたいのはおいといて

第9回Quesに参加してみたよ

「QA」と何かでググっていたところ、このイベントにぶつかった気がします。
他の会社ではどんなテストをしているのか興味があったので、いいタイミングでいいテーマの回に出会えたと思います。

公式サイト quesqa.com

イベントの内容はこんな感じでした

ーー

2016/11/18 19:00〜 @サイバーエージェント

第1部

「Amebaアプリ QAの歴史」

 株式会社サイバーエージェント Ameba統括本部

 Amebaメディア本部メディアQC室 関根 雄飛さん

第2部

「QAエンジニアのキャリアパスについて考える

〜いろいろな組織でリーダー/マネージャとしてやってきたこと〜」

 株式会社mediba 品質管理グループ 山本 久仁朗さん

ーー

質疑応答含めざっくり1時間弱ずつくらいで、時間いっぱいお話してくれた印象でした。

Amebaアプリ QAの歴史 について

公式サイトのレポートに資料があるので、細かい内容は書かずに思ったことだけ書きます。

テストフローや、利用しているツールなどかなり具体的に公開されていたので、
自分の仕事内容と比較しながら聞いていました。
テストフローはほぼ同じで、すべて人の手で最後までやっているところなど、親近感がありました。

似てる
・項目書とその中身:Googleスプレッドシート、区分の分け方、見た目など
・テスト実施前にテスト内容の共有
・夕会で仕様変更などの情報共有:弊社は朝会です

似てない
・項目書が機能ごとのシート分け
→エンハンスかそうでないかの違いだと思いますが、わたしは画面ごとで分けた項目書を見ることが多いので新鮮でした。

KPT法で項目の振り返り会
ガラパゴスでは、反省会は取り組み始めたばかりです。(いままではっきりとした形ではやっていませんでしたが、形になってきた)
方法論を参考にするのも、わかりやすくてよいかもしれないですね。

・開発チームとの距離
→人数の規模が違うので当然といえば当然なのですが、それを置いてもガラパゴスは開発チームとテストチームの距離は近いと思います!
OSでの挙動の違いを確認したり、どんな実装になっているか質問したり、
直接確認できるので物理的にも、雰囲気的にもコミュニケーションは取りやすい環境だと思います。

QAエンジニアのキャリアパスについて

山本さんがいままでどんなことをしてきたかについてのお話でした。
経験談おもしろかったです。

途中で知らない単語がたくさんあったので復習します

「シックス・シグマ」、「TPI/TPI NEXT」:プロセス改善方法
「Test.ssf」:テスト技術のものさし
「GQM」:モデル化の手法、ゴール・クエスチョン・メトリクス
「FiveCore」:会社名か英語ばっかり引っかかって…(泣)このリンクと関係ありそう?と思うのですがなにかまだわかってません
ISO/TS16949 コアツールとは|ISO9001 ISO14001コンサルティング 大阪 福岡 東京 400社を超える支援実績があります

「改善しよう」というところまでまだ意識がいっていないので、手法についてはさっぱりだったんですね!笑


全体的にとっても前向きな話でした。
冒頭にテスト工数についての話があって、

テスト工数は開発のだいたい40%の割合を占めている、大きければ60%以上!(そうなんだ、そんなに〜!)
→高品質にするには、テストに時間がかかる(わかる)
→テスト工数を効率化すれば、利益率も上がる?!(!!!!!!)

たしかに!!!同じ時間とお金をとってもらえるとしたら、中身濃いほうがいいに決まってますよね!
この話すごくしっくりきました。

他にびびっときたところは、

  • 社会人の勉強には答えがないよ。
  • いましかないから勉強しよ
  • 楽したかったら勉強しよ
  • テストは知恵と経験

勉強して、技術力をつけていきましょう!という内容にやる気が高まりました!!!
がんばります。

さいごに

生まれて初めてのイベントは、とっても刺激を受けました!
当日は平日でしたが、ガラパゴスフレックスタイム制、かつ「勉強?!どんどんしてこーい!」と送り出してくれる会社なので、 イベントや勉強会にも参加しやすい環境なんだと思います。
さらにいま、ガラパゴスでは刺激を求める貪欲エンジニアを大募集中です!!
ご興味ある方ご応募お待ちしております。

www.glpgs.com