Databricksノートブックによるソフトウェアエンジニアリングのベストプラクティス

[How to Stay True to Common Engineering Best Practices While developing With Databricks Notebooks \- The Databricks Blog](https://databricks.com/blog/2022/06/25/software-engineering-best-practices-with-databricks-notebooks.html)の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

# Databricksノートブック

ノートブックは、複雑な環境設定なしにクイックにデータを操作し始める方法としては人気のあるものです。ノートブックの作成者は、コードと説明のテキスト組み合わせることで、インタラクティブな分析からコラボレーティブなワークフローにクイックに移行できます。多くの場合、探索としてスタートしたノートブックはプロダクションのアーティファクトに進化します。例えば、

1. 新規のデータと進化するビジネスロジックに基づき定期的に実行されるレポート
1. 定期的なスケジュールあるいは継続的に実行される必要があるETLパイプライン
1. 新たなデータが到着した際に再トレーニングが必要な機械学習モデル

驚くかもしれませんが、多くのDatabricksのお客様は、少々の調整で**ノートブックをプロダクションの資産にパッケージングできる**ことを知っており、コードレビュー、テスト、モジュール性、継続的インテグレーション、バージョン管理されたデプロイメントのようなベストプラクティスと組み合わせています。

# 書き直すか、プロダクション化するか？

探索的分析を完了した後、従来からある知恵に基づくと、伝統的なIDEを用いて別の構造化されたコードベースでノートブックのコードを書き直すことになります。最終的には、プロダクションのコードベースはCIシステム、ビルドツール、ユニットテストのインフラストラクチャに組み込まれることになります。これはデータがほぼ静的であり、以降も大きな変更がない場合にはベストなアプローチとなります。しかし、多くの一般的なケースにおいては、データの変更に応じてプロダクションの資産を頻繁に変更、デバッグ、拡張しなくてはなりません。多くの場合、これはノートブックの探索を伴うことになります。それならばいっそ、行ったり来たりをスキップできたらと思います。

書き換えるのと比べて、ノートブックを直接プロダクション化することにはいくつかのメリットがあります。特に、

1. <INS>データとコードを一緒にテストできます。</INS>ユニットテストではビジネスロジックを検証しますが、データにおけるエラーはどうでしょうか？ノートブックで直接テストすることで、データフォーマットや分布に関する実行時チェックを含む、プロダクションを表現するデータを伴うビジネスロジックのチェックをシンプルにします。
1. <INS>何か問題が起きた際に、より密連携したデバッグループを提供します。</INS>昨夜ETLジョブが失敗しましたか？よくある原因としては、破損レコードのように予期していない入力データ、予期しないデータの偏り、データの欠如などがあります。プロダクションのジョブのデバッグには、多くの場合プロダクションのデータが必要となります。プロダクションのジョブがノートブックなのであれば、お手元のETLのジョブの一部あるいは全部を再実行でき、問題を引き起こしているプロダクションデータに対して直接インタラクティブな分析を行うことができます。
1. <INS>あなたのビジネスロジックを高速に進化させます。</INS>ML問題に対して新たなアルゴリズムや統計的アプローチを試したいですか？探索とデプロイメントが別のコードベースに分離されている場合、いかなる小さな変更も一方でのプロトタイピングが必要で、もう一方でのプロダクション化が必要となり、ロジックが適切に複製されていることを保証するために注意が必要となります。MLジョブがノートブックであるなら、シンプルにアルゴリズムを調整し、トレーニングジョブの並列のコピーを実行し、同じノートブックをプロダクションに移行することができます。

*「でも、ノートブックはテストやモジュール性、CIに適していないよ！」* とあなたは言うかもしれません。急がないでください！本書では、Databricksノートブックとそのようなソフトウェアエンジニアリングのベストプラクティスをどのように組み合わせるのかを説明します。どのようにバージョン管理、コードのモジュール化、ユニットテストとインテグレーションテストの適用、継続的インテグレーション/継続的デリバリー(CI/CD)の実装を行うのかを説明します。また、[サンプルのリポジトリ](https://github.com/databricks/notebook-best-practices/blob/main/README.md)と[ウォークスルー](https://docs.databricks.com/notebooks/best-practices.html)を通じてデモを提供します。そこそこの工数で、書き直すことなしに探索用のノートブックをプロダクションのアーティファクトにし、データドリブンソフトウェアのデバッグとデプロイメントを加速します。

# バージョン管理とコラボレーション

プロダクションエンジニアリングの基礎は、堅牢なバージョン管理とコードレビュープロセスを持つことです。時間経過と共に行われるコードへの変更の更新、リリース、ロールバックを行うために、[Databricks Repos](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140)は人気のある多くのGitプロバイダーとのインテグレーションをシンプルにします。また、コミット、プル、マージのような典型的なGitオペレーションを実行するためのわかりやすいUIを提供します。既存のノートブック、(pythonユーティリティのような)その他のヘルパーコードを、ソース管理のために簡単にDatabricksのリポジトリに追加することができます。
![](https://databricks.com/wp-content/uploads/2022/06/db-235-blog-img-1.png)
*Databricks Repos*におけるバージョン管理

バージョン管理と連携することで、Databricksワークスペース内で、Gitを通じた他の開発者とのコラボレーションができるようになります。プログラムからアクセスするために、Databricks Repos [API](https://docs.databricks.com/dev-tools/api/latest/repos.html)を用いることで皆様の自動化パイプラインとReposと連携できるようになり、決してUIでの利用のみに限定されません。

# モジュール性

プロジェクトが初期のプロトタイプのステージを通過すると、より容易に共有、テスト、維持できるように、コードをモジュールにリファクタリングすることになります。[任意のファイルのサポート](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140#files-in-repos%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96)と新たな[ファイルエディタ](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140#databricks-repo%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E9%9D%9E%E3%83%8E%E3%83%BC%E3%83%88%E3%83%96%E3%83%83%E3%82%AF%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%A5%AD)によって、Databricks Reposはモジュール化され、テスト可能なコードを伴うノートブックを実現します。Pythonプロジェクトでは、`.py`ファイルで定義されたモジュールをDatabricksノートブックで直接インポートすることができます。
![](https://databricks.com/wp-content/uploads/2022/06/db-235-blog-img-2.png)
*DatabricksノートブックでカスタムPythonモジュールをインポート*

また、開発者は`.py`ファイルにおけるモジュールに対するいかなる変更も即座にDatabricksノートブックに反映されるように、[%autoreload](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140#python%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%AA%E3%83%BC%E3%83%88%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%89)マジックコマンドを使用することができ、Databricksにおいてさらに密な開発ループを実現することができます。Databricks ReposにおけるRスクリプトにおいては、`source()`関数を用いることで最新の変更をノートブックにロードすることができます。

また、別のPython、Rモジュールに分割されたコードはお好きなIDEを使ってオフラインで編集することができます。コードベースが大きくなると、このことは特に有用になります。

Databricks Reposは、ノートブック間のコードのコピーを含む不安定なプロセスではなく、共有されたモジュール、ライブラリの開発を通じたコラボレーションを支援します。

# ユニットテスト、インテグレーションテスト

他の開発者とコラボレーションする際、コードに対する変更が期待通りに動作することをどのように保証しますか？これは、コード上で独立したそれぞれのロジックのユニットのテスト(ユニットテスト)と、依存関係のチェーンを伴うワークフロー全体のテスト(インテグレーションテスト)によって達成されます。テストスイートにおけるこの種のエラーは、別の開発者やプロダクションで実行されているジョブに影響を及ぼす前にコードの問題をキャッチするために活用されます。

Databricksを用いてノートブックのユニットテストを行うためには、Pythonファイルにテストを記述する`pytest`のような典型的なPythonテストフレームワークを活用します。以下に基本的なETLワークフローにおけるダミーデータセットを用いたユニットテストのシンプルな例を示します。
![](https://databricks.com/wp-content/uploads/2022/06/db-235-blog-img-3.png)
*pytestのfixtureとassertionを伴うPythonファイル*

Databricksノートブック(あるいはDatabricks [webターミナル](https://docs.databricks.com/clusters/web-terminal.html))からインタラクティブにこれらのテストを呼び出したり、エラーをチェックすることができます。
![](https://databricks.com/wp-content/uploads/2022/06/db-235-blog-img-4.png)
*Databricksノートブックからのpytestの呼び出し*

ノートブック全体をテストする際、プロダクションデータや他の資産に影響を与えたくはありません。言い換えると、ドライランを行いたいと考えます。このような挙動を制御するシンプルな方法は、特定のパラメーターが引き渡された際にのみプロダクションとして動作するようにノートブックを構成するというものです。Databricksでは、[Databricksウィジェット](https://qiita.com/taka_yayoi/items/4df1fd723bdab9a99b08)を用いて、ノートブックのパラメーター化を行うことができます。

```py:Python
# get parameter
is_prod = dbutils.widgets.get("is_prod")

# only write table in production mode
if is_prod == "true":
    df.write.mode("overwrite").saveAsTable("production_table")
```

プロダクションの資産にアクセスできないワークスペースでインテグレーションテストを実行しても同じ結果を得ることができます。どちらの方法でも、Databricksはユニットテストとインテグレーションテストの両方をサポートしており、ノートブックが進化し、変更の影響を手動でチェックすることが苦痛になったとしても、プロジェクトを成功に近づけます。

# 継続的インテグレーション / 継続的デプロイメント

早期かつ頻繁にエラーを捕捉するためのベストプラクティスは、自身のリポジトリのメインブランチに頻繁にコードをコミットすることです、ここでは、[GitHub Actions](https://github.com/features/actions)や[Azure DevOps Pipelines](https://azure.microsoft.com/en-us/services/devops/pipelines/)のような著名なCI/CDプラットフォームが、プルリクエストがマージされる前のこれらの変更に対するテストの実行を容易にします。この標準的なプラクティスをさらにサポートするために、Databricksでは新たな2つのGithub Actionsとして、Databricksノートブックの実行を起動する[run\-notebook](https://github.com/databricks/run-notebook/#run-notebook-v0)と、Python .whlファイルのようなビルドアーティファクトをクラスターにインストールできるようにDBFSに移動するための[upload\-dbfs\-temp](https://github.com/databricks/upload-dbfs-temp/#upload-dbfs-temp-v0)をリリースしました。これらのアクションは、皆様の組織のCI/CD戦略に適合するために、フレキシブルな[マルチステップのプロセス](https://github.com/databricks/notebook-best-practices/blob/main/.github/workflows/databricks_pull_request_tests.yml#L24)に組み込むことができます。

さらに、今ではDatabricksワークフローから[Gitのブランチ、タグ、コミットを参照できる](https://qiita.com/taka_yayoi/items/8a68279bcf36bdaf92c6)ようになっています。
![](https://databricks.com/wp-content/uploads/2022/06/db-235-blog-img-5.png)
*メインブランチに対して実行するように設定されたジョブ*

これによって、最新のプルリクエストに対してテストを実行できるので、継続的インテグレーションをシンプルなものにします。また、継続的デプロイメントもシンプルにします。Databricksに最新のコード変更をプッシュするための追加のステップを踏むのではなく、ジョブがバージョン管理システムの最新のリリースをプルするように設定することができます。

# まとめ

この記事では、ソフトウェアエンジニアリングのベストプラクティスを適用することでDatabricksノートブックを昇華するコンセプトを紹介しました。Databricksレイクハウスにおけるバージョン管理、コードのモジュール化、テスト、CI/CDをカバーしました。これらのトピックの詳細に関しては、[サンプルリポジトリ](https://github.com/databricks/notebook-best-practices/blob/main/README.md)や[関連のウォークスルー](https://qiita.com/taka_yayoi/items/740d94463bbf08c63dbb)をチェックしてください。

# 詳細はこちら

- Githubリポジトリ: https://github.com/databricks/notebook-best-practices/blob/main/README.md
- ドキュメント: https://qiita.com/taka_yayoi/items/740d94463bbf08c63dbb
- CI/CDのためのサービスプリンシパル: https://docs.databricks.com/dev-tools/ci-cd/ci-cd-sp.html

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)