Galapagos Tech Blog

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

JSONの読み書きでSwift 4.1のCodableを使ってみる。

ガラパゴスのコードヒーヨアン(twitter: @luinily)です。

以前Swift 4でJSONの扱いについての記事を書きましたが、今回はその続きで、Swift 4.1で追加される機能や、実際のプロジェクトをObjectMapperからCodableに変更して見た話をしようと思います。

下記の流れに沿っていこうと思います。

  • 単純な構造体でCodableとObjectMapperの紹介
  • Codableのキーとカスタムキーの紹介
  • Codableのカスタム読み込みと書き出しの紹介
  • Codableのデバグの紹介
  • プロジェクトを通したCodableとObjectMapperの比較

CodableとObjectMapperの紹介

この紹介で、下記のJSONをSwiftの構造体に読み込み、書き出しするための処理を紹介します。

JSON

{
    "food": "桜餅",
    "quantity": 1
}

構造体:

struct Food {
    let food: String
    let quantity: Int
}

Codable

CodableはSwiftが提供している構造体やクラスなどをJSONに書き出す、読み込むためのプロトコル。(厳密に言うと、JSONだけではなく、他のフォーマットにも使えまる) CodableはEncodable(書き出し用)とDecodable(読み込み用)の二つのプロトコルで構成されています。

構造体での対応:

struct Food: Codable {
    let food: String
    let quantity: Int
}

こういう単純な構造体では「Codable」というプロトコルを適用するだけです、時に実装が不要です。

JSONの読み込み:

let decoder = JSONDecoder()
let food = try? decoder.decode(data)

書き出し:

let encoder = JSONEncoder()
let data = try? encoder.encode(food)

JSONの読み込み書き出しはData型のオブジェクトから行われます。

ObjectMapper

ObjectMapperはJSONの読み込み、書き出しによく使われているライブラリー、Mappableというプロトコルを使います。

構造体での対応:

struct Food: Mappable {
    var food: String!
    var quantity: Int!

    init?(map: Map) {
        mapping(map: map)
    }

    mutating func mapping(map: Map) {
        food <- map["food"]
        quantity <- map["quantity"]
    }
}

こういう単純な構造体でも「Mappable」というプロトコルを適用した上で、各プロパティーを「let」から「var」に変えて、型に「!」を追加して、「init?(map: Map)」と「func mapping(map: Map)」という関数を実装する必要があります。

「init?(map: Map)」の実装は簡単ですが、「mapping」の実装はもうちょっと手間がかかります: 

  • 各プロパティに対して 「property <- map["キー"]」というあまり見慣れてない行を書く必要がある
  • 各プロパティのキーを入力する必要があります。
  • 書き出し、読み込みに特別な処理をする必要がある場合ちょっと複雑になります。

その処理はObjectMapperが行う処理が原因です:構造体・オブジェクトを実態化してから、JSONを読み込んでプロパティーの値を設定しますので、値が入ってない状態で実態化できる必要と、実態化後に値の変更できるようにする必要があります。

JSONの読み込み:

let food =  Mapper<Food>().map(JSONObject: jsonObject)

書き出し:

let jsonDictionarry = Mapper<Food>().toJSON(food)

比較

構造体での対応はキー、読み込み関数、書き出し関数の自動生成ができるCodableの方がはるかに軽いです。その上、Codableはinit()関数で読み込みを行なっていることで、varだけではなく、letも使えて、!を使用する必要もありません。今回のような簡単なクラスや構造体ではCodableを宣言するだけで対応できます。

ObjectMapperはキーが自動生成されませんので書く必要ありますが、キーの文字列は自由に定義できます。mapping(map)関数雨の中でJSONとの変換に必要な処理も定義できます。Codableの方は同じのようにキーをカスタマイズするのと、書き出し、読み込みの処理をカスタマイズすることができますか。

Codableのキー

キーに使われる文字列がプロパティ名そのままですので、自動生成されるCodableのキーに複数問題があります。

  • JSONでのキーの書き方はスネークケース(snake_case)、Swiftではカーメルケース(camelCase)を使います。このまま自動生成されるキーを使うと、Swiftのプロパティ名をスネークケースにするか、JSONをカーメルケースにする必要があります。できれば避けたい問題です。
  • プロパティ名と違う文字列をキーに使い時もあります。
  • クラスや構造体にJSONの書き出し、読み込みと関係ないプロパティがあった場合現状ではキーが作成されて、読み込み書き出しされようとします。

snake_caseとcamelCaseの自動変換(Swift 4.1から)

Swift 4.1で新しく追加された機能ですが、Encoderの「keyEncodingStrategy」やDecoderの「keyDecodingStrategy」を設定することで、camelCaseのプロパティ名からsnake_caseのキーの自動作成できるようになりました。

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase

使えるストラテージーが三つあります:

  • useDefaultKeys → プロパティ名をそのままキーに使います
  • convertFromSnakeCase / convertToSnakeCase → プロパティ名をcamelCase、snake_caseに変換します
  • custom(([CodingKey]) -> CodingKey) → 引数で渡すクロージャーを使用し、変換します。

カスタムキーの定義

Codableでも必要な時は本来自動的に生成される「CodingKeys」という列挙型を追加することでカスタムキーを使うことができます。

struct Food: Codable {
    let food: String
    let quantity: Int

    enum CodingKeys: String, CodingKey {
        case food = "Food"
        case quantity
    }
}
  • 構造体、クラスなどの中で定義する必要があります。
  • キーの列挙型の定義は「enum CodingKeys: String, CodingKey」にする必要があります。
  • ケース名はプロパティ名と同じ
  • カスタムしたいキーは「= "カスタム値"」で定義できます。
  • カスタムしないキーも定義しないといけないんですが、Stringでの値は定義しなくても自動的に作成されます。
  • CodingKeysを定義する場合、書き込み、書き出しされるプロパティ全てをcaseとして定義する必要があります。

上記の条件でわかると思いますが、書き出し、読み込みしたくないプロパティがある場合、CodingKeysを定義して、そのプロパティ以外のプロパティ全てをcaseとして定義する必要があります。

struct Food: Codable {
    let food: String 
    let quantity: Int 
    var eaten: Bool = false ← CodingKeysに定義されてないため、書出読込されない

    enum CodingKeys: String, CodingKey {
        case food = "Food"    ← カスとマイズされたキー
        case quantity         ← 自動生成されるキー
    }
}

ここでは、カスタムキーについてまだ一つの疑問が残るとお思います:キーの自動変換とカスタムキーがどういうふうに組み合わせられるのかということです。 例えば例のJSONに新しいキーを追加します。

{
    "food": "桜餅",
    "quantity": 1
    "food_weight": 100
}

「food_weight」というキーが追加されました。Swift側ではプロパティーとして追加しますが、Food型に「foodWeight」というプロパティーを入れると名前がちょっと被ってしまいます、「weight」として定義した方がいいと思います。

struct Food: Codable {
    let food: String 
    let quantity: Int 
    let weight: Int

    enum CodingKeys: String, CodingKey {
        case food = "Food"    ← カスとマイズされたキー
        case quantity         ← 自動生成されるキー
        case weight = ""
    }
}

この場合、カスタムキーの値を「food_weight」にするべきか、「foodWeight」にするべきかのどちらでしょうか。

この問題の答えはいつCodingKeysのキーがJSONのキーに変換されるかによって変わります。ヒントとしては、キーの変換の設定は、CodingKeysやFoodではなく、encoderやdecoderの方で行なっていることです。 つまりSwiftのプロパティからJSONキーの生成はこのように行われています:

f:id:glpgsinc:20180522170019p:plain

カスタムキーの定義を行う場合、CodingKeyの値を定義しますので、 JSONキーの変換前の状態にしなければなりません。

struct Food: Codable {
    let food: String 
    let quantity: Int 
    let weight: Int

    enum CodingKeys: String, CodingKey {
        case food = "Food"
        case quantity
        case weight = "foodWeight"
    }
}

先の図に入れるとこうなります: f:id:glpgsinc:20180522170413p:plain

Codableで書き出し、読み込みカスタム処理

Codableでも必要がある場合、カスタムな書き出し関数、読み込み関数の定義ができます。 例えばさっきのJSONの「food_weight」の値をIntからStringに変更します。

{
    "food": "桜餅",
    "quantity": 1
    "food_weight": "100"
}

Food構造体の方ではIntのままにします、StringとIntの変換が必要ようになります。 ついでに、Foodにもう一つのオプショナルプロパティを追加します。 オプショナルプロパティはCodableでもObjectMapperでもJSONにキーがない可能性があるときに使います。

struct Food: Codable {
    let food: String 
    let quantity: Int 
    let weight: Int
    let origin: String?

    enum CodingKeys: String, CodingKey {
        case food = "Food"
        case quantity
        case weight = "foodWeight"
    }
}

カスタム読み込み

読み込み関数は「init(from decoder: Decoder) throws」で定義します。

init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)

    food = try values.decode(String.self, forKey: . food)
    quantity = try values.decode(Int.self, forKey: . quantity)
    weight = try Int(values.decode(String.self, forKey: . weigh))
    origin = try values.decodeIfPresent(String.self, forKey: . quantity)
}

まずは「decoder」からキーを使って、「values」を取得します。

そのあとは各キーに対する値を取得して、必要な追加処理をします。

  • 必須キーの場合、「try values.decode(String.self, forKey: . food)」を使います。一つ目の引数はそのキーの値の型、ここではString、二つ目の引数はキー
  • キーが必須でない場合、「try values.decodeIfPresent(String.self, forKey: . quantity)」を使います。「decode」と同じ使い方ですが、キーがなかった場合にエラーを起こしません。
  • 今回はweightをStringとして取得したあと、Intに変換するカスタム処理を追加しています。

注意点としては、キーがない可能性がある場合はちゃんと「decodeIfPresent」を使うことと、カスタム処理行わないキーに対しても処理を書かなければなりません。

カスタム書き出し

書き出しは読み込みに似ていて、定義する関数は「func encode(to encoder: Encoder) throws」です。

func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(food, forKey: . food)
    try container.encode(quantity, forKey: . quantity)
    try container.encode(String(weight), forKey: . weight)
    try container.encodeIfPresent(origin, forKey: . origin)
}    

読み込みの場合はDecoderからvaluesを取得していたが、今回はEncoderからcontainerを取得します。

そのあと各キーに対する書き出し処理を書きます。

  • 必須キーの場合は、「try container.encode(food, forKey: . food)」を使います。引数はプロパティ値とキーです。
  • プロパティがnilになっている可能性がある場合、「container.encodeIfPresent(origin, forKey: . origin)」を使います。encodeと同じ使い方が、値がnilであった場合エラー起こしません。
  • 今回はweightをStringに変換してから書き出します。

Codableで楽に読み込みと書き出しのカスタム関数がかけることがわかりました。現状ではカスタム処理されるキーだけではなく、全てのキーに対しての処理を書く必要があります。いずれは特別処理をしたいキーの処理を書いた後に、「残りのキーは自動処理して良いよ」のようなやり方があればさらに使いやすくなるかと思います。

列強型

Codableのデバグ

今まで書いたコードを見た気づいたと思いますが、Codableの処理はエラーを返すことができます。「init(from decoder: Decoder)」も、「func encode(to encoder: Encoder)」も「throws」が付いていますし、「encode」、「decode」関数を使うところはtryをつけています。 このおかげで、読み込みや書き出しの際に何らかの問題があった場合エラー処理とバグ対応がしやすくなっています。

lldbにdecodeの際にエラーが出た場合どういう情報得られるか複数の例を見て見ましょう。

JSONに必須キーが含まれていない。

構造体:

struct Food {
    let food: String
    let quantity: Int
}

JSON

{
    "food": "桜餅",
}

lldbで読み込み処理して見るとこうなります。

(lldb) po decoder.decode(Food.self, from: jsonData)
▿ DecodingError
  ▿ keyNotFound : 2 elements
    - .0 : CodingKeys(stringValue: "quantity", intValue: nil)
    ▿ .1 : Context
      - codingPath : 0 elements
      - debugDescription : "No value associated with key CodingKeys(stringValue: \"quantity\", intValue: nil) (\"quantity\")."
      - underlyingError : nil

「Decoding」エラーがプリントアウトされて、エラーの詳細が見れます。

  • エラーの種類が書いてあります:「keyNotFound」(キーがみつからなかったと)
  • どのキーがエラーの原因になったか:「CodingKeys(stringValue: "quantity", intValue: nil)」

結論は「quantity」というキーがJSONで見つからなかったため読み込みができなかったことがわかります。

カスタム読み込み関数を定義した場合、メンバーのタイプがオプショナルになっても、読み込み関数で「decodeIfPresent」ではなく、「decode」を使うと同じエラーが出ます。

② データのタイプが違う

構造体:

struct Food {
    let food: String
    let quantity: Int
}

JSON

{
    "food": "桜餅",
        "quantity": "1"
}

lldbで読み込み処理して見るとこうなります。

(lldb) po decoder.decode(Food.self, from: jsonData)
▿ DecodingError
  ▿ typeMismatch : 2 elements
    - .0 : Swift.Int
    ▿ .1 : Context
      ▿ codingPath : 1 element
        - 0 : CodingKeys(stringValue: "quantity", intValue: nil)
      - debugDescription : "Expected to decode Int but found a string/data instead."
      - underlyingError : nil

同じくエラーが表示されます。

  • エラーの種類は「typeMismatch」(型が一致しません)
  • どのキーが原因となったか:「 CodingKeys(stringValue: "quantity", intValue: nil)」
  • エラーの詳細:「Expected to decode Int but found a string/data instead.」(Intを読み込む期待でしたが、代わりにstring/dataがありました。)

「quantity」というキーに対して、Intを期待していたのに、Stringがあったことがわかります。

③ 無効なJSON

そもそもJSONが無効な場合(「,」や「}」がたりないなどの場合)

(lldb) po decoder.decode(Food.self, from: jsonData)
▿ DecodingError
  ▿ dataCorrupted : Context
    - codingPath : 0 elements
    - debugDescription : "The given data was not valid JSON."
    ▿ underlyingError : Optional<Error>
  • エラーの種類は「dataCorrupted」(損傷したデータ)
  • エラーの詳細:「The given data was not valid JSON.」(与えられたデータが有効なJSONではありません)

一つのアプリでObjectMapperからCodableへの移行試した感想

Swiftのバージョンと共に更新される

Codableの強みの一つはSwiftの1部になっていることです。Swiftのバージョンが上がっても、同時にリリースされますし、ライブラリーの追加が不要です。ObjectMapperの方はSwiftのバージョンが上がっても、対応に時間かかる可能性があります。

ObjectMapperより対応が軽いが、場合によって総合行数があまり変わらない場合も

Codableの実装とObjectMapperの実装に使うコード量を比較してみました。 もともとJSONに関係するクラスと構造体が25個あります。ObjectMapperでは全てのクラス、構造体に実装が必要でしたが、 Codableの方では、14クラスに実装が不要でした(Codableをクラス宣言に追加するだけ)、6クラスにキーだけの実装が必要、残りの5クラスに読み込みや書き出しの関数の実装が必要でした。

ただ、ObjectMapperと違って、書き出し読み込み関数を別々で書く必要があって、今回のプロジェクトで書き出し読み読み込みがカスタムされたクラスが大き目だったため、Codableでの総合対応行数がObjectMapperより1割ぐらいしか変わりませんでした。

ObjectMapperよりデバグしやすい

エラーの説明があるため、どこが悪いかわかりやすいです。ObjectMapperは逆にブレークポイントなど使っても悪いところが探しにくいです。

列挙型のための処理が不要!

CodableはStringやIntというタイプになっている列挙型にも適用できますので、JSON用のIntやStringへの変換の処理を書き出し読み込み関数に追加しなくていいです。

(個人的な)結論

ObjectMapperとCodableを両方使った経験からしては、新規アプリであればぜひCodableの方をオススメしたいと思います。Codableの方が対応が楽のと、問題があった場合デバグしやすいところが大きいです。Swiftのバージョンが変わった時対応を待つ必要もないところが便利だと思います。

ただし、既存アプリの場合は、Codableに変更するための対応に加えて、[String: Any]のJSONディクショナリーではなく、Dataからの読み込み書き出しになりますので、場合によってネットワーク系のライブラリーにも作業が必要可能性がありますので、問題ないかのを確認してから検討した方がいいかと思います。

「マインドマップを使ったテスト分析設計勉強会」参加レポート〜後編〜

こんにちは、この前ニチアサの録画に失敗したテストチームの文豪です。

今回は「マインドマップを使ったテスト分析設計勉強会」参加レポートの後編です。

gtech.hatenablog.com

マインドマップを使ったテスト分析設計勉強会」

■日時
2018/05/16 19:30~21:30
■場所
株式会社ガラパゴス
■登壇者
セッション1:とののさん@tonono2587
セッション2:鈴木三紀夫さん(@mkoszk
Twitterハッシュタグ
#NaITE_mm

nagasaki-it-engineers.connpass.com

後輩あべべと一緒に参加してきました。
後編では、セッション2「テスト要求分析を語る夕べ(出張編)」についてレポートしていきたいと思います。

なお、あべべと同じくテスト設計の経験はほぼゼロです。最近始めたところです。
ご承知おきください。

その前に

文豪もマインドマップ書いたので、ちらっとレポートします。
お題は前回記事を参照ください。

書いてみた

文豪は数年前に『マインドマップから始めるソフトウェアテスト』を読んでいるので、おぼろげな記憶を頼りにとりあえず書いてみました。

f:id:glpgsinc:20180521150714j:plain
メインブランチはボタン3つと、画面表示です。
(フォームと書いてあるのはそのとき「画面表示」という言葉がぱっと出なかったからです)
・これはできるべき
・こんなバグありそう
・ユーザーのしそうな操作
の3点を考えながら書きました。
お題の数取器はWEBアプリなのですが、普段WEBアプリのテストをしないのでその辺は難しかったです。

共有後に、目から鱗だったことは以下です。
・十進法かを確認する
・+ボタンを押して+1されるのはいつか:ボタンを押したとき?放したとき?
・ボタンのどこを押しても反応するか

感想

・文豪の中には「メインブランチはボタンのような画面を構成するもので出す」という発想しかありませんでした。なので品質特性などでメインブランチを出す、というのはよい気付きでした。
・参加者の方から「論理的に文章で考えられない人にマインドマップは向いているのでは」というようなお話がありました。文豪はわりと(論理的かはともかく)文章でざくざく書くタイプなので、もしかしたらマインドマップは得意でないかも。でもテスト分析には活用できそうなので、今後使っていけたらと思いました。
マインドマップの略はMM

それでは

本題の「テスト要求分析を語る夕べ(出張編)」のレポートです

話し手は鈴木三紀夫さん、セッション1で使用した『マインドマップから始めるソフトウェアテスト』の共著者のお一人です。
テーマはそのものずばり「テスト要求分析」でした。
が、文豪はテスト設計初心者なので、MUZUKASHIと思いながら聞いていました。

主に以下のお話をしていただきました。
・テスト分析
・テストプロセス
・テスト要求分析プロセスのアウトプット
ステークホルダーの分析
実際の資料はまだまだ続きがあったのですが、時間内に終わりませんでした。
6月26日頃に続きを発表してくださるかも、とのことでした。
参加せねば(((((((((((っ・ω・)っ ブーン

というわけでお聞きしたお話の中で、気になったものを列挙していきます。ざっくりです。

*「分析」という言葉の定義について

辞書では「分けること」を指している
→本当に「分ける」だけが「分析」か
→論理学の本では「分けて」「再構成すること」
→分析は「分ける」だけでなく「再構成すること」も必要と考える

*「テスト分析」の指すもの

以下の3種類を指している
①テスト結果の分析のこと
②第三者検証会社が仕事を始める前に行う分析のこと
③テスト設計の前のアクティビティ

①との混合を避けるため、③のことは「テスト要求分析」と呼んでいるそうです。
(今回のお話の主題は③になります)

*「プロセス」という言葉の定義について

JSTQBの用語集では「相互関係のある活動のセット」
JSTQB認定テスト技術者資格-シラバス(学習事項)・用語集-

辞書では「物事を進める手順、変化するときの経過や過程」
鈴木さんは「入力から出力に変換する諸活動の連鎖」と説明しているそうです。

*テストプロセスとは

JSTQBの用語集では、「テスト計画、コントロール…によって構成される」とあり、プロセスの構成要素を列挙して定義づけている
・テストプロセスは時代とともに変わっていく
初めの頃は「実行」「報告」という2つのアクティビティしかなかったが、今は「計画」「要求分析」〜「評価」まで増えた。

*テスト要求分析についての解説は多くない


*テスト要求分析のアウトプット

・アウトプットはテスト条件あるいはテスト観点
・テスト条件とは「◇◇な場合、〇〇すると、■■となる」と書けるもの
 ◇:条件、状態、前提
 ◯:トリガー、イベント、操作
 ■:期待結果
・テスト観点とは「テストしたいと思うモノやコト」

*テスト分析を始める前に

ステークホルダーを把握し、重要度・影響度でステークホルダーを分析する
・表よりオニオンモデルの方が出てきやすい
ステークホルダーからユーザー要求を獲得する
→ユーザー要求が多くなってきたらリッチピクチャーの出番
ユーザーの「思い」は、1つだけではない (1/2) - ITmedia エンタープライズ

感想

・2003年頃にはまだ「テスト設計」という言葉は一般的ではなかったらしく、ある会社が「テスト設計」という言葉を使い始めたら、テストケースの書き方が変わり欠陥が激減したそうです。言葉1つで、ここまで変わるんだなと思いました。
・バックワードチェイニングなる人材育成の方法論があるそうです。よさげです。
・リッチピクチャーすごい
・発表資料がスライドでなくドキュメントでした。とってもよいと思ったので、機会があれば文豪もドキュメントで資料作ろうと思いました。
・MUZUKASHIとは思いましたが、楽しかったです。

マインドマップ、テスト要求分析についてお話をお聞きし、いくつか学びがありました。テスト設計のお勉強を始めたところなので、これから活かせていけたらと思います。

閲覧いただきありがとうございました!


ところで

ガラパゴスではエンジニアを募集しています。興味を持たれた方はぜひ弊社の採用ページをご覧ください。

www.glpgs.com

「マインドマップを使ったテスト分析設計勉強会」参加レポート〜前編〜

こんにちは、テストチームのあべです。
テストエンジニア歴はもうすぐ1年のひよっこです。

今回は、発表者が先輩のとののさん(@tonono2587)、会場が自社ということもあり、「マインドマップを使ったテスト分析設計勉強会」に参加してきました!

マインドマップを使ったテスト分析設計勉強会」

■日時
2018/05/16 19:30~21:30
■場所
株式会社ガラパゴス
■登壇者
セッション1:とののさん(@tonono2587)
セッション2:鈴木三紀夫さん

nagasaki-it-engineers.connpass.com

NaITE(長崎IT技術者会)のマインドマップ本読書会SIGメンバーさんの活動報告会を兼ねた勉強会、という形でした。

今回の勉強会はセッションが2つありました。ので、一緒に参加した先輩の文豪さんと2回に分けてレポートします!

今回は、セッション1「【使ってみた】テストにマインドマップ」です(^^)
主な内容はこちら

ちなみに

あべは、テスト設計、分析、テストケース作成の経験がありません。
1年間、テスト実施者として経験を積んできました。

また、「マインドマップから始めるソフトウェアテスト」は未読で参加しています。
マインドマップについても、勉強会当日にネットで20分ほど学習しただけの、全くの素人です。もちろん、書いたこともありませんでした。

そんな、ソフトウェアテストの経験もマインドマップの知識も浅い、
初心者のレポートであることをご承知おきくださいm( )m

SIG活動報告

まずはSIGメンバーの活動報告がありました。

メンバーの参加動機

■テスト業務の改善

  • 1個の改修でどこに影響があるのかすぐにわからない
  • テスト技法自体はなんとなくわかってきたが、設計にもっと活かしたい
  • 要求分析的な部分も考えたい
  • バグ分析もできたらいいな

活動内容

マインドマップから始めるソフトウェアテスト」の読破&実践を通して、
日々の活動内容の改善を目指す

マインドマップを描いているうちにわかったこと

  • 内容を俯瞰してみられる
  • 自分の考える癖が見える
  • 考えられることが増える

マインドマップからテストケースに落としてみてわかったこと

マインドマップを描いてみる

描いてみましょう!ということで、以下のお題でマインドマップを描いてみることになりました。

■お題

数取器( 数取器|ブラウザ・スマホですぐ使えるWEBアプリ
使い方
「+」ボタン:クリックする度に数字が+1される
「-」ボタン:クリックする度に数字が-1される
「Clear」ボタン:クリックすると数字が0にもどる

■作成時間:10分

参加者のみなさんがもくもくと書き進めて行くなか、私はいきなりつまずきました。

・・・なにをかいていいかわからない!

テーマはもちろん「数取器」です。
しかしその先に伸ばすべきメインブランチに何を書けばいいかわかりません。
前述のとおり、私はテスト分析も設計も、テストケース作成の経験もありません。
メインブランチにはなにをかくべき?ボタン?品質特性?技法の名前??なにが正解なんだ???
完全に、パニックです。
ですが、さすがに何も描かないのは良くないので、とりあえずメインブランチをボタンにして書いてみました。

そうなるまでのあべの頭の中の流れは、
品質特性では書ける気がしない。。
→「表示」「機能」みたいな要素でも多分うまくまとめられないな〜
→とりあえずボタンごとにどんなテストがしたいか書き出してみよう!
という感じでした。

それがこちら↓ f:id:glpgsinc:20180517150925j:plain 最初の5分くらいは完全にパニックになっていたので、ブランチもかなり少ないしまとまっていません(笑)

マインドマップを共有する

各自で書いた後、周りの人と各々のマインドマップを共有しました。
そのとき、参加者の方の意見で「なるほど!」と思ったのは、

  • 「+」ボタンの表示範囲が大きかった→ボタンのどこでも反応する?
  • 「-」ボタンを押し続けるとマイナスになるのか
  • 更新をかけたときは値がリセットされるのか
  • ボタンを長押しするとどうなるのか

またメインブランチも、私のようにボタンだったり、「機能」「表示」などの要素だったり、人によってかなり違いがありました。

マインドマップをテストに使うコツ

作成→共有後、とののさんマインドマップをテストに使うときに、感じたこと、それを解決するコツを紹介してくださいました。

■メインブランチを出すのが難しい
  • メインブランチをいろんな方法で出してみる。
    メインブランチの出し方
    • 品質特性
    • 利用者の立場:実装/ユーザー
    • 意地悪漢字
    • 業種/職種/経験
    • モデルを基に発想:入力>変換>出力
■ブランチを広げるのが難しい
  • 気にしすぎないで思いついたことはどんどん描く(階層/構造/見た目/内容...)
  • ブランチのそばにメモを書く
■「手描き」自体難しい(後でメインブランチを入れ替えたくなる/書ききれない)
  • ツールをつかってみる (WEB/アプリ/付箋)
  • 描ききれないところはメインブランチごと別紙へ

まとめ

  • マインドマップを書くのにはコツがいる
    メインブランチの出し方、マインドマップ全体の整理の仕方
  • 始めやすい、楽しくできる
  • 繰り返し描くうちに、マインドマップの使い方自体上手くなる、慣れてくる
  • テスト観点が多くげられるようになってくる
    描きながらどう整理するか、考える順番をどうするか
  • 視覚的にまとまるので、他人と共有しやすい 共有することで、別の考えも取り入れられる

感想など

  • はじめやすい
    マインドマップを描いたことがなくても、なんとかそれっぽい形に描くことができました。
    必要なのは紙とペンだけなので、思いついたときにすぐはじめられていいなと思いました。
  • 活用できそう
    ソフトウェアテストの分析以外にも、自己分析や旅の計画など、いろいろなことに活用できそうだなと思いました。
  • 自分がどんなふうに考えているかわかる
    頭のなかでぐるぐる考えるより、自分がどんな順番で考えてるかが目に見えてわかると、自分の考え方や癖(とののさんも仰っていましたね)が見えてくる感じがありました。自分の考え方の良いところ、悪いところを直すきっかけにもなりそうです。
  • 知識がある程度必要
    これはマインドマップを使わない場合でも当然なのですが、ソフトウェアテストの知識はある程度必要だなと感じました。知識がないと、今回の私のように、前に進めないままパニックということになりかねません。 ソフトウェアテスト以外でマインドマップを使うときも、テーマについてはある程度知っておいたほうがいいなと感じました。

さいごに

マインドマップ」とはなにか、テスト分析に使うとどうなるのか、を学ぶことができました。
今回の勉強会をきっかけに、マインドマップについて、テスト分析についてを学びます! ゆくゆくはマインドマップを使ってテスト分析できるよう頑張ります(^^)

ここまで読んでいただき、ありがとうございました!

文豪さんの後編をお楽しみに!

ところで

ガラパゴスではエンジニアを募集しています。興味を持たれた方はぜひ弊社の採用ページをご覧ください。

www.glpgs.com