본문 바로가기

IT 상식

Flutter : 모바일 앱 개발의 미래?

Dart의 힘

Flutter는 구글이 개발한 Dart 언어를 사용합니다. 여러분이 Java를 써본 적이 있으시다면, Dart의 문법과 꽤 비슷하다는 것을 느끼실 것 같습니다. 하지만 좀 더 깊이 들어다보면, 문법면에서 꽤 다른 언어라는걸 알게 될 겁니다.

Dart 에 대해서 범주에 벗어나기 때문에 깊이 다루진 않지만, 제 생각에 가장 도움되는 기능인 비동기 연산 (asynchronous operations) 은 한번 더 짚고 넘어가야 할 것 같습니다. Dart 언어가 전폭적으로 지원해주는 기능일 뿐 아니라, Flutter 코드를 쉽게 작성할 수 있게 합니다.

이 기능은 Flutter 앱에서 IO, DB Query, API Fetch 와 같이 오래걸리는 연산을 할때 가장 많이 사용하게 될겁니다. 비동기 연산 없이는 오래걸리는 연산이 끝날때까지 다른 처리가 중지되어 있을 겁니다. 이 것을 방지하기 위해 Dart는 asyncawait 키워드를 제공하고 있고, 이를 이용하면 오래걸리는 연산을 하는 동안에 다른 처리가 계속되게 할 수 있습니다.

몇 가지 예제를 봅시다 : 오래걸리는 연산을 비동기 연산 없이 다루기 vs 비동기 연산으로 다루기

// 비동기 연산 없이 하기
import 'dart:async';

main() {
    longOperation();
    printSomething();
}

longOperation() {
    Duration delay = Duration(seconds: 3);
    Future.delayed(delay);
    print('이 글이 보여지기까지 3초가 걸렸다.');
}

printSomething() {
    print('시간이 좀 걸린 것 같아!');
}

그 결과는?

이 글이 보여지기까지 3초가 걸렸다.
시간이 좀 걸린 것 같아!

이상적인 결과는 아니네요. 오래걸리는 연산때문에 앱이 멈춰있는 걸 그 누구도 원하지 않았을 것 같은데요,  async 와 await 키워드를 이용해서 조금만 손 봐봅시다.

// 비동기 연산으로
import 'dart:async';

main() {
    longOperation();
    printSomething();
}

Future<void> longOperation() async {
    var retVal = await runLongOperation();

    print(retVal);
}

const retString = '다른 연산의 멈춤 없이, 3초를 기다렸다가 반환되었다.';
Duration delay = Duration(seconds: 3);

Future<String> runLongOperation() => Future.delayed(delay, () => retString);

printSomething() {
    print('올바르게 출력된 것 같아!');
}

다시 결과를 보면?

올바르게 출력된 것 같아!
다른 연산의 멈춤 없이, 3초를 기다렸다가 반환되었다.

비동기 연산 덕분에, 우리는 코드가 실행되는 동안에 다른 코드가 실행될 수 있게 되었습니다.

한번 구현해서 안드로이드와 iOS 동시에 실행

Android와 iOS 앱을 개발하기 위해 다른 코드베이스로 구현하는 것은 많은 시간을 사용합니다. 즉, Flutter와 같은 SDK를 사용하면, 두 운영체제에서 하나의 코드베이스로 구현 할 수 있고, 완벽하게 네이티브 앱처럼 작동합니다. 즉, 스크롤링과 네비게이션같은 것들이 OS 에서 제공하는 것과 동일한 수준으로 작동합니다.

또한 Flutter로 개발한 앱은 어떤 기기나 어떤 시뮬레이터에서도 빌드할 수 있고, 실행이 가능합니다.

UI 개발한번 구현해서 안드로이드와 iOS 동시에 실행

UI 개발은 지루합니다. 저는 백엔드 개발자에 가까워서, UI 개발은 다른 코드와의 의존도가 높은 것처럼 느껴집니다. 그래서 더욱더 간단한 것을 원했었고, 그래서 Flutter를 빠져들게 되었습니다.

여러가지 위젯을 결합하여 UI가 만들어 지고, UI를 원하는 앱의 모양대로 수정합니다. 여러분은 위젯들이 어떻게 표현되는지만 알면 그 위젯을 완벽히 이용할 수 있습니다. UI를 배치하기 위해 Row, Column, Container 위젯을 사용합니다. 컨텐츠를 표현하기 위해 Text, RaisedButton 같은 위젯을 사용합니다. 이 위젯들은 Flutter가 제공하는 수많은 위젯중의 아주 일부지만, 이 것들만으로 간단한 UI를 구현할 수 있습니다. 

@override
Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text('Flutter App'),
            centerTitle: true,
            elevation: 0,
        ),
        body: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
                Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                        Container(
                            child: Text('Some text'),
                        ),
                        Container(
                            child: RaisedButton(
                                onPressed: () {
                                    // Do something on press
                                },
                                child: Text('PRESS ME'),
                            ),
                        ),
                    ],
                ),
            ],
        ),
    );
}

Flutter는 앱의 분위기를 자연스럽게 해주는 트릭이 있습니다. 앱의 전체적으로 글꼴, 색상을 수동으로 변경하려면 일일히 확인해가면서 수정할 수 있지만, 시간이 많이 걸리게 됩니다. 이러한 문제점을 해결하기 위해 Flutter는 색, 글꼴, 입력 필드 등 여러가지의 것들을 담을 수 있는 ThemeData 를 제공합니다. 이 기능은 앱의 디자인을 일관되게 유지하는데 매우 유용합니다.

theme: ThemeData(
    brightness: Brightness.dark,
    canvasColor: Colors.grey[900],
    primarySwatch: Colors.teal,
    primaryColor: Colors.teal[500],
    fontFamily: 'Helvetica',
    primaryTextTheme: Typography.whiteCupertino.copyWith(
        display4: TextStyle(
            color: Colors.white,
            fontSize: 36,
        ),
    ),
),

앱의 색, font family, Text style 등의 설정을 위와 같은 ThemeData에 설정하면, 앱 전체적으로 자동으로 반영되게 됩니다. Text style 을 Text 위젯에 수동으로 지정할 수도 있습니다.

child: Text(
    'Some text',
    style: Theme.of(context).primaryTextTheme.display4,
),

개발을 더욱 효율적으로 하기 위해, Flutter는 사용자가 코드상의 UI를 변경할 때마다 앱을 다시 시작하지 않고 코드를 반영하게 할 수 있습니다. (Hot Reload) 코드 수정을 하고 저장하면 1초만에 앱에 반영된 것을 볼 수 있습니다.

라이브러리들

Flutter 는 기본적으로 홀륭한 기능을 제공하지만, 그 이상이 필요할 때가 있습니다. Dart와 Flutter 기반으로 되어있는 방대한 라이브러리를 사용하면 됩니다. 앱에 광고를 넣고싶나요? 새 위젯을 원하시나요? 이 모든 것을 위한 라이브러리들이 많습니다.

만약 여러분이 많은 것을 만드신다면, 여러분이 만든 라이브러리를 커뮤니티에 공유하는 것 조차 순식간에 가능합니다. 그 반대로 프로젝트에 라이브러리를 추가하는 것은 pubspec.yaml 파일에 딱 한줄만 넣으면 될 정도로 간단합니다. 예를 들어 sqflite 라이브러리를 프로젝트에 추가하고 싶다면 (역주: sqflite는 SQLite를 쉽게 사용할 수 있게 도와주는 라이브러리)

dependencies:
  flutter:
    sdk: flutter
  sqflite: ^1.0.0

파일에 한 줄 넣고나서, 명령줄에 flutter packages get 을 입력하면 바로 라이브러리를 사용할 수 있습니다. 라이브러리들이 Flutter 앱을 우아하게 만들고 개발하는데 많은 시간을 단축시켜줍니다.

백엔드 개발

오늘날 대부분의 앱은 어떤 데이터에 의존하고 있고, 데이터를 나중에 화면에 뿌려주기 위해 어딘가에 저장을 해야합니다. 그래서 Flutter 와 같은 새로운 SDK로 앱을 만들 때, 꼭 이 점을 고려를 해야 합니다.

다시한번 말씀드리자면, Flutter 앱은 Dart 언어로 만들어지고, Dart 언어는 백엔드 개발에서 더욱 굉장해집니다. 저는 위에서 단순함에 대해서 많은 이야기를 했고, Dart와 Flutter의 백엔드 개발도 예외는 아닙니다. 초보자와 전문가 모두에게 데이터기반 앱(data-driven app) 을 만드는 것은 놀랍도록 간단하지만, 단순하다고 품질이 부족하지도 않습니다.

이전 섹션과 연결되어, 라이브러리가 있기 떄문에 원하는 데이터베이스를 선택할 수 있습니다. (역주: sqlite, firebase, userdefaults 등등..) sqflite 라이브러리를 사용하면 SQLite 데이터베이스를 매우 빠르게 가동할 수 있습니다. 그리고 싱글턴 을 활용하면 , 어디서든 데이터베이스에 접속하여 데이터를 조회할 수 있습니다.

class DBProvider {
    // Singleton
    DBProvider._();

    // Static object to provide us access from practically anywhere
    static final DBProvider db = DBProvider._();
    Database _database;

    Future<Database> get database async {
        if (_database != null) {
            return _database;
        }

        _database = await initDB();
        return _database;
    }

    initDB() async {
        // Retrieve your app's directory, then create a path to a database for your app.
        Directory documentsDir = await getApplicationDocumentsDirectory();
        String path = join(documentsDir.path, 'money_clip.db');

        return await openDatabase(path, version: 1, onOpen: (db) async {
            // Do something when the database is opened
        }, onCreate: (Database db, int version) async {
            // Do something, such as creating tables, when the database is first created.
            // If the database already exists, this will not be called.
        }
    }
}

데이터베이스에서 데이터를 얻어낸 후에 모델을 객체(object)로 변환하거나 JSON 으로 변환해서 사용할 수 있습니다.

class User {
    int id;
    String name;

    User({
        this.id,
        this.name,
    });

    factory User.fromJson(Map<String, dynamic> json) => new User(
        id: json['id'],
        name: json['name'],
    );

    Map<String, dynamic> toJson() => {
        'id': id,
        'name': name,
    };
}

위 객체는 사용자에게 보여주기 위한 데이터는 아니겠지만, FutureBuilder 나 StreamBuilder 사이에 들어가게 될 것입니다. Flutter, SQLite 등의 여러 기술들로 데이터 기반 앱을 만들고 싶으시다면 다음 글도 읽어 보시기 바랍니다. (링크는 출처 참고)

결론

Flutter를 이용하면 끝없는 가능성을 가지고 있고, 광범위한 앱도 쉽게 만들수 있다고 생각합니다. 만약 모바일 앱을 개발해 보았는데, 플루터를 시도해보지 않았다면 꼭 한번 해보시기 바랍니다. Flutter를 몇 달 동안 사용해 보았는데, 이는 분명 모바일 개발의 미래라고 해도 무방할 것 같습니다. 그렇지 않다면 최소 올바른 방향으로 나아가는 한걸음이라고 생각합니다.

원본 출처 : https://www.freecodecamp.org/news/why-i-think-flutter-is-the-future-of-mobile-app-development-768332b73c0d/

※ 댓글과 공감은 큰 힘이 됩니다 ♥