{"id":84,"date":"2025-07-16T14:46:50","date_gmt":"2025-07-16T05:46:50","guid":{"rendered":"http:\/\/34.64.61.65\/?p=84"},"modified":"2025-07-16T14:51:23","modified_gmt":"2025-07-16T05:51:23","slug":"3-flutter-%ed%94%8c%eb%9f%ac%ed%84%b0%ec%9d%98-%ec%8b%ac%ec%9e%a5-dart-%ec%96%b8%ec%96%b4-%ea%b0%9c%eb%b0%9c-%ec%b4%88%eb%b3%b4%eb%8f%84-%ec%89%bd%ea%b2%8c-%eb%b0%b0%ec%9a%b0%eb%8a%94-%ea%b8%b0","status":"publish","type":"post","link":"https:\/\/hed-g.me\/?p=84","title":{"rendered":"3. [Flutter] \ud50c\ub7ec\ud130\uc758 \uc2ec\uc7a5, Dart \uc5b8\uc5b4! \uac1c\ubc1c \ucd08\ubcf4\ub3c4 \uc27d\uac8c \ubc30\uc6b0\ub294 \uae30\ubcf8 \ubb38\ubc95"},"content":{"rendered":"\n<h1 class=\"wp-block-heading is-style-text-subtitle is-style-text-subtitle--1\">Flutter \uac1c\ubc1c\uc790\ub97c \uc704\ud55c Dart \uc5b8\uc5b4 \uc644\ubcbd \uac00\uc774\ub4dc<\/h1>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Android\/iOS \uac1c\ubc1c\uc790\uac00 Flutter\ub85c \uc804\ud658\ud560 \ub54c \ubc18\ub4dc\uc2dc \uc54c\uc544\uc57c \ud560 Dart \uc5b8\uc5b4\uc758 \ud575\uc2ec \uac1c\ub150\ub4e4<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ub4e4\uc5b4\uac00\uba70<\/h2>\n\n\n\n<p>\uc548\ub155\ud558\uc138\uc694! \ubaa8\ubc14\uc77c \uac1c\ubc1c \uacbd\ud5d8\uc774 \uc788\uc73c\uc2dc\uac70\ub098 \uc6f9 \ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \ubaa8\ubc14\uc77c\ub85c \uc601\uc5ed\uc744 \ud655\uc7a5\ud558\ub824\ub294 \uac1c\ubc1c\uc790\ubd84\ub4e4\uc744 \uc704\ud55c Dart \uc5b8\uc5b4 \uac00\uc774\ub4dc\ub97c \uc900\ube44\ud588\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p>Flutter\ub97c \ubc30\uc6b0\uae30 \uc704\ud574\uc11c\ub294 \uba3c\uc800 Dart \uc5b8\uc5b4\ub97c \uc774\ud574\ud574\uc57c \ud569\ub2c8\ub2e4. \ud558\uc9c0\ub9cc \uac71\uc815\ud558\uc9c0 \ub9c8\uc138\uc694! Java\/Kotlin, Swift, JavaScript\ub97c \uc0ac\uc6a9\ud574\ubcf4\uc2e0 \ubd84\uc774\ub77c\uba74 Dart\ub294 \ub9e4\uc6b0 \uce5c\uc219\ud558\uac8c \ub290\uaef4\uc9c8 \uac83\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\uc774 \uae00\uc5d0\uc11c\ub294 \uc2e4\uc81c Flutter \uc571 \uac1c\ubc1c\uc5d0\uc11c \uc790\uc8fc \uc0ac\uc6a9\ub418\ub294 Dart\uc758 \ud575\uc2ec \uac1c\ub150\ub4e4\uc744 \uc2e4\ubb34 \uc608\uc81c\uc640 \ud568\uaed8 \uc124\uba85\ub4dc\ub9ac\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Dart \uc5b8\uc5b4 \uc18c\uac1c<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uc65c Dart\uc778\uac00?<\/h3>\n\n\n\n<p>Flutter\ud300\uc774 Dart\ub97c \uc120\ud0dd\ud55c \uc774\uc720\ub294 \uba85\ud655\ud569\ub2c8\ub2e4:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>AOT(Ahead-of-Time) \ucef4\ud30c\uc77c<\/strong>: \ub124\uc774\ud2f0\ube0c \uc218\uc900\uc758 \uc131\ub2a5<\/li>\n\n\n\n<li><strong>JIT(Just-in-Time) \ucef4\ud30c\uc77c<\/strong>: \uac1c\ubc1c \uc911 Hot Reload \uc9c0\uc6d0<\/li>\n\n\n\n<li><strong>\uac00\ube44\uc9c0 \uceec\ub809\uc158<\/strong>: \uba54\ubaa8\ub9ac \uad00\ub9ac \uc790\ub3d9\ud654<\/li>\n\n\n\n<li><strong>\ub2e8\uc77c \uc2a4\ub808\ub4dc \ubaa8\ub378<\/strong>: \ubcf5\uc7a1\ud55c \ub3d9\uc2dc\uc131 \ubb38\uc81c \ud574\uacb0<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\ub2e4\ub978 \uc5b8\uc5b4\uc640\uc758 \ube44\uad50<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Java\/Kotlin \uc2a4\ud0c0\uc77c\uacfc \ub9e4\uc6b0 \uc720\uc0ac\nclass User {\n  String name;\n  int age;\n\n  User(this.name, this.age);  \/\/ \uc0dd\uc131\uc790 \ub2e8\ucd95 \ubb38\ubc95\n}\n\n\/\/ JavaScript\ucc98\ub7fc \ub3d9\uc801 \ud0c0\uc774\ud551\ub3c4 \uc9c0\uc6d0\nvar data = {'name': 'John', 'age': 30};<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2. \ubcc0\uc218\uc640 \ud0c0\uc785 \uc2dc\uc2a4\ud15c<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ubcc0\uc218 \uc120\uc5b8\uc758 \ubca0\uc2a4\ud2b8 \ud504\ub799\ud2f0\uc2a4<\/h3>\n\n\n\n<p>Dart\ub294 \uac15\ud0c0\uc785 \uc5b8\uc5b4\uc774\uc9c0\ub9cc \ud0c0\uc785 \ucd94\ub860\uc744 \uc9c0\uc6d0\ud558\uc5ec \uac1c\ubc1c \ud3b8\uc758\uc131\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \ud0c0\uc785 \ucd94\ub860 \ud65c\uc6a9 (\uad8c\uc7a5)\nvar userName = 'John Doe';  \/\/ String\uc73c\ub85c \ucd94\ub860\nvar userAge = 25;           \/\/ int\ub85c \ucd94\ub860\nvar isActive = true;        \/\/ bool\ub85c \ucd94\ub860\n\n\/\/ \uba85\uc2dc\uc801 \ud0c0\uc785 \uc120\uc5b8 (API \uacbd\uacc4\uc5d0\uc11c \uad8c\uc7a5)\nString getUserName() =&gt; userName;\nint calculateAge(DateTime birthDate) =&gt; \n    DateTime.now().year - birthDate.year;\n\n\/\/ \uceec\ub809\uc158 \ud0c0\uc785 \uba85\uc2dc\nList&lt;String&gt; tags = &#91;'flutter', 'dart', 'mobile'];\nMap&lt;String, dynamic&gt; apiResponse = {'status': 'success', 'data': &#91;]};<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">final vs const: \uc2e4\ubb34\uc5d0\uc11c\uc758 \ud65c\uc6a9<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class AppConfig {\n  \/\/ \ucef4\ud30c\uc77c \ud0c0\uc784 \uc0c1\uc218 - \ube4c\ub4dc \uc2dc\uc810\uc5d0 \uacb0\uc815\n  static const String appName = 'MyAwesomeApp';\n  static const int maxRetryCount = 3;\n  static const Duration requestTimeout = Duration(seconds: 30);\n\n  \/\/ \ub7f0\ud0c0\uc784 \uc0c1\uc218 - \uc571 \uc2e4\ud589 \uc911 \ud55c \ubc88\ub9cc \uc124\uc815\n  final String deviceId;\n  final DateTime appStartTime;\n\n  AppConfig() \n    : deviceId = _generateDeviceId(),\n      appStartTime = DateTime.now();\n\n  static String _generateDeviceId() {\n    \/\/ \ub514\ubc14\uc774\uc2a4 \uace0\uc720 ID \uc0dd\uc131 \ub85c\uc9c1\n    return DateTime.now().millisecondsSinceEpoch.toString();\n  }\n}\n\n\/\/ \uc0ac\uc6a9 \uc608\nvoid main() {\n  final config = AppConfig();\n  print('\uc571 \uc774\ub984: ${AppConfig.appName}');\n  print('\uc2dc\uc791 \uc2dc\uac04: ${config.appStartTime}');\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">late \ud0a4\uc6cc\ub4dc: \uc9c0\uc5f0 \ucd08\uae30\ud654 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class ApiService {\n  late final Dio _dio;\n  late final String _baseUrl;\n\n  \/\/ \ucd08\uae30\ud654 \uba54\uc11c\ub4dc\uc5d0\uc11c late \ubcc0\uc218\ub4e4\uc744 \uc124\uc815\n  Future&lt;void&gt; initialize() async {\n    _baseUrl = await _loadBaseUrlFromConfig();\n    _dio = Dio(BaseOptions(\n      baseUrl: _baseUrl,\n      connectTimeout: Duration(seconds: 5),\n      receiveTimeout: Duration(seconds: 10),\n    ));\n  }\n\n  Future&lt;String&gt; _loadBaseUrlFromConfig() async {\n    \/\/ \uc124\uc815 \ud30c\uc77c\uc774\ub098 \ud658\uacbd \ubcc0\uc218\uc5d0\uc11c URL \ub85c\ub4dc\n    return 'https:\/\/api.example.com';\n  }\n\n  Future&lt;Map&lt;String, dynamic&gt;&gt; get(String endpoint) async {\n    final response = await _dio.get(endpoint);\n    return response.data;\n  }\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. \ud568\uc218\uc640 \uba54\uc11c\ub4dc<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ud568\uc218\ud615 \ud504\ub85c\uadf8\ub798\ubc0d \uc2a4\ud0c0\uc77c<\/h3>\n\n\n\n<p>Dart\ub294 \ud568\uc218\ub97c \uc77c\uae09 \uac1d\uccb4\ub85c \ucde8\uae09\ud558\uc5ec \ud568\uc218\ud615 \ud504\ub85c\uadf8\ub798\ubc0d \ud328\ud134\uc744 \uc9c0\uc6d0\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \uace0\ucc28 \ud568\uc218 \ud65c\uc6a9\nList&lt;T&gt; processData&lt;T&gt;(\n  List&lt;T&gt; data,\n  bool Function(T) filter,\n  T Function(T) transform,\n) {\n  return data\n      .where(filter)\n      .map(transform)\n      .toList();\n}\n\n\/\/ \uc2e4\uc0ac\uc6a9 \uc608\uc81c\nclass UserService {\n  List&lt;User&gt; filterActiveUsers(List&lt;User&gt; users) {\n    return processData(\n      users,\n      (user) =&gt; user.isActive &amp;&amp; user.lastLoginDays &lt; 30,\n      (user) =&gt; user.copyWith(displayName: user.name.toUpperCase()),\n    );\n  }\n}\n\n\/\/ \uc775\uba85 \ud568\uc218\uc640 \ud074\ub85c\uc800\nclass EventHandler {\n  final List&lt;VoidCallback&gt; _listeners = &#91;];\n\n  void addListener(VoidCallback callback) =&gt; _listeners.add(callback);\n\n  void fireEvent() {\n    for (final listener in _listeners) {\n      listener();\n    }\n  }\n\n  \/\/ \ud074\ub85c\uc800\ub97c \ud65c\uc6a9\ud55c \uc774\ubca4\ud2b8 \ub9ac\uc2a4\ub108\n  VoidCallback createLoggingListener(String tag) {\n    return () =&gt; print('&#91;$tag] Event fired at ${DateTime.now()}');\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\uc120\ud0dd\uc801 \ub9e4\uac1c\ubcc0\uc218 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Named Parameters (\uad8c\uc7a5 \ud328\ud134)\nclass HttpClient {\n  Future&lt;Response&gt; request(\n    String url, {\n    Map&lt;String, String&gt;? headers,\n    Duration? timeout,\n    int maxRetries = 3,\n    bool followRedirects = true,\n  }) async {\n    \/\/ \uad6c\ud604...\n  }\n}\n\n\/\/ \uc0ac\uc6a9 \uc2dc \uac00\ub3c5\uc131\uc774 \ub9e4\uc6b0 \ub192\uc74c\nfinal response = await httpClient.request(\n  'https:\/\/api.example.com\/users',\n  headers: {'Authorization': 'Bearer $token'},\n  timeout: Duration(seconds: 30),\n  maxRetries: 5,\n);\n\n\/\/ \ube4c\ub354 \ud328\ud134\uacfc \uacb0\ud569\nclass ApiRequestBuilder {\n  String? _url;\n  Map&lt;String, String&gt; _headers = {};\n  Duration _timeout = Duration(seconds: 30);\n\n  ApiRequestBuilder url(String url) {\n    _url = url;\n    return this;\n  }\n\n  ApiRequestBuilder header(String key, String value) {\n    _headers&#91;key] = value;\n    return this;\n  }\n\n  ApiRequestBuilder timeout(Duration timeout) {\n    _timeout = timeout;\n    return this;\n  }\n\n  Future&lt;Response&gt; execute() async {\n    if (_url == null) throw ArgumentError('URL is required');\n    \/\/ HTTP \uc694\uccad \uc2e4\ud589\n  }\n}\n\n\/\/ \uc0ac\uc6a9 \uc608\nfinal response = await ApiRequestBuilder()\n    .url('https:\/\/api.example.com\/users')\n    .header('Authorization', 'Bearer $token')\n    .header('Content-Type', 'application\/json')\n    .timeout(Duration(seconds: 45))\n    .execute();<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4. \ud074\ub798\uc2a4\uc640 \uac1d\uccb4\uc9c0\ud5a5 \ud504\ub85c\uadf8\ub798\ubc0d<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ubaa8\ub358 \ud074\ub798\uc2a4 \uc124\uacc4 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \ubd88\ubcc0 \ud074\ub798\uc2a4 \ud328\ud134 (\uad8c\uc7a5)\nclass User {\n  final String id;\n  final String name;\n  final String email;\n  final DateTime createdAt;\n  final bool isActive;\n\n  const User({\n    required this.id,\n    required this.name,\n    required this.email,\n    required this.createdAt,\n    this.isActive = true,\n  });\n\n  \/\/ copyWith \ud328\ud134\uc73c\ub85c \ubd88\ubcc0\uc131 \uc720\uc9c0\ud558\uba74\uc11c \uc218\uc815\n  User copyWith({\n    String? id,\n    String? name,\n    String? email,\n    DateTime? createdAt,\n    bool? isActive,\n  }) {\n    return User(\n      id: id ?? this.id,\n      name: name ?? this.name,\n      email: email ?? this.email,\n      createdAt: createdAt ?? this.createdAt,\n      isActive: isActive ?? this.isActive,\n    );\n  }\n\n  \/\/ \ud329\ud1a0\ub9ac \uc0dd\uc131\uc790 \ud328\ud134\n  factory User.fromJson(Map&lt;String, dynamic&gt; json) {\n    return User(\n      id: json&#91;'id'] as String,\n      name: json&#91;'name'] as String,\n      email: json&#91;'email'] as String,\n      createdAt: DateTime.parse(json&#91;'created_at'] as String),\n      isActive: json&#91;'is_active'] as bool? ?? true,\n    );\n  }\n\n  Map&lt;String, dynamic&gt; toJson() {\n    return {\n      'id': id,\n      'name': name,\n      'email': email,\n      'created_at': createdAt.toIso8601String(),\n      'is_active': isActive,\n    };\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n    return other is User &amp;&amp;\n        other.id == id &amp;&amp;\n        other.name == name &amp;&amp;\n        other.email == email &amp;&amp;\n        other.createdAt == createdAt &amp;&amp;\n        other.isActive == isActive;\n  }\n\n  @override\n  int get hashCode {\n    return Object.hash(id, name, email, createdAt, isActive);\n  }\n\n  @override\n  String toString() {\n    return 'User(id: $id, name: $name, email: $email, '\n           'createdAt: $createdAt, isActive: $isActive)';\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\ucd94\uc0c1 \ud074\ub798\uc2a4\uc640 \uc778\ud130\ud398\uc774\uc2a4 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \ub370\uc774\ud130 \ub808\uc774\uc5b4 \ucd94\uc0c1\ud654\nabstract class UserRepository {\n  Future&lt;List&lt;User&gt;&gt; getAllUsers();\n  Future&lt;User?&gt; getUserById(String id);\n  Future&lt;User&gt; createUser(User user);\n  Future&lt;User&gt; updateUser(User user);\n  Future&lt;void&gt; deleteUser(String id);\n}\n\n\/\/ \ub85c\uceec \uc800\uc7a5\uc18c \uad6c\ud604\nclass LocalUserRepository implements UserRepository {\n  final Box&lt;Map&lt;dynamic, dynamic&gt;&gt; _userBox;\n\n  LocalUserRepository(this._userBox);\n\n  @override\n  Future&lt;List&lt;User&gt;&gt; getAllUsers() async {\n    return _userBox.values\n        .map((json) =&gt; User.fromJson(Map&lt;String, dynamic&gt;.from(json)))\n        .toList();\n  }\n\n  @override\n  Future&lt;User?&gt; getUserById(String id) async {\n    final json = _userBox.get(id);\n    return json != null \n        ? User.fromJson(Map&lt;String, dynamic&gt;.from(json))\n        : null;\n  }\n\n  @override\n  Future&lt;User&gt; createUser(User user) async {\n    await _userBox.put(user.id, user.toJson());\n    return user;\n  }\n\n  \/\/ ... \ub098\uba38\uc9c0 \uba54\uc11c\ub4dc \uad6c\ud604\n}\n\n\/\/ API \uae30\ubc18 \uad6c\ud604\nclass ApiUserRepository implements UserRepository {\n  final Dio _dio;\n\n  ApiUserRepository(this._dio);\n\n  @override\n  Future&lt;List&lt;User&gt;&gt; getAllUsers() async {\n    final response = await _dio.get('\/users');\n    final List&lt;dynamic&gt; usersJson = response.data&#91;'users'];\n    return usersJson\n        .map((json) =&gt; User.fromJson(json as Map&lt;String, dynamic&gt;))\n        .toList();\n  }\n\n  \/\/ ... \ub098\uba38\uc9c0 \uba54\uc11c\ub4dc \uad6c\ud604\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Mixin\uc744 \ud65c\uc6a9\ud55c \ucf54\ub4dc \uc7ac\uc0ac\uc6a9<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \ub85c\uae45 \uae30\ub2a5\uc744 mixin\uc73c\ub85c \ubd84\ub9ac\nmixin LoggerMixin {\n  String get logTag =&gt; runtimeType.toString();\n\n  void logInfo(String message) {\n    print('&#91;$logTag] INFO: $message');\n  }\n\n  void logError(String message, &#91;Object? error, StackTrace? stackTrace]) {\n    print('&#91;$logTag] ERROR: $message');\n    if (error != null) print('Error: $error');\n    if (stackTrace != null) print('StackTrace: $stackTrace');\n  }\n\n  void logDebug(String message) {\n    if (kDebugMode) {\n      print('&#91;$logTag] DEBUG: $message');\n    }\n  }\n}\n\n\/\/ \ub124\ud2b8\uc6cc\ud06c \uc0c1\ud0dc \ud655\uc778 mixin\nmixin NetworkAwareMixin {\n  Future&lt;bool&gt; get isConnected async {\n    final connectivityResult = await Connectivity().checkConnectivity();\n    return connectivityResult != ConnectivityResult.none;\n  }\n\n  Future&lt;T&gt; executeWithNetworkCheck&lt;T&gt;(Future&lt;T&gt; Function() operation) async {\n    if (!await isConnected) {\n      throw NetworkException('No internet connection');\n    }\n    return await operation();\n  }\n}\n\n\/\/ mixin\ub4e4\uc744 \ud65c\uc6a9\ud55c \uc11c\ube44\uc2a4 \ud074\ub798\uc2a4\nclass UserService with LoggerMixin, NetworkAwareMixin {\n  final UserRepository _repository;\n\n  UserService(this._repository);\n\n  Future&lt;List&lt;User&gt;&gt; getUsers() async {\n    logInfo('Fetching users...');\n\n    try {\n      final users = await executeWithNetworkCheck(\n        () =&gt; _repository.getAllUsers(),\n      );\n\n      logInfo('Successfully fetched ${users.length} users');\n      return users;\n    } catch (e, stackTrace) {\n      logError('Failed to fetch users', e, stackTrace);\n      rethrow;\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5. \uceec\ub809\uc158\uacfc \uc81c\ub124\ub9ad<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uc2e4\ubb34\uc5d0\uc11c \uc790\uc8fc \uc0ac\uc6a9\ud558\ub294 \uceec\ub809\uc158 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class DataProcessor {\n  \/\/ List \ubcc0\ud658\uacfc \ud544\ud130\ub9c1\n  List&lt;String&gt; extractUserNames(List&lt;User&gt; users) {\n    return users\n        .where((user) =&gt; user.isActive)\n        .map((user) =&gt; user.name)\n        .toList();\n  }\n\n  \/\/ Map\uc744 \ud65c\uc6a9\ud55c \uadf8\ub8f9\ud551\n  Map&lt;String, List&lt;User&gt;&gt; groupUsersByDomain(List&lt;User&gt; users) {\n    final groupedUsers = &lt;String, List&lt;User&gt;&gt;{};\n\n    for (final user in users) {\n      final domain = user.email.split('@').last;\n      groupedUsers.putIfAbsent(domain, () =&gt; &#91;]).add(user);\n    }\n\n    return groupedUsers;\n  }\n\n  \/\/ Set\uc744 \ud65c\uc6a9\ud55c \uc911\ubcf5 \uc81c\uac70\n  Set&lt;String&gt; getUniqueEmails(List&lt;User&gt; users) {\n    return users.map((user) =&gt; user.email).toSet();\n  }\n\n  \/\/ \ud568\uc218\ud615 \uc2a4\ud0c0\uc77c \uccb4\uc774\ub2dd\n  List&lt;User&gt; processUsers(List&lt;User&gt; users) {\n    return users\n        .where((user) =&gt; user.isActive)\n        .where((user) =&gt; user.email.contains('@company.com'))\n        .map((user) =&gt; user.copyWith(\n              name: user.name.trim().toUpperCase(),\n            ))\n        .toList()\n      ..sort((a, b) =&gt; a.name.compareTo(b.name));\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\uc81c\ub124\ub9ad\uc744 \ud65c\uc6a9\ud55c \ud0c0\uc785 \uc548\uc804\uc131<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ API \uc751\ub2f5 \ub798\ud37c \ud074\ub798\uc2a4\nclass ApiResponse&lt;T&gt; {\n  final bool success;\n  final T? data;\n  final String? error;\n  final int statusCode;\n\n  const ApiResponse({\n    required this.success,\n    this.data,\n    this.error,\n    required this.statusCode,\n  });\n\n  factory ApiResponse.success(T data, {int statusCode = 200}) {\n    return ApiResponse(\n      success: true,\n      data: data,\n      statusCode: statusCode,\n    );\n  }\n\n  factory ApiResponse.error(String error, {int statusCode = 500}) {\n    return ApiResponse(\n      success: false,\n      error: error,\n      statusCode: statusCode,\n    );\n  }\n\n  \/\/ \uacb0\uacfc \ucc98\ub9ac\ub97c \uc704\ud55c \ud328\ud134 \ub9e4\uce6d \uc2a4\ud0c0\uc77c \uba54\uc11c\ub4dc\n  R when&lt;R&gt;({\n    required R Function(T data) success,\n    required R Function(String error) error,\n  }) {\n    if (this.success &amp;&amp; data != null) {\n      return success(data as T);\n    } else {\n      return error(this.error ?? 'Unknown error');\n    }\n  }\n}\n\n\/\/ \uc81c\ub124\ub9ad \uc800\uc7a5\uc18c \ud328\ud134\nabstract class CacheRepository&lt;T&gt; {\n  Future&lt;void&gt; save(String key, T item);\n  Future&lt;T?&gt; get(String key);\n  Future&lt;void&gt; delete(String key);\n  Future&lt;void&gt; clear();\n  Future&lt;List&lt;T&gt;&gt; getAll();\n}\n\nclass HiveCacheRepository&lt;T&gt; implements CacheRepository&lt;T&gt; {\n  final Box&lt;String&gt; _box;\n  final T Function(Map&lt;String, dynamic&gt;) _fromJson;\n  final Map&lt;String, dynamic&gt; Function(T) _toJson;\n\n  HiveCacheRepository(\n    this._box,\n    this._fromJson,\n    this._toJson,\n  );\n\n  @override\n  Future&lt;void&gt; save(String key, T item) async {\n    final jsonString = jsonEncode(_toJson(item));\n    await _box.put(key, jsonString);\n  }\n\n  @override\n  Future&lt;T?&gt; get(String key) async {\n    final jsonString = _box.get(key);\n    if (jsonString == null) return null;\n\n    final json = jsonDecode(jsonString) as Map&lt;String, dynamic&gt;;\n    return _fromJson(json);\n  }\n\n  \/\/ ... \ub098\uba38\uc9c0 \uba54\uc11c\ub4dc \uad6c\ud604\n}\n\n\/\/ \uc0ac\uc6a9 \uc608\nfinal userCache = HiveCacheRepository&lt;User&gt;(\n  userBox,\n  (json) =&gt; User.fromJson(json),\n  (user) =&gt; user.toJson(),\n);<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6. \ube44\ub3d9\uae30 \ud504\ub85c\uadf8\ub798\ubc0d<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Future\uc640 async\/await \uc2e4\ubb34 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class NetworkService {\n  final Dio _dio;\n  final Duration defaultTimeout;\n\n  NetworkService(this._dio, {this.defaultTimeout = const Duration(seconds: 30)});\n\n  \/\/ \uae30\ubcf8\uc801\uc778 HTTP \uc694\uccad \ud328\ud134\n  Future&lt;ApiResponse&lt;T&gt;&gt; request&lt;T&gt;(\n    String method,\n    String path, {\n    dynamic data,\n    Map&lt;String, dynamic&gt;? queryParameters,\n    Duration? timeout,\n    T Function(Map&lt;String, dynamic&gt;)? parser,\n  }) async {\n    try {\n      final response = await _dio.request(\n        path,\n        data: data,\n        queryParameters: queryParameters,\n        options: Options(\n          method: method,\n          receiveTimeout: timeout ?? defaultTimeout,\n        ),\n      );\n\n      if (response.statusCode == 200) {\n        final responseData = parser != null \n            ? parser(response.data)\n            : response.data as T;\n        return ApiResponse.success(responseData);\n      } else {\n        return ApiResponse.error(\n          'Request failed with status: ${response.statusCode}',\n          statusCode: response.statusCode!,\n        );\n      }\n    } on DioException catch (e) {\n      return _handleDioException(e);\n    } catch (e) {\n      return ApiResponse.error('Unexpected error: $e');\n    }\n  }\n\n  \/\/ \uc5d0\ub7ec \ucc98\ub9ac \ud328\ud134\n  ApiResponse&lt;T&gt; _handleDioException&lt;T&gt;(DioException e) {\n    switch (e.type) {\n      case DioExceptionType.connectionTimeout:\n      case DioExceptionType.sendTimeout:\n      case DioExceptionType.receiveTimeout:\n        return ApiResponse.error(\n          'Request timeout',\n          statusCode: 408,\n        );\n      case DioExceptionType.badResponse:\n        return ApiResponse.error(\n          'Server error: ${e.response?.statusCode}',\n          statusCode: e.response?.statusCode ?? 500,\n        );\n      case DioExceptionType.cancel:\n        return ApiResponse.error('Request cancelled');\n      default:\n        return ApiResponse.error('Network error: ${e.message}');\n    }\n  }\n\n  \/\/ \ubcd1\ub82c \uc694\uccad \ucc98\ub9ac\n  Future&lt;(List&lt;User&gt;, List&lt;Post&gt;)&gt; fetchUserDataParallel(String userId) async {\n    final futures = await Future.wait(&#91;\n      getUserProfile(userId),\n      getUserPosts(userId),\n    ]);\n\n    return (\n      futures&#91;0] as List&lt;User&gt;,\n      futures&#91;1] as List&lt;Post&gt;,\n    );\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Stream\uc744 \ud65c\uc6a9\ud55c \uc2e4\uc2dc\uac04 \ub370\uc774\ud130 \ucc98\ub9ac<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class ChatService {\n  final WebSocketChannel _channel;\n  late final StreamController&lt;ChatMessage&gt; _messageController;\n\n  ChatService(this._channel) {\n    _messageController = StreamController&lt;ChatMessage&gt;.broadcast();\n    _listenToMessages();\n  }\n\n  Stream&lt;ChatMessage&gt; get messages =&gt; _messageController.stream;\n\n  void _listenToMessages() {\n    _channel.stream.listen(\n      (data) {\n        try {\n          final json = jsonDecode(data) as Map&lt;String, dynamic&gt;;\n          final message = ChatMessage.fromJson(json);\n          _messageController.add(message);\n        } catch (e) {\n          print('Failed to parse message: $e');\n        }\n      },\n      onError: (error) {\n        _messageController.addError(error);\n      },\n      onDone: () {\n        _messageController.close();\n      },\n    );\n  }\n\n  void sendMessage(String text) {\n    final message = {\n      'type': 'message',\n      'text': text,\n      'timestamp': DateTime.now().toIso8601String(),\n    };\n    _channel.sink.add(jsonEncode(message));\n  }\n\n  void dispose() {\n    _channel.sink.close();\n    _messageController.close();\n  }\n}\n\n\/\/ Stream \ubcc0\ud658\uacfc \ud544\ud130\ub9c1\nclass DataStreamProcessor {\n  Stream&lt;List&lt;User&gt;&gt; processUserStream(Stream&lt;List&lt;User&gt;&gt; userStream) {\n    return userStream\n        .where((users) =&gt; users.isNotEmpty)\n        .map((users) =&gt; users.where((user) =&gt; user.isActive).toList())\n        .distinct((previous, current) =&gt; \n            const ListEquality().equals(previous, current))\n        .debounceTime(Duration(milliseconds: 300));\n  }\n\n  \/\/ \uc5ec\ub7ec \uc2a4\ud2b8\ub9bc \uacb0\ud569\n  Stream&lt;SearchResult&gt; combineSearchStreams(\n    Stream&lt;String&gt; queryStream,\n    Stream&lt;List&lt;String&gt;&gt; suggestionsStream,\n  ) {\n    return Rx.combineLatest2(\n      queryStream.debounceTime(Duration(milliseconds: 500)),\n      suggestionsStream,\n      (query, suggestions) =&gt; SearchResult(\n        query: query,\n        suggestions: suggestions\n            .where((s) =&gt; s.toLowerCase().contains(query.toLowerCase()))\n            .toList(),\n      ),\n    );\n  }\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7. \ub110 \uc548\uc804\uc131 (Null Safety)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uc2e4\ubb34\uc5d0\uc11c\uc758 \ub110 \uc548\uc804\uc131 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class UserValidator {\n  \/\/ \ub110 \uc548\uc804 \uba54\uc11c\ub4dc \uccb4\uc774\ub2dd\n  String? validateEmail(String? email) {\n    return email\n        ?.trim()\n        .toLowerCase()\n        .let((email) =&gt; email.contains('@') ? email : null);\n  }\n\n  \/\/ \ub110 \ubcd1\ud569 \uc5f0\uc0b0\uc790 \ud65c\uc6a9\n  String getDisplayName(User? user) {\n    return user?.name ?? \n           user?.email?.split('@').first ?? \n           'Unknown User';\n  }\n\n  \/\/ \uc548\uc804\ud55c \ud0c0\uc785 \uce90\uc2a4\ud305\n  int? parseAge(dynamic value) {\n    if (value is int) return value;\n    if (value is String) return int.tryParse(value);\n    return null;\n  }\n\n  \/\/ \uc870\uac74\ubd80 \uba64\ubc84 \uc811\uadfc\n  void updateUserIfActive(User? user, String newName) {\n    user?.let((user) {\n      if (user.isActive) {\n        \/\/ \uc0ac\uc6a9\uc790 \uc5c5\ub370\uc774\ud2b8 \ub85c\uc9c1\n        updateUser(user.copyWith(name: newName));\n      }\n    });\n  }\n}\n\n\/\/ Extension\uc744 \ud65c\uc6a9\ud55c \ub110 \uc548\uc804\uc131 \ud5a5\uc0c1\nextension NullableExtensions&lt;T&gt; on T? {\n  R? let&lt;R&gt;(R Function(T) transform) {\n    final value = this;\n    return value != null ? transform(value) : null;\n  }\n\n  T orElse(T defaultValue) {\n    return this ?? defaultValue;\n  }\n\n  T orElseGet(T Function() defaultValueProvider) {\n    return this ?? defaultValueProvider();\n  }\n}\n\n\/\/ \uc0ac\uc6a9 \uc608\nfinal user = await userService.getUser(userId);\nfinal avatar = user\n    ?.profileImageUrl\n    ?.let((url) =&gt; CachedNetworkImage(imageUrl: url))\n    ?? const CircleAvatar(child: Icon(Icons.person));<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\uc548\uc804\ud55c JSON \ud30c\uc2f1 \ud328\ud134<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class SafeJsonParser {\n  static T? tryParse&lt;T&gt;(\n    Map&lt;String, dynamic&gt;? json,\n    String key,\n    T Function(dynamic) parser,\n  ) {\n    try {\n      final value = json?&#91;key];\n      return value != null ? parser(value) : null;\n    } catch (e) {\n      print('Failed to parse $key: $e');\n      return null;\n    }\n  }\n\n  static List&lt;T&gt; parseList&lt;T&gt;(\n    Map&lt;String, dynamic&gt;? json,\n    String key,\n    T Function(Map&lt;String, dynamic&gt;) itemParser,\n  ) {\n    try {\n      final list = json?&#91;key] as List&lt;dynamic&gt;?;\n      if (list == null) return &#91;];\n\n      return list\n          .whereType&lt;Map&lt;String, dynamic&gt;&gt;()\n          .map(itemParser)\n          .toList();\n    } catch (e) {\n      print('Failed to parse list $key: $e');\n      return &#91;];\n    }\n  }\n}\n\n\/\/ \uc548\uc804\ud55c \ubaa8\ub378 \ud074\ub798\uc2a4\nclass SafeUser {\n  final String id;\n  final String name;\n  final String? email;  \/\/ \uc120\ud0dd\uc801 \ud544\ub4dc\n  final int age;\n  final List&lt;String&gt; tags;\n  final DateTime? lastLogin;  \/\/ \uc120\ud0dd\uc801 \ud544\ub4dc\n\n  SafeUser({\n    required this.id,\n    required this.name,\n    this.email,\n    required this.age,\n    this.tags = const &#91;],\n    this.lastLogin,\n  });\n\n  factory SafeUser.fromJson(Map&lt;String, dynamic&gt; json) {\n    return SafeUser(\n      id: json&#91;'id'] as String? ?? '',\n      name: json&#91;'name'] as String? ?? 'Unknown',\n      email: json&#91;'email'] as String?,\n      age: SafeJsonParser.tryParse(json, 'age', (v) =&gt; v as int) ?? 0,\n      tags: SafeJsonParser.parseList(\n        json, \n        'tags', \n        (item) =&gt; item&#91;'name'] as String,\n      ),\n      lastLogin: SafeJsonParser.tryParse(\n        json, \n        'last_login', \n        (v) =&gt; DateTime.parse(v as String),\n      ),\n    );\n  }\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">8. \ud568\uc218\ud615 \ud504\ub85c\uadf8\ub798\ubc0d \ud328\ud134<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ubd88\ubcc0\uc131\uacfc \uc21c\uc218 \ud568\uc218<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \uc21c\uc218 \ud568\uc218 \uc608\uc81c\nclass MathUtils {\n  \/\/ \uc785\ub825\uc5d0\ub9cc \uc758\uc874\ud558\uace0 \ubd80\uc791\uc6a9\uc774 \uc5c6\ub294 \uc21c\uc218 \ud568\uc218\n  static double calculateDistance(Point a, Point b) {\n    final dx = a.x - b.x;\n    final dy = a.y - b.y;\n    return sqrt(dx * dx + dy * dy);\n  }\n\n  \/\/ \ub9ac\uc2a4\ud2b8\ub97c \ubcc0\uacbd\ud558\uc9c0 \uc54a\uace0 \uc0c8\ub85c\uc6b4 \ub9ac\uc2a4\ud2b8 \ubc18\ud658\n  static List&lt;int&gt; addToAll(List&lt;int&gt; numbers, int value) {\n    return numbers.map((n) =&gt; n + value).toList();\n  }\n}\n\n\/\/ \ud568\uc218 \uc870\ud569 \ud328\ud134\nclass StringProcessor {\n  static String Function(String) compose(\n    List&lt;String Function(String)&gt; functions,\n  ) {\n    return (input) =&gt; functions.fold(input, (acc, fn) =&gt; fn(acc));\n  }\n\n  static final processors = {\n    'trim': (String s) =&gt; s.trim(),\n    'lower': (String s) =&gt; s.toLowerCase(),\n    'removeSpaces': (String s) =&gt; s.replaceAll(' ', ''),\n    'capitalize': (String s) =&gt; s.isEmpty \n        ? s \n        : s&#91;0].toUpperCase() + s.substring(1),\n  };\n\n  \/\/ \uc0ac\uc6a9 \uc608\n  static final nameProcessor = compose(&#91;\n    processors&#91;'trim']!,\n    processors&#91;'lower']!,\n    processors&#91;'capitalize']!,\n  ]);\n}\n\n\/\/ \ud568\uc218\ud615 \uc5d0\ub7ec \ucc98\ub9ac\nclass Result&lt;T, E&gt; {\n  final T? _value;\n  final E? _error;\n  final bool _isSuccess;\n\n  const Result._(this._value, this._error, this._isSuccess);\n\n  factory Result.success(T value) =&gt; Result._(value, null, true);\n  factory Result.error(E error) =&gt; Result._(null, error, false);\n\n  bool get isSuccess =&gt; _isSuccess;\n  bool get isError =&gt; !_isSuccess;\n\n  T get value {\n    if (_isSuccess) return _value as T;\n    throw StateError('Cannot get value from error result');\n  }\n\n  E get error {\n    if (!_isSuccess) return _error as E;\n    throw StateError('Cannot get error from success result');\n  }\n\n  \/\/ \ud568\uc218\ud615 \ubcc0\ud658\n  Result&lt;R, E&gt; map&lt;R&gt;(R Function(T) transform) {\n    return _isSuccess \n        ? Result.success(transform(_value as T))\n        : Result.error(_error as E);\n  }\n\n  Result&lt;R, E&gt; flatMap&lt;R&gt;(Result&lt;R, E&gt; Function(T) transform) {\n    return _isSuccess \n        ? transform(_value as T)\n        : Result.error(_error as E);\n  }\n\n  T orElse(T defaultValue) {\n    return _isSuccess ? _value as T : defaultValue;\n  }\n\n  \/\/ \ud328\ud134 \ub9e4\uce6d \uc2a4\ud0c0\uc77c\n  R when&lt;R&gt;({\n    required R Function(T) success,\n    required R Function(E) error,\n  }) {\n    return _isSuccess \n        ? success(_value as T)\n        : error(_error as E);\n  }\n}\n\n\/\/ \uc2e4\uc0ac\uc6a9 \uc608\uc81c\nclass UserService {\n  Future&lt;Result&lt;User, String&gt;&gt; getUser(String id) async {\n    try {\n      final user = await _apiService.getUser(id);\n      return Result.success(user);\n    } catch (e) {\n      return Result.error('Failed to fetch user: $e');\n    }\n  }\n\n  Future&lt;Result&lt;String, String&gt;&gt; processUserData(String userId) async {\n    final userResult = await getUser(userId);\n\n    return userResult\n        .map((user) =&gt; user.name.toUpperCase())\n        .map((name) =&gt; 'Processed: $name');\n  }\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">9. \uc131\ub2a5 \ucd5c\uc801\ud654\ub97c \uc704\ud55c Dart \ud328\ud134<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uba54\ubaa8\ub9ac \ud6a8\uc728\uc801\uc778 \ucf54\ub4dc \uc791\uc131<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class PerformanceOptimizedService {\n  \/\/ \uc9c0\uc5f0 \ucd08\uae30\ud654\ub97c \ud1b5\ud55c \uba54\ubaa8\ub9ac \uc808\uc57d\n  late final RegExp _emailRegex = RegExp(r'^&#91;w-.]+@(&#91;w-]+.)+&#91;w-]{2,4}\n<h3>\ube44\ub3d9\uae30 \ucf54\ub4dc \ucd5c\uc801\ud654<\/h3>\n<pre><code class=\"language-dart\">class AsyncOptimizer {\n  \/\/ \ubcd1\ub82c \ucc98\ub9ac\ub85c \uc131\ub2a5 \ud5a5\uc0c1\n  Future&lt;UserProfile&gt; loadUserProfile(String userId) async {\n    \/\/ \uc21c\ucc28 \uc2e4\ud589 (\ub290\ub9bc)\n    \/\/ final user = await userService.getUser(userId);\n    \/\/ final posts = await postService.getUserPosts(userId);\n    \/\/ final followers = await followService.getFollowers(userId);\n\n    \/\/ \ubcd1\ub82c \uc2e4\ud589 (\ube60\ub984)\n    final futures = await Future.wait(&#91;\n      userService.getUser(userId),\n      postService.getUserPosts(userId),\n      followService.getFollowers(userId),\n    ]);\n\n    return UserProfile(\n      user: futures&#91;0] as User,\n      posts: futures&#91;1] as List&lt;Post&gt;,\n      followers: futures&#91;2] as List&lt;User&gt;,\n    );\n  }\n\n  \/\/ \uc870\uac74\ubd80 \ube44\ub3d9\uae30 \uc2e4\ud589\n  Future&lt;List&lt;Post&gt;&gt; getPostsConditionally(String userId) async {\n    final cachedPosts = await cacheService.getPosts(userId);\n\n    if (cachedPosts.isNotEmpty) {\n      return cachedPosts;  \/\/ \uce90\uc2dc\ub41c \ub370\uc774\ud130 \uc0ac\uc6a9\n    }\n\n    \/\/ \ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \uac00\uc838\uc624\uae30\n    final posts = await apiService.getPosts(userId);\n\n    \/\/ \ubc31\uadf8\ub77c\uc6b4\ub4dc\uc5d0\uc11c \uce90\uc2dc \uc800\uc7a5 (await \uc5c6\uc774)\n    unawaited(cacheService.savePosts(userId, posts));\n\n    return posts;\n  }\n\n  \/\/ \ud0c0\uc784\uc544\uc6c3\uacfc \uc7ac\uc2dc\ub3c4 \ud328\ud134\n  Future&lt;T&gt; executeWithRetry&lt;T&gt;(\n    Future&lt;T&gt; Function() operation,\n    int maxRetries,\n    Duration timeout,\n  ) async {\n    for (int attempt = 0; attempt &lt;= maxRetries; attempt++) {\n      try {\n        return await operation().timeout(timeout);\n      } catch (e) {\n        if (attempt == maxRetries) rethrow;\n\n        \/\/ \uc9c0\uc218 \ubc31\uc624\ud504\n        await Future.delayed(Duration(seconds: math.pow(2, attempt).toInt()));\n      }\n    }\n\n    throw StateError('This should never be reached');\n  }\n}<\/code><\/pre>\n<hr>\n<h2>\ub9c8\ubb34\ub9ac<\/h2>\n<p>\uc774\uc81c Dart \uc5b8\uc5b4\uc758 \ud575\uc2ec \uac1c\ub150\ub4e4\uc744 \uc2e4\ubb34 \uc911\uc2ec\uc73c\ub85c \uc0b4\ud3b4\ubcf4\uc558\uc2b5\ub2c8\ub2e4. \uac01 \uac1c\ub150\uc740 Flutter \uc571 \uac1c\ubc1c\uc5d0\uc11c \uc2e4\uc81c\ub85c \uc790\uc8fc \uc0ac\uc6a9\ub418\ub294 \ud328\ud134\ub4e4\uc785\ub2c8\ub2e4.<\/p>\n<h3>\ub2e4\uc74c \ub2e8\uacc4<\/h3>\n<ol>\n<li><strong>Flutter \uc704\uc82f \uc2dc\uc2a4\ud15c<\/strong> \ud559\uc2b5<\/li>\n<li><strong>\uc0c1\ud0dc \uad00\ub9ac<\/strong> (Riverpod, Bloc) \uc801\uc6a9<\/li>\n<li><strong>\uc2e4\uc81c \ud504\ub85c\uc81d\ud2b8<\/strong>\ub85c \uc5f0\uc2b5<\/li>\n<\/ol>\n<h3>\ucd94\ucc9c \ud559\uc2b5 \uc790\ub8cc<\/h3>\n<ul>\n<li><a href=\"https:\/\/dart.dev\/guides\">Dart \uacf5\uc2dd \ubb38\uc11c<\/a><\/li>\n<li><a href=\"https:\/\/flutter.dev\/docs\">Flutter \uacf5\uc2dd \ubb38\uc11c<\/a><\/li>\n<li><a href=\"https:\/\/dartpad.dev\/\">Dart Pad<\/a> - \uc628\ub77c\uc778 \ucf54\ub4dc \uc2e4\uc2b5<\/li>\n<\/ul>\n<p>\uad81\uae08\ud55c \uc810\uc774 \uc788\uc73c\uc2dc\uba74 \uc5b8\uc81c\ub4e0 \ub313\uae00\ub85c \ub0a8\uaca8\uc8fc\uc138\uc694! \ud568\uaed8 \uc131\uc7a5\ud558\ub294 Flutter \uac1c\ubc1c\uc790\uac00 \ub418\uc5b4\ubd05\uc2dc\ub2e4! \ud83d\ude80<\/p>\n<hr>\n<p><strong>\uad00\ub828 \uae00<\/strong><\/p>\n<ul>\n<li><a href=\"\ub9c1\ud06c\">Flutter \uc0c1\ud0dc \uad00\ub9ac \uc644\ubcbd \uac00\uc774\ub4dc<\/a><\/li>\n<li><a href=\"\ub9c1\ud06c\">Flutter \uc131\ub2a5 \ucd5c\uc801\ud654 \ud301<\/a><\/li>\n<li><a href=\"\ub9c1\ud06c\">Flutter \uc544\ud0a4\ud14d\ucc98 \ud328\ud134<\/a><\/li>\n<\/ul>\n);\n  late final DateFormat _dateFormatter = DateFormat('yyyy-MM-dd');\n\n  \/\/ \uc2f1\uae00\ud1a4 \ud328\ud134\uc73c\ub85c \uc778\uc2a4\ud134\uc2a4 \uc7ac\uc0ac\uc6a9\n  static PerformanceOptimizedService? _instance;\n  static PerformanceOptimizedService get instance {\n    return _instance ??= PerformanceOptimizedService._();\n  }\n  PerformanceOptimizedService._();\n\n  \/\/ \uce90\uc2dc\ub97c \ud1b5\ud55c \uc911\ubcf5 \uacc4\uc0b0 \ubc29\uc9c0\n  final Map&lt;String, bool&gt; _validationCache = {};\n\n  bool isValidEmail(String email) {\n    return _validationCache.putIfAbsent(\n      email,\n      () =&gt; _emailRegex.hasMatch(email),\n    );\n  }\n\n  \/\/ \uc2a4\ud2b8\ub9bc \uad6c\ub3c5 \uad00\ub9ac\n  final List&lt;StreamSubscription&gt; _subscriptions = &#91;];\n\n  void addSubscription(StreamSubscription subscription) {\n    _subscriptions.add(subscription);\n  }\n\n  void dispose() {\n    for (final subscription in _subscriptions) {\n      subscription.cancel();\n    }\n    _subscriptions.clear();\n    _validationCache.clear();\n  }\n}\n\n\/\/ \ud6a8\uc728\uc801\uc778 \uceec\ub809\uc158 \uc0ac\uc6a9\nclass CollectionOptimizer {\n  \/\/ Set\uc744 \uc0ac\uc6a9\ud55c \uc911\ubcf5 \uc81c\uac70\uc640 \ube60\ub978 \uc870\ud68c\n  static List&lt;String&gt; removeDuplicatesEfficient(List&lt;String&gt; items) {\n    return items.toSet().toList();\n  }\n\n  \/\/ Map\uc744 \uc0ac\uc6a9\ud55c \ube60\ub978 \uc870\ud68c\n  static User? findUserByIdEfficient(List&lt;User&gt; users, String id) {\n    \/\/ O(n) \ub9e4\ubc88 \uc21c\ud68c\ud558\ub294 \ub300\uc2e0\n    \/\/ final user = users.firstWhere((u) =&gt; u.id == id);\n\n    \/\/ O(1) \uc870\ud68c\ub97c \uc704\ud55c Map \uc0ac\uc6a9\n    final userMap = {for (final user in users) user.id: user};\n    return userMap&#91;id];\n  }\n\n  \/\/ \ub300\uc6a9\ub7c9 \ub370\uc774\ud130 \uccad\ud06c \ub2e8\uc704 \ucc98\ub9ac\n  static Future&lt;List&lt;T&gt;&gt; processInChunks&lt;T&gt;(\n    List&lt;T&gt; items,\n    Future&lt;T&gt; Function(T) processor,\n    int chunkSize,\n  ) async {\n    final results = &lt;T&gt;&#91;];\n\n    for (int i = 0; i &lt; items.length; i += chunkSize) {\n      final chunk = items.sublist(\n        i,\n        math.min(i + chunkSize, items.length),\n      );\n\n      final chunkResults = await Future.wait(\n        chunk.map(processor),\n      );\n\n      results.addAll(chunkResults);\n    }\n\n    return results;\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\ube44\ub3d9\uae30 \ucf54\ub4dc \ucd5c\uc801\ud654<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ub9c8\ubb34\ub9ac<\/h2>\n\n\n\n<p>\uc774\uc81c Dart \uc5b8\uc5b4\uc758 \ud575\uc2ec \uac1c\ub150\ub4e4\uc744 \uc2e4\ubb34 \uc911\uc2ec\uc73c\ub85c \uc0b4\ud3b4\ubcf4\uc558\uc2b5\ub2c8\ub2e4. \uac01 \uac1c\ub150\uc740 Flutter \uc571 \uac1c\ubc1c\uc5d0\uc11c \uc2e4\uc81c\ub85c \uc790\uc8fc \uc0ac\uc6a9\ub418\ub294 \ud328\ud134\ub4e4\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ub2e4\uc74c \ub2e8\uacc4<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Flutter \uc704\uc82f \uc2dc\uc2a4\ud15c<\/strong> \ud559\uc2b5<\/li>\n\n\n\n<li><strong>\uc0c1\ud0dc \uad00\ub9ac<\/strong> (Riverpod, Bloc) \uc801\uc6a9<\/li>\n\n\n\n<li><strong>\uc2e4\uc81c \ud504\ub85c\uc81d\ud2b8<\/strong>\ub85c \uc5f0\uc2b5<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">\ucd94\ucc9c \ud559\uc2b5 \uc790\ub8cc<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/dart.dev\/guides\">Dart \uacf5\uc2dd \ubb38\uc11c<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/flutter.dev\/docs\">Flutter \uacf5\uc2dd \ubb38\uc11c<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/dartpad.dev\/\">Dart Pad<\/a> &#8211; \uc628\ub77c\uc778 \ucf54\ub4dc \uc2e4\uc2b5<\/li>\n<\/ul>\n\n\n\n<p>\uad81\uae08\ud55c \uc810\uc774 \uc788\uc73c\uc2dc\uba74 \uc5b8\uc81c\ub4e0 \ub313\uae00\ub85c \ub0a8\uaca8\uc8fc\uc138\uc694! \ud568\uaed8 \uc131\uc7a5\ud558\ub294 Flutter \uac1c\ubc1c\uc790\uac00 \ub418\uc5b4\ubd05\uc2dc\ub2e4! \ud83d\ude80<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>\uad00\ub828 \uae00<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\ub9c1\ud06c\">Flutter \uc0c1\ud0dc \uad00\ub9ac \uc644\ubcbd \uac00\uc774\ub4dc<\/a><\/li>\n\n\n\n<li><a href=\"\ub9c1\ud06c\">Flutter \uc131\ub2a5 \ucd5c\uc801\ud654 \ud301<\/a><\/li>\n\n\n\n<li><a href=\"\ub9c1\ud06c\">Flutter \uc544\ud0a4\ud14d\ucc98 \ud328\ud134<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Flutter \uac1c\ubc1c\uc790\ub97c \uc704\ud55c Dart \uc5b8\uc5b4 \uc644\ubcbd \uac00\uc774\ub4dc Android\/iOS \uac1c\ubc1c\uc790\uac00 Flutter\ub85c \uc804\ud658\ud560 \ub54c \ubc18\ub4dc\uc2dc \uc54c\uc544\uc57c \ud560 Dart \uc5b8\uc5b4\uc758 \ud575\uc2ec \uac1c\ub150\ub4e4 \ub4e4\uc5b4\uac00\uba70 \uc548\ub155\ud558\uc138\uc694! \ubaa8\ubc14\uc77c \uac1c\ubc1c \uacbd\ud5d8\uc774 \uc788\uc73c\uc2dc\uac70\ub098 \uc6f9 \ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \ubaa8\ubc14\uc77c\ub85c \uc601\uc5ed\uc744 \ud655\uc7a5\ud558\ub824\ub294 \uac1c\ubc1c\uc790\ubd84\ub4e4\uc744 \uc704\ud55c Dart \uc5b8\uc5b4 \uac00\uc774\ub4dc\ub97c \uc900\ube44\ud588\uc2b5\ub2c8\ub2e4. Flutter\ub97c \ubc30\uc6b0\uae30 \uc704\ud574\uc11c\ub294 \uba3c\uc800 Dart \uc5b8\uc5b4\ub97c \uc774\ud574\ud574\uc57c \ud569\ub2c8\ub2e4. \ud558\uc9c0\ub9cc \uac71\uc815\ud558\uc9c0 \ub9c8\uc138\uc694! Java\/Kotlin, Swift, JavaScript\ub97c \uc0ac\uc6a9\ud574\ubcf4\uc2e0 \ubd84\uc774\ub77c\uba74 Dart\ub294 \ub9e4\uc6b0 \uce5c\uc219\ud558\uac8c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[43],"tags":[114,110,78,113,111,79,112,106],"class_list":["post-84","post","type-post","status-publish","format-standard","hentry","category-flutter","tag-android","tag-dart","tag-flutter","tag-ios","tag-111","tag-79","tag-112","tag-106"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/hed-g.me\/index.php?rest_route=\/wp\/v2\/posts\/84","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hed-g.me\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hed-g.me\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hed-g.me\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hed-g.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=84"}],"version-history":[{"count":2,"href":"https:\/\/hed-g.me\/index.php?rest_route=\/wp\/v2\/posts\/84\/revisions"}],"predecessor-version":[{"id":107,"href":"https:\/\/hed-g.me\/index.php?rest_route=\/wp\/v2\/posts\/84\/revisions\/107"}],"wp:attachment":[{"href":"https:\/\/hed-g.me\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=84"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hed-g.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=84"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hed-g.me\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=84"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}