클린 아키텍처 스터디 2부 정리

Adam·2023년 1월 10일
0

클린 아키텍쳐

목록 보기
3/7
post-thumbnail
  • 2부에서 크게 다룰 구조는 구조적 프로그래밍, 객체 지향 프로그래밍, 함수형 프로그래밍이다
  • 해당 패러다임은 개발자가 하지 말아야 할지 알려준다.

구조적 프로그래밍

goto문 보다는 조건/반복문을 사용하는 프로그래밍 방식

goto문이란?

C언어에서 어떤 특정 함수를 실행하게끔 하는 커맨드 aka jump문
ex)

#include <stdio.h>
int main()
{
    int i, j;

    for ( i = 0; i < 10; i++ )
    {
        printf_s( "Outer loop executing. i = %d\n", i );
        for ( j = 0; j < 2; j++ )
        {
            printf_s( " Inner loop executing. j = %d\n", j );
            if ( i == 3 )
                goto stop;
        }
    }

    // This message does not print:
    printf_s( "Loop exited. i = %d\n", i );

    stop:
    printf_s( "Jumped to stop. i = %d\n", i );
}

Output

Outer loop executing. i = 0
Inner loop executing. j = 0
Inner loop executing. j = 1
Outer loop executing. i = 1
Inner loop executing. j = 0
Inner loop executing. j = 1
Outer loop executing. i = 2
Inner loop executing. j = 0
Inner loop executing. j = 1
Outer loop executing. i = 3
Inner loop executing. j = 0
Jumped to stop. i = 3
  • 무분별한 goto문을 활용하는 것보다는 분기와 반복이라는 제어구조를 사용하는 것이 효율적으로 세분화 하는 것이 가능하다는 이념을 가진 구조 이념
  • 모든 프로그램을 순차, 분기, 반복 3가지 구조로만 표현이 가능하다
  • 현재는 구조적 프로그래밍이 일반화 되면서 goto문은 거의 사용되지 않음
  • 거대한 소프트웨어에 대한 기획을 받더라도 해당 소프트웨어을 고수준의 기능들로 분해 이를 다시 저수준의 함수들로 분해하고 이런 분해된 기늗을을 구조적 프로그래밍의 구조를 이용해 표현이 가능

결론

구조적 프로그래밍이 가치 있는 이유

  • 프로그래밍에서 반증 가능한 단위를 만들어 낼 수 있음
  • 프로그램의 흐름이 복잡해지는 것을 막음

아키텍트의 자세

소프트웨어 아키텍트는 모듈, 컴포넌트, 서비스가 쉽게 반증 가능하도록(테스트하기 쉽도록) 만들기 위해 노력해야되며 이를 위해 구조적 프로그래밍과 유사한 제한적인 규칙들을 받아들여야됨

객체 지향 프로그래밍

캡슐화, 상속, 다형성에 대한 이해가 필수

캡슐화

데이터와 함수가 구성된 집단을 확실히 구분을 지을 수 있고, 이 구분선을 기준으로 바깥에서 데이터는 은닉이 되고 public 표기가 된 함수만 노출이 됨

완전 캡슐화

오브젝트에 포함되어 있는 변수는 외부에서 직접 접근하지 못하게 하고, 이 변수와 연관된 메소드를 만들어 메소드를 통해서만 변수에 접근할 수 있게 하는 것(변수는 private 메소드는 public)

@Service
@RequiredArgsConstructor
public class EventImagesService {
    private final EventImagesRespository eventImagesRespository;

    public void save(EventImages eventImages){
        eventImagesRespository.save(eventImages);
    }

    public List<EventImages> findByEventIdx(int eventIdx) {
        return eventImagesRespository.findByEventIdx(Long.valueOf(eventIdx));
    }
}

서비스 클라스에서 레포지토리는 직접 접근하지 못하고 이 안에 있는 메소드 save와 findByEventIdx만 접근 가능

이때 save 메소드의 eventImages명이 바뀌게 된다면 다시 컴파일 과정에서 오류가 뜨는데 이는 캡슐화가 깨진 것이다.

상속

자식 클래스가 부모 클래스를 선택해서 물려 받는 것.
이때 자식 클래스가 부모 클래스로 부터 필드와 메서드를 물려 받는다.

상속의 장점

중복 된 코드를 줄이고, 유지보수가 편리

class A {
	String aField = "클래스 A 필드";
	public void aMethod() {
		System.out.println(aField);
		// System.out.println("A : "+ bField); // 컴파일 에러(자식 필드 사용 불가)
	}
}

class B extends A {
	String bField = "클래스 B 필드";
	public void bMethod() {
		System.out.println(aField); // 부모 클래스 필드 사용
		System.out.println(bField); // 본인 클래스 필드 사용
		// System.out.println("B : "+cField); // 컴파일 에러(자식 필드 사용 불가)
	}
}

class C extends B {
	String cField = "클래스 C 필드";
	public void cMethod() {
		System.out.println(aField); // 조부모 클래스 필드 사용
		System.out.println(bField); // 부모 클래스 필드 사용
		System.out.println(cField); // 본인 클래스 필드 사용
	}
}

자식 클래스가 더 다양한 기능이 가능하므로 자식 클래스로 인스턴스를 생성하는 것이 효율적이다.

다형성

부모-자식 상속 관계에 있는 클래스에서 상위 클래스가 동일한 메시지로 하위 클래스들을 서로 다르게 동작시키는 객체 지향 원리
부모 클래스가 자식 클래스의 동작 방식을 알수 없어도 오버라이딩을 통해 자식 클래스를 접근
이는 실행 시점에서 성격이 결정되는 동적 바인딩 때문, 컴파일 시점에는 부모 클래스가 자식의 맴버 함수밖에 접근 불가

다형성의 장점

  1. 여러 객체를 하나의 타입으로 관리해 유지보수가 쉬움
  2. 객체를 재사용하는 것이 쉬워짐
  3. 클래스간 의존성이 줄어들어 확장성이 높아짐

의존성의 역전

기존에는 main함수가 고수준의 함수를 호출, 고수준의 함수가 저수준의 함수를 호출하는 제어의 흘름
추상화 된 인터페이스나 상위클래스를 두어서 변화에 영향을 받지 않게 하는 것

  • 배포 독립성 : 특정 컴포넌트의 소스코드가 변경이 되면 해당 코드만 배포해도 된다
  • 개발 독립성 : 독립적으로 배포가 가능하기 때문에 모듈을 독립적으로 개발 가능

함수형 프로그래밍

자료처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임
race, deadlock, concurrent update 모두 가변변수로 인해 발생

  • race condtion : 두 개 이상의 프로세스가 공통 자원을 병행적으로 읽거나 쓰는 동작을 할 때, 공용 데이터에 대한 접근이 어떤 순서에 따라 이루어졌는지에 따라 그 실행 결과가 같지 않고 달라지는 상황
  • deadlock : 프로세스가 각자 프로그램을 실행하기 위해 두 자원 모두에 엑세스 해야할 때, 프로세스는 두 자원 모두를 필요로 하므로 필요한 두 리소스를 사용하여 프로그램을 수행할 때까지 이미 소유한 리소스를 해제하지 않는 상태
  • concurrent update : 여러 데이터베이스 세션이 한 데이터를 동시에 업데이트 하게 했을때 데이터에 이상이 발생하는 현상

어플리케이션을 제대로 구조화하려면 변수를 변경하는 컴포넌트와 변경하지 않는 컴포넌트를 분리할 필요가 있으며 이렇게 분리 후 가변 변수들을 보호하는 적절한 수단이 있어야 한다.
최대한 많은 처리를 불편 컴포넌트로 옮기고 가변 컴포넌트는 최대한 적게 사용해야함

이벤트 소싱

하드웨어적 성능이 증가하며 가변 변수를 사용할 필요성이 감소
상태가 아닌 트랜잭션을 저장하는 전략이 이벤트 소싱

함수형 프로그래밍 예시

Java에서 forloop 대신 forEach를 사용하는 방식

List<Integer> numbers = List.of(1, 2, 3, 4, 5);

//for loop
for (int idx = 0; idx < numbers.size(); idx++) {
   System.out.println(numbers.get(idx));
}

//functional
numbers.forEach((num) -> {
   System.out.println(num);
});

forloop에서는 idx가 가변적 변수지만 forEach문을 쓰게 되면 각 num에 값이 할당이 돼 변경이 되지 않는 컴포넌트로 할당이 돼 사용할 수 있다.
혹은 final 변수를 선언하는 방식도 자바에서 함수형 프로그램의 예시이다

profile
Keep going하는 개발자

0개의 댓글