|Hello everyone,|
||
|I'd like to initiate a vote on a new DAG authorship best practice.|
||
|## Proposal|
||
|When a `@task.branch` (or `BranchPythonOperator`) function has **at
least two `return` statements**, and **exactly one of them returns a
non-empty list**, the function is effectively acting as a binary gate —
either run a specific set of downstream tasks, or skip them all.|
||
|In that case, **`@task.short_circuit`** (`ShortCircuitOperator`) is a
simpler and more readable alternative: it expresses the same intent by
returning `True`/`False`, rather than requiring the caller to reason
about list-vs-empty-list semantics.|
||
|### Before|
||
|```python|
|from airflow.decorators import task|
||
|@task.branch|
|def check_condition():|
|if some_condition:|
|return ["downstream_task"]|
|return []|
|```|
||
|### After|
||
|```python|
|from airflow.decorators import task|
||
|@task.short_circuit|
|def check_condition():|
|return some_condition|
|```|
||
|The same principle applies to the classic operator form.|
||
|## Rationale|
||
|- **Clarity:** `@task.short_circuit` makes intent immediately obvious —
the task either proceeds or it doesn't. Readers no longer need to
inspect return values to determine that the branch is binary.|
|- **Less boilerplate:** Eliminates the need to wrap a boolean condition
in a single-element list.|
|- **Correct semantics:** `@task.branch` with a single non-empty return
is a degenerate case of branching; `@task.short_circuit` is the
idiomatic tool for this pattern.|
|- **Consistency:** The rule applies equally to the TaskFlow API
(`@task.branch`) and the traditional operator API
(`BranchPythonOperator`), covering both authorship styles uniformly.|
||
|## Cases NOT affected by this proposal|
||
|This best practice only applies when the function structure is
unambiguously binary:|
||
|- Functions with **multiple non-empty list returns** are genuine
branching logic — no change suggested.|
|- Functions with **only a single return** — no change suggested.|
|- Functions returning **non-list values** (strings, `None`, etc.) — no
change suggested.|
||
|## Call for Consensus|
||
|Please let me know if you have concerns, questions, or support.|
||
|Thank you,|
|Dev-iL|
||
|---|
||
|## See Also|
||
|1. [apache/airflow#43176
(comment)](https://github.com/apache/airflow/issues/43176#issuecomment-2667604469)
— original proposal in the static checks tracking issue|
|2. [astral-sh/ruff#23579](https://github.com/astral-sh/ruff/pull/23579)
— Draft Ruff PR implementing (`task-branch-as-short-circuit`)|