데이터 구조는 프로그램에서 중요한 역할을 한다. 그러나 데이터들이 여러 서비스에서 무분별하게 참조된다면 혼란과 버그를 낳을 수 있다.
따라서 데이터구조를 리팩토링 함에 따라, 데이터 구조로 인한 유지보수 비용을 절약하자.
참조가 불분명하여 변수가 어디서 변경될지 예측하지 못한다던가, 역할이 2개 이상인 변수가 있다면 쪼개야한다.
double temp = 2 * (height + width);
System.out.println(temp);
// 하나의 변수에 2번의 대입이 일어난다.
temp = height * width;
System.out.println(temp);
해당 코드는 다음과 같이 변수쪼개기를 실행할 수 있다.
final double perimeter = 2 * (height + width);
System.out.println(perimeter);
final double area = height * width;
System.out.println(area);
구체적 예시는 생략, 대신 개인적 생각을 조금 말해보자면 변수 쪼개기 하나만으로도 다음과 같은 이득을 얻을 수 있다라고 생각한다.
1. 가독성 향상
2. 디버깅 편리
3. Side Effect를 줄인다.
데이터 레코드에서의 필드 이름은 프로그램을 이해하는데 아주 큰 역할을 한다. 그래서 직관적인 네이밍 작업은 추후에 프로그램을 이해하는데 있어 중요하다.
public class Organization{
public String name;
}
public class Organization {
@Getter //캡슐화 작업
@Setter //캡슐화 작업
private String title
}
역시 예제 자체는 내가 설명할 필요가 없을 정도로 간단한 예시, 추가로 개인적 견해
네이밍은 굉장히 중요한 작업
변수 이름 추천 사이트 : https://www.curioustore.com/
애용하자.
파생변수는 다소 직관적이지 못한 코드흐름을 만들 수 있다. 파생변수가 의미가 매우 직관적이라서 간단하게 사용될 수 있다면 좋겠지만, 우리의 코드들은 그렇지 않다.
그래서 파생 변수가 어디서 참조되어 막기 위해, 이를 불변함수로 변경하여 side effect를 막는다.
class Billing {
private int discount;
private int discountedTotal;
public int getDiscountedTotal(){
return this.discountedTotal;
}
/*
뿐만아니라 discountedTotal 이 무엇을 의미하는지 자체가 불분명하다.
코드가 한번에 읽히지 않았음. < 물론 내 능지 탓도 있겠지만...
discount가 discountedTotal 자체를 관리할 책임을 지고있는지 다시 생각해보면 좋을문제라고 생각 들었다.
내가 생각했을때는 discountedTotal이 최종 할인된 가격을 가리킨다면 setDiscount는 2가지 책임을 가지고 있는 것이 된다.
1. 할인 금액을 설정하는 책임
2. 최종할인된 할인 금액을 설정하는 책임
*/
public void setDiscount(int discount){
final int old = this.discount;
this.discount = discount;
this.discountedTotal = old - discount;
}
}
class Billing{
private int discount;
private int baseTotal;
//매번 값을 계산하여 리턴함으로써 값이 다른곳에서 참조하지 않도록 막음.
public int getDiscountedTotal(){
return this.baseTotal - this.discount;
}
//또한 setDiscount()가 하나의 책임만 가짐으로써 코드가 직관적이고 유지보수하기 편해짐.
public void setDiscount(int discount){
this.discount = discount;
}
}
baseTotal은 어디서 계산되는지는 생략 되있는듯
class Product {
//애초에 책임 자체가 잘못되어있다. -> 캡슐화를 구데기로 해놓은 케이스.
//클린코드에서 데메테르 법칙 자체를 지키지 않은코드
//Product는 Price객체의 프로퍼티를 직접 접근할 권리가 없고,
//Price 객체에 요청하여 amount에 대해 접근화 해야 한다.
void applyDiscount(int discount){
this.price.amount -= discount;
}
}
class Product {
//좀 낫지만 캡슐화가 지켜지지 않음
void applyDiscount(int discount){
this.price = new Money(this.price.amount - arg, this.price.currency);
}
}
class Product {
//이러면 pirce의 가격 측정 정책이 바뀌더라도 side Effect가 발생할 가능성이 굉장히 줄어듬
//왜냐하면 Product는 Price 내부의 프로퍼티가 어떻게 변경되는지는 관심 X
void applyDiscount(int discount){
int amount = this.price.getAmount();
this.price = new Money(amount, this.price.getCurrency());
}
}
참조로 처리할 경우 역시 Side Effect가 생길 수 있다. 내부 객체의 값이 얼마든지 바뀔 수 있기 때문에, 프로그램 흐름을 어렵게 하기 때문이다.
그리고 일단 객체를 직접 참조할 경우, 참조한 객체와 강력한 결합이 생기기 때문에 분리하기 어려워 진다.
해당 코드는 예시로 이야기해도 좋을 것 같아서 예를 든다.
class Person {
private Telephone telephone;
//객체를 생성할 때 새로 생성해서 불변을 보장한다.
// setter를 제거한다 -> 오직 하나의 setter로만 둠.
void setTelephone(Telephone telephone){
this.Telephone = new Telephone("010-xxxx-xxxx");
}
@Override
public boolean equals(Person otherPerson){
return otherPerson.getTelephone().getNumber() == telephone.getTelephone();
}
}
//동치성 추가
class Telephone {
@Pattern(message ="invalid phone number", regexp = "/^.*(?=^.{8,15}$)(?=.*\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&+=]).*$/ " )
private String number;
public String getNumver(){
return this.number;
}
}
값은 불변속성을 띄고 있기 때문에, A에서 변경한 부분이 B화면에도 반영되야 한다면 공유적인 데이터를 사용해야 한다고 한다.
상태관리 플랫폼은 다양하게 사용되고 있다 생각되고, 실제로 프론트나 앱쪽에서는 어떻게 관리 되는지, 스터디 중 물어보기.
Customer customer = new Customer(customerData);
Customer customer = customerReository.get(CustomerData.id);
변경전은 객체를 생성하는 거고, 변경후는 이미 생성되어있는 객체를 가져오는예 (영속성을 유지하는 예)
(물론 둘다 객체를 어플리케이션 메모리에 새로 올릴 가능성이 있는 것은 맞다.)
즉 둘다 안좋은 코드가 아니라는 말.
public getPotentialEnergy(double mass, double height){
return mass * 9.81 * height;
}
public static double EARTH_GRAVITY = 9.81;
public getPotentialEnergy(double mass, double, height){
return mass * EARTH_GRAVITY * height;
}
의미전달 면에서 좋다고한다.
9.81이 읽는 사람 측면에서는 어떠한 값을 의미하는지 유추할 수 없기 때문이다.
데이터를 조직화하는데 있어서총 6가지의 예시를 제시해뒀다.
1. 변수 쪼개기 -> Side Effect방지 , 가독성 향상
2. 필드 이름 바꾸기 -> 가독성 향상
3. 파생변수를 질의 함수로 바꾸기 -> Side Effect 방지, 캡슐화
4. 참조를 값으로 바꾸기 -> Side Effect 방지
5. 값을 참조로 바꾸기 -> ???
값을 공유할 때 사용한다는데 잘 모르겠다.
6. 매직리터럴을 함수로 변경하기 -> 가독성향상
결과적으로 데이터 구조를 조직화 한다는 것은 Side Effect방지와 가독성 향상에 중요한 역할을 한다생각하고, 잘 실천해서 좋은 코드를 짜도록 하자.