Transitive compile dependencies question

I’m working on a new project and trying to be very thoughtful about both the boundaries of my API and about reducing transitive compile dependencies (if that’s the correct terminology for this).

I read somewhere that one useful way to check for compile dependencies is:

mix xref graph --label compile-connected --fail-above 0

However it is failing under the following conditions:

I have 3 modules


MyApp.Schemas.Base is a __using__ macro used to set a bunch of repetitive settings that are shared between schemas such as binary ids, timestamp formats etc. It looks like this:

defmodule MyApp.Schemas.Base do
  @moduledoc false

  defmacro __using__(_opts) do
    quote do
      use Ecto.Schema

      @foreign_key_type :binary_id
      @primary_key {:id, :binary_id, read_after_writes: true}
      @schema_prefix unquote(MyApp.Repos.Local.prefix())
      @timestamps_opts [type: :utc_datetime_usec]

Which I then “use” in my schemas:

defmodule MyApp.Schemas.AccountSchema do
  use MyApp.Schemas.Base
  import Ecto.Changeset
  # etc...

When running the xref check I get the following output:

❯ mix xref graph --label compile-connected --fail-above 0
└── lib/my_app/schemas/base.ex (compile)
└── lib/my_app/schemas/base.ex (compile)

This output makes sense to me… but I wonder if there’s any to avoid this around it, or at the very least a way to tell xref command to exclude this particular module (without increasing the --fail-above counter which is error prone).

Or maybe I’m just thinking about this all wrong…

Anyway I’m hoping someone has bumped into this before and can share their insights.

1 Like

This appears to be the offending line

@schema_prefix unquote(MyApp.Repos.Local.prefix())

Once I changed that to a static string the issue was resolved

@schema_prefix "my_app"

I’m still trying to figure out why that was the case :thinking:

1 Like

compile-connected is looking for transitive compile-time dependencies; when Base has this line:

@schema_prefix unquote(MyApp.Repos.Local.prefix())

then every module that does use MyApp.Schemas.Base gets a compile-time dependency on Base (naturally) and transitively also on MyApp.Repos.Local.