Skip to content

Namespace referencing rules enforcement for Clojure programs

Notifications You must be signed in to change notification settings

nogden/ns-rules

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

What's this all about?

ns-rules allows you to enforce dependency rules between Clojure namespaces.

Consider the following imaginary Clojure codebase that handles shipping.

src/
  shipping/
    entity/
      ship.clj
      route.clj
      port.clj
      cargo_manifest.clj
      contract.clj
    service/
      database.clj
      event_log.clj
    use_case/
      cargo_assignment.clj
      routing.clj
      contract_verification.clj
    infrastructure/
      postgres.clj
      kafka.clj

This codebase has been written with certain assumptions about the dependencies between the various namespaces. Specifically,

  1. entities may only reference other entities,
  2. services may only reference entities,
  3. use_cases may only reference entities and services, and
  4. infrastructure may reference anything.

These rules are not enforced in anyway and over time, as teams change, such rules are often forgotten to the detriment of the codebase.

ns-rules can enforce these rules with the following configuration.

ns-rules.edn

{:src-dirs ["src"]
 :rules    [shipping.entity.*   {:restrict-to [shipping.entity.*]}
            shipping.service.*  {:restrict-to [shipping.entity.*]}
            shipping.use_case.* {:restrict-to [shipping.entity.*
                                               shipping.service.*]}]}

If we run ns-rules in the project root we see that the rules are being obeyed.

example $ ns-rules
All checks passed
 12 files checked
  5 namespaces matched a rule
  0 warnings
  0 files skipped

However if we break a rule, ns-rules will tell us in great detail.

example $ ns-rules
────[namespace_rule_violation]────────────────────

    × 'shipping.entity.port' is not allowed to reference 'shipping.service.database'

   ╭───[src/shipping/entity/port.clj:1:1] shipping.entity.port:
 1 │ (ns shipping.entity.port
 2 │   (:require [shipping.service.database :as database]))
   ·              ────────────┬────────────
   ·                          ╰───────────── this reference is not allowed


Found 1 rule violation
 12 files checked
 10 namespaces matched a rule
  0 warnings
  0 files skipped

By calling ns-rules from a Git pre-commit hook you can ensure that the commit will fail if your dependency rules are violated.

But why is this Clojure tool written in Rust?

Clojure is a beautiful language and a joy to use, but it is not a good fit for all cases. A CLI tool such as this should not make the user wait and Clojure's lengthy startup time prevents instant results. Personally, I hate waiting for my tools and on today's hardware there is no excuse for something like this not to be instant, so Rust it is.

About

Namespace referencing rules enforcement for Clojure programs

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published