Нехайповый Dart, который стоит попробовать

Тимофей Лавренюк

Corcentric

Дисклеймер

Целью этой презентации не является обидеть любитей TypeScript-а, а лишь показать преимущества и недостатки одной технологии перед другой

  • Что мы знаем о Dart
  • Как я пришел к Dart
  • Особенности Dart
  • Экосистема Dart

План

Что мы знаем о Dart?

1

A client-optimized language for fast apps on any platform

Google

Кто использует

Немного истории...

2011

Появился

2011

2018

Появился

медленно развивался

Как я пришел к Dart?

2

Research: на чем можно писать front-end, кроме TypeScript?

  • Язык от JetBrains
  • Много информации
  • Сыроват для Web
  • Нет UI-фреймворка
  • Нет пакетного менеджера
  • Синтаксис OCaml от Facebook
  • Мало информации
  • Есть UI-framework
  • Есть пакетный манеджер
  • Много функциональщины
  • Язык от Mozilla
  • Компилируется в WebAssembly, может общаться с JS кодом
  • Нет стабильного UI-фреймворка
  • Есть пакетный менеджер
  • Язык от Google
  • Не много, но и не мало информации
  • Есть UI-фреймворк
  • Есть пакетный менеджер

Мой выбор

Почему не TypeScript?

Обучение и документация

Надежность

Вывод ошибок 

Как начать работать с Dart?

SDK

IDE

void main() {
  print('Hello, World!');
}

Как научиться писать хорошо на Dart?

Как учат JS?

МНОГО

Что предлагает Dart?

Особенности Dart

3

2011

2018

Появился

медленно развивался

Dart 2.0

Строгая типизация

Типизация в Javascript (ее нет)

Типизация в TypeScript (гибкая)

The Dart language is type safe: it uses a combination of static type checking and runtime checks to ensure that a variable’s value always matches the variable’s static type. Although types are mandatory, type annotations are optional because of type inference.

  • Numbers
  • Strings
  • Booleans
  • Lists
  • Sets
  • Maps

Типы данных

Простота

List numbers = [1,2,3];

print(numbers.first); // 1
print(numbers.last); // 3
Map<String, String> users =
	{"1": "Foo", "2": "Bar"};
    
List<String> usernames = users.values;
List<String> userIds = users.keys;
class SomeClass {
  double number;
  callFunction() {}
}
SomeClass nullClass;

final value = nullClass ?? SomeClass();
final number ??= SomeClass().number;

print(nullClass?.callFunction());
class Foo {
    Foo({
    	this.paramOneName = '1',
        this.paramTwoName = '2' });
    
    String paramOneName;
    String paramTwoName;
}

var foo = Foo(paramTwoName: '3');
class Bar {
    Bar();
    
    Foo f1;
    Foo f2;
}

Bar bar = Bar()
    ..f1 = Foo(paramTwoName: '2')
    ..f2 = Foo(paramOneName: '10');
mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}
class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

Вспомогательные классы

  • DateTime
  • Duration
  • Uri

this не теряется

Core libraries

  • dart:core
  • dart:async
  • dart:collection
  • dart:html
  • dart:io
  • ...

dart:async

Future<int> future = Future(asyncFunction);
future.then((int value) {
  print(value);
}).catchError((e) {
  print('Error');
});
 
someFunc () async {
  try {
    int value = await future;
  } catch(e) {
    print('Error');
  }
}

Streams

Stream<int> timedCounter(Duration interval, [int maxCount]) async* {
  int i = 0;
  while (true) {
    await Future.delayed(interval);
    yield i++;
    if (i == maxCount) break;
  }
}
 
var counterStream = timedCounter(const Duration(seconds: 1), 15)
counterStream.listen(print);
someStream
  .map(...)
  .reduce(...)
  .skip(...)
  .take(...)
  .timeout(...)
  .transform(...)
  .listen((result) {
     print(result);
  })

stream_transform

rx_dart

dart:collection

dart:convert

  • Base64Encoder
  • Base64decoder
  • JsonDecoder
  • JsonEncoder
  • HtmlEscape
  • ...

dart:html

Stream

Это все из коробки (SDK)

Сторонние библиотеки

json_serializer

{
    "name": "Foo",
    "email": "somemail@example.com"
}

JSON response

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';


@JsonSerializable()
class User {
  User(this.name, this.email);

  String name;
  String email;

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

built_value

built_collection

abstract class User implements Built<User, UserBuilder> {

  factory User([updates(UserBuilder b)]) = _$User;
  User._();

  @nullable
  String get firstName;

  @nullable
  String get lastName;
}
User user = User((builder) =>
    builder..firstName = 'One'
		   ..lastName = 'Two'
);

User secondUser = user.rebuild((builder) =>
	builder..lastName = 'Three'
);

// user != secondUser

intl

http

...

Экосистема Dart

4

Форматирование кода

class User
{
  String paramNumberOne      = 1;
  String paramNumbeTwo       = 2;
  String paramNumbeThree     = 3;

  num age;

  num get age => _age;

  set age (num age)
  {
    _age = age;
  }
}
class User {
  String paramNumberOne = 1;
  String paramNumbeTwo = 2;
  String paramNumbeThree = 3;

  num age;
}

Dart Formatter

dartfmt -w --fix lib 

Dart 👍

Linter

analysis_options.yaml

dartanalyzer --fatal-warnings lib

Dart 👍👍👍

Документация

Dart documentation guide

dartdoc

F1

Dart 👍👍👍

Пакетный менеджер

name: project name
version: 0.0.1

environment:
  sdk: '>=2.4.0 <3.0.0'

dependencies:
  intl: ^0.15.7

pubspec.yaml

Dart 👍👍

Разработка приложений

Web

import 'package:angular/angular.dart';

@Component(
    selector: 'user-info',
    templateUrl: 'user_info.html')
class UserInfo implements OnInit {
    User(this.dataController)
    
    DataController dataController;

    Stream<String> userName;
	
    void ngOnInit() {
        userName = dataController.info.userName;
    }
}

НО

Мало информации

Велосипедостроение

Подключение JS библиотек

@JS('draw2d')
library draw2d;

@JS('Canvas')
class Canvas {
  external factory Canvas(String name, [num x, num y]);

  external Canvas add(Figure figure, [num x, num y]);
  external Canvas addSelection(ArrayList /*Figure|List<Figure>*/ object);
  external Canvas clear();
  external void destroy();
  external void fireEvent(String name, [dynamic attr]); /*Object*/
  external Point fromCanvasToDocumentCoordinate(num x, num y);
  external Point fromDocumentToCanvasCoordinate(num x, num y);
  external num getAbsoluteX();
  external num getAbsoluteY();
}

Build system

Debug

Chrome Dev Tools

Выводы

Batteries included

iOS

Android

  • Меньше устройств
  • Меньше приложений
  • Больше качественных приложений
  • Залиться в AppStore - Challenge
  • Больше устройств
  • Больше приложений
  • Меньше качественных приложений
  • Залиться в Play Market - Easy

Dart

JS/TS

  • Мало кто использует
  • Мало библиотек
  • Много качественных библиотек
  • Залиться в Pub  - Challenge
  • Тяжело начать, легче поддерживать.
  • Отличная документация
  • Очень многие используют
  • Очень много библиотек
  • Мало качественных библиотек
  • Залиться в NPM - Easy
  • Легко начать, тяжелее поддерживать.
  • Документаций много и все разные

Продуктивность разработки

TS

Dart

Dart хорош, но не везде

Стоит попробовать Dart, если хочется:

  • Почувствовать себя крутым девелопером уровня C#/Java
  • Повышать кругозор новых языков, оставаясь писать frontend
  • Забыть про многие странные вещи из JS
  • Не жить в мире, где на все случаи есть библиотека и подробная документация к ней

2011

2018

Появился

2019

медленно развивался

Dart 2.0

Flutter-Хайп

2011

2018

Появился

2019

Будущее

медленно развивался

Dart 2.0

Flutter-Хайп

Dart 2.5 ML Completion

Dart 2.7 Extensions

Null safety

Вопросы?

Нехайповый Dart, который стоит попробовать

By Timofey Lavrenyuk

Нехайповый Dart, который стоит попробовать

  • 473