[우아한테크코스 7기 백엔드] 1주차 프리코스 회고 - 문자열 덧셈 계산기
제출(PR 링크 & 소감문)
PR 링크
우아한테크코스 1주차 프리코스를 진행한 뒤 제출 한 PR링크입니다.
https://github.com/woowacourse-precourse/java-calculator-7/pull/617
[문자열 덧셈 계산기] 서해윤 미션 제출합니다. by haennni · Pull Request #617 · woowacourse-precourse/java-cal
github.com
소감문
우아한테크코스 1주차 프리코스를 진행한 뒤 제출 한 소감문입니다.

미션
우아한테크코스 7기 백엔드 프리코스 1주차 미션
과제 - 문자열 덧셈 계산기
입력한 문자열에서 숫자를 추출하여 더하는 계산기를 구현한다.
- 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환한다.
- 예: "" => 0, "1,2" => 3, "1,2,3" => 6, "1,2:3" => 6
- 앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 "//"와 "\n" 사이에 위치하는 문자를 커스텀 구분자로 사용한다.
- 예를 들어 "//;\n1;2;3"과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료되어야 한다.
입출력 요구 사항
입력
- 구분자와 양수로 구성된 문자열
출력
- 덧셈 결과
실행 결과 예시
덧셈할 문자열을 입력해 주세요.
1,2:3
결과 : 6
요구사항 정의
프리코스 1주차 과제를 진행하며 코드를 무작정 작성하면 시간이 오래 걸릴 것 같아 먼저 요구사항을 정의하고 코드 구현을 하는 게 좋겠다고 생각하여 정리를 하였습니다!
객체지향적으로 설계를 하고자하여 main클래스에서 코드를 다 작성하는 것이 아닌 역할별로 클래스를 나누어서 메인 클래스에서 의존성을 주입받아 결과를 반환하는 식으로 작성을 해보았는데요. 빈 문자열이 들어오면 0을 반환해주거나, 사용자가 입력을 잘못한 경우(음수를 입력하거나 구분자 외의 문자열을 입력했을 시) IllegalArgumentException 예외를 터트리는 검증 처리를 Validation 클래스에서, 기본 구분자로 파싱을 해주거나, 사용자가 커스텀구분자를 지정한 경우 커스텀 구분자를 구분자 상수에 등록하고 파싱을 해주는 기능을 InputParser클래스 에서 구현하였습니다.
그리고 최종적으로 입력 값을 덧셈해주는 기능은 Application 클래스에서 Validation과 InputParser를 통해 add() 메소드를 통해서 구현하도록 설계하였습니다!

기능 구현
Validator.class
- 빈 문자열 확인
- 유효성 검사
- 숫자가 아닌 문자열이 들어왔는지 확인
public class Validator {
/*1.빈 문자 확인*/
public boolean isNull(String input) {
return input.isEmpty();
}
/*2.유효성 검사*/
public void validation(String[] numbers) {
for (String num : numbers) {
if (!isNumeric(num)){
throw new IllegalArgumentException("숫자가 아닌 값이 포함되었습니다.");
}
if (Integer.parseInt(num) < 0) {
throw new IllegalArgumentException("음수가 입력되었습니다. 양수만 입력해주세요.");
}
}
}
private boolean isNumeric(String str) {
try {
Integer.parseInt(str);
return true;
} catch(NumberFormatException e){
return false;
}
}
}
InputParser.class
- 기본 구분자 상수인 DEFAULT_DELIMITER로 지정
- 기본 구분자로 문자열 파싱 진행
- 만약 문자열의 시작이 커스텀 구분자의 시작인 “//”로 시작한다면 → 커스텀 구분자 추출 후 상수에 추가로 등록 → 문자열 파싱 진행
- 추가학습
- 정규식
public class InputParser {
private static final String DEFAULT_DELIMITER = ",|:";
public String[] parse(String input) {
String delimiter = DEFAULT_DELIMITER;
input = input.replace("\\\\n", "\\n");
if (input.startsWith("//")) {
int delimiterIndex = input.indexOf("\\n");
delimiter = input.substring(2, delimiterIndex);
input = input.substring(delimiterIndex + 1);
delimiter = DEFAULT_DELIMITER + "|" + Pattern.quote(delimiter);
}
return input.split(delimiter);
}
}
Application.class
- InputParser와 Validator를 의존성 주입하여 사용한다.
- validator.inNull → 입력값이 없으면 0을 반환
- inputParser → 구분자 기준으로 문자열을 파싱함
- for문을 통해서 input 숫자 값들을 sum에 더해주고 return
public class Application {
private final InputParser inputParser;
private final Validator validator;
public Application(InputParser inputParser, Validator validator) {
this.inputParser = inputParser;
this.validator = validator;
}
public int add(String input) {
int sum = 0;
/*1. 빈 문자열 입력 시 0 반환*/
if (validator.isNull(input)) {
return sum;
}
/*2. 구분자 기준으로 파싱*/
String[] parse = inputParser.parse(input);
/*3. 문자열에 음수 혹은 문자열이 포함되어있는지 유효성 검사*/
validator.validation(parse);
for (String num : parse) {
sum += Integer.parseInt(num);
}
return sum;
}
public static void main(String[] args){
// TODO: 프로그램 구현
InputParser inputParser = new InputParser();
Validator validator = new Validator();
Application application = new Application(inputParser, validator);
System.out.println("덧셈할 문자열을 입력해 주세요.");
int result = application.add(Console.readLine());
System.out.println("결과 : " + result);
}
}
Test Code
- ApplicationTest.class
- InputParserTest.class
- ValidatorTest.class
class ApplicationTest extends NsTest {
@Test
void 커스텀_구분자_사용() {
assertSimpleTest(() -> {
run("//;\\\\n1");
assertThat(output()).contains("결과 : 1");
});
}
@Test
void 예외_테스트() {
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("-1,2,3"))
.isInstanceOf(IllegalArgumentException.class)
);
}
@Override
public void runMain() {
Application.main(new String[]{});
}
}
public class InputParserTest {
InputParser inputParser = new InputParser();
@Test
void 기본_구분자로_파싱() {
String input = "1,2:3";
String[] result = inputParser.parse(input);
assertArrayEquals(new String[]{"1", "2", "3"}, result);
}
@Test
void 커스텀_구분자로_파싱() {
String input = "//@@!*!@\\\\n1@@!*!@2,3";
String[] result = inputParser.parse(input);
assertArrayEquals(new String[]{"1","2","3"}, result);
}
}
public class ValidatorTest {
Validator validator = new Validator();
@Test
void 빈_문자열_테스트() {
String[] input = {};
try {
validator.validation(input); // 예외가 발생하지 않아야 함
} catch (Exception e) {
fail("예외가 발생하지 않아야 합니다."); // 예외가 발생하면 테스트 실패
}
}
@Test
void 숫자가_아닌_값_테스트() {
String[] input = {"1", "A"};
assertThatThrownBy(() -> validator.validation(input))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("숫자가 아닌 값이 포함되었습니다.");
}
@Test
void 음수_입력_테스트() {
String[] input = {"1", "-1"};
assertThatThrownBy(() -> validator.validation(input))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("음수가 입력되었습니다. 양수만 입력해주세요.");
}
}
1주차 프리코스 회고
1주차 프리코스 회고
제가 우아한테크코스를 신청한 가장 큰 이유는 바로 프리코스 경험이었습니다. 항상 Java와 Spring을 중심으로 백엔드 개발을 공부해왔지만, 막상 누군가에게 Java의 문법을 설명하라고 하면 자신 있게 말하지 못하겠다는 생각이 들었습니다. Java가 객체지향프로그래밍(OOP)의 대표적인 언어임에도 불구하고, 제 코드를 돌아봤을 때 누군가 “과연 객체 단위로 코드를 나누고, 객체 간의 상호작용을 고려하고 있는가?”라는 질문을 한다면 “아닌 것 같습니다…🥲”라고 답할 것 같습니다.
우아한테크코스에 합격한다면 정말 기쁘겠지만, 프리코스를 통해 한발짝 더 기술적으로 깊이 있는 개발자에 가까워지는 것이 저의 목표였습니다. 저와 같은 고민을 하고 있는 분이라면, 프리코스를 꼭 한 번 경험해보시길 권하고 싶습니다!
1주차 과제: 처음 마주한 “객체지향 설계”와 “TDD”
이번 과제는 1주차인 만큼 과제 자체는 비교적 쉬웠다고 생각합니다. 하지만 우아한테크코스에서 강조한 “객제지향설계”와 “TDD”에 익숙하지 않아 어떻게 과제를 풀어 나가야할 지 갈피를 잡지 못해 어려움을 겪었던 것 같습니다🤔
기존에 해오던 코딩 테스트는 백준이나 프로그래스에서 하나의 클래스(Soluction)에 모든 코드를 작성하며 문제를 해결하는 알고리즘이나 자료구조에 시간을 많이 썼다고 하면, 프리코스에서는 ”어떻게 하면 더 클린 코드를 작성할 수 있을까?”, “객체지향적으로 설계할 수 있을까?”라는 고민에 더 많은 시간을 많이 사용한 것 같습니다. 고민 끝에 검증 처리를 검증 처리는 Validation 클래스로, 사용자의 입력 처리는 InputParser로 각각 기능을 분리한 뒤 메인 로직은 Application클래스에서 실행하는 구조로 코드를 작성했습니다.
Git 관리: 터미널 명령어
“Github Desktop”을 통해서 항상 git을 관리해왔었는데, 이번 기회를 통해 우아한테크코스에서 배운 방법으로 터미널을 통해 git push와 pull등을 해보았습니다. 사실 프로젝트를 처음 진행하면서 git도 처음 알게되었는데, 그때 당시에는 여러명의 팀원들이 함께 git을 사용하였기에 최대한 피해를 주지않기 위해서 프로젝트 대표님의 git Desktop 사용방법을 그대로 외워서 로봇처럼 이슈 → 커밋 → PR을 반복해왔었어서.. 이번 과제를 통해서 확실히 git의 기본 명령어와 친해진 것 같아서 의미있는 시간이 되었던 것 같습니다. 첫 과제라 익숙하지 않아 6개의 커밋밖에 작성하지 못했지만, 코드 리뷰를 진행하며 다른 분들의 코드를 보니 같은 과제에서 20~30개의 커밋을 작성하신 분들도 있었습니다.🥲 이를 통해 커밋을 얼마나 세분화해야 하는지 뼈저리게 느꼈고, 다음 과제에서는 커밋 단위를 더 잘게 나눠야겠다고 다짐했습니다.
회고: 성장했다고 생각하자
회고를 하며 생각해보니 Application 클래스에서의 add 메서드를 계산 로직만 처리하는 별도의 비즈니스 로직 클래스로 분리하는 것이 더 좋은 코드가 되었겠다라는 아쉬움이 남습니다.. 🥹 왜 이런 부족한 점은 항상 회고에서만 보이는 걸까요? 아쉽지만 그때의 나는 인지하지 못했던 점을 회고하면서 인지하고 부족함을 느꼈다는 것은 1주차 과제를 진행하던 때의 나보다 한층 성장했다!라고 긍정적으로 생각하고 다음 과제는 꼭 리팩토링데 더욱 힘을 써야겠다고 다짐하며..1주차 회고를 마무리하겠습니다!
프리코스 진행 당시 노션에서 미리 작성 된 글을 가져온 것으로, 내용에 누락이 있을 수 있습니다. 🙂
자세한 내용은 노션에서 확인해주세요.
https://hail-buttercup-c86.notion.site/1-c7a1a3e45e1e4a07bca1ef9c1b1e0dfe?pvs=4
프리코스 1주차 회고 | Notion
제출(PR 링크 & 소감문)
hail-buttercup-c86.notion.site