Real-world planning and development – of modern Rich client-side applications – Итак



Real-world planning and development – of modern Rich client-side applications – Итак

0 0


prsnttn

neverminf

On Github paulkarabilo / prsnttn

Планирование и разработка

современного фронт-енда в реальных условия

Павел Карабило, Front-End Dev. pkarabilo@cogniance.com Cogniance

Фронт-енд толстеет

$("div")
    .show()
    .css({"margin": "10px"})
    .animate()...
                        

MV*

Паттерны

Модули

ООП

Unit-тесты

Разработчикам приходится

  • ...серьезно задумываться об архитектуре
  • ...делать на клиенте то, что еще недавно делали на сервере
  • ...следить, чтобы это все не било по производительности
  • ...и плюс к этому всему - старые добрые анимации, валидации формочек и пр.

А тем временем

HTML5, CSS3, ES6

Фреймворки, библиотеки, языки

Блогпосты, книги

Конференции, доклады

Заказчики, требования, технологии

Почему мы сейчас именно здесь и от этого всего никуда не деться?

Типичный back-end в 2005

  • Работа с БД
  • Валидация/фильтрация пользовательских данных
  • Просчет отношений и зависимостей
  • Роутинг
  • Работа со сторонними сервисами
  • Бизнес-логика
  • Рендеринг шаблонов

Типичный front-end в 2005

  • Валидация формочек
  • Простенькие изменения интерфейса и анимации
  • В редких случаях - AJAX

Типичный back-end в 2013

  • Работа с БД
  • Валидация/фильтрация
  • Работа с непубличными данными
  • Легковесный API интерфейс

Типичный фронт-енд в 2013

  • Просчет зависимостей
  • Роутинг
  • Сохранение состояния
  • Кеширование
  • Работа со сторонними сервисами
  • Бизнес-логика
  • Ренденринг шаблонов
  • Валидации формочек, анимации и т.п.

Положение дел в 2016

  • Бэк-енда как такового нет
  • Клиенты легко общаются между собой (WebRTC, например)
  • Для хранения данных используются сторонние сервисы
Да задолбали вы уже со своим джаваскриптом (Н. Закас)
Enough with the javascript already! (N. Zackas)
Any application that can be written in Javascript, will eventually be written in JavaScript Atwood's Law
...we’ve been working to take back control of our front-end performance by moving the rendering to the server. This has allowed us to drop our initial page load times to 1/5th of what they were previously (twitter.com)

Правильно?

Простая арифметика

  • Клиентов намного больше, чем серверов
  • Быстрее сделать 1 раз на клиенте чем 100500 раз на сервере
  • Нет смысла делать на сервере то, что можно сделать на клиенте
  • Нет предела хитростям в оптимизации
<td data-key="username"
    data-id="234233"
    data-ndocuments="7"
    data-permissions="user,moderator,admin">
        JOHN DOE
    </td>
                            
[
    ...
    {
        "username": "JOHN DOE",
        "id": "234233",
        "ndocuments": "7",
        "permissions": ["user", "moder", "admin"]
    }
]
                            

В чем разница?

  • Нет оверхеда на компиляцию\распаковку данных
  • Данные не смешаны с представлением
  • Сервер освобождается от ненужной головной боли

Но головной боли прибавляется на клиенте

Анализ и планирование

Работа с требованиями

Выделение основных задач на клиентской стороне

  • RESTful API/другой специфичный интерфейс с сервером?
  • Кеширование на клиенте?
  • Обработка больших объемов данных?
  • Много взаимодействия с пользователем?
  • Повышенные требования к надежности/отказоустойчивости?
  • Необходимость высокой производительности?
  • Валидации?
  • Продвинутые виджеты?
  • Крутые анимации и эффекты?
  • Риск изменения/дополнения требований?

Задачи на этапе планирования

  • Выбрать язык разработки
  • Определиться с используемыми технологиями
  • Выбрать основной фреймворк
  • Подобрать дополнительные библиотеки и плагины
  • Спланировать архитектуру
  • Определиться с дополнительными инструментами - test/build/deploy

Зачем париться, ведь %libname% плюс напильник могут все!

  • Пилить фичи
  • Пилить фичи быстро
  • Пилить фичи качественно
  • Быстро вносить изменения в запиленные фичи...
  • ... и, конечно же, фиксить баги
  • Масштабировать все что уже запилено в любые стороны

А с точки зрения разработчика?

  • Писать код
  • Писать красивый, читабельный код
  • Писать очень мало красивого, читабельного кода
  • Писать очень мало красивого, читабельного кода, и чтобы он еще делал все что надо

Выбор языка разработки

  • Количество языков которые компилируются в js давно перевалило за сотню
  • Можно компилировать из кучи существующих - C, Java, Lisp, Python, etc
  • Полностью новые языки - CoffeeScript, LiveScript, etc
  • "Набалдашники" для синтаксиса, статической типизации, асинхронных вещей - TypeScript, etc
  • ALTJS.ORG

В чем суть и преимущества?

  • Javascript не идеален, имеет много недостатков
  • Количество кода на одну фичу/задачу
  • Скорость разработки
  • Трансляция, как эффективная замена lint
  • Защита от дурака

Ок, а недостатки есть?

  • Увеличивается порог вхождения
  • В браузере все равно дебажим скомпилированный JS...
  • ...который не всегда выглядит понятно и красиво
  • JS все равно надо знать на высоком уровне

Пара примеров

Coffeescript

a = (n for n in items when n in [1..10])
                        

Compiled JS

var a, n,
  __indexOf = [].indexOf || function(item) { ... };

a = (function() {
  var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = items.length; _i < _len; _i++) {
       n = items[_i];
       if (__indexOf.call([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], n) >= 0) {
          _results.push(n);
       }
    }
    return _results;
})();
                            

В народе:

var a = [];

$.each(items, function (i, item) {

    if (item >= 1 && item <= 10) {
        a.push(item);
    }

});

                            

А лучше?

var a = _.filter(items, function (item) {
    return (item >= 1 && item <= 10)
});
                            

ASYNC

ICS

parallelSearch = (keywords, cb) ->
  out = []

  await
    for k,i in keywords
      search k, defer out[i]

  cb out
                

Статическая типизация

class Model {
    url: string;

    constructor(url: string) {
        this.url = url;
    }
}

var user = new Model(1);

/*Supplied parameters do not match any signature of call target.
Could not select overload for 'new' expression.*/
                        

Выбор основного фреймворка

  • Их очень много, однако основных игроков около десятка
  • Не существует "универсальных" фреймворков
  • Не существует "идеальных" фреймворков

Избранные цитаты разработчиков

"Мы изучали фреймворк по ходу разработки, поэтому все так криво написано"
"В следующем проекте буду использовать только %frameworkname%"
"Все кто не использует %frameworkname% - впустую тратят деньги заказчика"
"Да я быстрее с нуля напишу, чем буду в этом всем разбираться"
"Фронт-ендщик - не программист"

Суть выбора фреймворка

  • Максимум востребованных фичей должно поставляться из коробки
  • Все должно максимально гибко ии быстро настраиваться...
  • ...и масштабироваться
  • В идеале - полное отсутствие императивщины и jQuery-style

Правильно выбранный фреймворк:

  • Минимизирует время планирования архитектуры
  • Увеличивает скорость написания и качество кода
  • Делает невозможным написание некачественного кода
  • Автоматизирует от 80% задач

Неправильно выбранный фреймворк:

  • Заставляет городить кучу императивного кода
  • На каждый чих надо писать свой велосипед
  • Минимальное изменение требований влечет фундаментальный рефакторинг

Frameworkless JS?

Время против размера

Все равно jQuery

Ближе к делу

Неправильный выбор фреймворка/библиотек приносит больше проблем, чем все остальные просчеты вместе взятые

Мотивация/оправдания

  • Несформированные требования на начальном этапе работы
  • Успешное применение в предыдущих проектах
  • Привычка
  • Вдохновляющий доклад на очередной конференции
  • Желание попробовать что-то новое

Потеря времени

Потеря денег

Стратегия/тактика

Выделение общей концепции разрабатываемого приложения

Начало

Ключевые моменты

Приложения

Необходимые элементы

Фреймворки

Списки дополняются по мере появления нового опыта

Мораль: не забивать гвозди отверткой

Простая грубая арифметика

Время работы программиста есть произведение среднего времени на написание 1 команды на количество написанных команд

Perf = Tavg * Ncmd

При изменениях или рефакторинге:

Perf = 2 * Tavg * Ncmd

Простой пример

Получить данные с сервера, передать в шаблон

Backbone

var Users = Backbone.Collection.extend({
    url: "/api/users"
})

var UsersView = Backbone.View.extend({

    template: _.template($('#my-template').html()),

    initialize: function () {
        this.collection = new Users();
        this.collection.on("sync", this.render, this);
        this.collection.fetch();
    },

    render: function () {
        this.$el.html(this.template(this.collection.toJSON()));
        return this;
    }
});
                            

Angular

myNgApp.controller("Ctrl", ["$scope", "$http", function ($scope, $http) {

    $scope.items = $http.get("/api/some/endpoint");

}])
                            

Выбор правильного инструмента позволил:

  • Уменьшить в 5 раз время на первоначальное выполнение задачи
  • Уменьшить в 10 раз время на возможные изменения

Посчитать то же самое, но с синхронизацией данных

Users.get(id).save();
                            

Angular?

myNgApp.controller("Ctrl", ["$scope", "$http", function ($scope, $http) {
    var User = $resource('/user/:userId', {userId: '@id'});

    var user = User.get({userId: id}, function() {
          user.$save();
    });

}]);
                            

Выборка данных из коллекции

var names = Users.pluck("name");
                            

Angular?

ОК, так как же выбрать то что нужно?

Анализ + Планирование + Гугл

Первый шаг - отбор кандидатов

  • Максимум требований - из коробки
  • То чего нет из корбки - должно быть в виде плагина
  • Все должно максимально декларативно конфигурироваться

Для каждого кандидата гуглить:

  • Best practices
  • Idioms
  • Common pitfalls
  • Anti-patterns
  • Open-source projects
  • %feature_name% in %candidate_name%

Второй шаг - сужение круга

Остается 2, максимум - 3

По мини-проекту на каждого кандидата

А лучше - по два

  • Должны быть схожие фичи
  • Обязательно построить окружение
  • Тесты
  • Минимум своих велосипедов
  • Не больше 500 строчек своего кода
  • Обязательно проверить масштабируемость
  • Максимум - 2 вечера на проект

Масштабируемость

Одна модель данных и 10 моделей данных

1 вьюшка и 10 вьюшек

Количество кода растет нелийнейно?

На каждую кнопку новый велосипед?

Следующий!

Итого

Около недели на исследования и планирование

Коллосальное снижение вероятности фейла

Legacy code?

В следующий раз

Вопросы?