2021년 2월 14일 일요일

플러터

플러터 토이 프로젝트를 한달 해보면서 느낀 플러터의 인상을 정리합니다. 프레임워크의 장단점을 완전히 파악하기에는 부족하지만 다른 언어와의 차이점은 바로 느낄 수 있었습니다.  플러터는 구글에서 개발한 크로스 플랫폼 모바일//데스크 GUI 애플리케이션 소프트웨어 디자인 프레임워크입니다.  모바일, 웹 그리고 데스크까지 포함되어 계획이 웅대한 프로젝트이지만 사실 안드로이드와 iOSGUI만 성공적으로 통합해도 성공이라고 할 수 있습니다.  한마디로 안드로이드폰 APP과 아이폰 APP를 한 프로그램으로 완성하겠다는 취지입니다.  이와 비슷한 프레임워크로 javascript를 기반으로 하는 리액트 네이티브(React Native)가 있습니다. 같은 용도의 프레임워크를 의식해서 개발한 탓인지 리액트 네이티브와 유사한 점도 플러터에 많습니다. 플러터를 시작하면서 리액트도 잠깐 고민했었는데 1인이 개발및 테스트하기에는 플러터 쪽이 쉬워 보여 플러터로 매진하기로 했습니다.


플러터를 써 보면 객체 지향 프로그램(이하 Object Oriented Program, OOP)이라는 사실을 여실히 느낍니다. 플러터는 Dart라는 컴퓨터 언어를 사용하는데 이 언어로 GUI 구성을 위한 다양한 Widget를 미리 만들어 놓았습니다. WidgetRN의 컴포넌트와 비슷합니다. Widget를 포함하여 플러터는 철저한 객체 지향 프로그램을 형태를 취합니다. 지향 정도가 아니라 객체 그 자체입니다.

RN OOP 형태이지만 HTML 태그인지 class tag인지 애매한 <>를 아직 사용합니다아래는 “Hello World”를 휴대폰 화면에 출력하는 RN 예입니다  


const App = () => {
  return (
    <SafeAreaView style={styles.container}>
      <Text>Hello World</Text>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

export default App;


같은 작업을 플러터에서는 아래와 같이 객체 이름, 프로퍼티 만으로 구성합니다.  MyApp -> MaterialApp -> Scaffold -> Center -> Text 로 이어지는 객체 구조로 이루어져 있습니다.


void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

위치 조차 Center, Column, Row와 같은 Widget 클래스로 정할 수 있습니다.  아래 프로그램은 화면 가운데에 column 방향으로 빨간, 파랑, 초록 순의 Container를 배치하라는 뜻입니다. 프로그램의 일부입니다만 이런 내용이 반복적으로 나오면 프로그램의 줄 수를 길게 만들어 이 형식에 익숙하기 전까지 프로그램을 이해하는데 어려움이 있을 수 있습니다

Center(
  child: Column(
    children: <Widget>[
      Container(
        color: Colors.red,
        width: 100.0,
        height: 100.0,
      ),
      Container(
        color: Colors.blue,
        width: 100.0,
        height: 100.0,
      ),
      Container(
        color: Colors.green,
        width: 100.0,
        height: 100.0,
      ),
    ],
  ),
)

child:, children:, color:, width:, height: 는 모두 각 객체의 프로퍼티입니다화면을 구성하는데 json이나 xml 파일을 따로 두지 않습니다. 대신 객체 안에 객체가 들어가는 단계가 깊어서 플러터에서는 클래스 단위가 아닌 프로퍼티 단위를 한 줄에 적는 위 방식이 아래보다 일반적입니다.

Center(
  child: Column( children: <Widget>[
      Container(color: Colors.red, width: 100.0, height: 100.0,),
      Container(color: Colors.blue, width: 100.0, height: 100.0,),
      Container(color: Colors.green, width: 100.0, height: 100.0,),
],),
)


그리고 위 프로그램을 보면 확실히 드러나는데 class의 인수를 지정할 때 “)”로 바로 닫지 않고 “,)” 쉼표가 앞에 있습니다. 쉼표를 놔두면 프로퍼티를 추가하기로 편한 플러터에서는 관용적으로 쉼표를 사용합니다.  이 쉼표에다 Class 끝부분에 가면 Class에서 나온 “)”, 리스트에서 나온 “]”, 블록에서 나온 “}”가 쏟아져서 혼란을 초래합니다. Android Studio는 자동적으로 “//”comment를 표시해서 짝을 맞추는데 도움을 주고 반드시 “;” 혹은 “,” 가 있어야 하는 부분은 적색 밑줄이 표시되어 컴파일 전에 수정하도록 유도합니다



요즘 컴퓨터 언어들은 도움이 될 것 같은 신개념 기술은 서로 차용하는 경향이 있습니다. 객체 지향은 물론이고 lambda, map/reduce, filter, await/async 등이 여기에 해당하는데 그 중에 flutter(실질적으로는 Dart) await/async가 특이합니다. Javascriptawait이 있지만 Dart fileNetwork IO에는 반드시 await/async를 사용해야 합니다. IO에는 await/async가 선택이 아니라 필수라는 뜻입니다.

await/asyncthen 구문으로 대체하는데 firebase(구글이 제공하는 DB 서비스)의 객체의 method및 프로퍼티와 섞이면 아래와 같은 복잡한 문장도 만들어질 수 있으니 구문을 익히는데 시간이 필요합니다.


_db.collection("comments").add(
{
  "text": commentCntl.text,
  "user": userid,
}
).then((c1) {
    _db.collection("posts").doc(arg.post.id).update({
      "remarks": FieldValue.arrayUnion([c1]),
      "ncomments": FieldValue.increment(1)});
    }).then((_) {
      Navigator.pop(context, true);
});

이상 플러터를 사용하면서 느낀 인상입니다


댓글 없음:

댓글 쓰기