Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Refactored: Implementation and Design Smells #1636

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

akshat799
Copy link

Implementation Smell Refactoring:

  1. Refactoring Type: Extract Method
  • Location: initializr-web/src/main/java/io/spring/initializr/web/support/DefaultDependencyMetadataProvider.java
    
  • Smell Type: Complex Method
    
  • Class Name: DefaultDependencyMetadataProvider
    
  • Method Name: get
    
  • Line: 41
    
  • Reason: The original `DefaultDependencyMetadataProvider` class had a `get` method with a cyclomatic complexity of 9, making it complex, hard to read, and difficult to test. Refactoring using the Extract Method technique split it into `getDependencies`, `getRepositoriesDependencies`, and `getBoms`, reducing complexity and improving maintainability. This enhanced readability, reusability, and testability while adhering to the Single Responsibility Principle.
    
  1. Refactoring Type: Decompose conditional
  • Location: initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriter.java
    
  • Smell Type: Complex Conditional
    
  • Class Name: MavenBuildWriter
    
  • Method Name: get
    
  • Line: 358
    
  • Reason: The original code had a long and complex conditional statement checking multiple attributes of `MavenBuild` and `MavenBuildSettings`, making it harder to read and maintain. To improve clarity, I extracted separate methods—`isBuildEmpty()` and `isBuildSettingsEmpty()`—to handle the different aspects of the condition. This decomposition makes the logic more readable, modular, and easier to modify in the future. Now, the `writeBuild` method focuses on its primary purpose while delegating condition checks to dedicated helper methods.
    
  1. Refactoring Type: Introduce explaining variable
  • Location: initializr-generator/src/main/java/io/spring/initializr/generator/version/VersionParser.java
    
  • Smell Type: Complex Conditional
    
  • Class Name: VersionParser
    
  • Method Name: findLatestVersion
    
  • Line: 143
    
  • Reason: Introducing explaining variables breaks down complex logic into smaller, self-explanatory parts, which improves the overall readability of the code. By refactoring the lambda in the findLatestVersion method to as#termediate boolean values, it becomes clear what each condition is checking for, reducing cognitive load for future maintainers. This method of refactoring not only simplifies understanding but also aids in debugging and modifying the logic as requirements evolve.
    

Design Smell Refactoring:

  1. Refactoring Type: Pull Up Method
  • Location: initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/gradle/GradleBuild.java , initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenBuild.java
    
  • Class Name: GradleBuild and MavenBuild
    
  • Smell Type: Duplicate Code / Missing Abstraction
    
  • Method Name: plugins, extensions
    
  • New Interface Name: BuildExtensionsAndPlugins
    
  • New Interface Location: initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/BuildExtensionsAndPlugins.java
    
  • Reason: The purpose of creating this interface is to enforce a common contract between the build implementations. By abstracting out the common methods (extensions() and plugins()), we reduce duplicated code and simplify client code that interacts with both Maven and Gradle builds, allowing for easier maintenance and extension in the future.
    
  1. Refactoring Type: Extract Class
  • Location: initializr-web/src/main/java/io/spring/initializr/web/project/DefaultProjectRequestToDescriptionConverter.java
    
  • Class Name: DefaultProjectRequestToDescriptionConverter
    
  • Smell Type: Long Class/ Feature Concentration
    
  • Method Name: validate, validatePlatformVersion, validateType, validateLanguage, validatePackaging, validateDependencies
    
  • New Class Name: ProjectRequestValidator
    
  • New Class Location: initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestValidator.java
    
  • Reason: I refactored the code by extracting the validation logic from the DefaultProjectRequestToDescriptionConverter class into a new ProjectRequestValidator class to separate responsibilities, improving maintainability, readability, and testability.
    
  1. Refactoring Type: Push Down Method
  • Location: initializr-generator/src/main/java/io/spring/initializr/generator/language/Language.java
    
  • Interface Name: Language
    
  • Smell Type: Unutilized Abstraction
    
  • Method Name:jvmVersion
    
  • Class Name where the methods are shifted to: AbstractLanguage
    
  • Class Location: initializr-generator/src/main/java/io/spring/initializr/generator/language/AbstractLanguage.java
    
  • Reason: The language interface was implemented by 4 different classes but utilized by only abstractLanguage by Overriding it. So I am moving the jvmversion method to this abstract class.
    

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 28, 2025
@mhalbritter
Copy link
Contributor

There are a lot of new POM files (e.g. initializr-actuator/.flattened-pom 2.xml), please remove those.

Copy link
Contributor

@mhalbritter mhalbritter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @akshat799 , I've left some comments for your consideration.

@@ -86,7 +87,8 @@ private GradleBuild createGradleBuild(BuildItemResolver buildItemResolver,

@Bean
public BuildCustomizer<GradleBuild> defaultGradleBuildCustomizer(ProjectDescription description) {
return (build) -> build.settings().sourceCompatibility(description.getLanguage().jvmVersion());
return (build) -> build.settings()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that improves things. Please revert.

@@ -46,7 +47,7 @@ public DefaultMavenBuildCustomizer(ProjectDescription description, InitializrMet
public void customize(MavenBuild build) {
build.settings().addOverrideIfEmpty(true);
build.settings().name(this.description.getName()).description(this.description.getDescription());
build.properties().property("java.version", this.description.getLanguage().jvmVersion());
build.properties().property("java.version", ((AbstractLanguage) this.description.getLanguage()).jvmVersion());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that improves things. Please revert.

@@ -100,7 +100,8 @@ public KotlinProjectSettings kotlinProjectSettings(ObjectProvider<KotlinVersionR
String kotlinVersion = kotlinVersionResolver
.getIfAvailable(() -> new InitializrMetadataKotlinVersionResolver(metadata))
.resolveKotlinVersion(this.description);
return new SimpleKotlinProjectSettings(kotlinVersion, this.description.getLanguage().jvmVersion());
return new SimpleKotlinProjectSettings(kotlinVersion,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that improves things. Please revert.

@@ -46,7 +46,7 @@ public String id() {
return this.id;
}

@Override
// @Override
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert.

* @return the JVM version or {@value DEFAULT_JVM_VERSION} if not set
*/
String jvmVersion();
// /**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert.

* @param <P> the type of the plugin container
* @author Akshat Gulati
*/
public interface BuildExtensionsAndPlugins<E, P> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for that abstraction? I can't see any usages of it.

@@ -37,7 +37,7 @@ void javaLanguage() {
assertThat(java).isInstanceOf(JavaLanguage.class);
assertThat(java.id()).isEqualTo("java");
assertThat(java.toString()).isEqualTo("java");
assertThat(java.jvmVersion()).isEqualTo("11");
assertThat(((JavaLanguage) java).jvmVersion()).isEqualTo("11");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that improves things. Please revert.

@@ -46,7 +46,7 @@ void kotlinLanguage() {
assertThat(kotlin).isInstanceOf(KotlinLanguage.class);
assertThat(kotlin.id()).isEqualTo("kotlin");
assertThat(kotlin.toString()).isEqualTo("kotlin");
assertThat(kotlin.jvmVersion()).isEqualTo("1.8");
assertThat(((KotlinLanguage) kotlin).jvmVersion()).isEqualTo("1.8");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that improves things. Please revert.

@@ -55,7 +55,7 @@ void groovyLanguage() {
assertThat(groovy).isInstanceOf(GroovyLanguage.class);
assertThat(groovy.id()).isEqualTo("groovy");
assertThat(groovy.toString()).isEqualTo("groovy");
assertThat(groovy.jvmVersion()).isEqualTo("1.8");
assertThat(((GroovyLanguage) groovy).jvmVersion()).isEqualTo("1.8");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that improves things. Please revert.

@@ -274,7 +275,7 @@ void convertShouldSetLanguageForProjectDescriptionFromRequest() {
request.setJavaVersion("1.8");
ProjectDescription description = this.converter.convert(request, this.metadata);
assertThat(description.getLanguage().id()).isEqualTo("java");
assertThat(description.getLanguage().jvmVersion()).isEqualTo("1.8");
assertThat(((AbstractLanguage) description.getLanguage()).jvmVersion()).isEqualTo("1.8");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that improves things. Please revert.

@mhalbritter
Copy link
Contributor

mhalbritter commented Mar 31, 2025

You also need to sign the commits, as explained here.

@mhalbritter mhalbritter added the status: waiting-for-feedback We need additional information before we can continue label Mar 31, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
status: waiting-for-feedback We need additional information before we can continue status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants