객체지향적 코드 개선: Setter 지양과 명령형 메서드 사용

Yu Seong Kim·2024년 8월 21일
0

SpringBoot

목록 보기
23/29

이번에는 기존에 사용하던 getter/setter 중심의 코드에서 벗어나, 객체지향적인 설계 원칙을 따르는 코드로 개선하는 과정을 공유하려고 합니다. 특히, Java와 Spring Boot 환경에서 setter 사용을 지양하고 명령형 메서드를 활용하여 코드를 더욱 가독성 있고 유지보수하기 쉽게 만드는 방법을 다룹니다.

기존 코드 -> Setter 중심의 설계

프로젝트를 진행하면서 Getter/Setter를 활용해 객체의 상태를 관리하였습니다.
저는 같은 패턴, 비슷한 코드 작성 방식으로 프로젝트를 진행하였고, api 기능만 잘 되는 것을 넘어서 객체지향적 코드를 유지하면서 기능까지 되면 더 좋을 것 같다고 생각했습니다.

사실, 이런 코드는 작성하기는 쉽지만, 객체지향적인 설계 원칙에서는 객체의 상태를 직접 노출하고 관리하기 때문에 캡슐화가 부족할 수 있습니다.

@Service
@Slf4j
@RequiredArgsConstructor
public class SignServiceImpl implements SignService {
    private final JavaMailSender javaMailSender;
    private Logger logger = LoggerFactory.getLogger(SignServiceImpl.class);
    private final JwtProvider jwtProvider;
    private final SignDao signDao;
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    @Override
    public ResultDto SignUp(SignUpDto signUpDto, HttpServletRequest request) {
        User user = (User) request.getSession().getAttribute("user");
        ResultDto resultDto = new ResultDto();
        if (user != null) {
            user.setUserName(signUpDto.getName());
            user.setGender(signUpDto.getGender());
            user.setBirth(signUpDto.getBirth());
            user.setPassword(passwordEncoder.encode(signUpDto.getPassword()));
            user.setWeight(signUpDto.getWeight());
            user.setHeight(signUpDto.getHeight());
            user.setNickName(signUpDto.getNickname());
            user.setPhoneNumber(signUpDto.getPhoneNumber());
            user.setLoginMethod("Normal");
            user.setCreate_At(LocalDateTime.now());
            user.setUpdate_At(LocalDateTime.now());
            signDao.saveSignUpInfo(user);

            resultDto.setDetailMessage("회원가입 완료");
            setSuccess(resultDto);
        } else {
            resultDto.setDetailMessage("회원가입 실패");
            setFail(resultDto);
            throw new IllegalArgumentException();
        }

        return resultDto;
    }
    // 기타 메서드들...
}

위 코드는 명확하게 보이지만, 객체의 내부 상태를 외부에서 변경할 수 있게 하는 setter 사용이 많습니다.
이는 객체의 자율성을 해칠뿐만 아니라 유지보수 시 실수를 초래할 수 있습니다.

개선된 코드: 명령형 메서드를 통한 상태 관리

객체지향적 설계를 위해 setter를 지양하고, 객체 내부에서 상태를 관리할 수 있도록 명령형 메서드를 도입했습니다. 이를 통해 객체는 자신의 상태를 더 잘 관리할 수 있게 되며, 캡슐화가 강화됩니다.

User 엔티티 개선

기존 User 엔티티에 saveProfile 메서드를 추가하였습니다.

    public void saveProfile(String name, String gender, String birth, String nickname, String phoneNumber, String height, String weight, String encodedPassword) {
        this.userName = name;
        this.gender = gender;
        this.birth = birth;
        this.nickName = nickname;
        this.phoneNumber = phoneNumber;
        this.height = height;
        this.weight = weight;
        this.password = encodedPassword;
    }

개선된 회원가입 코드: 리팩토링을 통한 가독성과 유지보수성 향상

이전 코드는 setter를 많이 사용할 뿐만 아니라, 중복되는 코드가 많이 존재하였습니다. 그렇기 때문에 많은 setter 호출로 인한 코드의 흐름이 매우 복잡해지고, 메서드 목적이 명확히 드러나지 않았습니다. 또한 여러 곳에서 코드를 수정해야할 문제가 발생할 가능성이 많습니다.

다음과 같이,
리팩토링하여 개선한 코드는 사용자의 여러 속성을 한 번에 설정할 수 있도록 하였습니다.

    @Override
    public ResultDto SignUp(SignUpDto signUpDto, HttpServletRequest request) {
        User user = (User) request.getSession().getAttribute("user");
        ResultDto resultDto = new ResultDto();

        if (user != null) {
            // User 객체 내부에 상태 변경 메서드들을 사용
            user.saveProfile(
                    signUpDto.getName(),
                    signUpDto.getGender(),
                    signUpDto.getBirth(),
                    signUpDto.getNickname(),
                    signUpDto.getPhoneNumber(),
                    signUpDto.getHeight(),
                    signUpDto.getWeight(),
                    passwordEncoder.encode(signUpDto.getPassword())
            );
            user.setLoginMethod("Normal");
            user.updateTimestamps(LocalDateTime.now());

            signDao.saveSignUpInfo(user);

            resultDto.setDetailMessage("회원가입 완료");
            setSuccess(resultDto);
        } else {
            resultDto.setDetailMessage("회원가입 실패");
            setFail(resultDto);
            throw new IllegalArgumentException("User not found in session");
        }

        return resultDto;
    }

즉, 개선한 코드는 다음과 같은 장점이 존재합니다.

  1. 코드 가독성 향상: saveProfile 메서드를 통해 사용자의 프로필 정보를 한 번에 설정하므로, 코드의 흐름이 명확해졌습니다. 이제 SignUp 메서드를 읽을 때, 사용자의 프로필을 설정하는 부분이 더 직관적입니다.

  2. 중복 제거: 반복적인 setter 호출이 제거되어 코드가 간결해졌습니다. 이는 코드 유지보수성을 높이는 데 기여합니다.

  3. 유지보수성 향상: 필드가 추가되거나 변경될 때 saveProfile 메서드만 수정하면 되므로, 코드의 유지보수가 훨씬 용이해졌습니다.

결론

이렇게 setter를 지양하고 명령형 메서드를 도입함으로써, 코드의 가독성을 높이고 유지보수성을 향상시킬 수 있었습니다. 객체지향적인 설계를 따르는 코드로 개선한 후에는 코드가 더 직관적이며, 객체의 상태를 안전하게 관리할 수 있다는 장점이 있습니다.

리팩토링은 단순히 코드를 줄이는 것이 아니라, 코드의 가독성과 유지보수성을 높이기 위한 중요한 과정이라 생각했습니다. 이번 리팩토링을 통해 기존의 반복적이고 읽기 어려운 코드를 개선하여, 더 직관적이고 유지보수하기 쉬운 코드를 만들 수 있었습니다. 앞으로도 코드의 품질을 높이기 위해 리팩토링을 지속적으로 적용할 예정입니다.

마지막으로 자신의 코드와 남들의 코드를 여러 번 비교하면서 배웁시다.

profile
Development Record Page

0개의 댓글