Improving Maintainability with Reusable Design in Devlime

Improving Maintainability with Reusable Design in Devlime

1. Background

Devlime development was conducted in a way that multiple developers work simultaneously, each responsible for their own features and domains. Since it is based on the Vizend platform, the project structure and basic development methods were somewhat unified, and the overall architecture was well established.

However, as the product scale increased and functionalities grew, there was a gradually increasing situation where modifying existing functions or analyzing code written by other developers became necessary. In this process, it was frequently observed that, despite being the same or very similar functions, they were implemented differently by each developer.

For example, the logic for querying specific data was used identically across multiple screens, but it was directly implemented in each service, and even though the UI for displaying statuses on the screens had similar functionalities, they used different styles and structures.

In the early stages of development, this approach was not a significant issue. However, as the number of functions increased, duplicated code quickly grew, and the situation of having to find and modify multiple locations to change the same functionality repeatedly occurred.

Moreover, the different representation methods on each screen resulted in a lack of consistency in the UI/UX experience that users felt.

Accordingly, improvements were made not just by focusing on implementing functions but by commonizing frequently used logic and UI to enhance reusability and reduce maintenance costs.

2. Issues with the Existing Approach

2.1 Backend

In the backend, even though the functionalities were identical, different implementation methods by developers led to the following problems.

Firstly, readability decreased. The code performing the same functionality was implemented in different forms, leading to a considerable amount of time spent for readers to understand the functionalities.

Secondly, there was a lack of reusability. Specific library API calls and common data query logic were redundantly implemented across multiple services. For instance, the logic for retrieving employee information was written directly in several services.

Member member = memberClient.findMember(citizenId);

This method led to the need to repeatedly write the same code every time a new feature was developed.

Thirdly, maintenance costs increased. Since the same functionality existed in various places, it became necessary to find and change all locations when modifications were required.

Fourthly, the likelihood of errors increased. Even though the logics were similar, there were cases where exception handling or validation logic were missing in some services, potentially leading to problems where the same functionality returned different results.

2.2 Frontend

Similar problems also existed in the frontend.

First, screens displaying the same information operated in different ways. For example, data such as Status, Priority, and Type were displayed differently on each screen.

Second, the UI/UX was not consistent. Even though they were components showing the same information, colors, styles, and layouts were applied differently on each screen.

Third, there was repetitive multilingual processing logic. Whenever displaying the Display Name of the Member object, separate language processing logic was written for each screen.

Fourth, common functionalities were not reused. Functions such as member profile, time representation, error handling, and pattern processing were duplicated across multiple screens.

3. Improvement Directions and Design

To solve the problems, we first analyzed the repeatedly used functionalities. In this process, the commonization targets could be broadly divided into backend and frontend.

3.1 Commonization Targets in Backend

In the backend, the following items were prioritized.

  • Enum Class

  • Library Client Usage Logic

  • Common Query Logic

  • Repeatedly Used Domain Functions

  • Common Task Logic

3.2 Frontend Common Target

The frontend has been standardized focusing on the following items.

  • Enum Representation Method

  • Status and Priority Display UI

  • Member Profile UI

  • Multilingual Processing Function

  • Timezone Processing Function

  • Grid Common Settings

  • Error Handling

Not only were functions standardized, but the design was also carried out to maintain consistency in user experience.

4. Implementation Process

4.1 Separation of Backend Common Modules

First, we standardized the logic for calling libraries that are used repeatedly. Previously, each service called libraries directly. Here is a simple example code.

Member member = memberClient.findMember(citizenId);

This was separated into the Extern layer.

@Service
@RequiredArgsConstructor
public class MemberExtern {

    private final MemberClient memberClient;

    public Member getMember(String citizenId) {
        return memberClient.findMember(citizenId);
    }
}

Through this, library dependencies can be managed in one place, and exception handling and post-processing logic were also standardized.

4.2 Improvement of Enum Representation

Previously, the Enum values were exposed directly on the screen.

Late
LeftEarly
HolidayWork

However, it was difficult to provide user-friendly displays, and any changes in the UI affected the domain, which was problematic. To resolve this, we separated the domain values from the UI display values.

LeftEarly("Early Leave")

Additionally, we improved the frontend to manage screen representations through a DisplayName Map. This allows for adjustments to the display without modifying the domain model even when screen changes are necessary.

4.3 Commonization of Multilingual Processing

We improved the approach of handling the Display Name of the Member object individually for each screen. Previously, each screen would directly determine the language.

After the improvement, we changed to processing through a common function.

getMemberDisplayName(member)

This allowed us to manage the multilingual processing logic in one place and minimized the scope of modifications when changing language policies.

4.4 Commonization of UI Components

We separated the frequently used member profile UI into a common component.

Previously, the creation of Avatars, calculation of initials, and configuration of Tooltips were implemented separately for each screen. After the improvement, we changed to using only one component. Specific UI/UX elements were grouped as components, and the flexibility within the component was increased through parameters.

<MemberProfileGroup
  members={members}
  maxVisible={10}
/>

This allowed us to ensure consistency in screen design and provide the same user experience even in new screens.

5. Results of Implementation

After applying reusable code design, we were able to observe the following effects.

First, development productivity improved. Previously, every time a new feature was developed, similar logic had to be reimplemented, but by utilizing common modules and components, development time was significantly reduced.

Second, maintainability has been improved. With common logic gathered in one place, it has become easier to identify the scope of impact during modifications, reducing redundant modification tasks.

Third, code quality has improved. By using a single implementation method for the same functionality, exception handling and validation logic could be applied consistently.

Fourth, UI/UX consistency has improved. By providing common features such as status display, member information, and multilingual support in the same way, we were able to ensure uniformity in user experience.

Finally, the organized content from the standardization process was shared as a Notion document to ensure that team members could develop based on the same criteria. This has laid the foundation for improving not just simple code reuse, but the overall development productivity and maintainability of the team.

Bignow

Site footer