🏴 우테코 프리코스 과제 4 - 크리스마스 프로모션
바빠서 지금에야 시작한다...주말엔 자격증시험에, 오늘까지 매일이 과제마감일에... 팀플에...OTL... 그래도 이번 우테코 과제 매우 재밌어 보인다 😲 실제 개발 업무 같다! 실제 업무처럼 이메일 형식으로 과제를 받는데, 이벤트 플래너가 되어 프로그램을 개발해 보는 과제이다. 신과제라니, 멋지게 코딩해보자!!! 과제와 팀플을 끝내고, 새벽 2시 반에 시작하지만 힘차게 시작 🙂...
근데 이번 과제가 마지막이라 그런가,분량이 확 늘었다. 비공개 저장소에서 작업한다는 점도! 이번엔 정말, 3주동안 받은 피드백을 최대한 고려해서 혼자 생각해 코딩하라는 뜻이 담겨 있는 것 같다.😃
🪜 지난 과제 피드백 & 회고
이번 공통 피드백에서는 정말 꿀 정보들만 가득했다.bb 내가 고민했던 부분들에 대한 개별 피드백을 받는 느낌이다. 특히 연관성 있는 상수는 static final 대신 enum을 활용해야 한다는 점이 인상 깊었다.찾아보니, 이에 대한 이유는 다음과 같다.
- 가독성: enum은 상수 값들을 그룹화하고 이름을 부여하는 데 효과적이다. 이로 인해 코드의 가독성이 향상되며, 상수 값이 어떤 의미를 가지는지 명확하게 드러난다. 반면 "static final" 상수는 단순한 숫자나 문자열 값만 가지고 있기 때문에 이러한 정보가 부족하다.
- 타입 안정성: enum은 열거형 타입으로 간주되므로, 컴파일러가 상수 값의 타입을 엄격하게 검사할 수 있다.
- 코드 완성 기능: IDE(Integrated Development Environment)에서 enum을 사용하면 자동 완성 기능을 활용하여 상수 값의 목록을 쉽게 확인하고 선택할 수 있기 때문에, 이는 개발자의 실수를 줄인다.
- 유지보수성: enum은 연관된 상수 값을 모아서 정의하기 때문에 유지보수가 용이하다. 상수 값을 추가하거나 제거할 때 enum 내부만 수정하면 되므로, 관련된 코드의 수정이 최소화된다.
* 함수(메서드) 라인에 대한 기준
함수 라인에 대한 기준을 15라인(공백포)으로 명확히 설정함으로써, 함수분리를 위한 고민을 해야한다.
*발생할 수 있는 예외 상황에 대해 고민한다
늘 예외상황을 고민하고 이 과정을 빼먹지 않아야한다. 예외를 빼먹지말자. 또한, 예외에 대한 케이스도 테스트해야 한다.
*비즈니스 로직과 UI 로직을 분리한다.
이는 단일 책임 원칙에도 위반된다. 현 객체의 상태를 보기 위한 로그 메시지 성격이 강하다면 toString()을 통해 구현하고, View에서 사용할 데이터라면 getter 메서드를 통해 데이터를 전달한다.
*final 키워드를 사용해 값의 변경을 막는다
최근에 등장하는 프로그래밍 언어들은 기본이 불변 값이다. 자바는 final 키워드를 활용해 값의 변경을 막을 수 있다.
*객체의 상태 접근을 제한한다
인스턴스 변수의 접근 제어자는 private으로 구현한다.
* getter를 사용하는 대신 객체에 메시지를 보내자
객체는 객체스럽게 사용해야 한다. 데이터를 가지는 객체가 일하도록 한다.
*필드(인스턴스 변수)의 수를 줄이기 위해 노력한다
필드(인스턴스 변수)의 수가 많은 것은 객체의 복잡도를 높이고, 버그 발생 가능성을 높일 수 있다. 필드에 중복이 있거나, 불필요한 필드가 없는지 확인해 필드의 수를 최소화한다.
*테스트 코드도 코드다
테스트 코드도 지속적인 리팩토링이 필요하다.
*테스트를 위한 코드는 구현 코드에서 분리되어야 한다
테스트를 위한 편의 메서드를 구현 코드에 구현하지 마라. 아래의 예시처럼 테스트를 통과하기 위해 구현 코드를 변경하거나 테스트에서만 사용되는 로직을 만들지 않는다.
- 테스트를 위해 접근 제어자를 바꾸는 경우
- 테스트 코드에서만 사용되는 메서드
*메서드 시그니처를 수정하여 테스트하기 좋은 메서드로 만들기
단위 테스트를 할 때 테스트하기 어려운 부분은 분리하고 테스트 가능한 부분을 단위 테스트한다.
*private 함수를 테스트 하고 싶다면 클래스(객체) 분리를 고려한다
가독성의 이유만으로 분리한 private 함수의 경우 public으로도 검증 가능하다고 여겨질 수 있다. public 함수가 private 함수를 사용하고 있기 때문에 자연스럽게 테스트 범위에 포함된다.
하지만 가독성 이상의 역할을 하는 경우, 테스트하기 쉽게 구현하기 위해서는 해당 역할을 수행하는 다른 객체를 만들 타이밍이 아닐지 고민해 볼 수 있다. 다음 단계를 진행할 때에는 너무 많은 역할을 하고 있는 함수나 객체를 어떻게 의미 있는 단위로 분할할지에 초점을 맞춰 진행한다.
🚀 기능 요구 사항 분석
이번엔 특히 기능 요구 사항이 많아서 명세 정리의 필요성을 절실히 느꼈다. 하나씩 프로젝트 로직 흐름을 타며 필요한 기능들을 적어나가보자. 적어나가면서 어떻게 구현하면 좋을지 떠오르는 아이디어를 메모했다.
◼️ 메뉴 저장하기 (메뉴카테고리,메뉴명,가격)
memo : 보는 순간 연관성 있는 상수들이므로 Enum으로 메뉴에 대한 정보 값들을 함께 묶어줘야 겠다 생각함!
◼️ 12월 이벤트 계획 및 기간 설정
▪️크리스마스 디데이 할인(2023년 12월 1일부터 25일까지)
할인 금액은 12월 1일에 1,000원으로 시작하여 매일 100원씩 증가. 총 주문금액에서 해당금액만큼 할인.
▪️ 평일 할인 (2023년 12월 1일부터 31일까지)
일요일부터 목요일까지 디저트 메뉴 1개당 2,023원 할인.
▪️ 주말 할인 (2023년 12월 1일부터 31일까지)
금, 토요일에 메인 메뉴 1개당 2,023원 할인.
▪️ 특별 할인 (2023년 12월 1일부터 31일까지)
이벤트 달력에 별이 있는 날에 총주문 금액에서 추가 1,000원 할인.
▪️ 증정 이벤트 (2023년 12월 1일부터 31일까지)
할인 전 총주문 금액이 12만 원 이상일 때 샴페인 1개 증정.
◼️ 혜택 금액에 따른 12월 이벤트 배지 부여하기
▪️ 5천 원 이상 혜택: 별 배지
▪️ 1만 원 이상 혜택: 트리 배지
▪️ 2만 원 이상 혜택: 산타 배지
memo : 헷갈리지 말 것. 주문 금액이 아닌 혜택 금액에 따른 배지 부여!
◼️이벤트 제한 조건 걸기
▪️ 최소 주문 금액: 10,000원 이상.
▪️ 음료만 주문 제한: 음료만 주문할 수 없음.
▪️ 주문 한도: 한번에 최대 20개까지 주문 가능.
◼️ '12월 이벤트 플래너' 개발 요구사항 반영
▪️ 식당 방문 날짜 입력 받기: 1 ~ 31 사이의 숫자만 유효. (유효하지 않을 시, 특정 에러메시지)
▪️ 메뉴 입력: 형식에 맞는 메뉴와 개수 입력. (유효하지 않을 시, 특정 에러 메시지)
▪️ 에러 처리: 위의 각 유효하지 않은 입력에 대해 "[ERROR]"로 시작하는 에러 메시지 제공.
▪️ 주문 내역 출력: 주문 메뉴, 할인 전 총주문 금액, 증정 메뉴, 혜택 내역, 총혜택 금액, 할인 후 예상 결제 금액, 이벤트 배지 정보 제공. 해당되지 않을시 "없음" 출력
🎯 프로그래밍 요구 사항 분석
이번 주차에 추가된 요구 사항에서 특히 주목한 부분은 다음과 같다. MVC(Model-View-Controller) 패턴을 따라 코딩하라는 지시사항 같다. 늘 내가 해왔던 방식이지만, 입출력 분리를 특히 더 신경쓰자!
- InputView, OutputView 클래스를 참고하여 입출력 클래스를 구현한다. 입력과 출력을 담당하는 클래스를 별도로 구현한다.
- 도메인 로직에 단위 테스트를 구현해야 한다. (단, UI(System.out, System.in, Scanner) 로직은 제외한다. )핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 분리해 구현한다.
🍒 최초 클래스 기능 명세
📝 MenuItem.enum | - 메뉴 저장 - menu, price, category(enum) |
📝 EventPeriodChecker.class | - 특정 날짜가 포함하는 이벤트 기간 판단 - 디데이 / 평일 할인 / 주말할인 / 특별 할인 / 증정 포함되는지 판단 |
📝 EventDay.enum | - 디데이 / 평일 할인 / 주말할인 / 특별 할인 / 증정 날짜 저장 |
📝 EventDiscountCalculator.class | - 날짜에 해당하는 이벤트들에 따른 할인 금액 계산 |
📝 EventBadge.enum | - 별,트리,산타 배지 저장 - 혜택 금액 포함 |
📝 Order.class | - 고객 주문 정보 저장 |
📝 OrderManager.class | - 이벤트 주의사항 안내 - 고객 주문 정보 에러 처리 |
📝 InputView.class | - 유저 입력 담당 |
📝 outputView.class | - 출력 담당 |
📝 InputValidator.class | - 유저 입력 값 검증 |
📝 EventPlanner.class | - 이벤트 전체 흐름 로직을 담당 |
이번엔 기능이 전에 비해 조금 복잡해진 만큼, 명세를 작성할 때 고민이 많이 되었다. 일단 상수값 클래스들을 먼저 정의하고,이를 이용하는 도메인 클래스를 정의후, 점점 큰 단위의 클래스를 작성하는 방식으로 명세를 차근차근 작성했다.
추가로, 이제까지 나중에 상수 분리를 하고 폴더구조를 정리했는데, 이번에는 한 번에 몰아서 리팩토링 하지 않고 그때 그때 코드를 정리하자도 다짐했다.💪
🔘 코드 구현 개발 일지
👩💻 개발 후 최종 클래스 기능 명세
먼저, MVC 패턴에 따라 패키지를 분리했고, 처음 명세와 바뀐 부분이 있다면 유저인풋값을 Order객체로 변환하는 orderStrParser클래스가 추가 되었고,클래스 이름이 바뀐 점이다.
원래는 EventPeriodChecker 클래스는 특정 날짜가 주말, 평일, 특별한 날짜인지를 판별하는 기능을 수행하고, EventPeriod 열거형(enum)은 특정 이벤트 기간을 나타내며, 주어진 날짜가 해당 이벤트 기간 내에 있는지를 판별하는 기능을 수행했다.
근데 내가 작성하면서도 클래스명때문에 계속 기능구분이 헷갈렸다 -_-...; 클래스 이름은 해당 클래스의 책임과 주요 기능을 명확하게 반영해야 하기 때문에,아래와 같이 바꾸어 기능적 차이를 드러냈다.
EventPeriodChecker.class -> DateTypeEvaluator.class
EventPeriod.class -> EventSchedule.class
📜 객체가 최대한 일을 하게 하려 했다.
이번 피드백에서 데이터를 가지는 객체가 일하도록 한다.는 원칙에 신경쓰고 이를 지키려 애썼다 쉬운 예시로, 단순한 getter대신 정보 및 메시지를 내부에서 최대한 처리하는 식으로, 관련 로직은 최대한 해당 관련 객체 내에서 처리하려 했다. 이처럼 객체가 자신의 데이터를 직접 처리하고 관리해야 유지보수 및 확장이 용이해진다.
근데 여기서, 만약 너무 뚱뚱해질 것 같다면 Validator 같은 유효성 처리 클래스는 따로 분리했다. 뭐든 유연하게 대처...!
📜 static,final 을 붙이는 경우를 신경 썼다.
이제까지 생각보다 이 부분을 큰 고려 없이 무의식적으로 코딩했었던 것 같다. 따라서 이번 과제에서는 내부 속성이 없고여러번 쓰이는 경우 static을 꼭 붙이고, 불변 값, 상수에는 final과 enum을 최대한 활용했다.
📜 리팩토링 과정에서, 필드(인스턴스 변수)의 수를 줄이기 위해 노력 했다.
필드(인스턴스 변수)의 수가 많은 것은 객체의 복잡도를 높이고, 버그 발생 가능성을 높일 수 있다. 따라서 필드에 중복이 있거나, 불필요한 필드가 없는지 확인해 필드의 수를 최소화했다. 근데 놀랍게도, 사소한 부분이라고 생각했는데 이 부분만 고쳐나가도 코드가 눈에 띄게 가독성 있고 깔끔해 졌다. 🤔결코 사소한 부분이 아니었음...
아래 부분 예시를 보면, 이 원칙을 지키는 것만으로도 코드가 정리된 것을 볼 수 있다.
변수 정리 전)
public static int calculateTotalDiscount(Order order) {
int totalDiscount = 0;
// 크리스마스 디데이 할인 계산
totalDiscount += calculateChristmasDDAYDiscount(order);
// 평일 할인 및 주말 할인 계산
totalDiscount += calculateWeekDayDiscount(order);
totalDiscount += calculateWeekendDiscount(order);
// 특별 할인 계산
if (isSpecialDay(order.getUserChoiceDate())) {
totalDiscount += calculateSpecialDayDiscount(order);
}
totalDiscount += calculateGiftDiscount(order);
return totalDiscount;
}
public static int calculateChristmasDDAYDiscount(Order order) {
LocalDate date = order.getUserChoiceDate();
int dailyDiscount = 0;
if (isWithinChristmasDDayEventPeriod(date)) {
int userChoiceDay = date.getDayOfMonth();
dailyDiscount -= BASE_DISCOUNT_AMOUNT + (userChoiceDay-1) * DAILY_DISCOUNT_INCREASE;
}
return dailyDiscount;
}
변수 정리 후)
public static int calculateTotalDiscount(Order order) {
return calculateChristmasDDAYDiscount(order) +
calculateWeekDayDiscount(order) +
calculateWeekendDiscount(order) +
calculateSpecialDayDiscount(order) +
calculateGiftDiscount(order);
}
public static int calculateChristmasDDAYDiscount(Order order) {
LocalDate date = order.getUserChoiceDate();
if (!isWithinChristmasDDayEventPeriod(date)) {
return 0;
}
int userChoiceDay = date.getDayOfMonth();
return -(BASE_DISCOUNT_AMOUNT + (userChoiceDay - 1) * DAILY_DISCOUNT_INCREASE);
}
그리고 리팩토링 과정에서, 재사용되는 부분은 하나의 함수로 만들어 통일했다. 예를들어 나는 처음에 주문 중 디저트 카테고리에 속한 것을 카운트 하는 코드, 메인 카테고리에 속한 것을 카운트 하는 코드를 따로 만들었다. 하지만 리팩토링을 하면서 이를 category 파라미터로 받아 하나의 함수로 통합했다. 이런식으로 최대한 반복되는 코드를 줄여 나갔다.
public static int countDessertCategoryItems(Order order) {
int dessertCategoryItemCount = 0;
for (MenuItem menuItem : order.getMenuItems()) {
if (menuItem.getCategory() == Category.DESSERT) {
dessertCategoryItemCount+=order.getItemQuantity(menuItem);
}
}
return dessertCategoryItemCount;
}
private static int countCategoryItems(Order order, Category category) {
return order.getMenuItems().stream()
.filter(menuItem -> menuItem.getCategory() == category)
.mapToInt(order::getItemQuantity)
.sum();
}
📜 정규표현식 사용
그리고 정규표현식을 익히는 걸 귀찮게만 여겼는데, 입력값 형식 예외 처리를 위해서 이보다 좋은 건 없었다 하하..그래서 덕분에 이번 기회로, 미뤄왔던 정규표현식을 공부할 수 있어좋았다. 특히 정규표현에러가나서 한참 해맸는데, 한글 문자열을 제대로 처리하지못해서 일어나는 에러였다.
해결책으로는 정규식을 수정하여 유니코드 문자를 포함할 수 있도록 해야 했다.( 이를 위해 \\w 대신에 유니코드 문자 범위를 나타내는 \\p{L}을 사용했다. p{L}은 모든 언어의 문자를 포함하는 유니코드 범주이다. )
📜 테스트 코드의 중요성
아마 이번 코스에서 가장 큰 수확은테스트의 중요성을 깨달은 게 아닌가 싶다 🤔 사실 테스트를 작성한다는 것은 단순히 동작이 제대로 되는지 확인하는 것 뿐만 아니라, 테스트 하기 좋은 코드를 작성하고 이를 위해 메서드 분리를 하면서 코드를 의미있는 단위로 분할하는 것에도 의미가 더 크다는 생각이 들었다.
때문에 더욱 테스트 코드에 신경썼고, 이 과정에서 오류를 찾아내고 미처 생각지 못한 에러 처리를 하는 등 많은 이점을 경험했다.
프리코스 마지막 주차인 지금은, 테스트 코드는 정말 개발자에게 필수라 생각된다. 하지만 아직 테스트 코드 작성을 올바르게 하는 것이 어렵다. 그래서 관련 서적을 찾아 공부해볼 예정이다!
🪜 구현 과정에서의 실수 및 성찰
이번 과제를 하며 아쉬운 점은, Stream을 많이 안 써봤다는 거다.사실 이번 과제를 하면서 반복문 Depth를 줄이기위해 Stream을 적극적으로 사용하려 했다. 근데 이게 아직 손에 익지 않으니 나도모르게 계속 반복문으로 구현을 했다. Stream한번 따로 시간내서 공부해야겠다.🤨
그리고 객체의 완전한 분리와 역할분담을 실천하지못했다. 불변 객체를 만들자 다짐했건만,, 클래스 Order에서 객체를 처음 생성(초기화) 후에도 객체가 가지는 상태를 변경할 수 있게한 부분이 있다(setUserChoiceDate). 만든 후에 계속 거슬렸는데,제출 마감까지 시간이 없어서 이 부분을 수정하지못했다. 으악.
불변 객체를 사용하면 많은 이점이 있다. 쓰레드에 안전하여 멀티 쓰레드 환경에서 동기화를 고려하지 않아도 된다. 또한 상태가 변경되지 않아 일관성과 신뢰성이 있기 때문에, 객체를 Map Key와 Set 요소로 사용하기에 적합하다.
불변객체를 생성하기 위해서는 아래와 같은 점을 유의해야 한다.(출처 아래 표기)
- setter 메소드를 사용하지 마라
- 모든 필드를 final 과 private를 사용해서 선언해라
- 클래스를 final 로 선언하여 Overriding을 막아라
- 객체를 생성하기 위한 생성자 혹은 정적 팩토리 메소드를 추가해라
- 인스턴스 필드에 가변객체가 포함된다면 방어적 복사를 이용하여 전달해라
부끄럽게도 나는 객체에 final을 붙이면 상태 변경이 불가능 한 줄 알았다. 하하 😅final 예약어는 변수에 사용시 값을 수정할 수 없는 상수로 만들어주고, 메소드에 사용시 Overriding을 할 수 없고, 클래스에 사용시 상속이 불가능하게 만든다. 따라서 객체 선언시에 final 예약어를 사용한다 하더라도, 객체 내부상태는 변경할 수 있다고 한다.
이밖에도 enum을 쓸지 상수를 쓰는게맞을지 헷갈렸는데, 단순 상수가 아닌 로직이나 상태를 가진 값들을 표현해야 한다면 enum이 낫다고 한다.확장 가능성이 있거나 타입 안전성이 중요할때도 enum을 써야한다. 그래서 최대한 시작날짜,끝날짜를 포함하는 이벤트 스케줄이나 이름을 가진 뱃지등은 정보를 묶어 enum으로 나타냈다.
👀 마지막 과제를 마치며...
우테코를 하며 늘 시간에 쫓겼다. 사실 모각코나 오프라인 모임도 많이 나가보고 싶었지만,아무래도 학기중이라 과제 더미와 팀플,각종 할일들에 늘 정신 없고 시간이 없어 그러지 못한 점이 많이 아쉽다. 그래도 커뮤니티를 열어주셔서 코드리뷰 채널 등을 통해 다른 사람들의 개발 과정을 엿볼 수 있어서 좋았다. 깔끔한 코드를 볼때는 왠지모를 희열까지 들었다...!
어쨌든, 이번 프리코스 기간동안 눈 앞의 마감 과제와 갈등하고 밤을 지새웠는데,그래도 4주차까지 끝내니 후련하고 뭔가 아쉬운 기분까지 든다.사실 질 높은 코드를 작성하기 위해 깊게 고민해 보는 시간을 갖기는 쉽지 않다. 하지만 이번 코스를 하면서 '좋은 과제'와 '피드백'을 통해서 혼자 찾아보고 공부하면서 이에 대해 깊게 고민해 볼 수 있었다. 이것만으로도 참으로 큰 수확이다.
기대되는 점은, 비록 이번 프리코스는 혼자 했지만 우테코를 통해 사람들과 같이 의견을 주고받으며 공부하면 더욱 빨리 성장할 수 있을거라 생각된다. 실제로, 나눔과 잡담방을 보며 주워듣는 지식들을 학습하는 것만으로도 정말 공부할 거리가 넘쳐나고 의미있었다.
특히 마지막 과제는 진짜 메일로 요구사항을 받고 작업을 하는 것 같아서 너무 재밌었다...ㅎㅎ4주 간 상세한 과제들로 많은 생각을 던져준 우테코에 감사드리며, 글을 마무리 한다.
참고글 모음
https://tecoble.techcourse.co.kr/post/2020-04-28-ask-instead-of-getter/
getter를 사용하는 대신 객체에 메시지를 보내자
getter는 멤버변수의 값을 호출하는 메소드이고, setter는 멤버변수의 값을 변경시키는 메소드이다. 자바 빈 설계 규약에 따르면 자바 빈 클래스 설계 시, 클래스의 멤버변수의 접근제어자는 private
tecoble.techcourse.co.kr
https://tecoble.techcourse.co.kr/post/2020-05-07-appropriate_method_for_test_by_parameter/
메서드 시그니처를 수정하여 테스트하기 좋은 메서드로 만들기
…
tecoble.techcourse.co.kr
☕ 자바 Enum 열거형 타입 문법 & 응용 💯 정리
Enum 열거 타입 먼저 Enum은 "Enumeration"의 약자다. Enumeration은 "열거, 목록, 일람표" 라는 뜻을 가지고 있으며, 보통 한글로는 열거형이라고 부른다. 즉, 열거형(enum)은 요소, 멤버라 불리는 명명된 값
inpa.tistory.com
https://ittrue.tistory.com/177
[Java] 자바 정규 표현식(Regex) 개념 정리 및 활용
Intro 대부분의 웹 서비스에서 회원 가입을 필요로 하며, 회원 가입 시 ID 또는 비밀번호를 설정할 때 특정 조건에 맞추어 입력하라고 요구한다. 예를 들어 비밀번호 입력 시 영문 대소문자를 한
ittrue.tistory.com
https://jamesdreaming.tistory.com/203
[ 자바 코딩 ] 숫자 콤마 찍기 (금액 표기)
안녕하세요. 제임스 입니다. 자바에서 숫자에 콤마를 찍어 금액을 표기 하는 방법에 대해 알아 보겠습니다. ■ DecimalFormat 을 이용하여 숫자에 콤마 찍기 java.lang.Object java.text.Format java.text.NumberForm
jamesdreaming.tistory.com
https://velog.io/@pgmjun/%EC%9A%B0%ED%85%8C%EC%BD%94-6%EA%B8%B0
[우테코 6기] IntelliJ에서 Java 테스트 커버리지 확인하기
우테코 프리코스를 진행하면서 요구사항에 의해 테스트 코드를 작성하였다. 실수를 방지하기 위해 정말 꼼꼼하게 테스트 코드를 작성하며, 엣지 케이스를 찾기 위해 열심히 노력하였다.
velog.io
[Java / enum] - 왜 enum이 상수 클래스보다 더 좋은건데??
서론 안녕하세요, 우테코 6기 백엔드 지원자 Zangsu 입니다! 우선, 글을 작성하기 전 미리 말씀 드리자면, 저는 대부분의 상수를 별도의 클래스를 생성해 관리하고 있었는데요. 그 이유는 다음과
zangsu.tistory.com
https://dev-cool.tistory.com/23
불변객체(Immutable Object)를 사용해야하는 이유
1. 불변객체(Immutable Object)란? 불변객체는 말그대로 변하지않는 객체로 객체가 생성된후 내부 상태가 변하지 않는 객체를 의미한다. 불변객체는 Setter 메소드를 제공하지 않으며, 내부상태를 제공
dev-cool.tistory.com
'개발프로젝트' 카테고리의 다른 글
[개발프로젝트] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 chapter 02- 테스트 (0) | 2023.12.20 |
---|---|
[개발프로젝트] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 chapter 01 (0) | 2023.12.19 |
utc3 (0) | 2023.11.07 |
utc2 (0) | 2023.10.31 |
utc1 (1) | 2023.10.24 |