The Existence Check
Before version 1.2.0 Knigge
used to try to verify at compile time whether the implementation module of a facade exists.
If Knigge
found the implementation missing it would raise an error.
The idea being that this would catch spelling mistakes and the like before releasing the application. Having a spelling error in delegating to the implementation is no bueno: it will crash and burn in a horrible disaster at runtime.
At the time the idea seemed great - and to be honest I still think it does - but reality turned out to be more complicated.
Knigge VS the Compiler
Sometimes Knigge
would find the implementing module to be missing even though it was there, no spelling error, no nothing.
Anybody who had the pleasure experiencing this would - very rightfully I must say - wonder what the hell was going on.
As it turns out there is no guarantee about the order in which the Elixir compiler will compile the modules of your project.
While it does ensure that dependencies get resolved - such as specifying a @behaviour
in your module - it will happily chug along compiling your modules in parallel.
And don't get me wrong, that's a good thing, I like that the compiler does this.
It's a great way to speed up compilation, and proves that there are no weird interdependencies in the order of compilation; but it does lead to a problem with Knigge
.
You see, sometimes the compiler might start with your implementation module MyImplementation
.
It would then encounter the @behaviour MyFacade
line, interrupt compilation of the module and compile MyFacade
.
In cases like this the existence check works just fine.
In other cases the compiler might start with compiling MyFacade
.
Finding no dependencies it would happily chug along, resolve use Knigge
and ... BOOM!
Knigge
would raise a tantrum because it cannot find MyImplementation
.
So what can we do about it?
Introducing mix knigge.verify
Instead of doing the existence check at compile time Knigge
now offers the knigge.verify
mix task.
By using a Mix.Task
Knigge
bypasses the whole compilation conundrum since the task runs after your project was fully compiled.
The task scans your app for all modules which use Knigge
by checking for a __knigge__/0
function. If this function is found the task fetches the implementation of the facade using __knigge__(:implementation)
and then verifies that the returned module actually exists.
After performing this check for all found modules it prints the results and exits with an error code if an implementing module was found missing.
As such you can easily integrate mix knigge.verify
into your CI pipeline to ensure that all implementations exist before pushing to production.
Roadmap
In addition to having the mix knigge.verify
task I would like to create a compiler step which performs the existence check. This could then be added to your project in mix.exs
under the compilers
key in your project
function (similar to how phoenix
and gettext
add additional compiler steps).
Furthermore I could imagine adding additional verification steps in the future:
- ensuring the implementation actually implements all necessary callbacks
- somehow integrating with
dialyzer
to check the types of the implementation
But until the necessary research and experiments have been done it's hard to say where the journey will go. Nevertheless feel free to open issues to discuss potential features at any time.