You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In a large application there may be code that has the following qualities:
Is complex, yet has a very small and simple interface through which it is accessed
Internals of the implementation are isolated (i.e. the rest of the code depends only on said interface + e.g. single constructor call to create the instance implementing the interface)
Changes rarely
Can be tested in isolation of the rest of the app (and possibly there are a lot of tests)
The first examples of such functionality that come into my mind are e.g.:
Optimization algorithms (the rest of the app only uses the produced optimal result, not the steps needed to arrive there)
Code dealing with importing some data from various file formats (the rest of the app only cares about the imported data, not where it came from or what logic was involved to produce it)
The goal then is to unburden the app by extracting such loosely-coupled part of the codebase code into a separate Java library (published as a JAR file and included as a dependency in the app).
The code there is identical to the case-1, except the implementation details of the PV module layout algorithm were removed (they are irrelevant to this scenario).
While normally there would be a separate project for the library, here I simply moved the classes into a com.company.library package.
Thought process
The app has the following as top-level concepts: RoofFace, PvModuleDefinition, PvModulePosition. They are central to the whole app and would offer a lot more behavior than the example code shows.
At the same time, objects representing these concepts are the input/output of the algorithm we want to extract into a library.
Therefore it seems:
Extracting these shared concepts into the new library would not work, as they have a lot of behavior unrelated to the functionality of the library
Extracting these shared concepts into a separate library (on which both the app and the algorithm library would depend) would technically work, but it would unnecessarily hinder the evolution of the top-level domain concepts in the app (as we'd then have to update 2-3 places instead of 1)
The only option remaining seems to be to create an alternative object model representing the same concepts in the library (likely having a much narrower view of these concepts - e.g. if a RoofFace offers 10 methods in the app model, in the library it maybe be enough if it had just 1 or 2 methods).
In the example app I created two variations of this:
Variation A (see LibraryVariantAPvModuleLayouts) uses Java records for the library model
The usage in LibraryVariantACallingPvModuleLayouts then is very simple for both inputs and outputs
Variation B (see LibraryVariantBPvModuleLayouts) defines interfaces for the library model
The example implementation (LibraryVariantBCallingPvModuleLayouts) has to additionally adapt app's model to the library's model, which bloats the implementation a little.
An alternative could be for the app's core interfaces to extend from library's interfaces (meaning "a roof face concept in the app at the same is a roof face concept of the library"), which would remove the need for adapting input (but would still require adapting the output), but at the same time it would push a rather insignificant detail from the library all the way up into the most central app's interfaces. This does not seem desirable.
Discussion
Having multiple representations of the same concept (e.g. RoofFace) in a single app (including the library) does not seem desirable, yet I don't see a clean way to avoid it.
From the perspective of Domain-Driven Design (DDD), maybe the library would even be considered its own Bounded Context (as it has its own language - those 3 concepts were slightly redefined in the library)? This would seem to be a somewhat unexpected implication of a refactoring done for purely technical reasons.
Or maybe there is some better way to extract a part of a codebase into a library?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Context
In a large application there may be code that has the following qualities:
The first examples of such functionality that come into my mind are e.g.:
The goal then is to unburden the app by extracting such loosely-coupled part of the codebase code into a separate Java library (published as a JAR file and included as a dependency in the app).
Example code
See case-2 module.
The code there is identical to the
case-1
, except the implementation details of the PV module layout algorithm were removed (they are irrelevant to this scenario).While normally there would be a separate project for the library, here I simply moved the classes into a
com.company.library
package.Thought process
The app has the following as top-level concepts:
RoofFace
,PvModuleDefinition
,PvModulePosition
. They are central to the whole app and would offer a lot more behavior than the example code shows.At the same time, objects representing these concepts are the input/output of the algorithm we want to extract into a library.
Therefore it seems:
The only option remaining seems to be to create an alternative object model representing the same concepts in the library (likely having a much narrower view of these concepts - e.g. if a
RoofFace
offers 10 methods in the app model, in the library it maybe be enough if it had just 1 or 2 methods).In the example app I created two variations of this:
LibraryVariantAPvModuleLayouts
) uses Java records for the library modelLibraryVariantACallingPvModuleLayouts
then is very simple for both inputs and outputsLibraryVariantBPvModuleLayouts
) defines interfaces for the library modelLibraryVariantBCallingPvModuleLayouts
) has to additionally adapt app's model to the library's model, which bloats the implementation a little.Discussion
RoofFace
) in a single app (including the library) does not seem desirable, yet I don't see a clean way to avoid it.Beta Was this translation helpful? Give feedback.
All reactions