SE-189 (restrict cross-module struct initializers) and layered architecture

Some background

I have two modules, let's call them ViewModels and ConfiguredViewModels where ConfiguredViewModels has a dependency on ViewModels.

The first one has a lot of types represented with structs.
The second one knows how to create instances of the types from the first module using application data (like user, settings information, etc). It defines new initializers for them that take application data as parameters.

The problem

The accepted SE-189 proposal makes this approach less convenient because of the need of creating public initializers for all types in ViewModels and using those in ConfiguredViewModels.

I understand the motivation behind the proposal and what problem it targets. I think this example might be slightly different because the modules are intended to be used together internally. But perhaps it is a common one?

Questions

  1. Do you have any advice on how to achieve similar layered access without the overhead of exposing public initializers in the first module?
  2. Are there any access level configurations for module dependencies that I'm missing?
  3. Do you have a suggestion about a more suitable way of structuring the code to achieve a similar effect?
1 Like

I'm biased as the author of SE-0189, but I think if you really have two modules, that implies that you actually might want to use ViewModels without using ConfiguredViewModels. If that's not the case, why not make them the same module? (Is it a compile time thing?)

1 Like

I can't speak to this specific use case, but putting code in a separate module is the only way to put a solid dependency boundary around it. On large scale projects this can be pretty important. Hopefully Swift has a lighter-weight solution to this someday.

I think the best long-term answer to the use case in question is to eventually revisit SE-0018. This would allow explicit control of the visibility of compiler-synthesized initializers. I would revisit that proposal someday but don't have bandwidth to work on implementation.

4 Likes

It is the case. We are using ViewModels configured differently in other targets (for integration and unit tests).

I agree with @anandabits, merging the modules is an option but it will make an explicit rule that we currently have that is enforced through the project structure, into a guideline that needs to be enforced manually.

Thanks for pointing me to SE-0018 - I didn't know about it and will spend some time reading through - it feels like something that should be revisited.