<번역/정리> 11가지 플러터 람다 기법으로 코드가 200% 깔끔해지는 방법

2025. 5. 21. 19:04·Flutter/하루 한 입 플러터

https://medium.com/@alaxhenry0121/11-flutter-lambda-techniques-that-will-make-your-code-200-cleaner-424e6d21b796 더 깔끔한 코드, 더 스마트한 작업

 

11 Flutter Lambda Techniques That Will Make Your Code 200% Cleaner

Learn how to leverage Flutter lambdas to write cleaner, more maintainable code. These 11 practical techniques will transform your Flutter.

medium.com

제가 이해하기 위해 달아놓은 주석들은 이 글씨로 표시됩니다.

 

📌 모든 Flutter 프로젝트에서 제가 겪었던 코딩 악몽

2년 전, 저는 간단해 보이는 Flutter 앱을 디버깅하고 있었습니다. 사용자는 카탈로그를 탐색하고, 장바구니에 아이템을 추가하고, 결제할 수 있었습니다. 하지만 기능이 늘어남에 따라 코드베이스 문제도 커졌습니다. 이벤트 핸들러는 여기저기 흩어져 있었고, 콜백 지옥이 사용자 인터랙션을 괴롭혔으며, 최악의 문제는 상태 관리가 예측 불가능한 엉망진창이 되었다는 것입니다.

제가 참석했던 워크숍에서 한 Flutter 전문가가 제 접근 방식을 영원히 바꿔놓을 말을 했습니다.

"Flutter에서 함수와 콜백을 처리하는 방식은 여러분의 코드를 유지 관리하기 즐거운 것으로 만들 수도 있고, 디버깅하기 끔찍한 악몽으로 만들 수도 있습니다." - Flutter DevSummit 2023


그의 말이 옳았습니다. 우리 코드베이스를 분석한 결과, 초기 단계에 작성된 형편없이 구조화된 콜백 함수와 이벤트 핸들러에서 70%의 버그가 발생했다는 것을 발견했습니다.

그때 저는 Flutter 람다와 함수형 프로그래밍의 세계에 깊이 빠져들었습니다. 저는 어떤 튜토리얼에서나 볼 수 있는 기본적인 익명 함수에 대해 이야기하는 것이 아닙니다. 엉킨 코드를 깨끗하고 유지 관리 가능한 걸작으로 바꿀 수 있는 강력하고 우아한 기술을 의미합니다.

오늘 저는 앱을 구축하는 방식을 혁신한 11가지 Flutter 람다 기술을 공유하고 싶습니다. 이것들은 단순한 "코딩 트릭"이 아니라, 프로젝트가 10만 줄 이상의 코드로 성장해도 제 코드베이스를 깨끗하고 관리하기 쉽게 유지하는 데 도움이 된 전략적 패턴입니다.

Flutter 문서에서 제안하듯이 (하지만 실제로 구현하는 개발자는 거의 없습니다):

"함수형 프로그래밍은 단순히 함수를 사용하는 것에 그치지 않고, 올바른 함수를 올바른 방식으로, 올바른 추상화 수준에서 조합하여 솔루션을 만드는 것입니다."


프로젝트가 커짐에 따라 자체 복잡성으로 인해 무너지지 않는 Flutter 앱을 만들고 싶다면 계속 읽으십시오.

 

🚀 1. 간단한 람다 - 더 깨끗한 Flutter 코드의 관문

람다 표현식(익명 함수라고도 함)은 대부분의 Flutter 개발자에게 친숙하겠지만, 그 잠재력을 최대한 활용하는 사람은 거의 없습니다.

// 이렇게 하지 말고
void onPressed() {
  print('Button pressed!');
}
...
ElevatedButton(
  onPressed: onPressed,
  child: Text('Click me'),
)

// 이렇게 작성하세요
ElevatedButton(
  onPressed: () => print('Button pressed!'),
  child: Text('Click me'),
)

장점:

  • 코드의 시각적 clutter 감소
  • 관련된 기능을 함께 유지
  • 간단한 이벤트 핸들러 및 콜백에 적합
  • 위젯 트리의 가독성 향상

단점:

  • 복잡한 로직에는 다루기 어려울 수 있음
  • 제한적인 디버깅 정보
  • 과용하기 쉽고 "화살표 지옥"을 만들 수 있음

최적의 사용: UI 이벤트 핸들러, 간단한 콜백, 리스트 변환.

피해야 할 경우: 함수 로직이 2-3줄 이상이거나 복잡한 오류 처리가 필요한 경우.

실제 경험: 저는 흩어져 있는 메서드가 있는 400줄짜리 위젯을 모든 간단한 이벤트 핸들러에 람다를 전략적으로 사용하여 깔끔한 150줄짜리 컴포넌트로 줄였습니다.

 

 

2. 다중 명령문 람다 - 한 줄 이상이 필요할 때

콜백 로직에 여러 명령문이 필요한 경우에도 블록 본문 구문을 사용하여 람다를 사용할 수 있습니다.

ElevatedButton(
  onPressed: () {
    final user = UserManager.getCurrentUser();
    if (user != null) {
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => ProfileScreen(user: user)),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Please log in first')),
      );
    }
  },
  child: Text('View Profile'),
)

장점:

  • 관련된 로직을 위젯과 함께 유지
  • 이 핸들러만을 위한 별도의 메서드를 만들 필요 없음
  • 더 나은 컨텍스트 보존
  • 중간 정도 복잡성의 로직에 대한 가독성 향상

단점:

  • 과용하면 위젯 트리의 가독성이 떨어질 수 있음
  • 명명된 함수에 비해 여전히 제한적인 디버깅
  • UI 코드에 복잡성을 숨길 수 있음

최적의 사용: 단일 위젯에 특정한 중간 정도 복잡성의 이벤트 핸들러.

피해야 할 경우: 동일한 로직이 여러 곳에서 재사용되거나 10줄을 초과하는 경우.

폼 제출 로직을 흩어져 있는 메서드 대신 블록 본문 람다를 사용하도록 리팩토링한 후, 우리 팀의 신규 개발자 온보딩 시간이 며칠에서 몇 시간으로 줄었습니다.


3. 람다 클로저 - 우아하게 컨텍스트 캡처하기

람다의 가장 강력한 기능 중 하나는 해당 스코프 내의 변수를 "클로즈 오버"할 수 있다는 것입니다. (캡쳐 할 수 있음) 

Widget buildCounter(String label, int initialValue) {
  int counter = initialValue;

  return StatefulBuilder(
    builder: (context, setState) => Column(
      children: [
        Text('$label: $counter'),
        ElevatedButton(
          onPressed: () => setState(() => counter++),
          child: Text('Increment'),
        ),
      ],
    ),
  );
}

장점:

  • 클래스 수준 변수 없이 상태를 캡슐화
  • 깨끗하고 자체 포함된 컴포넌트 생성
  • prop drilling 감소
  • 코드의 모듈성 향상

단점:

  • 클로저를 이해하지 못하면 예상치 못한 동작을 초래할 수 있음
  • 적절히 관리하지 않으면 메모리 누수를 일으킬 수 있음
  • 독립적으로 테스트하기 어려움

최적의 사용: 내부 상태 또는 동작을 가진 재사용 가능한 UI 컴포넌트 생성.

피해야 할 경우: 상태가 앱 전체에 광범위하게 공유되거나 영구 저장되어야 하는 경우.

저는 클로저 기반 람다를 사용하여 20개 이상의 필드가 있는 폼을 각자 자체 유효성 검사 상태를 관리하는 모듈식 컴포넌트로 리팩토링했습니다. 그 결과 코드는 60% 줄었고, 상태 관련 버그는 100% 감소했습니다.

 

 

여기서 왜 중첩된 람다구문을 써야하는지 이해가 안갔다 

본격 람다 파헤치기

더보기
더보기
더보기
Widget buildCounter(String label, int initialValue) {
  int counter = initialValue;

  return StatefulBuilder(
    builder: (context, setState) {
      void increment() {
        setState(() {
          counter++;
        });
      }

      return Column(
        children: [
          Text('$label: $counter'),
          ElevatedButton(
            onPressed: increment,
            child: Text('Increment'),
          ),
        ],
      );
    },
  );
}

저 코드가 만약 중첩된 람다 구문이 아닐 경우를 작성해봤는데, 이렇다고 볼 수 있겠다.

 

이게 왜 중첩된 구문이 되는 것일까 


1. 바깥쪽 람다: () => ...

- (): 파라미터가 없는 익명 함수를 정의합니다. 버튼이 눌릴 때 이 함수가 호출
- =>: 이 화살표 뒤에 오는 표현식의 결과가 이 람다 함수의 (암시적인) 반환 값이 됨

2. 안쪽 람다: () => counter++
 setState는 콜백 함수를 인자로 받는다


- () => counter++: 이것이 setState에 전달되는 또 다른 익명 함수 (람다) 임
    - `()`: 파라미터가 없는 익명 함수입니다.
    - `=> counter++`: 이 람다가 실행되면 `counter` 변수의 값을 1 증가시키고 (후위 증가 연산자) 그 값을 반환함 

여기서는 클로저가 캡쳐 한게 핵심인데
- counter 변수는`buildCounter 함수의 스코프 내에서 int counter = initialValue;로 정의
- 안쪽 람다는 이 counter 변수를 자신의 스코프처럼 기억하고 접근하여 값을 변경할  수 있다 ! 

좀 더 (내가) 이해하기 쉽게 실행 순서를 써보자면 

1. 사용자가 `ElevatedButton`을 누름
2. `onPressed`에 할당된 바깥쪽 람다 `() => setState(() => counter++)` 가 실행
3. 바깥쪽 람다는 즉시 `setState()` 함수를 호출
4. `setState()` 함수는 인자로 받은 안쪽 람다 `() => counter++` 를 나중에 (Flutter 프레임워크가 적절한 시점에) 실행
5. 안쪽 람다가 실행되면서 클로즈 오버된 `counter` 변수의 값이 1 증가
6. `setState()`가 호출되었기 때문에 Flutter는 해당 위젯 (`StatefulBuilder` 내부의 익명 빌더 함수가 반환하는 `Column` 등)을 다시 빌드함
7. 다시 빌드 과정에서 `Text('$label: $counter')` 는 업데이트된 `counter` 값을 화면에 표시하게 됨 



onPressed: () => setState(() => counter++) 는 바깥쪽 람다 안에서 setState 함수를 호출하며, setState에 상태 업데이트 로직을 담은 안쪽 람다를 전달하는 방식으로 클로저를 활용하여 counter변수를 업데이트하고 UI를 갱신한다...
 ㄴ 너무 아직은 생소한 느낌이라 잘 쓸 수 있을지를 모르겠다 

 

 

 

 

4 변환 람다 - 컬렉션을 우아하게 처리하기

Dart의 함수형 컬렉션 메서드를 람다와 함께 사용하면 데이터 처리를 획기적으로 단순화할 수 있습니다.

// 이렇게 하지 말고
List<Widget> buildUserTiles(List<User> users) {
  List<Widget> tiles = [];
  for (var user in users) {
    if (user.isActive) {
      tiles.add(ListTile(
        title: Text(user.name),
        subtitle: Text(user.email),
      ));
    }
  }
  return tiles;
}

// 이렇게 작성하세요
List<Widget> buildUserTiles(List<User> users) {
  return users
      .where((user) => user.isActive)
      .map((user) => ListTile(
            title: Text(user.name),
            subtitle: Text(user.email),
          ))
      .toList();
}

장점:

  • 훨씬 더 간결한 코드
  • 명령형이 아닌 선언형 스타일
  • 복잡한 변환을 위한 체인 가능한 연산
  • 더 읽기 쉬운 의도

단점:

  • 매우 큰 컬렉션에서 성능 영향
  • 함수형 프로그래밍에 익숙하지 않은 개발자에게는 학습 곡선이 가파름
  • 디버깅하기 더 어려울 수 있음

최적의 사용: 데이터 구조 변환, 리스트 필터링, 위젯 컬렉션 빌드.

피해야 할 경우: 매우 성능에 민감한 코드와 거대한 데이터셋.

대시보드 앱에서 200줄 이상의 명령형 코드를 단 30줄의 변환 람다로 대체하여 데이터 처리를 더 유지 관리하기 쉽고 효율적으로 만들었습니다.

 

5. 파라미터로서의 콜백 함수 - 고차 함수의 힘

람다를 파라미터로 받는 고차 함수는 코드 재사용성을 획기적으로 향상시킬 수 있습니다.

Future<void> withErrorHandling(
  BuildContext context,
  Future<void> Function() action,
) async {
  try {
    await action();
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Error: ${e.toString()}')),
    );
  }
}
// 사용법
ElevatedButton(
  onPressed: () => withErrorHandling(
    context,
    () async => await userRepository.deleteAccount(),
  ),
  child: Text('Delete Account'),
)

장점:

  • 오류 처리와 같은 횡단 관심사를 중앙 집중화
  • 중복을 크게 줄임
  • 코드 의도를 더 명확하게 함
  • 강력한 추상화 가능

단점:

  • 주니어 개발자에게 혼란스러울 수 있음 ( 너무 혼란스러워요 )
  • 실행 흐름을 가릴 수 있음
  • 과용하면 콜백 지옥의 가능성

최적의 사용: 오류 처리, 로딩 상태, 권한 및 기타 횡단 관심사.

피해야 할 경우: 추상화로 인해 코드를 이해하기 어려워지는 경우.

API 호출에 대한 고차 함수 패턴을 구현한 후, 우리 팀은 오류 처리 코드를 80% 줄였고 여러 종류의 버그를 완전히 제거했습니다.

 

이 부분을 이해하기 위해 정리해보겠다. 

더보기
더보기
더보기

 

Future<void> withErrorHandling( 
// 이 함수의 의의 자체가 action함수에 담긴 작업을 꺼내서 실행해 보고, 
//혹시 문제가 생기면 알려주는 역할을함
  BuildContext context,
  Future<void> Function() action, 
  //쉽게 말하면 나중에 실행될, 결과가 없을 수도 있는 비동기 작업을 담는 상자 ! 
) async {
  try {
    await action();
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Error: ${e.toString()}')),
    );
  }
}
// 사용법
ElevatedButton(
  onPressed: () => withErrorHandling(
    context,
    () async => await userRepository.deleteAccount(),
  ),
  child: Text('Delete Account'),
)

 

  • withErrorHandling은 작업 실행과 오류 알림을 묶어줍니다.
  • onPressed의 람다는 withErrorHandling을 호출합니다.
  • 호출 시, 현재 화면 정보(context)와 실제 할 일(계정 삭제)을 전달합니다.
  • withErrorHandling은 할 일을 시도하다 에러나면 알림을 보여줍니다.
  • 결과적으로, 버튼 클릭 시 계정 삭제를 시도하고, 실패하면 사용자에게 알려줍니다.

 

 

 

 

6. 스트림 및 Future 변환기 - 람다를 이용한 반응형 프로그래밍

람다는 Flutter의 비동기 프로그래밍 모델로 작업할 때 빛을 발합니다.

Stream<SearchResult> getSearchResults(Stream<String> searchTerms) {
  return searchTerms
      .debounce((_) => TimerStream(true, Duration(milliseconds: 300)))
      .where((term) => term.length > 2)
      .switchMap((term) =>
          _performSearch(term).asStream().catchError((e) => SearchResult.error(e)))
      .startWith(SearchResult.initial());
}

장점:

  • 복잡한 비동기 워크플로우의 우아한 처리
  • 상태 전환에 대한 선언적 접근 방식
  • 상태 관리 복잡성 감소
  • 자연스러운 오류 처리

단점:

  • 학습 곡선이 가파름
  • 디버깅이 어려울 수 있음
  • 간단한 작업에는 잠재적인 성능 오버헤드

최적의 사용: 검색 인터페이스, 폼 유효성 검사 및 복잡한 비동기 요구 사항이 있는 모든 기능.

피해야 할 경우: 기본적인 Future로 충분한 간단한 일회성 비동기 작업.

반응형 람다를 사용하여 검색 기능을 재작성하여 코드를 70% 줄이면서 경합 상태를 제거하고 응답성을 개선했습니다.

 

이해가 안간다면,

더보기
더보기
더보기

(with Gemini)

사용자가 검색어를 입력하는 스트림(searchTerms)을 받아서, 일련의 변환 과정을 거쳐 검색 결과를 내보내는 스트림(Stream<SearchResult>)을 만듭니다.

각 부분 설명:

  1. Stream<SearchResult> getSearchResults(Stream<String> searchTerms):
    • 이 함수는 getSearchResults 라는 이름을 가지고 있습니다.
    • 입력으로 Stream<String> searchTerms 를 받습니다. 이는 사용자가 입력하는 검색어가 시간에 따라 흘러나오는 스트림이라고 생각하시면 됩니다 (예: "apple" -> "appl" -> "app" -> "ap" -> "a").
    • 출력으로 Stream<SearchResult> 를 반환합니다. 이는 검색 결과가 시간에 따라 흘러나오는 스트림입니다.
  2. .debounce((_) => TimerStream(true, Duration(milliseconds: 300))):
    • debounce 는 "디바운싱"이라고 불리는 기술입니다.
    • 사용자가 입력을 멈춘 후 일정 시간(여기서는 300ms)이 지나야 다음 단계로 이벤트를 전달합니다.
    • 예를 들어, 사용자가 빠르게 "apple"을 입력하면, "a", "ap", "app", "appl", "apple" 각각에 대해 검색을 시작하는 것이 아니라, 마지막 입력 후 300ms 동안 추가 입력이 없으면 "apple"에 대해서만 검색을 시작합니다. 이는 불필요한 검색 요청을 줄여줍니다.
    • (_) => TimerStream(true, Duration(milliseconds: 300)) 는 각 이벤트가 발생할 때마다 300ms 타이머를 시작하는 람다 함수입니다.
  3. .where((term) => term.length > 2):
    • where 는 특정 조건을 만족하는 이벤트만 다음 단계로 전달합니다.
    • 여기서는 검색어(term)의 길이가 2보다 큰 경우에만 다음 단계로 전달합니다. 짧은 검색어 (예: "a", "ab")에 대한 검색은 무시합니다.
  4. .switchMap((term) => _performSearch(term).asStream().catchError((e) => SearchResult.error(e))):
    • switchMap 은 각 검색어(term)를 받아서 새로운 스트림으로 변환합니다.
    • _performSearch(term) 은 실제 검색을 수행하는 (아마도 비동기) 함수라고 추측할 수 있습니다. 이 함수는 검색 결과를 반환할 것입니다.
    • .asStream() 은 _performSearch 가 반환하는 결과를 스트림으로 변환합니다 (아마도 Future 일 가능성이 높습니다).
    • .catchError((e) => SearchResult.error(e)) 는 검색 중에 오류가 발생하면, 오류 정보를 담은 SearchResult.error(e) 를 스트림으로 내보냅니다.
    • switchMap 의 중요한 점은, 새로운 검색어가 들어오면 이전의 진행 중이던 검색 스트림을 취소하고 새로운 검색 스트림으로 전환한다는 것입니다. 예를 들어, "appl" 검색 중에 "apple" 이 입력되면, "appl" 검색 결과는 무시되고 "apple" 검색 결과만 기다립니다.
  5. .startWith(SearchResult.initial()):
    • startWith 는 스트림이 시작될 때 초기 값 (SearchResult.initial())을 먼저 내보냅니다. 이는 검색이 아직 시작되지 않았거나 로딩 중인 상태를 UI에 보여주는 데 유용할 수 있습니다.

요약하자면, 이 코드는 다음과 같은 과정을 거쳐 검색 결과를 스트림으로 제공합니다.

  1. 사용자 입력 스트림을 받습니다.
  2. 입력 멈춤 후 300ms 동안 기다립니다.
  3. 길이가 2보다 큰 검색어만 처리합니다.
  4. 각 검색어에 대해 실제 검색을 수행하고, 결과를 스트림으로 변환하며, 오류를 처리합니다. (새로운 검색어 입력 시 이전 검색은 취소됩니다.)
  5. 시작 시 초기 상태를 스트림으로 먼저 내보냅니다.

이 코드는 반응형 프로그래밍의 강력한 기능을 활용하여 사용자 경험을 향상시키고 불필요한 작업을 줄이는 데 도움이 됩니다.

7. 메모이제이션된 람다 - 우아한 성능 최적화

메모이제이션은 비용이 많이 드는 함수 결과를 캐싱하여 성능을 획기적으로 향상시킬 수 있습니다.

Function<T, R> memoize<T, R>(R Function(T) fn) {
  final cache = <T, R>{};
  return (T param) {
    if (cache.containsKey(param)) return cache[param]!;
    final result = fn(param);
    cache[param] = result;
    return result;
  };
}
// 사용법
final getExpensiveData = memoize<String, Future<Data>>((id) async {
  return await apiService.fetchDetailedData(id);
});

장점:

  • 비용이 많이 드는 작업에 대한 극적인 성능 향상
  • 우아하고 선언적인 구현
  • 서버 부하 및 배터리 소모 감소
  • 호출 코드에 투명함

단점:

  • 캐시 크기에 따라 메모리 사용량 증가
  • 적절히 관리하지 않으면 오래된 데이터가 발생할 수 있음
  • 가변 데이터에 대해서는 추론하기 어려움

최적의 사용: 동일한 파라미터로 반복적으로 호출되는 비용이 많이 드는 계산, API 호출 및 복잡한 데이터 변환.

피해야 할 경우: 자주 변경되는 데이터로 작업하거나 메모리가 심각하게 제약되는 경우.

보고서 생성 기능에 메모이제이션을 적용했는데, 이전에는 3초가 걸리던 작업이 반복 호출 시 즉시 완료됩니다.

 

8. 커링된 함수 - 유연한 API를 위한 부분 적용

커링은 부분적으로 적용할 수 있는 함수를 생성하여 범용 함수에서 특화된 함수를 만듭니다.

Function(String) createUrlBuilder(String baseUrl) {
  return (endpoint) => '$baseUrl/$endpoint';
}
// 사용법
final apiUrlBuilder = createUrlBuilder('<https://api.example.com/v1>');
final usersUrl = apiUrlBuilder('users');  // <https://api.example.com/v1/users>
final ordersUrl = apiUrlBuilder('orders'); // <https://api.example.com/v1/orders>

장점:

  • 재사용 가능하고 특화된 함수 생성
  • 중복 감소
  • 코드의 구성 가능성 향상
  • 강력하고 유연한 API 가능

단점:

  • 많은 개발자에게 익숙하지 않은 구문
  • 과용될 수 있음
  • 함수 의도를 가릴 수 있음

최적의 사용: 구성, 어댑터 및 관련 함수 패밀리 생성.

피해야 할 경우: 커링이 불필요한 복잡성을 더하는 간단한 일회성 함수.

저는 커링을 사용하여 특화된 HTTP 요청 함수 패밀리를 만들어 네트워킹 코드를 40% 줄이면서 더 유지 관리하기 쉽게 만들었습니다.

 

9. 함수 합성 - 간단한 함수에서 복잡한 동작 구축

합성을 사용하면 간단한 함수를 결합하여 복잡한 동작을 구축할 수 있습니다.

T Function(V) compose<T, U, V>(T Function(U) f, U Function(V) g) {
  return (V v) => f(g(v));
}
// 사용법
final validateAndNormalize = compose<String, String, String>(
  (s) => s.trim().toLowerCase(),  // normalize
  (s) => s.isNotEmpty ? s : throw 'Empty input',  // validate
);

장점:

  • 깨끗하고 재사용 가능한 함수 파이프라인 생성
  • 복잡한 작업을 더 간단한 작업으로 분해
  • 단일 책임 함수 장려
  • 코드의 테스트 용이성 향상

단점:

  • 디버깅하기 어려울 수 있음
  • 일부 개발자에게 익숙하지 않을 수 있음
  • 타입 어노테이션이 장황해질 수 있음

최적의 사용: 데이터 처리 파이프라인, 유효성 검사 체인 및 변환.

피해야 할 경우: 작업이 너무 간단하여 합성이 불필요한 복잡성을 추가하는 경우.

우리의 텍스트 처리 파이프라인은 300줄의 엉망진창에서 각각 약 10줄의 10개의 합성된 함수로 바뀌었고, 유지 관리성이 크게 향상되었습니다.

 

10. 방어적 람다 - Dart의 null safety 이전의 null 안전성

Dart의 null safety가 있더라도 방어적 람다는 코드를 더 강력하게 만들 수 있습니다.

// Dart null safety 이전
V Function(T) guard<T, V>(V Function(T) fn, V defaultValue) {
  return (T param) {
    try {
      return fn(param);
    } catch (e) {
      return defaultValue;
    }
  };
}
// 사용법
final safeGetUserName = guard<User?, String>(
  (user) => user!.name,
  'Guest',
);

장점:

  • 런타임 예외 방지
  • 코드의 견고성 향상
  • 오류 처리 중앙 집중화
  • 사용자 경험 개선

단점:

  • 실제 버그를 숨길 수 있음
  • 함수 호출 오버헤드 추가
  • Dart null safety에서는 덜 필요함

최적의 사용: 실패를 정상적으로 처리해야 하는 외부 데이터, 사용자 입력 및 API 응답.

피해야 할 경우: 오류가 숨겨서는 안 되고 해결해야 할 실제 문제를 나타내는 경우.

API 응답 핸들러를 방어적 람다로 감싼 후 충돌이 95% 감소하고 사용자 유지율이 낮아집니다

 

 

저작자표시 비영리 동일조건 (새창열림)

'Flutter > 하루 한 입 플러터' 카테고리의 다른 글

<번역> Mastering Scrollable in Flutter  (0) 2025.02.20
'Flutter/하루 한 입 플러터' 카테고리의 다른 글
  • <번역> Mastering Scrollable in Flutter
복복씨
복복씨
개발자여, 사고하라 !
  • 복복씨
    정리노트
    복복씨
  • 전체
    오늘
    어제
    • 분류 전체보기 (118)
      • 개발새발자 (21)
        • 의 삶 (7)
        • 의 회고 (9)
        • 의 낙서장 (5)
        • 영어 (0)
      • FrontEnd (1)
        • React (1)
      • Flutter (38)
        • 새싹 (5)
        • Dart (8)
        • Flutter (14)
        • iOS 에서 Flutter 로 전환하며 (2)
        • 챗지피티랑놀.기 (3)
        • 하루 한 입 플러터 (2)
      • CS (7)
        • 짤막지식 (6)
      • IOS (6)
        • Swift (0)
        • UIKit (1)
        • SwitUI (4)
      • 머신러닝-딥러닝 (28)
        • 논문리뷰 (3)
        • study (16)
        • Kaggle (9)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    runzonedguarded
    Flutter Lifecycle
    dart
    시그널링데이터
    새싹
    getit
    플러터
    플러터 새싹
    테킷 앱스쿨
    깊은참조
    futurerecord2
    initState()
    부트캠프
    schedulemicrotask
    FLUTTER
    새싹 용산
    unawaited
    한주 회고
    코드 결합도
    IOS
    사그널링서버
    플러터 di
    flutter lottie
    flutter 애니메이션
    새싹 플러터
    swiftui 플러터
    용산캠
    핫 리로드
    expando
    멋쟁이 사자처럼
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
복복씨
<번역/정리> 11가지 플러터 람다 기법으로 코드가 200% 깔끔해지는 방법
상단으로

티스토리툴바