2주차 정리
내용 정리
전역 변수와 전역 메서드의 남용
모든 상수를 Constant 클래스로 통합할 경우 생기는 문제점
- 코드의 유지 보수성에 영향을 미친다. 상수를 추가할수록 점점 코드의 몸집은 불어나고, 수정을 하며 충돌을 일으킬 것이다.
- 코드 컴파일의 시간을 증가 시킨다. Constant 클래스를 수정할 때마다 Constant 클래스에 종속된 다른 클래스가 매번 다시 컴파일되어 불필요한 컴파일 시간을 낭비한다. 대규모 프로젝트는 컴파일 하는데 몇 분 또는 수십 분이 소요될 수도 있고, 개발 과정에서 단위 테스트가 실행 될 때마다 컴파일이 실행되기 때문에 긴 컴파일 시간은 개발 효율성에도 큰 영향을 미친다.
- 코드의 재사용 가능성에도 영향을 미친다. 이 프로젝트에서 개발한 클래스를 다른 프로젝트에서 재사용 하려고 할 때, 이 클래스가 Constant 클래스에 종속되어 있다면 어떻게 될까? 이 클래스가 Constant 클래스의 일부 상수만 사용하더라도 Constant 클래스 전체를 도입해야 한다. 실제로는 아무 관련도 없는 많은 상수들이 모듈에 포함되는 것이다.
Utils 클래스를 정의하기 전에
- Utils 클래스를 별도로 정의해야 하는가?
- Utils 클래스의 일부 메서드를 다른 클래스로 정의할 수가 있는가?
이 질문에도 여전히 Utils 클래스를 정의할 필요가 있다고 생각한다면 과감하게 정의한다
추상 클래스와 인터페이스의 정의와 차이점
추상 클래스의 특성
- 추상 클래스는 인스턴스화할 수 없으며 상속만 가능하다.
- 추상 클래스는 속성과 메서드를 포함할 수 있다.이때 클래스에 메서드에 코드 구현을 포함할 수 있고, 메서드에 코드 구현을 포함하지 않을 수도 있다. 이때 코드 구현을 포함하지 않는 메서드를 추상 메서드라고 한다.
- 하위 클래스는 추상 클래스를 상속할 때 추상 클래스의 모든 추상 메서드를 실제로 구현해야 한다.
인터페이스의 특성
- 인터페이스는 속성을 포함할 수 없다.
- 인터페이스는 메서드를 선언할 수는 있으나, 실제 코드 구현을 포함할 수 없다.
- 클래스가 인터페이스를 구현할 때는 인터페이스에 선언된 모든 메서드를 구현해야 한다.
합성이 상속에 비해 나은 점
상속 문제는 합성, 인터페이스, 위임이라는 세 가지 기술적 방법을 통해 해결할 수 있다.
public interface Flyable {
void fly();
}
public class FlyAbility implements Flyable {
@Override
public void fly() { ... }
}
// .. 나머지 코드 생략 ..
// - Tweetable interface
// - TweetAbility 클래스
public class Duck implements Tweetable, Flyable {
private FlyAbility flyAbility = new FlyAbility(); // 합성
private TweetAbility tweetAbility = new TweetAbility(); // 합성
// .. 일부 생략 ..
@Override
public void tweet() {
tweetAbility.tweet(); // 위임
}
@Override
public void fly() {
flyAbility.fly(); // 위임
}
}
is-a 관계는 합성과 인터페이스의 has-a 관계로 대체될 수 있고, 다형성은 인터페이스를 사용하여 달성될 수 있으며, 코드 재사용은 합성과 위임으로 목적을 달성할 수 있다. 이론적으로 합성, 인터페이스, 위임의 세 가지 기술 수단은 상속을 완전히 대체할 수 있다.
합성을 사용할지 상속을 사용할지 결정하기
클래스 간의 상속 구조가 안정적이어서 쉽게 변경되지 않고 상속 단계가 2단계 이하로 비교적 얕아 상속 관계가 복잡하지 않다면 과감하게 상속을 사용할 수 있다. 반대로 시스템이 불안정하고 상속 계층이 깊고 상속 관계가 복잡하면 상속 대신 합성을 사용해야 한다.
public class FeignClient { // Feign Client 프레임 코드
// .. 일부 코드 생략 ..
public void encode(String url) { ... }
}
public class CustomizedFeignClient extends FeginClient {
@Override
public void encode(String url) {
// .. 중복되는 encode() 구현 생략 ..
}
}
public void demofunction(FeignClient feignClient) {
// .. 일부 코드 생략 ..
feignClient.encode(url);
// .. 일부 코드 생략 ..
}
// 사용하기
FeignClient client = new CustomizedFeignClient();
demofunction(client);
나눌 내용
왜 리눅스 os는 C언어로 작성 됐을까?
https://www.quora.com/What-are-the-reasons-why-Linux-OS-is-written-in-C-language
- 리누스 토발즈는 C++와 같은 객체 지향 언어에서 일반적으로 나오는 코드 스타일을 좋아하지 않았다.
- 이미 C로 작성된 기존의 언어들의 예외들에 대한 정의가 잘 되어있어 안정적이었다.
- 당시에 시장을 지배하고 있던 언어가 C이기 때문이다.
GPT 답변
- 직접적인 메모리 접근 가능 (포인터)
- 어셈블리 언어와 가깝지만 이식성이 뛰어남
- 효율적인 실행 속도 (최소한의 오버헤드)
절차지향이 OS 개발에 적합
운영 체제는 많은 프로세스, 메모리 관리, 디바이스 드라이버 등의 기능을 다루어야 합니다. 객체지향(OOP)이 OS 개발에 반드시 유리한 것은 아닙니다.
✅ 운영 체제 개발에 절차지향이 유리한 이유
- 빠르고 직관적인 코드 실행 → OS는 성능이 중요하므로, 불필요한 추상화가 적은 절차지향 방식이 유리함 → 책에서 나온 코드 컴파일의 시간을 증가 시킨다. 라는 내용과 일맥상통 하는 듯
- 직접적인 하드웨어 제어 → 객체지향 언어는 가비지 컬렉션(GC) 같은 기능이 추가될 수 있어, 시스템 성능 저하 가능성 있음
- OS의 기능 자체가 계층적 설계 → 커널, 파일 시스템, 네트워크 스택 등은 절차적으로 동작하는 것이 효율적
그렇다고 객체지향이 운영 체제에서 전혀 쓰이지 않는 것은 아닙니다. 일부 운영 체제(예: Windows)는 일부 C++을 사용하고, 리눅스에서도 특정 서브 시스템에서 객체지향적 설계를 활용합니다.
도메인 모델 순수성 vs 도메인 모델 완전성
https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/
빈약한 도메인 모델 리팩토링?
빈약한 도메인 모델을 풍성한 도메인 모델로 전환하는 경우가 있는지..??
https://martinfowler.com/bliki/AnemicDomainModel.html
BO, Entity, VO 를 세세하게 나누는가?
회사에서는 개발 소요 시간이 짧아야 하고, 알아도 안 하시는 경우가 많기 때문에 (일관성을 유지한다는 명목으로) 직접적인 DB와 통신할 객체는 나누는 것은 많이 봤어도 BO, VO 등 세분화해 나누는 경우는 거의 없어, 실제로도 세분화하는 경우가 많은지? 혹은 단순한 로직에서는 나누지 않는 것인지?
따로 엔티티를 나누지 않으면 오히려 불편할 수도 있다…