注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。
このガイドは、トランスフォームを開発するパイプライン開発者向けの指針を示すものです。全般の推奨事項は、適切なパイプライン全般に関する上位の原則に重点を置いているため、プロジェクトマネージャーやプラットフォーム管理者にも役立つ可能性があります。
パイプライン開発はソフトウェア開発です
一般的なソフトウェア開発のベストプラクティスの多くは、データパイプラインを構成するトランスフォームの定義にも同様に適用できます。以下に、このアプローチを具体的に示す一般的なプラクティスをいくつか紹介します。
snake_case で記述します。この規約に従えば、作成した優れたデータセットを参照したい人は、その名前が AwesomeDataset や Awesome_Dataset ではなく、awesome_dataset であるとわかります。SNAPSHOT トランザクションを書き込んで以前のトランザクションを上書きします。データセットを削除しようとすると、同じ場所に新しいデータセットを作成する場合よりも多くの問題が生じる可能性があります。Foundry は開発中のブランチで循環依存をチェックしますが、コードの記述中にすべてのブランチを横断してチェックすることはありません。たとえば、master ブランチにのみ存在するオントロジーのライトバックデータセットがある場合が該当します。ただし、フィーチャーブランチを循環依存が含まれるブランチにマージしようとした際に、ほかのブランチで循環依存が検出された場合も、Foundry のチェックに失敗します。
複数のプロジェクトを通じたデータの流れ全体を整理するための包括的なモデルについては、推奨されるプロジェクト構造を参照してください。
/Documentation フォルダーと /Output フォルダーを設けることを検討します。ユースケースやワークフローに応じたプロジェクトでは、より具体的な名前が必要になりますが、プロジェクト構造と命名規則が、プロジェクトを訪れる人の道しるべになることを常に意識してください。/scratch フォルダーを作り、実験や使い捨ての作業に使うことを検討します。dataset1、dataset2 など)や1文字だけの名前を選ぶと、コードを読み、リファクタリングすることが難しくなります。また、新たに参加する開発者が作業内容を理解することも、はるかに難しくなります。/raw/my_important_dataset と、その後の /clean/my_important_dataset がある場合など、許容できるケースもあります。ただし、多くの場合、この命名パターンは、データセット名自体だけが目立つように表示されるビューで混乱を招く可能性があります。来歴は追跡され、簡単に確認できるため、このような「状態」をデータセット名に埋め込む必要はないことを覚えておいてください。列のデータ型を明示的にキャストする: データソースプロジェクトで作業する場合は、Data Connection のスキーマ推論で正しい値が選択されていても、raw → clean トランスフォームで列のデータ型を明示的にキャストします。これにより、列のデータ型が変更された場合や、同期中に無効な値によって誤った推論が行われた場合に、ソースシステムの破壊的変更を検出しやすくなります。
「時刻のみ」のデータ型にはタイムスタンプを使用する: Spark には、「10:59:00」のような値を持つフィールド向けの、時刻のみを表すデータ型がありません。Spark のタイムスタンプ型に付属する時刻関数を活用するには、値を秒数にキャストしてから -2208988800 を加算し、その後タイムスタンプにキャストして0年の時刻にします。あるいは、文字列のままにして、ユーザーが必要に応じてパースできるようにします。
すべての数値フィールドを数値データ型にキャストする: 545、972、314 のような航空機IDの列を考えてみます。これらを Integer 型の列にキャストしたくなるかもしれません(整数のように見えますし、ソースシステムでも整数である可能性があります)。しかし、これには重大な欠点があります。
545.0、1,234、右揃え)。異なるタイムゾーンでタイムスタンプを保存する: — Spark のタイムスタンプはタイムゾーンに依存しません。内部では UTC(Zulu、GMT とも呼ばれます)で保存されており、タイムゾーンに応じた表示はフロントエンドで行うことが想定されています。
from_unixtime() 関数 ↗を使用して、適切なタイムゾーンの文字列を保存します。to_utc_timestamp() 関数 ↗を使用して UTC に正規化します。コミットでコードをコメントアウトする: 変更を加える際に、古いコードをコメントアウトして、参照用や後で元に戻す必要がある場合に備えて残しておきたくなるかもしれません。試行錯誤の間はコメントアウトを使用してもかまいませんが、文をコメントアウトしたままコードをコミットしないでください。不要なコードが蓄積し、可読性が低下します。古いコードは過去のコミットで簡単に見つけられます。
作成者の詳細や日付を含むコメント: これらはコミットや Git リポジトリで自動的に追跡されます。手動でコメントに記載すると、更新されないままになりやすく、不要な情報が蓄積します。
冗長すぎるコメント: コメントでは、ロジック自体を説明するのではなく、判断の根拠を伝えるべきです。「自己文書化」されたコードを書くように努めます。一連の文を理解するのが難しい場合は、リファクタリングして簡素化すべき明確な兆候です。
master ブランチを保護する: チームで開発している場合や、個人で長期間続くプロジェクトに取り組んでいる場合は、master ブランチを保護し、GitFlow ↗ または好みの開発ワークフローを実践します。重要なのは、master に取り込むコードがレビューされ、テストされていることを確実にすることです。
コミットメッセージを書く: コミットメッセージは、リポジトリ内のすべての活動の記録です。時間をかけて、変更内容について役立つ説明を書いてください。
ブランチを整理する: 長期間使用するリポジトリでは、ブランチが蓄積することがあります。ブランチの開発を中止した場合、特にブランチが別のブランチにマージされた場合は、ブランチを削除して整理します。これにより、どのブランチで開発が継続しているかがわかりやすくなります。
リポジトリをアップグレードする: アップグレードを促すダイアログが表示されたら、手順に従ってリポジトリの言語バンドルをアップグレードします。このプロセスでは、アップグレードを含むプルリクエストがアクティブなブランチに対して作成されます。アップグレード用ブランチでパイプラインをビルドして、いずれのバージョン更新もコードに影響しないことを確認してかまいません。ただし、こうしたアップグレードを適用して最新の状態に保つことで、ほかで発生し、アップグレード版で修正済みのエッジケースを回避できることがよくあります。
コードレビューを実践する: チームメンバーと協力して変換処理を開発する際は、プルリクエストのプロセスにコードレビューを取り入れます。Palantir のブログ記事「コードレビューのベストプラクティス ↗」では、データ変換コードのレビューにも同様に適用できる多くの考え方を紹介しています。
リポジトリ間でコードを共有する: Foundry のリポジトリは、さまざまな理由からプロジェクト単位で運用されますが、パイプライン間で再利用できるロジックが存在することも多く、これにはいくつかの利点があります。
DRY に従った一般的なコードの再利用。
データ基盤の異なる領域間で、ロジックの分岐や不整合を回避。
基盤となるパイプラインを利用するのが理想的でありながら、はるかに厳しい SLA やパフォーマンス要件を持つパイプラインが存在する場合があります。この場合、多くはトランスフォームやデータセットではなくロジックを共有することで解決します。これにより、重要なパイプラインで、事前に絞り込んだデータセットを利用したり、トランスフォームの数を減らしたり、異なるビルドスケジュールを設定したりできます。
Code Repositories は、これを実現する優れた方法です。たとえば、Python トランスフォームを使用する場合は、ライブラリを Conda チャネルに公開して、ほかのリポジトリから利用できるようにできます。Python ライブラリの共有に関するドキュメントを参照してください。
共有リポジトリのもう1つの利点は、セマンティックバージョニングです。共有リポジトリでは、コミットにバージョン(例: 1.0.0、1.0.1、2.0.0)のタグを付けることができ、それを利用するライブラリでは、新しいバージョンをどのように取り込むかを選択できます。たとえば、リポジトリは最新バージョン(上記の2.0.0)を取り込むことも、特定のバージョン(たとえば1.0.1)のみを取り込み、手動で判断するまで新しいバージョンの取り込みを延期することもできます。後者は、パイプラインが重要であり、パイプラインの所有者が共有リポジトリへの変更を選択して取り込んだり、承認したりする機会を設けたい場合に、特に有用です。
リリース: 同様に、チームがパイプラインの明確なリリーススケジュールを設けたい場合の選択肢の1つは、ロジックを共有リポジトリ内の関数に切り出し、セマンティックバージョンを使用して、利用側のリポジトリを1.0.0、2.0.0、あるいは .0.0 のようなメジャーリリースに固定することです(この方法では、ステージング環境や長期間存続する develop ブランチを使用せずに済みます)。これにより、開発者は master でライブにすることなく、ロジックの改良を続け、中間リリースにタグを付けられます。さらに、利用側のリポジトリのブランチでは、リリース日より前に master にマージしない限り、開発者はいつでも中間バージョンを取り込めます。
ユニットテストは、コードの品質を向上させ、維持するための一般的な方法です。ユニットテスト ↗では、ソフトウェアの小さく独立したコンポーネント(「ユニット」)を、個別かつ独立した形で自動的にテストします。
Python ユニットテスト:Python ユニットテストの手順に従うことで、Python トランスフォームのリポジトリの CI チェックの一部として pytest ユニットテストを有効にできます。
Java ユニットテスト: Java トランスフォームのユニットテストを設定する手順は、Java ユニットテストのドキュメントに記載されています。
ユニットテストは、次の条件を満たす必要があります。
データの健全性を確認する: パイプラインの一部が完成すると、スケジュールを設定した後はそのまま放置してしまいがちです。しかし、ロジックに問題がなくても、流入するデータがビルドに影響する形で変化し、パフォーマンスの低下、データ規模の拡大、あるいはビルドの失敗につながることがあります。アラートを設定しなくても、データセットのサイズやビルド時間に対する基本的なチェックを設定すると、これらの主要なメトリクスの経時変化を確認でき、たとえばデータセットのサイズの増加率や平均ビルド時間を把握できます。利用可能なヘルスチェックの詳細と設定方法を参照してください。
ヘルスチェックを拡張する: ほとんどの場合、デフォルトのヘルスチェック設定で十分です。ただし、さらに柔軟性が必要な場合は、パイプラインに派生のヘルスチェックデータセットを1個以上追加することを検討してください。このデータセットのトランスフォームでは、任意のロジックを実行して入力データセット(検証対象のデータセット)の妥当性を判定し、「許可された値」のような単純なヘルスチェックでデータセットが有効かどうかを報告できる形式でデータを出力できます。
入力データセットが更新されるたびにこのデータセットがビルドされるようにスケジュールを設定すると、包括的なヘルスチェックを追加できます。
スケジューリングのベストプラクティスを確認してください。