Jackson:JSONとJavaの変換にとどまらない多彩な機能

Jackson は、完成度の高い多機能なオープンソースプロジェクトで、Indeed でも利用やサポート、コントリビューションを行っています。2回に渡るこの連載では、Jacksonの作者であり主任メンテナーを務める私が、Jacksonの主力機能や拡張機能、課題についてご紹介します。

Photo of Cape Flattery by Tatu Saloranta, Jackson's creator

  フラッタリー岬(撮影:Tatu Saloranta)

Jacksonの主力機能

JSONを読み取ったり返したりするWebサービスをJavaで開発する場合には、JavaオブジェクトとJSONを相互に変換するためのライブラリが必要です。この機能は、Javaの標準ライブラリ(JDK)にはありませんが、JacksonライブラリのJavaオブジェクトをJSONとして書き込み、JSONをJavaオブジェクトとして読み取る主力機能を使えます。記事の後半で、Jacksonのその他の機能についても紹介します。

Java JSONライブラリとしてのJacksonには、以下の特長があります。

  • 多機能
  • 設定を柔軟に変更でき、パフォーマンスが高い
  • 完成度と信頼性が高い(このプロジェクトの開始は13年前の2007年
  • 幅広く利用され、信頼されている

JacksonはMaven Centralから毎月2,500万回ダウンロードされており、16,000件のプロジェクトjackson-databindが使用されています。Core Infrastructure Initiativeの調査結果によると、JacksonはGuavaの次に広く利用されているJavaライブラリです。

Jacksonは直接使うこともできますが、今どきのユーザーは、Jackson機能が使われているライブラリやフレームワークを使うことの方が多いでしょう。こうしたライブラリやフレームワークでは、デフォルトでJSONのやり取りにJacksonを使用して、JSONのリクエストやレスポンスを処理したり、JSON設定ファイルをJavaオブジェクトとして使用します。

以下にいくつか例を挙げます。

これらのフレームワーク、ライブラリ、クライアントを使用しているユーザーは、自分がJacksonを使っていることに気づいていない場合もあります。この事実が分かるのはたいてい、使用上の問題のトラブルシューティングをするときや、デフォルトの処理を変更するときです。

Jacksonの使用例

以下の例は、Spring Boot フレームワークで要求/応答モデルのアノテーションを記述する方法を示しています。

// Model of updated and accessed content
public class User {
  private Long id;
  private String name;
  @JsonProperty(“dob”) // customize name used in JSON
  private LocalDate dateOfBirth;
  private LocalDateTime lastLogin;
  // plus public Getters, Setters
}

// Service endpoint definition
@RestController
@RequestMapping("/users")
public class UserController {
  // ...
  @GetMapping("/{id}")
  public User findUserById(@PathVariable Long id) {
    return userStorage.findUserById(id);
  }
  @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
  @ResponseStatus(HttpStatus.CREATED)
  public Long createUser(@RequestBody User user) {
    return userStorage.createUser(user);
  }
}

この例では、Spring BootフレームワークはJSONをUserクラスのインスタンスとして読み取ります。POSTメソッドでは、Userインスタンスをストレージハンドラーに引き渡します。さらに、この例は指定されたIDのUserインスタンスをストレージハンドラーによって取り出し、そのインスタンスのシリアライズされたJSONを書き込みます。詳しい説明は、「Jackson JSON Request and Response Mapping in Spring Boot」を参照してください。

JSONの読み書きは、以下のようにJackson APIによって直接行うこともでき、この場合はフレームワークもライブラリも不要です。

final ObjectMapper mapper = new ObjectMapper();
// Read JSON as a Java object:
User user;
try (final InputStream in = requestContext.getInputStream()) {
  user = mapper.readValue(in, User.class);
}
// Write a Java object as JSON
try (final OutputStream out = requestContext.getOutputStream()) {
  mapper.writeValue(out, user);
}

Jacksonの機能はJSONとJavaの変換だけではない

Jacksonの主力機能は、当初はJSONをJava対応にすることでしたが、モジュールによって急速に拡張されました。モジュールは、Jacksonのコアにプラグ可能な拡張コンポーネントで、コアがデフォルトでは取り扱わない機能に対応しています。Jacksonにはその他のJVM言語用の拡張もあります。

特に便利なJacksonモジュールと拡張のタイプをいくつか挙げます。

  • データフォーマットモジュール
  • データ型モジュール
  • Kotlin、Scala、Clojure用モジュール

データフォーマットモジュール

データフォーマットモジュールを使えば、JSON以外のフォーマットでエンコードされたコンテンツを読み書きできます。JSONの低レイヤーのエンコードに関する詳細はYAML、CSV、Protobufとは異なりますが、より高レイヤーのデータバインド機能は、似ているか同一です。高レイヤーのデータバインドは、Javaオブジェクトの構造を処理して、トークンストリームとして表現します(または、それと同じような抽象化を行います)。

Jacksonのコアのコードはフォーマットに依存しないものが大部分で、JSONフォーマットに固有の部分はごくわずかです。このため、このようなデータフォーマットモジュールによってJacksonを簡単に拡張して、ほかのデータフォーマットのコンテンツを読み書きできるようになります。これらのモジュールは、低レイヤーのストリーミングをJackson APIから実装しますが、Javaオブジェクトとコンテンツを互いに変換する際には、共通のデータバインド機能を使います。

これらのモジュールの実装を見てみると、ストリーミングパーサーとジェネレーター用のfactoryがあるのが分かります。これらのパーサーとジェネレーターは、特定のファクトリを使用してフォーマット特有の詳細を処理するObjectMapperを構成します。一方、ユーザーがやり取りする対象はフォーマットにほとんど依存しない、マッパーによって抽象化されたものだけです。

Jacksonに最初に追加されたデータフォーマットモジュールは、XML用の jackson-dataformat-xml です。現在サポートされるデータフォーマットには、以下のものがあります。

データフォーマットモジュールの使い方は、Jackson API JSONの使い方と似ていて、JsonMapper(または汎用のObjectMapper)を、XmlMapperなどのフォーマット別のマッパーに置き換えるだけです。フォーマットに固有の機能が存在し、これらを有効にするか無効にするかはユーザーが設定できます。また、データフォーマットによっては、コンテンツをJSONライクなトークン表現にマッピングするために追加のスキーマ情報が必要なものがありますが(Avro、CSV、Protobufなど)、APIの使い方はすべてのフォーマットで同様です。

先ほど紹介した、単純にJSONの読み書きを行う例を比較対象として、その他のデータフォーマットの読み書きを行う例を示します。

// XML usage is almost identical except it uses a different mapper object
ObjectMapper xmlMapper = new XmlMapper();
String doc = xmlMapper.writeValueAsString(user);
User user = xmlMapper.readValue(doc, User.class);

// YAML usage is almost identical except it uses a different mapper object
ObjectMapper yamlMapper = new YAMLMapper();
byte[] asBytes = yamlMapper.writeValueAsString(user);
User user2 = yamlMapper.readValue(asBytes, User.class);

// CSV requires Schema for most operations (to convert between property
// names and column positions)
// You can compose the schema manually or generate it from POJO.
CsvMapper csvMapper = new CsvMapper();
CsvSchema userSchema = csvMapper.schemaFor(User.class);
String csvDoc = csvMapper.writer(schema)
.writeValueAsString(user);
User user3 = csvMapper.readerFor(User.class)
.with(schema)
.readValue(csvDoc);

データ型モジュール

Jacksonのコアでは、Plain Old Java Object(POJO)と、ほとんどの標準JDKデータ型(文字列、数値、ブール、配列、コレクション、マップ、日付、カレンダー、URL、UUID)の読み書きが可能です。一方、Javaプロジェクトの多くは、Guava, Hibernate, Jodaなどのサードパーティライブラリによって定義される値型も使用します。これらの値型のインスタンスを単純なPOJOとして扱うと、特にコレクション型の場合にはうまく動作しません。明示的にサポートされていない限り、シリアライザやデシリアライザなどのハンドラーをユーザーが独自に実装してJacksonの機能を拡張する必要があります。Jacksonのコアにこのような明示的サポートを追加することは、最も一般的なJavaライブラリに対象を絞ったとしても大変な仕事で、難しい依存関係につながる可能性もあります。

この課題を解決するために、Jacksonにはデータ型モジュールという概念が付け加えられました。これらは、コアのJacksonとは別にビルドされてパッケージ化される拡張で、構築時にObjectMapperインスタンスに追加されます。データ型モジュールのリリースは、Jacksonチームと外部コントリビューター(サードパーティライブラリの作成者など)のどちらもが行います。これらのモジュールが追加される理由としてよくあるのは、作成者が特定のユースケースを解決する必要があって、その努力の成果をほかの技術者たちと共有するためです。

これらのモジュールはプラグ可能なので、異なるフォーマットのデータ型モジュールを使用でき、異なる値型を混合することも可能です。たとえば、Jodaで定義されたPeriodの値を含む、Hibernateに基づくGuava ImmutableListをJSON、CSV、またはXMLのフォーマットで読み書きできます。

データ型モジュールのリストはJackson Portalからご覧ください。以下にその一部をご紹介します。

データ型モジュールの実装のほかに、Jacksonデータ型モジュールの使用を直接サポートするフレームワークも多くあります。特に、以下のような各種の「イミュータブル」なライブラリがこのサポートを提供します。

Kotlin、Scala、Clojure用モジュール

Jacksonを使う場合に、ほかのJVM言語でPOJOとJDK型しか使えなくなることはありません。Jacksonには、ほかの多数のJVM言語でカスタム型を扱うための拡張が用意されています。

以下のJacksonモジュールがKotlinとScalaをサポートしています。

  • Jackson-module-kotlinは、Kotlin Dataクラス、Range、Pair、Triple、および一般的なKotlinスタイルの使用をサポートします。
  • Jackson-module-scalaは、Scala Caseクラス、Option、Either、Seq、およびScalaコレクション型をサポートします。

また、Clojureについては、同様なサポートを実装するためにJacksonを内部で使用するライブラリが、以下のようにいくつか存在します。

これによって相互運用がさらに簡素化され、Javaの機能をKotlin、Scala、Clojureから使用したり、逆にこれらをJavaから使用したりすることがもっと簡単になります。

次回予告

次回の記事では、Jacksonプロジェクトが今直面している課題と、その解決に皆さんがコントリビュートする方法についてお話しする予定です。


筆者紹介

Tatu Salorantaは、Indeed のスタッフソフトウェアエンジニアで、次世代の継続的デプロイメントシステムを統合するチームを率いています。Indeed の社外では、オープンソース分野での活動で広く知られる存在であり、@cowtowncoderのハンドルで、Jackson、Woodstox、lzf圧縮コーデック、Java ClassMateなど、多くの人気のあるオープンソースJavaライブラリを生み出しています。詳しい一覧についてはFasterXML Orgをご覧ください。


 

コードを書きたいエンジニアリングマネージャーにおすすめの 「ユニコーン」プロジェクトとは

エンジニアリングマネージャーがコードを書くことは、矛盾する2つのことを求められる訓練に近いでしょう。

マネージャーになりたての皆さんは、恐らくこれまでは専門職、いわゆる Individual Contributor (IC) として、コードの質や量の成果によって評価されてきたのではないでしょうか。マネージャーの成果はこれまでとは違う指標で評価されるため、日々の仕事も大きく変化します。マネージャーがコーディングするなんて無駄だと言ってくるメンターがいる一方で、コードを書き続けていないと技術が錆びつくリスクがあると言う人もいます。また、エンジニアリングマネージャーが IC の仕事を行うことを企業文化として奨励し、昇進の基準として明文化している企業もありますが、逆にこれがペナルティとなる企業もあります。どっちつかずでストレスのもとですね !

私の場合、管理職になってからは、頻度に差はあるものの、IC の仕事を基本的に四半期に1回はやり遂げるようにしています。この記事では、エンジニアリングマネージャー1としてコーディングする際の課題や利点、対象範囲が絞り込まれた手掛けやすいユニコーンプロジェクト (希少な、幻の意味から理想的なプロジェクトを指す)の見つけ方など、これまでに私が学んだことをご紹介します。

Unicorn

SVG SILH Ruby star rainbow sparkle

チーム (Team) に「I (自分)」はなくても、ユニコーン (Unicorn) には「U (あなた)」と「IC」の両方がある。ただの私のつぶやきにすぎませんが。

マネージャーがコードを書くことの大変さ

エンジニアリングマネージャーが IC の仕事を行う上での課題は、幅広いトピックへの対応と優先順位付けです。

管理職には幅広いトピックに対応する能力が求められます。人員計画の戦略のアイデア出しの会議に出ているかと思えば、同僚からの厳しいフィードバックを受け止め、はたまたカンバン形式の会議の進行役を務めたり。一方で、コーディングには数時間にわたって邪魔されずに作業 (ディープワーク) できる環境が必要です。会議の合間の30分でコードを書こうとしたことのある人には、こんな状況になることをわかってもらえるはずです。

[code language="python"]import numpy as np
import pandas as pd
# pull data here
If n in list(TODO):
# look this up, used to know how to do this[code]

リーダーとして優先順位の高い仕事はチームメンバーのサポートでしょう。キャリア面談やフィードバックのほか、創造性が高く大きなインパクトを残せるような仕事ができるようにチームをサポートすることなどが業務に含まれます。面談方式で実施することも多いですが、フォローアップ会議や関係者とのチェックインなどの時間も必要です。チームの人数が増えてくると、小さなプロジェクトのコーディングを完成するのに必要なたった数時間でさえ確保するのが難しくなり、週40時間の勤務時間では足りなくなってきます。 

コーディングの時間を確保すべき理由2

1つ目のメリットは、IC プロジェクトのコーディングをすることによって、チームメンバーや、彼らが業務で使用しているツール、抱えている課題などに共感できるようになる点です。具体的に言うと、メンバーの1人と一緒にプロジェクトの作業をしたのですが、それによって、Indeed のいくつかのサービスとその課題について直に学ぶことができました。その結果、後日行われた会議では、以前より具体的な内容を自信を持って話すことができました。メンテナンスチームに要望を提出したことで、アップデートの優先順位を上げてもらうことができ、自分のチームに大きなメリットがありました。 

次に、コーディング (数週間ぶりだったり数か月ぶりだったりしますが) をすることで、チームメンバーに助けを求める必要に迫られます。先日、私はデータラングリングで for 文のネストが1重や2重で終わらず、3重になってしまった問題を解決しようとしていました。それを見たチームメンバーが Big O Notation (ビッグ・オー記法) に「OH NO」があるからだと冗談を飛ばしたりしていましたが、私が皆に素直に助けを求めると、チーム内で協力して、コードの複雑さを解消できました (し、大いに笑いました)。私の経験上、人は誰かの役に立ちたいと思っていますし、悪戦苦闘している上司を助けられるという状況には特別なものがあります。マネージャーとしては、チームメンバーには困った時には周囲に助けを求められるようになってほしいと思います。リーダー自身が弱みを見せて助けを求めることも、チームメンバーに対するお手本となるでしょう。

最後は、コードを書き上げることで気分が上がるという利点で、これはマネージャーのメンタルヘルスにとって一番大切なことです。管理職の仕事は、完了できたという達成感につながりにくく、自己不信に陥ることも多いものです。IC の仕事は単体で成果がわかりやすいことが多いので、自分の手で何かを作り、「見て ! あれは私が作ったんです。悪くないでしょう ?」と胸を張って言うことで達成感を得ることができます。

マネージャーのコーディング作法

大まかに言うと、マネージャーとして IC の仕事をすることは、次のような点に気をつけるということです。 

  1. チーム内で緊急事態が起きていないことを確認する
  2. 明確でシンプルなユニコーンプロジェクトを見つける
  3. ディープワークの時間を確保する  
  4. 引き継ぎを念頭に置いて着手する 

これから、一つずつ具体的に説明します。 

チーム内で緊急事態が起きていないことを確認する

緊急案件に苦戦しているチームメンバーをよそにコーディングすることは、ローマの大火を眺めながらヴァイオリンを奏でていたという皇帝ネロと同じくらい危機管理に問題があるだけでなく、チームのサポートというマネージャーの重要な役目を果たしていないということにもなります。IC プロジェクトの作業範囲について考える前に、チーム内の物事が比較的落ち着いていることを確認しましょう。 

明確でシンプルなユニコーンプロジェクトを見つける

プロジェクトを適切な作業範囲で引き受けていたら起こらなかった失敗例を挙げてみます。

一度、新しいプロダクトのチームを手伝おうと張り切って、その四半期末までに開始したい A/B テストをいくつか引き受けたことがありました。その A/B テスト自体は問題なく管理できるシンプルなものでしたが、管理職の業務が忙しくなってきた時に状況は一変しました。そのうち Product Manager が尻拭いをする羽目になり、最後には、マネージャーと私は A/B テストを他の人に任せて完了してもらいました。PM を失望させることになり、落ち込みました。 

逆に、マネージャーにとって理想的な IC プロジェクトとは以下の通りです。 

  • 時間的制約が厳しくない 
  • 規模がかなり小さい
  • 依存関係がない 
  • 「あれば助かる」、つまりチームが優先順位を上げる必要があるほど重要ではないが、クオリティ・オブ・ライフ (QOL) が向上してよい影響をもたらす可能性がある
  • 自分の強みを活かせる 

つまりそれがユニコーンです。ユニコーンプロジェクトは常に存在するとは限りませんが、そもそも何を探すべきなのかをわかっていなければ、見つかりません。 

例えば、数年前にデザイン上の問題に対処していた時のことですが、UX のチームメンバー達が、「Y クエリに対する X が常に分かるわけじゃない。それが可能になるツールがあれば便利だね。」と話していました。求められているツールはかなり小さかったので、数時間で手際よく Ishbook を構築したのですが、いまだにサイトでユーザー行動を理解するツールとして利用されています。 

このようなユニコーンプロジェクトを見つけることで、チームも恩恵を受けることができます。 

また、IC プロジェクトは自分の強みを活かせるものであることも重要です。しばらく使っていないとコーディングスキルは落ちてしまい、以前よりコードを書くのが遅くなるため、ただでさえ落ち込んでしまいがちです。その結果、IC の仕事へのやる気を維持しにくくなり、このブログ記事と私自身も、皆さんのお役に立てなくなってしまいます。

アンケートや測定バイアスの分析、A/B テストのサポート、うまく設計したグラフの構築などが、私が通常行っている IC プロジェクトです。なぜそれらをやっているかというと、こういったことが好きで、得意な分野でもあり、気持ちも上がるからです。皆さんも、私と同じように感じられる IC プロジェクトを選べば、短時間でより質の高い成果物を生み出すことができるでしょう。 

ディープワークの時間を確保する

30分ずつ細切れの時間を使ったとしても、有意義なディープワークにはつながらないことが多いものです。私はマネージャーになってから毎週、午前中の数時間を押さえてディープワークに充て、コードを書いたり、専門分野の最新情報を読んだりしています。習慣づけておくことで、皆私が集中して作業にあたっている時間に予定を入れる前にメッセージをくれるようになりました。もちろんどうしても出席しなければならない会議も時にはありますが、コーディングのピーク時間はなるべく会議を避けるようにしています。ディープワークのために押さえた時間帯の会議依頼は自動的に欠席にしてくれるというGoogle カレンダーの新しい不在機能が追加されたので、さらに積極的にこの習慣を実行しています。 

私もディープワークを優先できない週もあれば、いつもより時間がとれる週もあります。毎週 IC の仕事に時間がとれないことに自分を責めるマネージャーを見てきましたが、やめましょう。それは現実的な目標ではありません。Ben Edmunds はマネージャーのコーディングについて著書の中でこう解説しています。「自分にとっての成功の形を再定義してみましょう。(中略) 毎日のタスクは動かせないものではないことを理解し、マネージャーとして流動的になる必要があります」。私もその通りだと思います。 

引き継ぎを念頭に置いて着手する

マネージャーのコーディングは皿回しのようなもので、管理職としてのさまざまな業務を素早くこなしつつ、同時進行で行っていく必要があります。プロジェクトのコーディングだけに時間を湯水のように使えるわけではないため、何を作ったとしても、プロトタイプのような物になってしまうことは避けられないかもしれません。マネージャーとして IC プロジェクトのコードを書く場合には、その後を他人に任せられるミニマル・バイアブル・プロダクト (MVP) とはどんなものかを具体的に頭に描いておきます。ヒント: 適切なコメントがあるコードとペアプログラミング。この MVP を最終目標に掲げておきましょう。  

マネージャーになってから作ったもののひとつに、Indeed の求人検索プロダクトで多変量 A/B テストをより厳密に実施できるツールがあります。質が良くないことはわかっていましたが (なんと、Google スプレッドシートからデータを取り込む仕様)、チームが必要としていた作業は可能であり、何もないよりはましだったのです。その後、このツールをチームメンバーに引き継ぐことができました。 

これは2つのよい結果をもたらしたと思っています。まず、自分のチームメンバーが私の専門知識から学ぶ機会を作れたことです。彼女は、多変量 A/B テストの統計的有意性の評価について、理解を深めることができました。2つ目に、彼女は私が作ったツールを元にしつつ、ずっと優れたものに仕上げました。私のプロトタイプはフォントが Comic Sans でしたが、彼女のバージョンではご覧のとおり美しくて理解しやすいグラフがあり、厳密に統計的アプローチが取られています。彼女のツールの V.1 は素晴らしい出来のプロジェクトであり、今でも活用されています。

まとめ

エンジニアリングマネージャーがコードを書くべきかどうかについては相反する意見が溢れていますが、コーディングをすることで共感が生まれ、チームメンバーとの信頼が築けるので、結果としてより仕事のできるリーダーになれるのは間違いないでしょう。専門職時代と同種類のプロジェクトを引き受けたり、会議の合間にコーディングを詰め込もうとしたりすると失敗への道に突き進んでしまうので、手掛けるコードの種類は大枠から見直しましょう。また、ディープワークに集中する時間を捻出することが大切です。そして、小規模で、緊急度が低く、引き継ぎが可能なユニコーンプロジェクトを探し、自分の強みを生かしてチームに価値をもたらしましょう。 


注釈

  1. ここで言う「エンジニアリング」とは、ソフトウェアエンジニアだけを指しているのではなく、データサイエンティストや QA をはじめとした、IC の仕事がコーディングにある程度関わる職種も含みます。(トップに戻る)
  2. エンジニアリングマネージメントの分野はまだ始まったばかりで、これをテーマにした書籍は最近までほとんど出版されていないと思います。本記事で引用したエビデンスの多くは個人の経験に基づくものであり、強みや経験は人それぞれだと思います。例えば、マネージャーとしてコーディングすることについて、「逆境を生き抜く力」を持つ助けになるという仮説を聞いたことがあります。しかし、私は最近 Git リポジトリで職場で恥をかくようなことをやってしまったばかりで、コーディングすることで本当にそのようなスキルが身に付いたかどうかは正直分かりません。そのため、この記事ではその部分は割愛しました。ただ、他のマネージャーの経験には興味があります。ソフトウェアエンジニアリングやデータサイエンスの分野で IC の仕事をする利点や欠点についてのデータを、質と量ともにさらに徹底的に集め、実証的に考えてみたいと思っています。興味のある方はぜひ私にご連絡ください。いくつかアイデアを温めています。(トップに戻る)

インクルーシブなコードを目指して

Indeed のインクルージョン施策は、従業員間の支援グループや推進イベントに留まりません。背景、経験、思想のダイバーシティが従業員の能力向上や成長を引き出し、より効果的な意思決定を可能にし、パワフルなイノベーションを生み出します。Indeed ではインクルージョンを推進するため事業のあらゆる階層と部門で心理的に安全な環境づくりを目指しており、その一環としてインクルーシブではない用語を社内のコードベースから無くしていくことにしました。

Image of five Indeed inclusion group members smiling and wearing shirts labeled "Women at Indeed" in a relaxed office setting

事業の成功にダイバーシティとインクルージョンは欠かせません。従業員のインクルージョン支援グループ「Women at Indeed」アムステルダム支部のリーダーたち。 (左から): Edwin Moses、Trudy Danso-Osei、Freek van Schaik、Renske van der Linden、Valerie Sampimon 

技術用語のインクルージョンへの対応

どのような言葉にも、コノテーション (元の意味以外に暗示される意味) により表現の幅が広がりますが、技術用語も例外ではありません。本来の意味以外のには、広く知られ、意味が理解されているものもありますが、文脈によって異なったり、個人の実体験の違いによって理解に差がある場合もあります。また長年にわたって用語に蓄積されたコノテーションとその語源との関係がほとんどなくなってしまう場合も少なくありません。

コンピューターサイエンスやソフトウェアエンジニアリングでは、便利で使い勝手がよく、意味をよくとらえた用語が数多く使われていますが、一部の人々に対して、その言葉の言外に含まれるネガティブで排他的な意味合いを無視して使用するように強いている場合もあります。

「master (マスター、主人)」と「slave (スレーブ、奴隷)」がその代表例でしょう。そこから「slave は master の制御に従って動作する従属的プロセスである」というコノテーションとして悪気なく解釈して使っているエンジニアもいますが、多くの人、特に有色人種にとっては、それは恐ろしい奴隷制度のイメージと直結した用語です。このコノテーションは、米国の奴隷制度のように一国の歴史にだけ存在するわけではありません。現代でも世界中で2,100~4,500万人の人々が現代の奴隷制の被害にあっていると推計されており、master と slave は過去の歴史というだけでなく、現代の世界的な人道危機をも表す用語です。

この他にもネガティブなコノテーションを持つ用語はたくさんあります。「blacklist (ブラックリスト)」のように色と価値判断を関連付けた用語、「tribal knowledge (部族の知識)」のように文化を搾取し蔑むような性質のある言葉がその一例でしょう。障がい者に対する差別用語にあたる「lame (レイム、足が不自由)」や「blind (ブラインド、盲目)」が誤った文脈で使用されると、障がいを持つ人にネガティブな影響をもたらしかねません。社会にはそういった特徴に基づいた偏見や先入観との絶え間ない戦いがあります。

実際に疎外された経験のある立場でなければ、挙げられた例のいくつかに驚くかもしれません。それでももし、同僚から、自分を排除したり傷つけたりする言葉が周りで飛び交っている状況だと言われたなら、当事者の立場に立って新しい用語を探すべきです。

話し合いをはじめる

Indeed では、インクルージョンと帰属意識をコアバリューの一部として2019年に正式に導入していますが、それ以前から、社内のエンジニアは問題のある用語を私たちのテクノロジーから取り除く活動を始めていました。

まずは排他的な用語を特定し、批判的な観点から見るため、社内の Wiki やブログ、専用のコンテンツハブでの議論を始めました。エンジニアなら誰でも Inclusive Terminology の Wiki ページに参加して意見を出せるようにし、集められた意見をもとに、従業員が用語についての責任ある決定ができるように、簡易版のクイックリファレンスガイドを作成しました。

Instead of Use Why
master* primary, main, trunk この2つは、抑圧的な関係性を表す特徴を持つ用語です。

*「slave」と一緒に使わずに、一般的な表現としてこの用語を使ったとしても、抑圧的な関係性の意味合いはなくなりません。過去の経緯から、Git ブランチでの「master」の使い方は、主人と奴隷の関係から生まれているからです

slave replica, secondary
whitelist allowlist, unblocklist この2つは善と悪という、文化に根ざした二項対立を示唆しています。
blacklist denylist, blocklist, banned
backlog grooming backlog refinement イギリス英語で「grooming (グルーミング)」は特定の法的な意味と共起します。
tribal knowledge institutional knowledge 「tribe (部族)」は物議を醸す用語で、先住民やアフリカ系のコミュニティに対するネガティブなコノテーションがあります。
grandfathered legacy, pre-existing 「grandfather clauses (祖父条項)」は、米国のジム・クロウ時代の差別的な法律に由来します。

エンジニアチームはコードに新しい言葉の導入方法を決めました。次にベストプラクティスやプロセスを共有しました。社内では、今でも話し合いを続けています。

ケーススタディ: Git プロジェクトで「master」を「primary」にリネームする

Git プロジェクトの master ブランチのリネームは片手間にできる作業ではありません。履歴が長いプロジェクトならなおさらです。先日、Indeed の Design Systems というチームが、この作業をチームのプロジェクトとして完了しました。作業工程は以下の通りです。

  1. master ブランチのクローンを作成し、そのクローンに「primary」という名前を付ける。
  2. GitLab のデフォルトブランチを「master」から「primary」にアップデートする。
  3. master ブランチをロックダウンする。記録の目的で残しますが、今後使用することはできません。
  4. 作成した primary ブランチに master ブランチの設定を適用する。

このシナリオでは、いくつか問題が発生する可能性があります。たとえば上記作業で primary ブランチを作成する前に、別のユーザーが master ブランチから新規のブランチを分岐させてしまうことが考えられます。また primary と master は同じ履歴を共有するため、ユーザーはその機能を primary にマージすることが理論的に可能です。そういった問題のリスクを緩和するため、リネーム作業中はコードフリーズを実施しました。さらにメインのプロジェクトのリネームを行う前に、比較的小規模のプロジェクトで作業工程をテストしています。

具体的な成果

この作業をトラッキングするにあたり、Indeed ではソフトウェア開発のトラッキングツールとして Atlassian の Jira を活用しました。フィルターとソートができるよう、インクルージョンの対象用語を含む Jira のチケットにラベルを追加することで、排他的な用語が存在する領域や、その用語を取り除く現在進行中の作業と進捗を俯瞰することを可能にしました。これまで113件中97件をクローズし、現在も作業を続けています。

Pie graph showing the number of Jira issues labeled "inclusive-terminology" by status, with 97 closed, 1 deferred, 9 on backlog, 1 pending review, 2 pending triage, and 3 in wish list status.

「inclusive-terminology」のラベルがついた Jira のステータス別件数

実現に至るまでの課題

この作業の過程において、エンジニア間で活発な議論が行われました。Indeed としては、この用語変更を、批判的であったり屈辱を与えるようなプロセスにだけはしないことを念頭に置き、トップダウンで強制するのではなく、草の根で進めて行くことにしました。これにより全員が敬意を持って用語変更の議論ができるようになり、その過程で互いに学び合うことにもつながりました。リーダーシップ側は必要に応じて支援したり方向性を示し、積極的に対話に関わっています。

議論の中で挙がった議題の中に、作業のコストと水準がありました。プロダクトの用語変更は徹底的に実施すると長期のプロジェクトになり、エンジニアの作業時間もかかります。実際に現時点でコードベースから「slave」という用語についてあと5,000件以上のインスタンスを削除しなければなりませんが、Indeed は、この作業をやり遂げていきます。この取り組みによって、排他的用語の削除にかかった時間と労力を上回る、心理的安全性がもたらされるでしょう。

未来に向けて

言語は使う人間の必要性に合わせて絶えず進化しており、使っていくうちに時代遅れにもなるでしょう。そういった意味で、コードベースの用語変更は1回限りの作業ではなく、継続していく活動であると Indeed は考えています。

私たちは今後も置換すべき用語を記録し、適切な代替用語を提案していきます。社内では新規のコードでそのような不適切な用語を使わないようにし、ベンダー各社にも自社プロダクトでの使用を避けるように協力をお願いしています。また、コードベースの変更に際しては、手順を守り、細心の注意を払って既存の用語の特定と置換を実施しています。

やらなければならないことはまだあります。Indeed では、常に排他的な用語とそうした言葉が示唆する事柄に対して意識を高めており、従業員間でこの話題について敬意を持って対話に取り組んでいます。皆で協力し、あらゆる人にとっての心理的安全性が確保され、インクルーシブで歓迎されている気持ちになれる職場づくりを目指しています。そして一連の活動を周知していくことで、Indeed がインクルージョンのモデル企業となり、テクノロジー業界全体の改善にもつながることを願っています。