Search
Duplicate

3. [클린 코드 with Java] 2단계 - 문자열 덧셈 계산기를 통한 TDD 실습

링크
점수
⭐️⭐️⭐️⭐️
완료일
2023/04/13
상태
완료
유형
인강

문자열 덧셈 계산기를 통한 TDD 실습

기능 요구사항

쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환 (예: “” => 0, "1,2" => 3, "1,2,3" => 6, “1,2:3” => 6)
앞의 기본 구분자(쉼표, 콜론)외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 “//”와 “\n” 사이에 위치하는 문자를 커스텀 구분자로 사용한다. 예를 들어 “//;\n1;2;3”과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
문자열 계산기에 숫자 이외의 값 또는 음수를 전달하는 경우 RuntimeException 예외를 throw한다.

프로그래밍 요구사항

메소드가 너무 많은 일을 하지 않도록 분리하기 위해 노력해 본다.

코드 구성

작성코드

피드백

1) static final 키워드를 붙여서 상수로
2) 숫자를 구분하는 ‘구분 문자’라는 것을 좀 더 명확하게
네이밍 관련 링크
import java.util.regex.Pattern; public class StringAddCalculator { private String regex = ",|:";
Java
복사
다음과 같이 변경
public class StringAddCalculator { private static final String DELIMITER = ",|:"; private static final String CUSTOM_DELIMITER = "//(.)\n(.*)";
Java
복사
3) 매번 계산할 때마다 Pattern 인스턴스를 생성하는 대신에, 미리 하나의 인스턴스를 생성해놓고 이를 재사용
if (Objects.isNull(input)) { return; } matcher = Pattern.compile("//(.)\n(.*)").matcher(input);
Java
복사
다음과 같이 변경
public class StringAddCalculator { private static final String DELIMITER = ",|:"; private static final String CUSTOM_DELIMITER = "//(.)\n(.*)"; private static final Pattern CUSTOM_DELIMITER_PATTERN = Pattern.compile(CUSTOM_DELIMITER); private String[] splitString(String input) { String delimiter = DELIMITER; Matcher matcher = CUSTOM_DELIMITER_PATTERN.matcher(input); if (isPatternMatch(matcher)) { delimiter = changeDelimiter(matcher); input = changeInput(matcher); } return input.split(delimiter); }
Java
복사
4) 상수 변경 및 멤버변수 지역변수로 변경
숫자 12 는 상수로 선언해서 의미를 부여해보자.
멤버 변수를 → 지역변수로 변경
private void changeRegex(Matcher matcher) { regex = matcher.group(1); } // 입력값 변경하기 private void changeStringInput(Matcher matcher) { StringInput = matcher.group(2); }
Java
복사
다음과 같이 변경
public class StringAddCalculator { private static final int ZERO = 0; private static final int FIRST = 1; private String changeDelimiter(Matcher matcher) { return matcher.group(FIRST); } // 입력값 변경하기 private String changeInput(Matcher matcher) { return matcher.group(SECOND); }
Java
복사
5)객체지향 생활 체조 원칙의 규칙 1: 한 메서드에 오직 한 단계의 들여쓰기만 한다.
for (int i = 0; i < strings.length; i++) { arr[i] = Integer.parseInt(strings[i]); if (arr[i] < 0) { throw new RuntimeException("음수가 입력되었습니다. 입력숫자를 확인해주세요."); } }
Java
복사
다음과 같이 변경
private int[] convertToNumberArray(String[] strings) { int [] arr = new int[strings.length]; for (int i = 0; i < strings.length; i++) { arr[i] = Integer.parseInt(strings[i]); throwExceptionIfNegative(arr[i]); } return arr; } private void throwExceptionIfNegative(int input) { if (input < 0) { throw new RuntimeException("음수가 입력되었습니다. 입력숫자를 확인해주세요."); } }
Java
복사
6)null 또는 빈 문자열을 테스트할 경우, @NullAndEmptySource 라는 어노테이션을 활용해보는 걸 추천
@Test @DisplayName("null 또는 빈 문자열 입력시 splitAndSum 체크") public void splitAndSum_null_또는_빈문자() { int result = stringAddCalculator.splitAndSum(null); assertThat(result).isEqualTo(0); result = stringAddCalculator.splitAndSum(""); assertThat(result).isEqualTo(0); }
Java
복사
다음과 같이 변경
@ParameterizedTest @DisplayName("null 또는 빈 문자열 입력시 splitAndSum 체크") @NullAndEmptySource public void splitAndSum_null_또는_빈문자(String text) { int result = stringAddCalculator.splitAndSum(text); assertThat(result).isEqualTo(0); }
Java
복사
7) 파일 끝에는 개행을 해야된다.
8) 다음과 같이 줄일 수 있다.
if (Objects.isNull(input) || "".equals(input)) { return true; } return false;
Java
복사
다음과 같이 변경
private boolean isNotValidValue(String input) { return Objects.isNull(input) || "".equals(input); }
Java
복사

피드백 이후 소스코드

소스코드

후기

오늘은 문자열 덧셈 계산기를 이용한 소스코드를 작성하였다.
기존의 소스코드의 습관이란, 고치기 힘든것 같다. 습관을 고치기위해서는 항상 인지하고, 이해하고 고치려고 노력해야 되는 것 같다. 위에 보여주는 예시를 항상 기억하고, 고치려고 마음 먹어보자.
깃허브 링크
4211
pull
출처