본문 바로가기

TIL

2022/02/10 TIL

The Red : Stream

FlatMap

  • Stream이 중복되어 있을 때 사용한다.
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

예제)

    @Test
    void test_flat_map(){
        String[][] strArray = new String[][]{
                {"a1, a2"},
                {"b1, b2"},
                {"c1, c2"},
        };
       List<String> stringList = Arrays.stream(strArray)
                .flatMap(x -> Arrays.stream(x)).collect(Collectors.toList());

      assertThat(stringList).containsExactly("a1, a2", "b1, b2", "c1, c2");
    }

Optional

  • Null을 예방하지 못하면 NullPointerExceion이 발생한다. 런타임 에러이기 때문에 예측하기가 쉽지 않다.
  • Optional은 Null일 가능성이 있는 객체를 담는다.

초기화

        Optional.of(user2.getName());
        Optional.ofNullable(user3);
        Optional.empty();

값 꺼내기

    @Test
    void test_get(){
        Optional.of(user3.getName()).orElse("defaultName");
        Optional.of(user3.getName()).orElseGet(() -> "defaultName");
        Optional.of(user3.getName()).orElseThrow(() -> new IllegalArgumentException());
    }

클린아키텍처 9장 : 리스코프 치환 원칙 (LSP)

S타입 객체 o1, T타입 객체 o2, T타입 정의한 프로그램 P 가 있을 때, o2 자리에 o1을 치환하더라도 P의 행위가 변하지 않는다면 S는 T의 하위 타입이다.

S o1;
T o2;

T o1; // 문제 없다면 S는 T의 하위 타입이다.

여기서 S는 T의 타위 타입이란 말은 Java에서 상속으로 표현할 수 있다.

Class S implements T

정사각형 / 직사각형 문제

class Rectangle{
    Double area(){
        return w * h;
    }
}

class Square{
    Double area(){
        return w * h / 2;
    }
}


class User{
    private Rectangle r = new Square();

    @Test
    void test_area(){
        r.setW(5);
        r.setW(2);
        assertThat(r.area()).isEqualTo(10);
    }
}

위의 테스트 코드는 개발자의 부주의로 실패하게 된다. (Rectangle 타입이기 때문에 Rectangle의 메소드가 사용될 수 있다고 착각할 경우)
또한 이렇게 실패하게 된다면 Rectangle과 Square의 관계가 상속관계가 맞는것인지 의심해봐야 한다.

코드를 아래처럼 변경하는 게 좋다.

interface Shape{
    Double area();
}

class Rectangle extends Shape {
    @Override
    Double area(){
        return w * h;
    }
}

class Square extends Shape {
     @Override
    Double area(){
        return w * h / 2;
    }
}


class User{
    private Rectangle r = new Square();

    @Test
    void test_area(){
        r.setW(5);
        r.setW(2);
        assertThat(r.area()).isEqualTo(10);
    }
}

행위가 사용하는 타입에 의존하지 않는 것이 중요하다
의존하지 않는다는 것 중 하나는 타입 검사를 하지 않는다는 것이다.

클린 아키텍처 10장 : 인터페이스 분리 원칙 (ISP)

class Ops{
    void op1(){...}
    void op2(){...}
    void op3(){...}
}

class User1{
    OPS ops = new Ops;
    ops.op1();
}

class User2{
    OPS ops = new Ops;
    ops.op2();
}

class User3{
    OPS ops = new Ops;
    ops.op3();
}

(정적 타입 언어의 경우) 위의 코드가 좋지 않은 이유는 무엇일까? op2라는 메소드가 수정되면 이를 사용하지 않는 User1과 User3 역시도 다시 컴파일돼야 한다는 것이다. 이는 불필요한 결합이다.

class Ops implements U1Ops, U2Ops, U3Ops{
    @Override
    void op1(){...}
    @Override
    void op2(){...}
    @Override
    void op3(){...}
}

interface U1Ops{
    void op1();
}

interface U2Ops{
    void op2();
}

interface U3Ops{
    void op3();
}

class User1{
    U1Ops ops = new Ops;
    ops.op1();
}

class User2{
    U2Ops ops = new Ops;
    ops.op2();
}

class User3{
    U3Ops ops = new Ops;
    ops.op3();
}

코드를 이렇게 바꾸면 결합이 느슨해진다.

클린 아키텍처 11장 : 의존성 역전 원칙 (DIP)

소스 코드 의존성이 추상에 의존하며 구체에는 의존하지 않는 시스템

정적 타입 언어에서는 import 구문은 오직 인터페이스나 추상 클래스 같은 추상적인 선언만을 참조해야 한다.
동적 타입 언어에서는 구체 모듈은 참조해서는 안된다. 하지만 이런 언어는 구체 모듈이 무엇인지 정의하기가 어렵다.

정적 타입 언어의 경우 의존성을 주입받으면 런타임 전까지 구현체에 의존하지 않을 수가 있다.

인터페이스를 변경하지 않고 구현체에 기능을 추가할 수 있는 방법을 찾는 것은 소프트웨어 설계의 기본이다.

인터페이스와 DIP의 조합으로 관심사도 분리할 수 있는 것 같다.

클린 아키텍처 12장 : 컴포넌트

컴포넌트는 배포 단위다.
컴포넌트는 배포할 수 있는 단위 입자다.

배포의 경계를 알게 되었습니다.

클린 아키텍처 13장 : 컴포넌트 응집도

REP : 재사용 / 릴리즈 등가 원칙

컴포넌트를 구성하는 모든 모듈은 공유하는 중요한 테마나 목적이 있어야 한다.
하나의 컴포넌트로 묶인 클래스와 모듈은 함께 릴리즈 되어야 한다.

CCP : 공통 폐쇄 원칙

동일한 이유로 동일한 시점에 변경되는 클래스를 컴포넌트로 묶어라
SRP와 비슷하게 하나의 컴포넌트는 변경의 이유가 하나여야 한다.

CRP : 공통 재상용 원칙

강하게 결합되지 않는 클래스는 컴포넌트로 묶으면 안 된다.
어떤 클래스를 묶어야 할지 보다 묶으면 안 될지에 중점을 둔다.

균형 다이어그램

REP와 CCP는 포함, CRP는 배제를 뜻한다.

응집도를 올리를 방법을 알게 되어 좋았습니다.

Java Study

Feeling

글이 읽히지 않는다.

기존 진행 중이던 스터디 (코드 숨, 회사 개발 스터디, 회사 책 스터디)에 Java 스터디를 오늘부터 시작하게 되었는데 이와 함께 개발 외적인 일정이 많이 있는 한 주여서 책이 잘 읽히지 않아 힘들었다.
하지만 최근에 이와 관련된 블로그를 보게 되었다. 이 글이 정말 공감되었고 도움이 많이 되었다.
코드 숨에서도 아샬 님, 종립 님, 윤석 님이 항상 책에 펜으로 적으면서 읽으라고 했는데 이번 기회를 통해 연필(아직은 왠지 볼펜에 손이 안 간다..)로 체크해가며 읽었다.
확실히 읽히지 않던 글이 눈에 들어왔고 아슬아슬 주어진 독서량을 읽을 수 있었다.

하루에 여러 권 읽기

주변에 다독을 하는 분들이 공통적으로 하는 조언은 하루에 2~3권의 책을 작은 분량으로 읽으라는 것이었다.
처음에 힘들었지만 조금씩 적용하다 보니 확실히 독서량이 느는 것이 느껴져서 기분이 좋았다.

Affiramtion

  • 건강이 제일 중요하다. 수면 시간을 보장하자.
  • 코드로 나타낼 수 없으면 내 것이 아니다. 코드로 표현하자.
  • 실무에서의 문제를 해결하지 못하면 좋은 개발자가 될 수 없다. 회사 코드를 1순위로 생각하자.

'TIL' 카테고리의 다른 글

2022/02/12 TIL  (0) 2022.02.13
2022/02/11 TIL  (0) 2022.02.12
2022/02/09 TIL  (0) 2022.02.10
2022/02/08 TIL  (0) 2022.02.08
2022/02/07 TIL  (0) 2022.02.08