Skip to content

Latest commit

Β 

History

History

Flutter

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Β 
Β 

Flutter

기본적으둜 Dart Style Guideλ₯Ό λ”°λ₯΄κ³  μžˆμ§€λ§Œ, λ³Έ λ¬Έμ„œμ—μ„œλŠ” Flutter에 쑰금 더 νŠΉν™”λœ μŠ€νƒ€μΌ κ°€μ΄λ“œλ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€.

λͺ©μ°¨

μ½”λ“œ μŠ€νƒ€μΌ

μ „λ°˜μ μΈ Flutter κ΄€λ ¨ μŠ€νƒ€μΌμ— λŒ€ν•΄ μž‘μ„±ν•©λ‹ˆλ‹€. νŠΉμ • νŒ¨ν‚€μ§€ κ΄€λ ¨ μŠ€νƒ€μΌμ€ Packages λ¬Έλ‹¨μ—μ„œ μž‘μ„±ν•©λ‹ˆλ‹€.

νŠΉμˆ˜ν•œ κΈ°λŠ₯을 가지고 μžˆλŠ” ν•¨μˆ˜, λ©”μ†Œλ“œ 및 μƒμ„±μžλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€

μ—¬λŸ¬ μ˜΅μ…˜μ΄ μžˆλŠ” 경우, κ°€μž₯ 관련성이 높은 μƒμ„±μžλ‚˜ λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ„Έμš”.

// BAD:
const EdgeInsets.TRBL(0.0, 8.0, 0.0, 8.0);

// GOOD:
const EdgeInsets.symmetric(horizontal: 8.0);

var λ˜λŠ” dynamic μ‚¬μš©μ„ ν”Όν•©λ‹ˆλ‹€

λͺ¨λ“  λ³€μˆ˜λ“€(variables)κ³Ό μΈμžλ“€(arguments)은 νƒ€μž…μ΄ μ‘΄μž¬ν•©λ‹ˆλ‹€. μ‹€μ œ μœ ν˜•μ„ νŒŒμ•…ν•  수 μžˆλŠ” κ²½μš°μ—λŠ” dynamic λ˜λŠ” Object νƒ€μž…μ˜ μ‚¬μš©μ„ ν”Όν•˜μ„Έμš”. κ°€λŠ₯ν•œ 경우 λͺ¨λ“  Generic νƒ€μž…μ˜ μœ ν˜•μ„ λͺ…μ‹œν• κ²ƒμ„ ꢌμž₯ν•©λ‹ˆλ‹€. Closure μ—μ„œ μ‚¬μš©λ˜λŠ” Parameter λ˜ν•œ νƒ€μž…μ΄ λͺ…μ‹œλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

λͺ¨λ“  κ²½μš°μ—μ„œ var κ³Ό dynamic μ‚¬μš©μ„ ν”Όν•˜μ„Έμš”. λ§Œμ•½, νƒ€μž…μ„ μ•Œ 수 μ—†λŠ” 경우라면 Object(λ˜λŠ” Object?)λ₯Ό μ‚¬μš©ν•˜μ—¬ Casting ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λŠ” μ΄μœ λŠ” dynamic 의 경우 λͺ¨λ“  정적 검사가 λΉ„ν™œμ„±ν™”λ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

μƒμˆ˜(Constant)의 Scopeλ₯Ό μ΅œμ†Œν™” ν•©λ‹ˆλ‹€

κΈ€λ‘œλ²Œ μ „μ—­ μƒμˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” λŒ€μ‹ , 관련성이 μžˆλŠ” ν΄λž˜μŠ€μ—μ„œ 둜컬 const λ˜λŠ” static const λ₯Ό μ‚¬μš©ν•˜μ„Έμš”. λ§Œμ•½, μ„ μ–Έν•œ μƒμˆ˜κ°€ λ§Žμ•„μ§„λ‹€λ©΄ abstract final class 둜 λž˜ν•‘ν•˜λŠ”κ²ƒμ„ ꢌμž₯ν•©λ‹ˆλ‹€.

λͺ…ν™•ν•˜μ§€ μ•Šμ€ 숫자 λ˜λŠ” Magic Number의 μ‚¬μš©μ„ ν”Όν•©λ‹ˆλ‹€

μ½”λ“œμƒμ˜ 숫자 및 ν…ŒμŠ€νŠΈμ—μ„œ μ‚¬μš©λ˜λŠ” λͺ¨λ“  숫자의 경우 λͺ…ν™•ν•˜κ²Œ 이해할 수 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. λ§Œμ•½, 숫자의 μΆœμ²˜κ°€ λͺ…ν™•ν•˜μ§€ μ•Šμ€ 경우 ν‘œν˜„μ‹μ„ κ·ΈλŒ€λ‘œ λ‘κ±°λ‚˜ λͺ…ν™•ν•œ 주석을 μΆ”κ°€ν•˜μ„Έμš”.

μ˜ˆμ‹œ:

// BAD:
const double kMaxWidth = 1200;

// GOOD:
/// κΈ°λ³Έ κ°’ 60에 해상도 쑰정을 μœ„ν•΄ 20을 κ³±ν•œ κ°’
const double kMaxWidth = 60 * 20;

initState() 와 dispose() ν•¨μˆ˜λ₯Ό Override ν•˜λŠ” 경우, super 호좜 μˆœμ„œλ₯Ό μ£Όμ˜ν•΄μ„œ μ‚¬μš©ν•©λ‹ˆλ‹€

initState() 의 경우 super.initState() λ₯Ό 호좜 ν•œ ν›„ 좔가적인 μž‘μ—…μ„ μ§„ν–‰ν•˜μ„Έμš”. 반면, dispose() 의 경우 super.dispose() λ₯Ό 호좜 ν•˜κΈ° 전에 좔가적인 μž‘μ—…μ„ μ§„ν–‰ν•˜μ„Έμš”.

initState() 의 경우 μœ„μ ―μ˜ μ΄ˆκΈ°ν™” κ³Όμ •μ—μ„œ μ€‘μš”ν•œ 생λͺ…μ£ΌκΈ° ν˜ΈμΆœμž…λ‹ˆλ‹€. 이λ₯Ό λ¨Όμ € ν˜ΈμΆœν•΄μ•Ό μœ„μ ―μ˜ μƒνƒœκ°€ μ•ˆμ •μ μœΌλ‘œ μœ μ§€λ©λ‹ˆλ‹€.

넀이밍

μ „μ—­ μƒμˆ˜μ˜ 이름은 접두사 "k" 둜 μ‹œμž‘ν•©λ‹ˆλ‹€

μ˜ˆμ‹œ:

const double kMaxWidth = 1200;
const Duration kAnimationDuration = Duration(milliseconds: 200);

κ·ΈλŸ¬λ‚˜, κ°€λŠ₯ν•œ 경우 kDefaultButtonColor 와 같이 μ „μ—­ μƒμˆ˜λ₯Ό μ„ μ–Έν•˜λŠ” λŒ€μ‹ , Button.defaultColor 와 같이 클래슀 내뢀에 μƒμˆ˜λ₯Ό μ„ μ–Έν•˜μ„Έμš”. ν•„μš”ν•œ 경우 abstract final class λ₯Ό μ‚¬μš©ν•˜μ—¬ μƒμˆ˜λ₯Ό μ„ μ–Έν•©λ‹ˆλ‹€.

ν¬λ§€νŒ…

클래슀 멀버듀을 μ˜λ―Έκ°€ 있게 μ •λ ¬ν•˜μ„Έμš”

initState 와 dispose 처럼 λͺ…ν™•ν•œ 라이프사이클이 μžˆλŠ” 경우, initState κ°€ dispose 보닀 λ¨Όμ € μ˜€λ„λ‘ μ •λ ¬ν•˜μ„Έμš”.

μ˜ˆμ‹œ:

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void build(BuildContext context) {

  }

  @override
  void dispose() {
    super.dispose();
  }
}

λ§Œμ•½, μˆœμ„œκ°€ λͺ…ν™•ν•˜μ§€ μ•Šμ€ κ²½μš°μ—λŠ” μ•„λž˜μ™€ 같은 μˆœμ„œλ₯Ό λ”°λ₯΄λ©°, 각 μˆœμ„œ μ‚¬μ΄μ—λŠ” 빈 라인을 μΆ”κ°€ν•©λ‹ˆλ‹€.

  1. μƒμ„±μžμ—μ„œ μ΄ˆκΈ°ν™”λ˜λŠ” final λ³€μˆ˜λ“€
  2. μƒμ„±μž : μƒμ„±μžλŠ” κΈ°λ³Έ μƒμ„±μžλ₯Ό λ¨Όμ € μ„ μ–Έν•˜κ³ , 좔가적인 μƒμ„±μžλŠ” κ·Έ 뒀에 μ„ μ–Έν•©λ‹ˆλ‹€.
  3. ν΄λž˜μŠ€μ™€ 같은 μœ ν˜•μ˜ μƒμˆ˜
  4. ν΄λž˜μŠ€μ™€ λ™μΌν•œ μœ ν˜•μ„ λ°˜ν™˜ν•˜λŠ” 정적 λ©”μ„œλ“œλ“€
  5. λ‹€λ₯Έ 정적 λ©”μ„œλ“œλ“€
  6. 정적 속성듀(properties)κ³Ό μƒμˆ˜λ“€
  7. λ³€κ²½ κ°€λŠ₯ν•œ 속성듀(properties)은 빈 라인 ꡬ뢄 없이 λ‹€μŒκ³Ό 같은 μˆœμ„œλ‘œ μž‘μ„±ν•©λ‹ˆλ‹€.
    • getter
    • private field
    • setter
  8. toString κ³Ό build λ₯Ό μ œμ™Έν•œ λ©”μ„œλ“œλ“€
  9. build λ©”μ„œλ“œ
  10. hashCode, toString λ©”μ„œλ“œ

μƒμ„±μžκ°€ μ—¬λŸ¬ ν•„λ“œλ₯Ό λ°›κ³  μžˆλ‹€λ©΄, ν•΄λ‹Ήν•˜λŠ” 클래슀 멀버 λ³€μˆ˜λ“€μ˜ μ„ μ–Έ μˆœμ„œλ„ 동일해야 ν•©λ‹ˆλ‹€.

μƒμ„±μž ꡬ문

μ΄ˆκΈ°ν™” λͺ©λ‘μ—μ„œ super() λ₯Ό ν˜ΈμΆœν•˜λŠ” 경우, μƒμ„±μžμ™€ 콜둠, 그리고 super ν‚€μ›Œλ“œ 사이에 곡백을 μœ μ§€ν•©λ‹ˆλ‹€. super class 에 전달할 μΈμžκ°€ μ—†μœΌλ©΄, super λ₯Ό ν˜ΈμΆœν•˜μ§€ λ§ˆμ„Έμš”.

μ˜ˆμ‹œ:

// one-line constructor example
class ConstantTween<T> extends Tween<T> {
  ConstantTween(T value) : super(begin: value, end: value);

  // ...
}

// fully expanded constructor example
class ConstantTween<T> extends Tween<T> {
  ConstantTween(
    T value,
  ) : super(
        begin: value,
        end: value,
      );

  // ...
}

μ΅œλŒ€ 80자의 쀄 길이λ₯Ό μ„ ν˜Έν•©λ‹ˆλ‹€

μ΅œλŒ€ 쀄 κΈΈμ΄λŠ” 80자λ₯Ό λͺ©ν‘œλ‘œ ν•˜μ§€λ§Œ, 쀄을 λ‚˜λˆ„μ—ˆμ„ λ•Œ 읽기 μ–΄λ €μ›Œμ§€κ±°λ‚˜, 쀄과 μ£Όλ³€ μ€„μ˜ 일관성이 λ–¨μ–΄μ§€λŠ” κ²½μš°μ—λŠ” ν•΄λ‹Ή 쑰건을 λ¬΄μ‹œν•˜κ³  μž‘μ„±ν•©λ‹ˆλ‹€.

// BAD (breaks after assignment operator)
final List<FooBarBaz> _members =
  <FooBarBaz>[const Quux(), const Qaax(), const Qeex()];

// BETTER (only slightly goes over 80 chars)
final List<FooBarBaz> _members = <FooBarBaz>[const Quux(), const Qaax(), const Qeex()];

// BETTER STILL (fits in 80 chars)
final List<FooBarBaz> _members = <FooBarBaz>[
  const Quux(),
  const Qaax(),
  const Qeex(),
];

μ—¬λŸ¬μ€„μ˜ 인자 및 νŒŒλΌλ―Έν„° ν•­λͺ©λ“€μ€ 2μΉΈμ”© λ“€μ—¬μ“°κΈ° ν•©λ‹ˆλ‹€

μ˜ˆμ‹œ:

Foo f = Foo(
  bar: 1.0,
  quux: 2.0,
);

μ—¬λŠ” κ΄„ν˜Έ 뒀에 μ€„λ°”κΏˆμ΄ μžˆλŠ” 경우, λ‹«λŠ” κ΄„ν˜Έ μ•žμ—λ„ μ€„λ°”κΏˆμ„ μΆ”κ°€ν•©λ‹ˆλ‹€

μ—¬λŠ” κ΄„ν˜Έ ( 뒀에 μ€„λ°”κΏˆμ΄ μžˆλŠ” 경우, λ‹«λŠ” κ΄„ν˜Έ ) μ•žμ—λ„ μ€„λ°”κΏˆμ„ μΆ”κ°€ν•©λ‹ˆλ‹€

μ˜ˆμ‹œ:

// BAD:
  foo(
    bar, baz);
  foo(
    bar,
    baz);
  foo(bar,
    baz
  );

// GOOD:
  foo(bar, baz);
  foo(
    bar,
    baz,
  );

μΈμžλ“€κ³Ό νŒŒλΌλ―Έν„° 리슀트 λ˜λŠ” List ν˜•μ‹μ„ ν‘œκΈ°ν•  λ•Œ Multi-line 으둜 μž‘μ„±ν•˜λŠ” 경우라면, 각 라인의 끝에 μ‰Όν‘œλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€

μ˜ˆμ‹œ:

List<int> myList = [
  1,
  2,
];
myList = <int>[3, 4];

foo1(
  bar,
  baz,
);
foo2(bar, baz);

ν•­λͺ© 쀑 ν•˜λ‚˜κ°€ multi-line callback, collection literal λ˜λŠ” switch ν‘œν˜„μ‹μΈ 경우 끝에 μ‰Όν‘œ 없이 μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ˜ˆμ‹œ:

// GOOD:
foo(
  bar,
  baz,
  switch (value) {
    true  => ScrollDirection.forward,
    false => ScrollDirection.reverse,
    null  => ScrollDirection.idle,
  },
);

// also GOOD:
foo(bar, baz, switch (value) {
  true  => ScrollDirection.forward,
  false => ScrollDirection.reverse,
  null  => ScrollDirection.idle,
});

// The same applies to collection literals and callbacks:
foo(<String>[
  'list item 1',
  'list item 2',
  'list item 3',
]);

Future.delayed(Durations.short1, () {
  if (mounted && _shouldOpenDrawer) {
    _drawerController.forward();
  }
});

λͺ¨λ“ κ²ƒμ„ ν•œμ€„λ‘œ μž‘μ„±ν• μ§€, Multi-line 으둜 μž‘μ„±ν• μ§€λŠ” 미적인 선택이며, κ°€μž₯ 읽기 μ‰¬μš΄ 방법을 μ„ νƒν•©λ‹ˆλ‹€. λ‹€λ§Œ, μ—°μ†λœ λ¦¬μŠ€νŠΈμ—μ„œλŠ” ν†΅μΌλœ μŠ€νƒ€μΌμ„ μ‚¬μš©ν•  것을 ꢌμž₯ν•©λ‹ˆλ‹€.

μ˜ˆμ‹œ:

  // BAD (because the second list is unnecessarily and confusingly different than the others):
  List<FooBarBaz> myLongList1 = <FooBarBaz>[
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
  ];
  List<Quux> myLongList2 = <Quux>[ Quux(1), Quux(2) ];
  List<FooBarBaz> myLongList3 = <FooBarBaz>[
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
  ];

  // GOOD (code is easy to scan):
  List<FooBarBaz> myLongList1 = <FooBarBaz>[
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
  ];
  List<Quux> myLongList2 = <Quux>[
    Quux(1),
    Quux(2),
  ];
  List<FooBarBaz> myLongList3 = <FooBarBaz>[
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
    FooBarBaz(one: firstArgument, two: secondArgument, three: thirdArgument),
  ];

=> 의 μ‚¬μš©μ€ 짧은 ν•¨μˆ˜ λ˜λŠ” λ©”μ„œλ“œμ—μ„œ μ‚¬μš©ν• κ²ƒμ„ ꢌμž₯ν•©λ‹ˆλ‹€

λ‹€λ§Œ, => λ₯Ό μ‚¬μš©ν–ˆμ„ λ•Œ λͺ¨λ“  λ‚΄μš©μ΄ ν•œμ€„λ‘œ μž‘μ„±μ΄ κ°€λŠ₯ν•œ κ²½μš°μ—λ§Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

μ˜ˆμ‹œ:

// BAD:
String capitalize(String s) =>
  '${s[0].toUpperCase()}${s.substring(1)}';

// GOOD:
String capitalize(String s) => '${s[0].toUpperCase()}${s.substring(1)}';

String capitalize(String s) {
  return '${s[0].toUpperCase()}${s.substring(1)}';
}

=>의 μ‚¬μš©μ€ λ¦¬ν„°λŸ΄ λ˜λŠ” switch ν‘œν˜„μ‹μ„ λ°˜ν™˜ν•˜λŠ” getter λ˜λŠ” callback μ—μ„œλ§Œ μ‚¬μš©ν•©λ‹ˆλ‹€

μ˜ˆμ‹œ:

// GOOD:
List<Color> get favorites => <Color>[
  const Color(0xFF80FFFF),
  const Color(0xFF00FFF0),
  const Color(0xFF4000FF),
  _mysteryColor(),
];

// GOOD:
bool get isForwardOrCompleted => switch (status) {
  AnimationStatus.forward || AnimationStatus.completed => true,
  AnimationStatus.reverse || AnimationStatus.dismissed => false,
};

μ½”λ“œκ°€ return λͺ…λ Ήλ¬Έλ§Œ ν¬ν•¨ν•˜λŠ” inline closureλ₯Ό μ „λ‹¬ν•˜λŠ” κ²½μš°μ—λ„ => λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 이런 κ²½μš°μ—λŠ” ], } λ˜λŠ” ) κ΄„ν˜ΈλŠ” callback 이 μ‹œμž‘ν•˜λŠ” 쀄과 같은 λ“€μ—¬μ“°κΈ°λ₯Ό κ°™μŠ΅λ‹ˆλ‹€.

μ˜ˆμ‹œ:

    // GOOD, but slightly more verbose than necessary since it doesn't use =>
    @override
    Widget build(BuildContext context) {
      return PopupMenuButton<String>(
        onSelected: (String value) { print('Selected: $value'); },
        itemBuilder: (BuildContext context) {
          return <PopupMenuItem<String>>[
            PopupMenuItem<String>(
              value: 'Friends',
              child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'),
            ),
            PopupMenuItem<String>(
              value: 'Events',
              child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'),
            ),
          ];
        }
      );
    }

    // GOOD, does use =>, slightly briefer
    @override
    Widget build(BuildContext context) {
      return PopupMenuButton<String>(
        onSelected: (String value) { print('Selected: $value'); },
        itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
          PopupMenuItem<String>(
            value: 'Friends',
            child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'),
          ),
          PopupMenuItem<String>(
            value: 'Events',
            child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'),
          ),
        ]
      );
    }

Packages

Import Convention

Flutter Framework κ΄€λ ¨ νŒ¨ν‚€μ§€λ₯Ό import ν•΄μ•Όν•˜λŠ” 경우 λ‹€μŒκ³Ό 같은 κΈ°μ€€μœΌλ‘œ μž‘μ„±ν•©λ‹ˆλ‹€.

  • material : λŒ€λΆ€λΆ„μ˜ μ•± κ°œλ°œμ‹œ μ„ νƒν•΄μ„œ μ‚¬μš©
  • cupertino : iOS μŠ€νƒ€μΌ μ•±μ΄λ‚˜ ν”Œλž«νΌ νŠΉν™”λœ iOS UIλ₯Ό μ œκ³΅ν•  λ•Œ μ‚¬μš©
  • foundation : UI μœ„μ ― λŒ€μ‹  Flutter의 κΈ°λ³Έ κΈ°λŠ₯μ΄λ‚˜ μƒνƒœ 관리λ₯Ό μœ„ν•œ 클래슀만 ν•„μš”ν•  λ•Œ μ‚¬μš©

Riverpod

λŒ€ν‘œμ μΈ μƒνƒœκ΄€λ¦¬ νŒ¨ν‚€μ§€ 쀑 ν•˜λ‚˜λ‘œ riverpod 을 μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

Notifier의 μƒμ„±μžμ— state μ΄ˆκΈ°ν™” λ‘œμ§μ„ μž‘μ„±ν•˜λŠ”κ²ƒμ„ ν”Όν•©λ‹ˆλ‹€

아직 initialized λ˜μ§€ μ•Šμ•˜κΈ°μ— ref λ“± 기타 ν”„λ‘œνΌν‹°λ“€μ„ μ‚¬μš©ν•  수 μ—†μœΌλ―€λ‘œ, Notifierμ—λŠ” μƒμ„±μžκ°€ μ—†μ–΄μ•Ό ν•©λ‹ˆλ‹€. λŒ€μ‹  build λ©”μ„œλ“œμ— λ‘œμ§μ„ μž‘μ„±ν•©λ‹ˆλ‹€.

class MyNotifier extends ... {
  // BAD:
  MyNotifier() {
    state = AsyncValue.data(42);
  }

  // GOOD:
  @override
  Result build() {
    state = AsyncValue.data(42);
  }
}

Code Generator - build_runner

μ½”λ“œ 생성 도ꡬ 쀑 ν•˜λ‚˜μΈ build_runner νŒ¨ν‚€μ§€λŠ” Dart μ½”λ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ νŒŒμΌμ„ μƒμ„±ν•˜λŠ” 방법을 μ œκ³΅ν•˜λŠ” νŒ¨ν‚€μ§€μž…λ‹ˆλ‹€. 반볡적인 μž‘μ—…μ„ μžλ™ν™” ν•˜κΈ°λ„ ν•˜λ©°, Static Metaprogramming 을 κ°€λŠ₯ν•˜κ²Œ ν•΄μ€λ‹ˆλ‹€. (Dart μ–Έμ–΄μ˜ 경우 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ»΄νŒŒμΌν•˜λŠ”λ° μΆ”κ°€ 단계가 ν•„μš”ν•˜λ‹€λŠ” 단점이 μžˆμ–΄ 이λ₯Ό λ³΄μ™„ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€.)

λ§Žμ€ νŒ¨ν‚€μ§€λ“€μ΄ build_runner λ₯Ό ν™œμš©ν•˜μ—¬ μ½”λ“œ 생성을 톡해 개발 생산성을 높이고 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, freezed νŒ¨ν‚€μ§€λŠ” 데이터 클래슀λ₯Ό μƒμ„±ν•˜λŠ”λ° μ‚¬μš©λ˜κ³ , json_serializable νŒ¨ν‚€μ§€λŠ” JSON 직렬화 μ½”λ“œλ₯Ό μƒμ„±ν•˜λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€.

이처럼 λ§Žμ€κ³³μ—μ„œ μ‚¬μš©ν•˜λŠ” 만큼 ν•œλ²ˆ μ½”λ“œμƒμ„±μ„ ν•˜κ²Œ 되면 λ§Žμ€ νŒŒμΌλ“€μ΄ μƒμ„±λ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ νŒŒμΌλ“€μ€ ν”„λ‘œμ νŠΈ λ‚΄μ—μ„œ 좔적이 μ–΄λ ΅κΈ° λ•Œλ¬Έμ— ν”„λ‘œμ νŠΈ λ‚΄μ—μ„œ νŠΉμ • 폴더에 μœ„μΉ˜ν•˜λ„λ‘ κ΄€λ¦¬ν•©λ‹ˆλ‹€.

root 폴더 ν•˜μœ„μ— build 폴더λ₯Ό μƒμ„±ν•˜μ—¬ 관리할 수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€

μ˜ˆμ‹œ:

project_root
β”œβ”€β”€ build/
β”‚   └── ...
└── lib/
    └── ...