문제
1. 특정 배열이 주어졌을 때 (ex [1, 2, 3])
2. 해당 배열의 subarray 만들기 (ex [1], [2], [3], [1,2], [1,3]..)
해결 1. 즉시 평가 방법으로 SubArray 만들기
해결 2. 지연 평가 방법으로 SubArray 만들기
왜 지연평가를 지향해야할까?
생각해보면 두 방법 모두 시간복잡도는 n^2으로 두 번 순회하면서 도는건데 다를게 있나? 라고 생각할 수 있다. 하지만 자세히 살펴보면
먼저 메모리 사용공간에서 차이를 보이게 된다. 즉시평가에서는 result에 모든 subarray를 담게된다. 위 예시를 보았을 때 최종적으로 6개의 배열이 담기는 순간에 return이 호출되고 이를 순회하면서 print되는 것을 확인할 수 있다. 반면 지연평가는 계산 내내 메모리 공간을 "하나의 배열"만 사용한다. 만약 메모리 공간을 엄청나게 사용해야하는 코드라면 즉시평가일때는 메모리가 터지지만 지연평가로 바꾸면 메모리가 안터지는 것을 경험할 수 있을 것이다.
두번째는 계산을 취소하고 싶을 때 불필요한 연산 과정을 줄일 수 있게된다. 만약 위 예제에서 [2]라는 배열이 subArray에 포함되어있는지 확인해야한다고 하자. 코드는 비슷해보이더라도 즉시평가방법은 모든 SubArray를 Result에 담은 다음에 Result에 for문 순회를 돌려서 [2] 가 나오는지 하나씩 비교해서 체크해야한다. 하지만 지연평가는 SubArray를 만드는 도중 [2] 배열이 나오면 즉시 스탑해서 결과값을 리턴할 수 있다.
세번째로 사이드 이펙트를 없앨 수 있다. 이건 개인적으로 iterator를 쓰면 코드가 예뻐진다는 느낌이 드는부분인데 1번 방법에서는 subarray를 구하면서 result 배열의 상태가 계속해서 변하는 것을 확인할 수 있다. 이는 for문 함수 밖에 존재하는 일종의 사이드 이펙트다. (물론 함수내부 상태이기 때문에 사이드 이펙트라고 부르긴 그렇지만 편의상 이렇게 표현했다) 반면 iterator의 경우에는 함수 내에 중간 상태 선언이라는 사이드이펙트가 사라지고 결과값이 보장되는 예쁜 함수(?)가 된다.
상태가 꼭 필요한지 필요하지 않은지 판단후 즉시평가, 지연평가 방법 선택하기
개념 | 동기 | 비동기 |
지연 평가 | Iterable (sync* + yield) | Stream (async* + yield) |
즉시 평가 | List, Set, Map | Future, Future<List> 등 |
즉시평가와 지연평가, 어떻게 프로젝트에 활용할 수 있을까? 기준은 상태가 필요한가 필요하지 않은가에 있다.
상태가 필요한 경우를 생각해보자. 플러터는 UI에 데이터를 보여주어야한다. 이는 정지된 데이터이기 때문에 PresentationLayer에는 어쩔수 없이 상태가 들어갈 수 밖에 없다. 즉 상태는 필수적이게 되고 이를 Bloc이나 Riverpod 같은 상태관리 도구로 최대한 상태는 한 곳에 모아서 인풋 액션 아웃풋 상태 옵저빙 형태로 다뤄주어야하는 방향이 되어버린다.
반면 상태가 필요하지 않은 대표적인 구역은 네트워크 통신이다. 캐싱을 제외하면 서버로부터 받은 데이터를 프레젠테이션 레이어까지 순수 연산로직만으로 전달해줄 수 있기 때문이다.
변하기 쉬운 상태는 최대한 한 곳에 모아 즉시평가를, 이외 로직들은 지연평가 방법으로 바꾸어 예측가능성 높은 코드를 작성하는 습관을 들여야겠다 :)
'Mobile Develop' 카테고리의 다른 글
Flutter가 UI를 렌더링하는 과정 살펴보기 (0) | 2025.04.28 |
---|---|
외부 객체에서 State 함수에 접근하는 방법 (0) | 2025.04.19 |
Stateless Widget 과 Stateful Widget 의 선택 기준 (0) | 2025.02.02 |
Jenkins가 Flutter 경로를 찾지 못해 발생한 이슈 트러블 슈팅 (0) | 2025.01.23 |
이벤트에 반응하여 Stateless 위젯 아이콘 이미지 색 바꾸기 (0) | 2024.08.13 |