Home > Back-end >  How to avoid duplicate code with a helper-method for shared REST-operations like GET and DELETE
How to avoid duplicate code with a helper-method for shared REST-operations like GET and DELETE

Time:01-14

I have two methods

  • methodOne (e.g. for a GET on questionaire)
  • methodTwo (e.g. for a DELETE on questionaire)

Both have almost same lines of code.

IntelliJ also underlines the code and shows a warning:

duplicated code fragment

methodOne

@Override
public QuestionnaireDTO methodOne(long projectManagerId, long questionnaireId) {

    //the part I want to write into a helper method
    ProjectManager projectManager = projectManagerRepository.findById(projectManagerId).orElseThrow(
            () -> new ResourceNotFoundException("ProjectManager", "id", projectManagerId));

    Questionnaire questionnaire = questionnaireRepository.findById(questionnaireId).orElseThrow(() ->
            new ResourceNotFoundException("Questionnaire", "id", questionnaireId));

    if(!questionnaire.getProjectManager().getId().equals(projectManager.getId())){
        throw new QuestionnaireApiException(HttpStatus.BAD_REQUEST, "Questionnaire not belonging to Project Manager");
    }
    // end of helper method

    // return of methodOne 
    return mapToDto(questionnaire);
    
}

methodTwo

@Override
public QuestionnaireDTO methodTwo(long projectManagerId, long questionnaireId) {

    //the part I want to write into a helper method
    ProjectManager projectManager = projectManagerRepository.findById(projectManagerId).orElseThrow(
            () -> new ResourceNotFoundException("ProjectManager", "id", projectManagerId));

    Questionnaire questionnaire = questionnaireRepository.findById(questionnaireId).orElseThrow(() ->
            new ResourceNotFoundException("Questionnaire", "id", questionnaireId));

    if(!questionnaire.getProjectManager().getId().equals(projectManager.getId())){
        throw new QuestionnaireApiException(HttpStatus.BAD_REQUEST, "Questionnaire not belonging to Project Manager");
    }
    // end of helper method

    // return of methodTwo 
    return questionnaireRepository.delete(questionnaire);
    
}

Questions

I want to write the duplicated part of the code (enclosed in comments above) into a helper method. I want to avoid duplicate code but I'm not sure how to structure the helper method.

How can I achieve it?

CodePudding user response:

You can actually just move the code 1:1 to a new method:

public QuestionnaireDTO methodTwo(long projectManagerId, long questionnaireId) {
    return mapToDto(findById(projectManagerId, questionnaireId));
}

public QuestionnaireDTO methodOne(long projectManagerId, long questionnaireId) {
    return questionnaireRepository.delete(findById(projectManagerId, questionnaireId));
}

private QuestionnaireDTO findById(long projectManagerId, long questionnaireId) {
    ProjectManager projectManager = projectManagerRepository.findById(projectManagerId).orElseThrow(
            () -> new ResourceNotFoundException("ProjectManager", "id", projectManagerId));

    Questionnaire questionnaire = questionnaireRepository.findById(questionnaireId).orElseThrow(() ->
            new ResourceNotFoundException("Questionnaire", "id", questionnaireId));

    if(!questionnaire.getProjectManager().getId().equals(projectManager.getId())){
        throw new QuestionnaireApiException(HttpStatus.BAD_REQUEST, "Questionnaire not belonging to Project Manager");
    }

    return questionnaire;
}

CodePudding user response:

The shared code can return a Questionnaire object or throw a ResourceNotFoundException:

private Questionnaire findQuestionnaire(long projectManagerId, long questionnaireId) {
    ProjectManager projectManager = projectManagerRepository.findById(projectManagerId).orElseThrow(
            () -> new ResourceNotFoundException("ProjectManager", "id", projectManagerId));

    Questionnaire questionnaire = questionnaireRepository.findById(questionnaireId).orElseThrow(() ->
            new ResourceNotFoundException("Questionnaire", "id", questionnaireId));

    if (!questionnaire.getProjectManager().getId().equals(projectManager.getId())){
        throw new QuestionnaireApiException(HttpStatus.BAD_REQUEST, "Questionnaire not belonging to Project Manager");
    }
    
    // return questionnaire if both IDs are valid
    return questionnaire;
}

CodePudding user response:

TL;DR: When IntelliJ warns about "duplicated code fragment" then Extract Method refactoring is a solving IDE-shortcut.


Always pays-off to add more context like used IDE and shown error-message to the question.

Before posted answers (from knittl and mureinik) show you the resulting code: definition of extracted helper-method findById and its usage in given methods methodOne and methodTwo.

This answer shows how IntelliJ supports you to follow the DRY principle and avoid duplication (most other IDEs have similar functions).

Extract Method refactoring

A common refactoring method, to either break code up and improve readability or to avoid duplication and follow DRY is: Extract Function or Extract Method

IntelliJ IDEA has an action for Extract Method:

The Extract Method refactoring lets you take a code fragment that can be grouped, move it into a separated method, and replace the old code with a call to the method.

To use the refactoring technique Extract Method select the code-block you want to extract (e.g. code enclosed in your given comments). Then you can choose among 4 ways as you prefer:

  • hover over the code (sometimes bulb-symbol appears) and press Alt Enter to show Intention Actions
  • right-click to open the context-menu, then navigate to: refactor, extract-method
  • Find action (Win/Linux: Ctrl Shift A) by name "Extract Method"
  • press the keyboard-shortcut for Extract Method action Ctrl Alt M (Win/Linux, different on Mac)

See also: 3 Ways to Refactor Your Code in IntelliJ IDEA | The IntelliJ IDEA Blog.

Intention Actions help on errors in IntelliJ

Since this error-message is shown as a result of IntelliJ's Code Inspection, it might be prepared to help you solving it.

In many cases (like here) these 1-2 steps are the quickest way from error to fix:

  1. Jump to issues/errors in code pressing F2 (Win/Linux). Those issues/errors can also be found by yellow gutter-marker or a red gutter-marker and bulb-symbol showing up.
  2. Use Intention Actions: Click on the bulb-symbol or press Alt Enter (Win/Linux) to show IntelliJ's Intention Actions. Select "Extract method from duplicate code"

See also: IntelliJ IDEA Documentation: Analyze duplicates to learn about IDE-support in finding and fixing duplication.

When and how extract-method in IntelliJ works

First a modal-dialog opens where you can enter the name of the method. Usually IntelliJ suggests the name and parameters that are used as input.

More important is the return-value or output. A method or function can only be extracted if either no or exactly one single return-value or output can be determined. In you case Questionnaire questionnaire is the singular output.

After confirming the dialog, your extracted helper-method was created by IntelliJ and all previous locations from where the code was extracted are replaced by a respective method-call.

  • Related