3.4 Structuring and constructing modules part 4: Accessing modules in any depths

One of the good parts about {box} package is it allows accessing deep nested scripts / folders in any depth as modules.

Building on what you learned in the previous section about creating modules from subfolders, {box} doesn’t limit you to just one level of nesting. You can organize your code into multiple layers of directories, creating a hierarchical structure that makes sense for your project’s complexity and organization needs.


3.4.1 Multi-level folder structures

Let’s update {./module} folder from Chapter 3.1, by updating (or just copy and paste the source code of {./module} in GitHub) matrix_ops.r to store functions that rewrites * for matrix multiplication and overrides ^ where a specific value, ^-1, implies the inverse of the matrix, and tables.r to store functions for displaying tables in R REPL, and extending the {./module/statistics} subfolder by adding another level of organization, e.g. you want to add statistical model utilities organized by model type, saved as {./module/statistics/models}* subfolder.

module/
├── __init__.r
├── convert.r
├── hello_world.r
├── matrix_ops.r              # <------------- Under root **{./module}** folder
├── not_func.r
├── tables.r                  # <------------- Under root **{./module}** folder
└── statistics/
    ├── __init__.r
    ├── cor.r
    ├── corrr.r
    ├── time_series.r
    └── models/               # <------------- Subfolder within subfolder
        ├── __init__.r
        ├── linear.r
        ├── logistic.r
        └── baseline_logit.r

In this structure, {./module/statistics/models}* is nested two levels deep from the root {./module} folder. Each directory still requires its own __init__.r file to be recognized as a module.

Note

Remember that every folder you want to treat as a module must contain an __init__.r file, regardless of its depth in the folder hierarchy.

Under {./module/statistics/models}* subfolder, place this in __init__.r file:

#' @export
box::use(
    ./linear,
    ./logistic,
    ./baseline_logit
)

And since we are adding another module within {./module/statistics}, update its __init__.r initialization file:

#' @export
box::use(
    ./cor,
    ./corrr,
    ./time_series, 
    ./models
)

3.4.2 Accessing deeply nested modules

You can access these deeply nested modules using the same syntax patterns you’ve already learned in the previous chapter, just with longer paths:

box::use(
    ./module/statistics/time_series
)

time_series$ACF(AirPassengers)
 [1] 1.0000000 0.9480473 0.8755748 0.8066812 0.7526254 0.7137700 0.6817336
 [8] 0.6629044 0.6556105 0.6709483 0.7027199

Or you can use the parent module and traverse through the hierarchy:

# Access through the parent module
box::use(
    md = ./module
)

# Navigate through the nested structure
md$statistics$time_series$ACF(AirPassengers)
 [1] 1.0000000 0.9480473 0.8755748 0.8066812 0.7526254 0.7137700 0.6817336
 [8] 0.6629044 0.6556105 0.6709483 0.7027199
Source code

The code for some script is too long. Navigate the source code by clicking each hyperlinked text:

  1. Under {./module}

  2. Under {module/statistics/models}

3.4.4 Best practices for deep nesting

While {box} allows you to nest modules at any depth, here are some of my software engineering principles to consider when organizing your code:

  • Keep it reasonable: Deeply nested structures can make navigation more complex. Most projects benefit from a relatively flat hierarchy, though the optimal depth depends on your project’s size and complexity.

  • Organize by functionality: Group related functions in a way that makes sense for your workflow. For example, keeping all model-related functions under {./module/statistics/models}, organized by algorithm type.

  • Use meaningful names: Choose folder names that clearly indicate their contents, making it easier to locate specific functionality.

  • Document your structure: A README file or comments explaining your module organization can help collaborators (and future you) understand the project layout.

  • Be mindful with ../: Frequent use of parent directory navigation might suggest opportunities to reorganize your structure.

Note

There’s no strict rule about module depth. The {box} package itself doesn’t impose limitations on nesting levels. Organize your modules in whatever way makes your code most maintainable and understandable for your specific project needs.