Files
deeplearning4j--deeplearning4j/ADRs/0036 - Namespace refactoring.md
T
2026-07-13 12:47:05 +08:00

262 lines
15 KiB
Markdown

# ADR: Migrate Project Namespaces to org.eclipse.deeplearning4j using OpenRewrite
## Status
Proposed
Proposed by: Adam Gibson (May 8, 2025)
Discussed with: Paul Dubs
## Context
The Deeplearning4j project ecosystem currently utilizes multiple root Java package namespaces, primarily `org.nd4j`, `org.deeplearning4j`, and `org.datavec`, along with existing code under `org.eclipse.deeplearning4j`, bindings to
external libraries (like FlatBuffers, ONNX, TensorFlow, Python), and various `contrib` and `codegen` modules. This distributed namespace structure can make navigation, maintenance, and
understanding component relationships more challenging than necessary.
The goal is to consolidate the core project codebase under a single, unified root namespace: `org.eclipse.deeplearning4j`. This aligns with the project's stewardship under the Eclipse Foundation and aims to create a clearer,
more consistent, and maintainable structure. Given the project's large scale, an automated refactoring approach using [OpenRewrite](https://docs.openrewrite.org/reference/rewrite-maven-plugin) is optimal for feasibility. This ADR proposes the strategy and
specific rules for this migration.
This is part of a 2 phase release plan where a milestone release that has the old package names is performed followed by the major renamespacing.
## Proposal
This ADR proposes using a comprehensive [OpenRewrite recipe](https://docs.openrewrite.org/reference/rewrite-maven-plugin) to automatically refactor the project's primary Java packages into the `org.eclipse.deeplearning4j` namespace. The refactoring follows a two-phase conceptual approach:
1. **Foundational Re-basing:** Map the main existing root packages (`org.nd4j`, `org.deeplearning4j`, `org.datavec`) to logical sub-packages under the new root (`.nd4j`, `.dl4jcore`, `.datavec`).
2. **Architectural Refinement:** Apply more specific rules to achieve a clearer target structure, including:
* Elevating the UI components to a top-level `org.eclipse.deeplearning4j.ui` package.
* Consolidating ND4J backend-specific code (including former `jita` and `jcublas` into `.cuda`) under `org.eclipse.deeplearning4j.nd4j.backend.[type]`.
* Structuring DataVec components functionally under `org.eclipse.deeplearning4j.datavec.*`.
* Isolating runtime bindings for external libraries under `org.eclipse.deeplearning4j.bindings.*`.
* Providing clear namespaces for `contrib` and `codegen` modules.
* Establishing top-level `common` and `resources` packages (though full consolidation requires further steps).
The core of the proposal is the following OpenRewrite YAML recipe, which implements the automated parts of this strategy:
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# OpenRewrite Recipe for Deeplearning4j Namespace Migration #
# Target Root: org.eclipse.deeplearning4j #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
type: org.openrewrite.Recipe
name: org.eclipse.deeplearning4j.refactor.NamespaceMigration
displayName: Migrate DL4J Project to org.eclipse.deeplearning4j Namespace
description: Comprehensive refactoring of core DL4J, ND4J, and DataVec packages under the org.eclipse.deeplearning4j root, including backend consolidation and UI elevation.
recipeList:
#--------------------------------------------------------------------------#
# Step 1: Handle Specific Component Moves (More Specific Rules First) #
#--------------------------------------------------------------------------#
# --- UI Components -> o.e.d.ui.* ---
- org.openrewrite.java.ChangePackage:
oldPackageName: org.deeplearning4j.ui
newPackageName: org.eclipse.deeplearning4j.ui
recursive: true
# Note: This rule assumes org.deeplearning4j.ui.* should be elevated.
# It must run before the general org.deeplearning4j -> o.e.d.dl4jcore rule.
# --- ND4J Backends -> o.e.d.nd4j.backend.[type].* ---
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.linalg.jcublas # Maps to cuda backend
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.cuda
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.jita # JITA components also map to cuda backend
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.cuda # Target same new package
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.linalg.cpu.nativecpu # Maps to cpu backend
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.cpu
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.presets.cuda # CUDA presets
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.cuda.presets
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.presets.cpu # CPU presets
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.cpu.presets
recursive: true
- org.openrewrite.java.ChangePackage: # Minimal backend?
oldPackageName: org.nd4j.linalg.minimal
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.minimal
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.presets.minimal
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.minimal.presets
recursive: true
- org.openrewrite.java.ChangePackage: # Common presets utils
oldPackageName: org.nd4j.presets
newPackageName: org.eclipse.deeplearning4j.nd4j.backend.common.presets
recursive: true
# --- Native Ops / Bindings Facades ---
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.nativeblas # Common native facade classes like NativeOpsHolder
newPackageName: org.eclipse.deeplearning4j.nd4j.nativeops.common
recursive: true
# --- Runtime Bindings (Wrappers/Runners for external libs/runtimes) ---
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.onnxruntime # ONNX Runtime Runner
newPackageName: org.eclipse.deeplearning4j.bindings.onnx.runtime
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.tensorflow.conversion # TF Runtime Runner/Converter
newPackageName: org.eclipse.deeplearning4j.bindings.tensorflow.runtime
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.tensorflowlite # TF Lite Runner
newPackageName: org.eclipse.deeplearning4j.bindings.tensorflowlite.runtime
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.tvm # TVM Runner
newPackageName: org.eclipse.deeplearning4j.bindings.tvm.runtime
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.python4j # Python Bindings
newPackageName: org.eclipse.deeplearning4j.bindings.python.api # Map core to .api
recursive: true # Handles subpackages like .numpy unless more specific rules added
# --- Specific Contrib Modules (Using explicit contrib namespacing) ---
# Note: fileMatcher might be needed in practice to limit these rules to specific module paths
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j # For classes directly in org.nd4j within nd4j-benchmark
newPackageName: org.eclipse.deeplearning4j.contrib.benchmark.nd4j
recursive: false # Avoid affecting subpackages handled below
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.bypass # Sub-package in nd4j-benchmark
newPackageName: org.eclipse.deeplearning4j.contrib.benchmark.nd4j.bypass
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.memorypressure # Sub-package in nd4j-benchmark
newPackageName: org.eclipse.deeplearning4j.contrib.benchmark.nd4j.memorypressure
recursive: true
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j # For classes directly in org.nd4j within version-updater
newPackageName: org.eclipse.deeplearning4j.contrib.versionupdater
recursive: false
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j.fileupdater # Sub-package in version-updater
newPackageName: org.eclipse.deeplearning4j.contrib.versionupdater.fileupdater
recursive: true
- org.openrewrite.java.ChangePackage: # For contrib blas-lapack-gen
oldPackageName: org.deeplearning4j
newPackageName: org.eclipse.deeplearning4j.contrib.blaslapackgen
recursive: true
- org.openrewrite.java.ChangePackage: # For contrib nd4j-log-analyzer
oldPackageName: org.nd4j.interceptor
newPackageName: org.eclipse.deeplearning4j.contrib.nd4jloganalyzer.interceptor
recursive: true
# --- Specific Codegen Modules ---
# Note: fileMatcher might be needed in practice
- org.openrewrite.java.ChangePackage: # For libnd4j-gen
oldPackageName: org.nd4j.descriptor
newPackageName: org.eclipse.deeplearning4j.codegen.descriptor
recursive: true
- org.openrewrite.java.ChangePackage: # For op-codegen
oldPackageName: org.nd4j.codegen
newPackageName: org.eclipse.deeplearning4j.codegen.op
recursive: true
- org.openrewrite.java.ChangePackage: # For codegen blas-lapack-generator
oldPackageName: org.deeplearning4j
newPackageName: org.eclipse.deeplearning4j.codegen.blaslapack
recursive: true
#--------------------------------------------------------------------------#
# Step 2: Apply General Re-basing Rules (Less Specific Rules Last) #
#--------------------------------------------------------------------------#
- org.openrewrite.java.ChangePackage:
oldPackageName: org.nd4j # General ND4J code not caught by specific rules above
newPackageName: org.eclipse.deeplearning4j.nd4j
recursive: true
# This will map remaining org.nd4j.* like linalg.api.*, samediff.*, common.*, etc.
- org.openrewrite.java.ChangePackage:
oldPackageName: org.deeplearning4j # General DL4J Core code (excluding UI already handled)
newPackageName: org.eclipse.deeplearning4j.dl4jcore
recursive: true
# This will map nn.*, models.*, datasets.*, eval.*, nlp.*, etc.
- org.openrewrite.java.ChangePackage:
oldPackageName: org.datavec # General DataVec code
newPackageName: org.eclipse.deeplearning4j.datavec
recursive: true
# This will map api.*, transform.*, image.*, arrow.*, etc.
#--------------------------------------------------------------------------#
# Step 3: Exclusions / Manual Handling (Commented Out for Safety) #
#--------------------------------------------------------------------------#
# --- DO NOT AUTOMATICALLY RUN THESE for generated binding specs ---
# --- Prefer changing generator configurations ---
# - org.openrewrite.java.ChangePackage:
# oldPackageName: com.google.flatbuffers
# newPackageName: org.eclipse.deeplearning4j.bindings.flatbuffers.spec # Or .core
# recursive: true
# - org.openrewrite.java.ChangePackage:
# oldPackageName: onnx
# newPackageName: org.eclipse.deeplearning4j.bindings.onnx.spec
# recursive: true
# - org.openrewrite.java.ChangePackage:
# oldPackageName: tensorflow # Includes tensorflow.framework, tensorflow.eager etc
# newPackageName: org.eclipse.deeplearning4j.bindings.tensorflow.spec
# recursive: true
#--------------------------------------------------------------------------#
# Step 4: Potential Cleanup (Run Separately After Migration) #
#--------------------------------------------------------------------------#
# - org.openrewrite.java.cleanup.OrganizeImports
# - org.openrewrite.java.cleanup.RemoveUnusedImports
# - org.openrewrite.java.format.AutoFormat
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# End of Recipe #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
## Consequences
### Advantages
* **Namespace Consistency:** Provides a single, unified root namespace (`org.eclipse.deeplearning4j`) for the entire project, aligning with Eclipse Foundation stewardship.
* **Improved Structure:** The refined Phase 2 structure (explicit backends, UI, common components, bindings) enhances architectural clarity and modularity compared to the original scattered namespaces.
* **Easier Navigation & Maintenance:** A consistent structure makes it easier for developers to find code, understand component relationships, and perform maintenance.
* **Foundation for Future Work:** Creates a cleaner base for developing new features and potentially consolidating shared functionality (e.g., in common utilities, resource management).
### Disadvantages
* **Significant Initial Effort:** Running this large-scale refactoring requires careful setup, dry runs, review, and validation.
* **Potential for Breakage:** Automated refactoring on this scale carries inherent risks. Build script issues, reflection usage, non-Java file references (like in XML or properties), and complex type resolution might lead to compilation errors or runtime issues requiring manual fixes.
* **Testing Burden:** Requires executing the full test suite (unit, integration, platform-specific) to ensure correctness after refactoring. Test code itself will also be refactored and needs verification.
* **External Bindings Complexity:** Handling generated code or bindings for libraries like FlatBuffers, ONNX, and TensorFlow requires careful consideration beyond simple package renaming; modifying generator configurations is preferred.
* **Learning Curve:** Teams unfamiliar with OpenRewrite will need to learn its usage and recipe development, especially for any necessary follow-up complex refactorings.
* **Merge Conflicts:** This constitutes a large change, potentially creating significant merge conflicts for ongoing feature branches. Coordination is essential.
### Technical details about the Namespace Refactoring
* **Tooling:** The proposal relies on OpenRewrite and its `org.openrewrite.java.ChangePackage` recipe.
* **Recipe Structure:** The YAML recipe uses a `recipeList` and applies more specific package mapping rules *before* more general ones to handle structural changes like backend separation and UI elevation correctly.
* **`ChangePackage` Limitations:** This recipe primarily uses `ChangePackage`. Achieving the full Phase 2 vision, especially consolidating classes from multiple old locations into a single new package (e.g., common utilities), may require additional recipes using `MoveClass`, `MovePackage`, or custom Java-based recipes after this initial migration.
* **Exclusions:** Generated binding specifications (`com.google.flatbuffers`, `onnx.*`, `tensorflow.*`) are intentionally excluded from automated changes due to high risk. Runtime wrappers/runners for these *are* included in the refactoring.
* **Process:** The recommended process involves: backup -> dry run -> review -> iterative recipe refinement (if needed) -> apply changes -> compile -> test -> manual code review -> commit.
## Discussion
The proposed structure aims for a balance between respecting the original component boundaries (ND4J, DL4J Core, DataVec) and creating a more modern, cohesive structure under the Eclipse Foundation namespace. Key decisions reflected in the proposal:
* Explicitly separating backend implementations (`.nd4j.backend.[type]`).
* Elevating UI to a top-level component (`.ui`).
* Designating clear homes for bindings (`.bindings`), contrib (`.contrib`), and codegen (`.codegen`).
* Establishing placeholders for consolidated common code (`.common`) and resource management (`.resources`), acknowledging full consolidation is a subsequent step.
* Using `.dl4jcore` to house the bulk of the original `org.deeplearning4j` code to distinguish it clearly within the new structure.
Further discussion within the development team is needed to confirm these target structures and plan the implementation, particularly the steps required beyond the initial automated recipe application for deeper Phase 2 refinements.