Closed rkaehdaos closed 2 years ago
왼쪽에서 존재하던 가변 데이터가 사라짐
변수의 용도 : 다양
변수 추출하기[6-3]와 비교 : → 목적이 다르다
- 유사점 : 중간 단계에 사용되는 변수를 추가
- 차이점:
- 추출하기 : 표현식을 변수로 추출
- 쪼개기 : 여러번 사용되는 한 변수를 여러 변수로 쪼갠 것 , 변수 하다당 역할 하나를 갖도록 강제화
재성님이 하셨던 문장슬라이드 8-6
const pricingPlan = retrievePricingPlan();
const order = retrieveOrder();
const baseCharge = pricingPlan.base;
let charge;
const chargePerUnit = pricingPlan.unit;
const units = order.units;
let discount;
charge = baseCharge + units * chargePerUnit; // charge 첫 대입
let discountTableUnits = Math.max(units - pricingPlan.discountThreshold, 0);
discount = discountTableUnits * pricingPlan.discountFactor;
if (order.isRepeat) discount += 20;
charge = charge - discount; // charge 두 번째 대입 , 다른 의미, discountCharge등의 다른 변수로 쪼개기
chargeOrder(charge);
i=i+<무언가>
형태라면? → 수집변수 → 쪼개면 안된다해기스 의 전파된 거리를 구하는 코드
haggis 양의 내장으로 만든 스코틀랜드 음식, 순대와 비슷
초기 : 발상지에서 초기 힘을 받아 일정 가속도
시간이 흐른후 2번쨰 힘을 받아 전파속도가 빨라진다고 가정
일반적인 물리 법칙을 적용
acc 변수에 값이 2번 대입된다
함수나 파일에서 특정 심벌이 쓰인 위치를 시각적으로 강조해주는 코드 편집기를 사용하면 도움이 된다
function discount(inputValue, quantity) {
if (inputValue > 50) inputValue = inputValue - 2;
if (quantity > 100) inputValue = inputValue - 1;
return inputValue;
}
6-7 변수 이름 바꾸기와 유사하지만 클래스의 필드 변수에 한한 케이스라는 것이 차이점
const organization = {name: "애크미 구스베리", country: "GB"}
이름 변경할 곳이 4곳
입력데이터 구조를 내부 데이터 구조로 복제했으므로 둘을 구분해야 독립적으로 작업할 수 있다 → 별도 필드를 정의하고 생성자/접근자에서 둘을 구분해서 사용하도록 해야 한다
데이터 구조를 불변으로 만들 수 있는 프로그래밍 언어 사용시
7-4 임시 변수를 질의 함수로 바꾸기와 유사(과정이), 목적은 다름
파생 변수
- 2 개(또는 그 이상)의 기본 변수에서 파생된 변수
- 백분율, 비율, 지수, 비율
- 기본 변수에 의존하므로 기본 변수중 하나 이상의 변경으로 파생 변수의 변경 발생 가능하지만 갱신이 안됨
- 문제를 일으킬 수 있음
- 질의함수 재정의 필요 : (값이 필요할 떄 다른 변수 값으로부터 계산하는)사용.
만약 discount setter가 없었으면 바꿀 필요가 없다
또다른 차이점 : 목적
- 임시변수 기법 : 스코프 확대 의도(함수 스코프에서 클래스 스코프로)
- 파생변수는 이미 클래스 스코프에 존재
가변 데이터의 문제
SW 문제 일으키는 가장 큰 골칫거리 중 하나
서로 다른 두 코드를 이상한 방식으로 결합할 수도
가변 데이터를 완전히 배제하기? → 현실적으로 불가능
마틴 파울러의 목소리 : 가변 데이터의 유효 범위를 가능한 좁혀야 한다
합당한 예외
작지만 확실하고 보기 흉한 예
class ProductionPlan {
constructor() {
this._adjustments = [];
this._production = 0;
}
get production() {return this._production;}
applyAdjustment(anAdjustment) {
this._adjustments.push(anAdjustment)
this._production += anAdjustment.amount
}
}
일반적인 코드 중복이 아닌 데이터 중복
신중하게 어셔션을 추가해서 검증해보자
이 파생 데이터 대체할 방법 ? 간단
VO
제 기억으로는 이펙티브 자바에도 아마 비슷한 내용이 있었던 것으로 기억
대부분의 OOP언어는 값 기반 동치성 비교를 위해 오버라이드 가능한 동치성 검사 수단 기본 제공
- Ruby :
==
연산자 오버라이드- Java :
Object.equals()
오버라이드동치성 검사 메서드(equals)를 오버라이드 할 때는 해시코드 생성 메서드도 함께 오버라이드
Java : `Object.hashCode() 메서드
jdk의 List 해시 코드 - 이펙티브 자바 : 매직넘버 31 HashMap : CLRS 나눗셈 방법 롬복 : 예전 277 사용, 현재 59 사용
앞의 reverse, 앞의 것의 배경과 같이 연관해서 생각해보자
값을 참조로 바꾸면 엔티티 하나당 객체도 단 하나만 존재
가변 데이터 악취
- 참조에는 반드시 가변 데이터 악취의 문제가 발생
- 특히 한 객체가 여러 장소에서 사용될 때
- 예) id 777인 Customer의 객체가 여러 곳에서 사용되기
- Value 객체인 경우엔 애초에 각자가 별개이므로 상관없음
- 그러면 이런 객체들을 한대 모아놓고 클라이언트들의 접근 관리해주는 일종의 저장소가 필요하다
- 저장소로 객체들을 캡슐화
- 저장소로만 객체들 접근
최근에 말하는 엔티티 : 도메인 모델의 엔티티 : 따라서 도메인 모델의 Entity VS Value객체로 구분해서 생각 엔티티 : 실체, 객체라는 의미, 식별자를 가진다 DB의 엔티티 : 실제로 SQL, DB에 존재하는 것이 아닌 일종의 개념 DB에서 엔티티는 논리 모델에서 사용, 테이블은 물리 모델에서 사용, 테이블은 DB, SQL에 실제로 존재, 물리적 구조
DTO VS VO
- VO는 위에서 봤듯이 불변, read-only 특징, 값 자체를 의미→따라서 같은 객체 보장을 위해 equals, hashcode를 재정의해줘야 한다
- DTO : 레이어간 데이터 전소응ㄹ 위해 정의된 객체 : 주로 json 직렬화등 직렬화에 사용되는 객체
- DTO는 원래 DAO 패턴에서 유래 : DAO에서 DB 처리 로직을 숨기고 DTO값을 내보내는 용도로 활용
- 현재는 거의 DTO는 엔티티를 프레젠테이션 단까지 내보내지 않기 위해 쓰이는 , 다 내보낼 필요도 없고
- DTO : getter/setter만을 가지고 비지니스 포함X
- 둘의 차이 개념상의 차이 : 값 자체에 의미가 있는 VO, 전달된 데이터보존의DTO
- VO는 setter가 없음 : 불변, readonly가 보장되어야 존재 자체의 신뢰성 확보
주문 클래스
엔티티 표현 객체가 여러개 만들면 혼란
리포지토리 패턴
- P of EAA [2002] : https://www.martinfowler.com/eaaCatalog/repository.html
- - 2015 재출간
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects. - Edward Hieatt and Rob Mee 도메인 객체에 접근하는 컬렉션과 비슷한 인터페이스를 사용해 도메인과 데이터 매핑 계층 사이를 중재한다 - 에드워드 하얏트, 롭 미 리포지토리에 의해 캡슐화되는 매핑 코드가 적절한 작업을 내부적으로 처리 데이터 저장소에 저장된 객체의 집합과 이를 대상으로 수행하는 작업을 개념상으로 캡슐화해 지속적 계층에 대한 좀 더 객체 지향적 관점을 제공한다
- 데이터 출처에 상관없이 돌일 인터페이스로 데이터에 엑세스 가능 - DataSource캡슐화
- 책에서는 이 앞에서 데이터 매퍼 패턴(도메인 객체를 DB 접근 상세로부터 격리하기 위해)을 소개 했는데 복잡한 도메인 모델의 경우 쿼리 구성 코드가 집중되는 매핑 계층을 기반으로 다른 추상 계층을 만듬 - 레포지토리 계층
- 도메인은 하위에 상관없이 레포지토리만 바라봄
- 레포지토리 교체로 단위테스트를 통한 검증 가능
예시 문제점
상수 와 리터럴
- 둘 다 변하지 않는 값
- 상수 : 변하지 않는 변수 → 메모리 위치
- 리터럴 : 데이터 그 자체, 변수나 상수에 넣는 변하지 않는 데이터 → 메모리 위치 안의 값
- 불변 클래스의 경운(immutable, VO) : 리터럴이라고 할 수 있고 객체 리터럴이라고 따로 칭하기도 한다
매직넘버, 매직리터럴
프로그래밍에서 비지니스적 의미를 가진 숫자,문자를 그대로 표현한 것
int maxStudents = numClassrooms * 30;
→ 매직 리터럴 30 → 교실 당 최대 학생 수를 의미한다는 것을 유추해야 한다
굉장히 나쁜 습관 → 무엇에 사용되는 지에 대한 컨텍스트가 없으며 나중에 값을 수정 시에도 문제가 된다
예를 들어서 30→ 35로 바꿔야 하는데 이미 30이라는 다른 숫자들이 존재함.. replace를 할 수 없음
원주율(π) : 3.14159...
표준 중력, 중력가속도(g) : 9.80665 m/s2
독자가 리터럴 값의 의미를 모른다면? → 숫자 자체로는 의미를 명확히 알려주지 못함 → 매직리터럴
매직 리터럴은 대체로 숫자가 많지만 다른 타입의 리터럴도 특별한 의미를 지닐 수 있다
솔루션 : 해당 값이 쓰이는 모든 곳을 적절한 이름의 상수로 바꿔주는 방법이 가장 좋다
aValue === "M"
→ aValue === MALE_GENDER
<<<< jisMale(aValue)
상수를 과용하는 것을 자제하자
const ONE = 1
: 의미 없는 상수 선언 → 의미 전달 면에서 리터럴을 바로 쓰는 것보다 나을게 없다
하나의 값이 여러 목적으로 사용되면??
다른 프로그램 요소와 마찬가지로 변수 이름을 제대로 짓는 일은 까다로우면서도 중요하다
ref인지 value인지 햇갈려 문제가 되는 코드
코드에 의미를 알기 어려운 리터럴? 매직 리터럴 바꾸기로 명확하게!
차례