目的と背景
Databricks、ひいてはNotebookの書き方におけるルールはあるのだろうか?
現状8年ほどエンジニアをしているが個人的にはないと感じてる。
もちろんPEP8のようにPythonをどう書くべきかという規約はある。
しかしNotebookについてはPEP8ほど公式なものはないし、今だに書き方はPEP8や基本的なコーディング規則を守りつつ人それぞれなのではないか?
今回はあえてそれについて、自分のよくやる型を定義し、さらにはそれを自動的に整形するCIの構築を目指したい。
スコープ
まずはDatabricks Notebookを構成する要素を考えてみたい
- widgets
- %pip install
- import
- config
- main
こんなところだと思う。
mainの中はDatabricks上でよくある処理であれば、ETLや機械学習およびその前処理等に進んでいくだろう。
mainの中に踏み込むのは流石に難しいので、上記の1〜5をどうやって正しく並べるか考えたい。
そして、正直この1〜5の順番で良いだろう。
widgetsについて

Databricksが初めての方に向けにも丁寧に書いていくが、まずdbutils.widgetsというコードを実行すると、Databricksは画面上部に入力欄が現れる。
ここには動的な値を入力できるので、Notebook全体においてコードには触れずに任意のパラメータで実行できるわけだ。
こちらも現状どこに書くべきか?という明確な回答は無いし、強制するものでは無いと思う。
ただ、今回は敢えて先頭に持ってきたい。
長い間触っていて以下2点を思う。
- やはり動的パラメータは一番上でまとめて定義しておきたい。
- Notebookを開いた時に動的パラメータはいち早くさっさと定義したい。との時に一番上にあると便利。
上記2点の理由から、まずはwidgetsを一番上にしてみよう。
libraryのinstallについて
次はinstallで良いと思う。
ただし必要なlibraryは %pip で installする必要があるのでそれを処理に挟む。
ちなみに余談ですがNotebook上に書くのが面倒な人は Computeに対して libraryを定義することも可能だ。 https://docs.databricks.com/aws/en/libraries/cluster-libraries
configについて
ここで次はconfigに移ろう。importと来たので次は config, class, functionで自然だと思う。
ここで初めてwidgetsの値を取得するようにしている。
もちろん正解はないが、下記のように値のvalidationを挟みたい理由が大きい

そして function等もここに定義したい。(もちろん切り出してもいいです)
mainについて
そして最後にmainとして処理を走らせよう。

こんな感じが個人的には好きな整ったNotebookだ。
ここからが本題、これを Auto formatできるのか?
正直かなり厳しいと思っていますが、できる限りを頑張ってみましょう。
以下が現状のNotebookのsource codeになっている。
# Databricks notebook source
# MAGIC %md
# MAGIC # widgets
# COMMAND ----------
dbutils.widgets.text("birthday", "")
# COMMAND ----------
# MAGIC %md
# MAGIC # install libraries
# COMMAND ----------
# MAGIC %pip install art
# MAGIC dbutils.library.restartPython()
# COMMAND ----------
from datetime import datetime
from art import tprint
# COMMAND ----------
# MAGIC %md
# MAGIC # config
# COMMAND ----------
birthday = dbutils.widgets.get("birthday")
try:
birthday = datetime.strptime(birthday, "%Y-%m-%d")
except ValueError:
raise ValueError(
"Invalid date format. Please provide a date in the format YYYY-MM-DD."
)
# COMMAND ----------
class CONFIG:
deco_text = "⭐️"
# COMMAND ----------
def say_happy_birthday(birthday):
print(CONFIG.deco_text*20)
birthday = birthday.strftime("%b. %d")
tprint(f"Happy Birthday: {birthday}!")
print(CONFIG.deco_text*20)
# COMMAND ----------
# MAGIC %md
# MAGIC # main
# COMMAND ----------
say_happy_birthday(birthday)
Databricksは一見Notebook見えるコードもDatabricks固有の記法を施したPythonコードが実体となっている。
これにより書く時はNotebook、レビュー時はPythonはという僕個人的な、そして誰かが共感してくれたのであろう夢が実現している。
またhttps://docs.databricks.com/aws/en/notebooks/notebook-formatにて ipynb形式が推奨されていて、標準で何もしないとは今はipynbとなっている。
個人的にはプロットや結果を残したい時にはこれでいいが、ETLっぽいコードを書くことが多いData Engineer側の僕にとってはpyファイルによるレビュー体制の方が優先されるので、基本的にpyファイルにしている。
なぜipynbが推奨なのか、気になって昔フォーラムに投稿したら「君のいうとおり、pyファイルのメリットもある。適材適所でいいんやで :)」と言われたので堂々とpyファイルも推していきたい。
https://community.databricks.com/t5/get-started-discussions/why-is-the-ipynb-format-recommended/td-p/111774
これを以下のようにいくつか並べ替えてみた。
- import 文を各所にバラバラに
- 関数定義も処理の直前に
- wigdetの定義も下の方に
(1個目は良くないが、2つ目は、、、まあたまーに分析系のコードなら許す、3つ目に至っては現状ルールなどないので、つまり1個目以外はそんなに悪いことをしていないが・・・ただ、やはりこのあたりも統一できるなら統一したいし、並び順が私は上で提唱した並びになったとしてもそんなデメリットもないと思う(傲慢)
なのでこれを並べ替えていけるか挑戦する。ただしやはり# MAGIC %pip install artなどが鬼門だ。ここがうまくいくだろうか。
ちなみに、多分AIを使えばうまくいくんだろうが、若干反則で面白くないのとファジーな要素を排除してできるなら挑戦してみたいと思う。
王道、black+isort+autoflake
結論:全然ダメ、そりゃそうよね、コメントだし
Ruff
去年から出てきた black isortとか全部コミコミみたいなやつです。
結論:全然ダメ、仕方ないよね
仕方ないのAIにたよろう
やはり既存の仕組みだとコメントとして扱われるマジックコマンドには対応できないのでAIでどうにかしよう。
指示文を以下のように与えた。
まあ、ちょっと長いですが、上の4つの順番で並べて欲しいっていうことと、 %pip ってただのコメントじゃないんだぜ、的なことを記載した。
# Copilot Instructions
## Databricks Python Notebooks
- Databricks notebooks are stored in plain `.py` files. Preserve the notebook markers such as `# Databricks notebook source` and any `# COMMAND ----------` delimiters.
- Treat `# MAGIC %pip ...` and similar lines as active notebook magics. Keep them near the top of the file in their original order so they execute before any Python code.
- Calls to `dbutils` or other Databricks helpers must remain untouched unless the user explicitly requests modifications.
## Logical Section Order
Follow this block order when creating or updating notebook code:
1. **Widgets**: declare widgets and retrieve their values immediately after the initial markdown or comments.
2. **Dependencies**: place installation magics (e.g., `# MAGIC %pip install ...`) and standard `import` statements after widget setup.
3. **Configuration / Helpers**: define configuration objects, constants, and helper functions next.
4. **Main Logic**: implement the primary execution flow at the end.
## Formatting Expectations
- Apply standard Python auto-formatting (Black-compatible, 88-char lines) while respecting the section order above.
- Keep a blank line between the major sections to make the notebook cell boundaries obvious.
- Do not reorder or remove Databricks magic commands; formatting must never move them away from the dependency section.
どうなったのか?
惜しい、、まずはdbutilsが上の方に戻ってきたので、私の好きな規約になっているし、多分markdownにも一定従ってくれたのだと思う。
しかしdbutilsがまだAIには早いのか、不要なgetを一回挟んでいる。

ただ、autoflakeやblackなどでは難しかった datetimeは無事に上に帰ってきていると同時に、嬉しいことにdbutilsよりも下にきている。私流で難しかったろうがありがとう。
そして最後 configのところがどうなったかというと下記のように直された・・・

つまり私が configの欄にまとめたかった widgetの変数の受け取りやconfig変数の定義は、
validate用の関数( parse_birthday )が用意されて、綺麗に次の関数に引き継がれたわけだ。
なんか、、、こっちの方が綺麗かも。。。
コーディングもうやめます調子乗ってすみませんでした。。。
最近英語を勉強してもしてもネイティブの言い回しに辿り着けないあの気持ちをコーディングでも味わってます。
でも結論、コンテキストを与えてあげることによって、綺麗に80%くらいは綺麗に整形できるようになったんじゃないでしょうか?
最後に
ここまでお読みいただきありがとうございました。
Databricks Notebookのコード規約なんてものは存在しないと思っていますが、一定社内のルールや共通認識を持っておいた方がきっといい開発が進むのではないでしょうか?
そしてやはり複雑になるはなるほどAI様様だと思う毎日で、みなさんもぜひ組織のメンバーや文化に準じたオリジナルコード規約レビューAIを作ってみてください。
