Jackson: More than JSON for Java

Jackson is a mature and feature-rich open source project that we use, support, and contribute to here at Indeed. As Jackson’s creator and primary maintainer, I want to highlight Jackson’s core competencies, extensions, and challenges in this two-part series.

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

   Photo of Cape Flattery by Tatu Saloranta

Jackson’s core competency

If you’re creating a web service in Java that reads or returns JSON, you need a library to convert Java objects into JSON and vice versa. Since this functionality is not available in the Java standard library (JDK), you can use the Jackson library for its core competency: writing Java objects as JSON and reading JSON as Java objects. Later in this post, I introduce Jackson’s additional features. 

As a Java JSON library, Jackson is:

Jackson is downloaded 25 million times per month via Maven Central, and 16,000 projects depend on jackson-databind. It’s the second most widely used Java library, after Guava, according to the Core Infrastructure Initiative’s census results.

You can use Jackson directly, but nowadays users are more likely to encounter its functionality exposed by libraries and frameworks. These libraries and frameworks use Jackson by default for JSON handling to expose JSON requests and responses; or JSON configuration files as Java objects.

Some examples are:

Users of these frameworks, libraries, and clients may not even be aware that they utilize Jackson. We are more likely to learn this when troubleshooting usage issues or making changes to default handling.

Examples of Jackson usage

The following example shows how to annotate request and response models in the Spring Boot framework.

// 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);
  }
}

In this example, the Spring Boot framework reads JSON as an instance of the User class. In the POST method, it passes a User instance to a storage handler. It also fetches the User instance via a storage handler for a given ID and writes serialized JSON of that instance. For a full explanation, see Jackson JSON Request and Response Mapping in Spring Boot.

You can also read and write JSON directly via the Jackson API, without any framework or library, as follows:

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 is more than JSON for Java

While Jackson’s core functionality originally started as JSON for Java, it quickly expanded through modules, which are pluggable extension components you can add to the Jackson core. These modules support features that the core does not handle by default. Jackson also has extensions for other JVM languages.

These are some of the types of Jackson modules and extensions that are especially helpful:

  • Data format modules
  • Data type modules
  • Modules for Kotlin, Scala, and Clojure

Data format modules

The data format modules allow you to read and write content that is encoded in formats other than JSON. The low-level encoding details of JSON differ from those of YAML, CSV, or Protobuf. However, much of the higher-level data-binding functionality is similar or identical. The higher-level data binding deals with the structure of Java Objects and expressing them as token streams (or a similar abstraction).

Most of the code in the Jackson core is format-independent and only a small part is truly JSON-format specific. So, these so-called data format modules can easily extend Jackson to read and write content in other data formats. The modules implement low-level streaming from the Jackson API, but they share common data-binding functionality when it comes to converting content to and from Java objects.

In the implementation of these modules, you find factories for streaming parsers and generators. They use a specific factory to construct an ObjectMapper that handles format-specific details, while you only interact with a (mostly) format-agnostic mapper abstraction.

The very first data format module added to Jackson is jackson-dataformat-xml for XML. Supported data formats now include:

The usage for data format modules is similar to the Jackson API JSON usage. You only need to change  JsonMapper (or the generic ObjectMapper) to a format-specific alternative like XmlMapper. There are format-specific features that you can enable and disable. Also, some data formats require additional schema information to map content into JSON-like token representation, such as Avro, CSV and Protobuf. But across all formats, the API usage is similar.

Examples

Compared to the previous example that simply reads and writes JSON, these are alternatives for reading and writing other data formats:

// 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);

Data type modules

Jackson core allows you to read and write Plain Old Java Objects (POJOs) and most standard JDK types (strings, numbers, booleans, arrays, collections, maps, date, calendar, URLs, and UUIDs). However, many Java projects also use value types defined by third-party libraries, such as Guava, Hibernate and Joda. It doesn’t work well if you handle instances of these value types as simple POJOs, especially collection types. Without explicit support, you would have to implement your own handlers as serializers and deserializers to extend Jackson functionality. It’s a huge undertaking to add such explicit support in Jackson core for even the most common Java libraries and could also lead to problematic dependencies.

To solve this challenge, Jackson added a concept called data type modules. These are extensions built and packaged separately from core Jackson and added to the ObjectMapper instance during construction. Data type modules are released by both the Jackson team and external contributors such as authors of third-party libraries. Authors usually add these modules because they want to solve a specific use case and then share the fruits of their labors with others.

Due to the pluggability of these modules, it is possible to use data type modules with different formats and to mix different value types. For example, you can read and write Hibernate-backed Guava ImmutableLists that contain Joda-defined Period values as JSON, CSV, or XML.

The list of known data type modules is long—see Jackson Portal. Here are some examples:

In addition to the data type module implementations, many frameworks also directly support Jackson data type module usage. In particular, various “immutable values” libraries offer such support, such as:

Modules for Kotlin, Scala, Clojure

If you’re using Jackson, you’re not limited to only using POJOs and JDK types with other JVM languages. Jackson has extensions to handle custom types of many other JVM languages.

The following Jackson modules support Kotlin and Scala.

And for Clojure, there are a few libraries that use Jackson under the hood to implement similar support, such as:

This simplifies interoperability further. It makes it easier to use Java functionality from Kotlin, Scala, Clojure, or vice versa.

What’s next

In my next post, I will share my observations on the challenges that the Jackson project faces and how you can contribute to help.


About the Author

Tatu Saloranta is a staff software engineer at Indeed. He leads the team that is integrating the next-generation continuous deployment system. Outside of Indeed, he is best known for his open source activities. Under the handle @cowtowncoder, he has authored many popular open source Java libraries, such as Jackson, Woodstox, lzf compression codec, and Java ClassMate. For a complete list see FasterXML Org.


Cross-posted on Medium.

Tweet about this on TwitterShare on FacebookShare on LinkedInShare on RedditEmail this to someone

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

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

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

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

Unicorn

SVG SILH Ruby star rainbow sparkle

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

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

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

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

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

リーダーとして優先順位の高い仕事はチームメンバーのサポートでしょう。キャリア面談やフィードバックのほか、創造性が高く大きなインパクトを残せるような仕事ができるようにチームをサポートすることなどが業務に含まれます。面談方式で実施することも多いですが、フォローアップ会議や関係者とのチェックインなどの時間も必要です。チームの人数が増えてくると、小さなプロジェクトのコーディングを完成するのに必要なたった数時間でさえ確保するのが難しくなり、週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 の仕事をする利点や欠点についてのデータを、質と量ともにさらに徹底的に集め、実証的に考えてみたいと思っています。興味のある方はぜひ私にご連絡ください。いくつかアイデアを温めています。(トップに戻る)
Tweet about this on TwitterShare on FacebookShare on LinkedInShare on RedditEmail this to someone

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

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 がインクルージョンのモデル企業となり、テクノロジー業界全体の改善にもつながることを願っています。

Tweet about this on TwitterShare on FacebookShare on LinkedInShare on RedditEmail this to someone