I have a project in OSS consisting of 20,000 lines of code and 300 classes. Also, These classes are divided into two modules: front-end and back-end.
A problem has recently arisen. It is that there are many classes in one module and it takes a long time to compile.
By changing just one line, Maven will try to rebuild all the classes in that module.
To solve this, I thought of further dividing it into several modules.
The current package configuration is as follows:
.
|
|-FrontModule/
|
|-BackEndModule/
| |-com.example.package/
| | |-resolver/
| | | |-...
| | |-loader/
| | |-installer/
| | |-BackendDaemon.java
We are considering refactoring this as follows:.
.
|
|-FrontModule/
|
|-BackEndModule/
| |-com.example.package/
| | |-BackendDaemon.java
|-ResolverModule/
| |-...
|-LoaderModule/
| |-...
|-InstallerModule/
| |-...
Currently, representative instances of resolver, loader, and installer are stored in BackendDaemon's constants.
The installer also operates using an instance of resolver in BackendDaemon.
In this situation, I believe that refactoring a package into a module will invariably result in interdependencies somewhere.
Is there any way or design to somehow split this huge code into modules?
I would appreciate it if someone could answer my question.
Also, since I am using a translator to translate from Japanese, if there are expressions that are difficult to understand or things that are not conveyed, please let me know.
Thank you.
A good way to do this is following the so-called onion architecture, see for example https://dev.to/barrymcauley/onion-architecture-3fgl. The basic idea is that you have your domain/service module at the core of your model. Being at the center means that it doesn't have any dependencies towards other modules. Around it you get in the first layer of modules where you put for example access to a database, then another layer with interfaces to other systems and finally user interfaces in the last layer of modules. The idea is that you only make dependencies that point inward and that way you prevent dependency loops.
I don't know what your application is about, but going by what you put in the question I'd say you have a domain module at the core, then a resolver in the 2nd layer. The next layer has your loader and installer. You already made the outermost layer in a separate module in the past, which is the front module.
Also keep in mind that you can use dependency inversion (the D of the famous SOLID acronym) to make sure that your dependencies point the right way. So if your domain module needs to resolve something, it'll use a 'ResolverInterface' from the domain module that is implemented by a class inside the resolver module. This way there is only a dependency from the resolver module towards the domain module. The dependency inversion framework (Spring is a very popular one) will make sure that the implementation of that 'ResolverInterface' will be available at runtime via Autowiring.
I think you should ask again why you want to split the project, using JRebel can optimize your compile time. Otherwise using a maven pom parent file with its submodules is a way! or even use other build tools or build flows with a little scripting. But I recommend organizing your project not only in IDE somehow conceptually, first pick an architecture base on your project scalability, prerequisites, and feature list then plan how to move step by step.
Related
is there a quick way to find (may be by using intellij or maven etc) all the interfaces (java) without any implementation.
I need to do above as we did some clean up of code where we removed a number of classes (and corresponding interfaces) which we think are not in use, but there could be the possibility that some interfaces may be left to be removed (due to manual error as it was huge clean up) which may be used by a bean which may cause run time exception. I am doing manual validation but if some automate way is present then it will be great.
regards
Sanjay
Try to perform (Analyze | Run Inspection by Name | Unsued declaration | Choose the necessary filters).
See the relevant documentation for more options.
We have a rather large-ish monolithic software we would like to refactor at a larger scale. First step will be to derive several artefacts, which can be compiled independently. Given the size of the application we would like to automate that as much as possible.
An example:
+ package1
| |
| + Service1
|
+ package2
| |
| + Service2
|
+ interfacepackage
Assuming, Service1 is only used from within package1, it should not be touched. Assuming Service2 is used from Service1 I would like to automatically generate a minimal interface for Service2, put that interface in the package interfacepackage and change the dependency within Service1 to the interface.
Doing this manually would be no trouble at all. Both Idea and Eclipse provide semi-automatic refactorings, but we would like to formulate them as meta-rules. I had hopes, that either eclipse or intellij have a programmatic interface to define such rules, but I have not been able to find them yet.
I have even found the eclipse refactoring scripts but these seem to be restricted to refactorings of named classes, so if I knew all services which should be refactored, eclipse refactoring scripts would help but not if I want to define conditions on classes to be refactored.
Where should I look for a solution?
Clarification: Comment: So what's your problem?
We have a high 3 digit number of services which make up this monolith. These are in approx. 20 different packages. The whole software is approaching 1 million lines of code. My problem is simply the size. Doing refactorings manually could take months, we might miss something doing it manually. Also, de-tangeling the services is the first step only. So we are expecting a lot of similar refactorings applied down the road.
IntelliJ IDEA has an "open api" that can be used for plugin development.
The advantage is that IntelliJ parses the java code, and the "meta model" is available to you as a plugin author.
In IntelliJ, the "AST" model refers to the "Abstract Syntax Tree". This structure is invaluable for plugins that do refactorings.
You can easily see the package structure, class names, code, and so on.
https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started.html
Note! Java functionality for plugin development has been externalised as a plugin.
https://blog.jetbrains.com/platform/2019/06/java-functionality-extracted-as-a-plugin/
Please also have a look at my own plugins on github, where I have posted the source code.
https://github.com/Steve-Murphy/unencapsulate-plugin
I'm fairly new to git and this might be a question with an obvious answer:
So I've got a project/framework I'm using to manage a bunch of automated test cases. So the folder code structure is below.
Java
|-Package1
|-Common code
|-tests
|- Client1 tests
|- Client2 tests
|
|
|- ClientN tests
Is it recommended to maintain client specific code in different branches? Or is it better to make a copy of the project and maintain in different repos per client? Basically each client has different tests written on top of same core using Selenium/TestNG.
Both options are possible but I think in here it is more a question of maintainability. I this case I would go for the separate repos approach but with an extra: git submodules
There are 2 reasons for choosing this approach:
complexity of maintaining separate branches. Each client would have a development workflow. That means you will probably have to branch off when you want to add a new feature to one of your clients from the existing client branch and things get messy. At some point you may start to confuse branches;
the second reason is keeping up with the common code; if you have the clients on separate branches how do you keep up with the common code updates? regular merges / rebases ... ? A lot more overhead on the long term than using separate git repos.
With the separate repos/submodule approach you would get something like this:
Common Code Repo ( referred to as CCR )
Client 1 Repo has CCR as submodule
Client 2 Repo has CCR as submodule
...
Client N Repo has CCR as submodule
Like this everything is managed independently and every project can have its own flow without having dependencies and messy branching structure.
In my project POM I have configured in build | plugins | plugin | configuration, the className tag that specifies one of the many classes for the services I want to offer. There are more though.
How do I configure the axis2-java2wsdl-maven-plugin to read multiple classes for all the services I wrote?
Not a good approach. There should be a separate WSDL for each service, otherwise it violates the concept of modularization. There are few suggestions for a workaround in this question.
Generating Single WSDL file for Multiple classes
Currently we have a project with a standard subversion repository layout of:
./trunk
./branches
./tags
However, as we're moving down the road of OSGi and a modular project, we've ended up with:
./trunk/bundle/main
./trunk/bundle/modulea
./trunk/bundle/moduleb
./tags/bundle/main-1.0.0
./tags/bundle/main-1.0.1
./tags/bundle/modulea-1.0.0
The 'build' is still quite monolithic in that it builds all modules in sequence, though I'm starting to wonder if we should refactor the build/repository to something more like:
./bundle/main/trunk
./bundle/main/tags/main-1.0.0
./bundle/main/tags/main-1.0.1
./bundle/modulea/trunk
./bundle/modulea/tags/modulea-1.0.0
In this pattern I would imagine each module building itself, and storing its binary in a repository (maven, ivy, or another path of the subversion repository itself).
Are there guidelines or 'best-practices' over project layouts once one goes modular?
The Subversion book contains two sections on this:
Repository Layout
Planning Your Repository Organization
A blog entry on the subject: "Subversion Repository Layout"
The short answer, though: while your mileage will vary (every situation is individual), your /bundle/<project>/(trunk|tags|branches) scheme is rather common and will likely work well for you.
This is very much up to personal preference, but I find the following structure suitable for large projects consisting of many modules:
branches
project-name
module1
branch-name
module2
possibly-another-branch-name
branch-name-on-a-higher-level-including-both-modules
module1
module2
tags
... (same as branches)
trunk
project-name
module1
module2
I have also often used the structure in large repositories containing many projects, because keeping all projects in the same repository makes cross-referencing projects and sharing code between them—with history—easier.
I like to use the structure with root trunk, tags and branches folders from the start because in my experience (with large repositories containing many projects), many sub-projects and modules will never have separate tags or branches, so there is no need to create the folder structure for them. It also makes it easier for the developers to check out the entire trunk of the repository and not get all the tags and branches (which they don't need most of the time).
I guess this is a matter of project or company policy though. If you have one repository for each project or a given developer is only likely to work on a single project in the repository at a time the rooted trunk may not make as much sense.
Just my two cents...
I just want to emphasize the comment in the SVN documentation (already quoted in another answer, same thread) http://svnbook.red-bean.com/en/1.4/svn.reposadmin.planning.html#svn.reposadmin.projects.chooselayout
The excerpt references the following structure :
/
trunk/
calc/
calendar/
spreadsheet/
…
tags/
calc/
calendar/
spreadsheet/
…
branches/
calc/
calendar/
spreadsheet/
"There's nothing particularly incorrect about such a layout, but it may or may not seem as intuitive for your users. Especially in large, multi-project situations with many users, those users may tend to be familiar with only one or two of the projects in the repository. But the projects-as-branch-siblings tends to de-emphasize project individuality and focus on the entire set of projects as a single entity. That's a social issue though. We like our originally suggested arrangement for purely practical reasons—it's easier to ask about (or modify, or migrate elsewhere) the entire history of a single project when there's a single repository path that holds the entire history—past, present, tagged, and branched—for that project and that project alone."
For my own, I tend to agree quite strongly with this and prefer the following layout:
/
utils/
calc/
trunk/
tags/
branches/
calendar/
trunk/
tags/
branches/
…
office/
spreadsheet/
trunk/
tags/
branches/
The reason are simply that its impractical to tag a complete project set when one would want to tag only a specific subset.
Let's use an example: If project-1 depends on moduleA v1.1 and moduleB v2.3, I don't want newer moduleA v2.x to appear in the tags. In fact, when coming back some days/weeks/months later to this tagged release, I would be forced to open the bundle descriptor in the tagged version of project-1 to read the version of moduleA actually required.
Moreover, if I have to make a specific backup of this release's sources onto a CD, I just want to export this tag without downloading hundreds of megabytes of unrelated stuff.
It was just my two cents.
I've answered a similar question in a StackOverflow Version Control Structure question. It actually fits even better here since we do heavy OSGi development and have lots of bundles. I must echo Anders Sandvig comments: keep trunk/tags/branches on the root level since you will only branch a limited set of modules. It also does not interfere with modules building individually.
I won't copy the answer I made before but it is entirely relevant to this question.