...

суббота, 10 октября 2020 г.

Flutter + чистая архитектура: разбираем на примере

На определённом этапе изучения новой технологии начинаешь задаваться вопросом - как правильно организовать архитектуру проекта? Мне в своё время повезло - попались опытные наставники, которые дали мудрые советы. Однако я считаю, что знания не должны лежать мёртвым грузом, поэтому пишу эту статью в помощь начинающим (и не только) flutter-разработчикам.

Чистая архитектура - это концепция построения архитектуры систем, предложенная Робертом Мартином (также известного как "дядюшка Боб"). Концепция предполагает построение приложения в виде набора независимых слоёв, что облегчает тестирование, уменьшает связность и делает приложение более простым для понимания.

Flutter - стремительно набирающий популярность фреймворк для разработки кроссплатформенных приложений. В списке поддерживаемых платформ - iOS, Android, web, в бете находится поддержка десктопа.

Под катом - рассказ о том, как построить flutter-приложение с использованием идей чистой архитектуры.


Конкретно с этой имплементацией я познакомился, когда пришёл работать в Progressive Mobile (пользуясь случаем, хочу передать привет - ребят, вы крутые!). Она хорошо себя показала на множестве проектов, которые мы делали, при этом развивалась от проекта к проекту.

Обычно приложение состояло из четырёх слоев:

  • data - слой работы с данными. На этом уровне, например, описываем работу с внешним API.

  • domain - слой бизнес-логики.

  • internal - слой приложения. На этом уровне происходит внедрение зависимостей.

  • presentation - слой представления. На этом уровне описываем UI приложения.

Слой представления ничего не знает о том, откуда появляются данные, которые он использует, слой данных не знает, кто и как будет использовать данные, что он предоставляет. Это позволяет легко вносить изменения в проект - например, мы можем переехать с REST на GraphQL и не изменить ни строчки кода в слое представления.

Далее мы, слой за слоем, построим мобильное приложение на Flutter. Поскольку цель у нас образовательная, приложение будет достаточно простым - оно покажет нам продолжительность дня и время рассвета и захода солнца в указанной точке Земли.

Создание проекта

Я предполагаю, что у вас уже установлен Flutter, если нет - почитать о том, как это делается, можно в официальной документации.

Создать проект можно с помощью инструментов вашей любимой IDE или из командной строки. В последнем случае вы должны выполнить в терминале команду:

flutter create myapp

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

Как уже говорилось выше, приложение будет состоять из 4 слоёв, поэтому создадим соответствующие папки. Заодно заметим, что код из стандартного примера содержит вёрстку экрана - то есть UI, а значит, место ему в слое представления.

Получилась следующая структура каталогов:

Содержание файлов main.dart, application.dart и home.dart можно посмотреть под спойлерами.

main.dart
import 'package:flutter/material.dart';

import 'internal/application.dart';

void main() {
  runApp(Application());
}
application.dart
import 'package:flutter/material.dart';
import 'package:habr_flutter_clean_arch/presentation/home.dart';

class Application extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Home(),
    );
  }
}
home.dart
import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}

На данном этапе приложение должно успешно собираться, хотя и будет выглядеть как пустой белый экран. Пожалуй, настало время для первого коммита.

Готовим domain

Кровь любого приложения - это данные, что перетекают из одной его части в другую. Данные обычно представлены в виде набора моделей.

Эти данные мы получаем из каких-то источников - например, обращаясь к удаленному серверу с помощью запросов или загружая из локальной базы данных.

Для нашего приложения мы воспользуемся бесплатным сервисом Sunrise Sunset, который позволяет получить информацию о продолжительности дня и времени восхода/захода солнца в указанной точке.

Мы будем делать запросы к этому сервису и использовать из полученной информации следующие данные:

  • время восхода

  • время захода

  • время, в которое наступает астрономический полдень

  • продолжительность дня

Теперь мы можем создать нашу первую модель. Добавим в папку domain директорию model, в которой создадим файл с именем day.dart. Опишем в этом файле нашу модель:

import 'package:meta/meta.dart';

class Day {
  final DateTime sunrise;
  final DateTime sunset;
  final DateTime solarNoon;
  final int dayLength;

  Day({
    @required this.sunrise,
    @required this.sunset,
    @required this.solarNoon,
    @required this.dayLength,
  });
}

Здесь мы определили конструктор с именованными аргументами, а аннотация @required говорит нам о том, что все аргументы являются обязательными.

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

Дело в том, что методы наподобие fromJson не имеют отношения к бизнес-логике, это всё часть слоя данных. Если описать его здесь, то наша модель превратится в кашу из обращений к мапе, что сильно усложнит понимание структуры модели, а использоваться всё равно будет только в момент получения данных. Поэтому мы вернёмся к этому вопросу, когда займемся слоем данных.

Итак, мы описали модель, теперь нужно поговорить об источнике данных.

В общем случае этих источников может быть довольно много, поэтому выделим для них свою собственную директорию - добавим в папке domain каталог repository. На уровне бизнес-логики мы описываем не сами эти источники, а лишь интерфейс взаимодействия с ними.

Создадим в этой директории файл day_repository.dart следующего содержания:

import 'package:meta/meta.dart';
import 'package:habr_flutter_clean_arch/domain/model/day.dart';

abstract class DayRepository {
  Future<Day> getDay({
    @required double latitude,
    @required double longitude,
  });
}

Поскольку в языке Dart нет интерфейсов в явном виде, вместо них используют абстрактные классы. В данном случае, мы указали, что наследники этого репозитория должны реализовывать метод getDay, который вернёт объект Future, разрешающий нашу модель Day. Обязательные аргументы этого метода - широта и долгота интересующей нас точки.

На данный момент у нас должна получиться следующая структура каталогов:

Пожалуй, можно закоммитить изменения и переходить к слою данных.

Готовим data слой

Помните я говорил о методе создания модели из сырого json? Настало время для его реализации.

На уровне слоя данных у нас будет реализована логика получения данных от бэкенда. Кроме того, здесь же будут описаны классы-наследники репозиториев из слоя бизнес-логики. Поэтому добавим в директорию data каталоги api и repository. Начнем работать с api.

Здесь мы опишем модель ApiDay, которая будет содержать метод fromApi - получение данных из json. На этом уровне у нас все модели будут начинаться с префикса Api, чтобы отличить их от моделей слоя бизнес-логики.

Зачем нужна отдельная модель ApiDay? С одной стороны, она может содержать методы манипуляции с сырыми данными - fromApi/toApi, что соответствует как раз уровню данных, а не бизнес-логики. Кроме того, полученные с бэкенда данные могут иметь довольно сложную структуру, не всегда удобную для нашего приложения и мы можем произвести необходимую подготовку на данном уровне. С другой стороны, благодаря такому разделению, мы получаем более прозрачную структуру - на уровне бизнес-логики нам не будут мешать бесполезные там методы fromApi/toApi, плюс, если бэкенд изменит формат присылаемых данных, нам будет достаточно поправить в одном месте нашу модель ApiDay, и на уровне бизнес-логики все будет работать без изменений.

Итак, давайте создадим в папке api/model файл api_day.dart следующего содержания:

api_day.dart
class ApiDay {
  final String sunrise;
  final String sunset;
  final String solarNoon;
  final num dayLength;

  ApiDay.fromApi(Map<String, dynamic> map)
      : sunrise = map['results']['sunrise'],
        sunset = map['results']['sunset'],
        solarNoon = map['results']['solar_noon'],
        dayLength = map['results']['day_length'];
}

В данном случае мы описали именованный конструктор, который из словаря, возвращаемого бэкендом, по нужным ключам присваивает значения полям модели.

Обратите внимание: в общем случае типы полей этой модели не совпадают с типами модели из domain слоя. Они имеют именно тот тип, который возвращает бэкенд. Для преобразования api-модели в обычную модель, создадим специальный класс-маппер, который будет сопоставлять поля двух моделей и выполнять преобразования при необходимости.

Добавим в директорию data/api папку mapper, в которой создадим файл day_mapper.dart,

day_mapper.dart
import 'package:habr_flutter_clean_arch/data/api/api_day.dart';
import 'package:habr_flutter_clean_arch/domain/model/day.dart';

class DayMapper {
  static Day fromApi(ApiDay day) {
    return Day(
      sunrise: DateTime.tryParse(day.sunrise),
      sunset: DateTime.tryParse(day.sunset),
      solarNoon: DateTime.tryParse(day.solarNoon),
      dayLength: day.dayLength.toInt(),
    );
  }
}

Класс DayMapper содержит статический метод, принимающий на входе объект ApiDay и превращающий его в модель бизнес-слоя Day. Этот метод потребуется нам на следующем шаге. А пока можно зафиксировать изменения в системе контроля версий.

Работаем с API

В общем случае вашему приложению могут потребоваться данные из разных источников. Например, какие-то данные вы будете получать с использованием REST, а какие-то - с использованием GraphQL. Чтобы сделать эту логику более прозрачной, работа с API у нас будет организована в виде двух слоёв.

На верхнем, более абстрактном, мы описываем интерфейс работы с API: набор методов, которые будут использоваться репозиториями для получения данных, и которые обращаются к нижележащему слою для фактического их получения. А заодно выполняет преобразование API-моделей в модели бизнес-логики.

На нижнем слое у нас будет набор классов, которые работают с конкретными сервисами, преобразуют данные слоя бизнес-логики в необходимый для запросов вид (например, json, FormData), выполняют фактические запросы, и обрабатывают полученные результаты. Поскольку этих классов может быть несколько, разумно выделить для них отдельный каталог.

У нас пока всего один сервис (напомню, мы используем Sunrise Sunset), давайте создадим для него в data/api/service файл sunrise_service.dart.

В экосистеме Flutter существует несколько пакетов для работы с сетью, мне больше нравится dio, но вы можете использовать любой другой.

Итак, давайте добавим в зависимости проекта этот пакет и вернёмся к нашему sunrise_service.dart.

sunrise_service.dart
import 'package:dio/dio.dart';
import 'package:habr_flutter_clean_arch/data/api/model/api_day.dart';
import 'package:meta/meta.dart';

class SunriseService {
  static const _BASE_URL = 'https://api.sunrise-sunset.org';

  final Dio _dio = Dio(
    BaseOptions(baseUrl: _BASE_URL),
  );

  Future<ApiDay> getDay({
    @required double latitude,
    @required double longitude,
  }) async {
    final query = {'lat': latitude, 'lng': longitude, 'formatted': 0};
    final response = await _dio.get(
      '/json',
      queryParameters: query,
    );
    return ApiDay.fromApi(response.data);
  }
}

Здесь мы создали объект dio и описали метод getDay, который с помощью этого объекта делает GET запрос к сервису и из полученных данных создает объект ApiDay.

В данном случае я оставил подготовку данных для запроса внутри метода getDay, что не очень хорошо: некоторым запросам требуется довольно много данных, некоторые из них потребуется предварительно преобразовать. Кроме того, этих запросов может быть большое количество, если оставить все так, то файл довольно быстро превратится в мешанину из словарей и методов.

Поэтому давайте вынесем подготовку данных для запроса в отдельный этап.

Готовим данные для запроса

Для этого в data/api создадим каталог request, в котором создадим файл get_day_body.dart, с таким содержанием:

get_day_body_dart
import 'package:meta/meta.dart';

class GetDayBody {
  final double latitude;
  final double longitude;

  GetDayBody({
    @required this.latitude,
    @required this.longitude,
  });

  Map<String, dynamic> toApi() {
    return {
      'lat': latitude,
      'lng': longitude,
      'formatted': 0,
    };
  }
}

Все наши подобные классы будут называться по шаблону <ИМЯ_МЕТОДА>Body и реализовывать метод toAPi для приведения данных к нужному виду.

В данном случае я добавил поле 'formatted': 0, потому что в этом случае сервис вернёт данные в формате ISO 8601 - фактически, это маленький костыль, который я добавил, чтобы быть уверенным, что данные всегда будут в нужном нам формате. Правильнее было бы передавать этот параметр явным образом.

Теперь мы можем изменить метод getDay в классе SunriseService:

sunrise_service.dart
import 'package:dio/dio.dart';
import 'package:habr_flutter_clean_arch/data/api/model/api_day.dart';
import 'package:habr_flutter_clean_arch/data/api/request/get_day_body.dart';

class SunriseService {
  static const _BASE_URL = 'https://api.sunrise-sunset.org';

  final Dio _dio = Dio(
    BaseOptions(baseUrl: _BASE_URL),
  );

  Future<ApiDay> getDay(GetDayBody body) async {
    final response = await _dio.get(
      '/json',
      queryParameters: body.toApi(),
    );
    return ApiDay.fromApi(response.data);
  }
}

Все методы в этом файле будут содержать в себе всего несколько строк, что облегчит их чтение, когда этих методов станет много.

Нижний слой API реализован, переходим к верхнему. Создадим в каталоге data/api файл api_util.dart:

api_util.dart
import 'package:habr_flutter_clean_arch/data/api/request/get_day_body.dart';
import 'package:habr_flutter_clean_arch/data/mapper/day_mapper.dart';
import 'package:meta/meta.dart';
import 'package:habr_flutter_clean_arch/data/api/service/sunrise_service.dart';
import 'package:habr_flutter_clean_arch/domain/model/day.dart';

class ApiUtil {
  final SunriseService _sunriseService;

  ApiUtil(this._sunriseService);

  Future<Day> getDay({
    @required double latitude,
    @required double longitude,
  }) async {
    final body = GetDayBody(latitude: latitude, longitude: longitude);
    final result = await _sunriseService.getDay(body);
    return DayMapper.fromApi(result);
  }
}

На этом уровне мы преобразуем данные бизнес-слоя в необходимый сервису вид, выполняем фактический запрос и преобразуем полученные данные в вид, приемлемый для бизнес-слоя.

Фактически, класс ApiUtil служит единой точкой входа в мир API для всех репозиториев, самостоятельно решая, к какому сервису обращаться за данными. Если завтра нам потребуется получать координаты городов из другого сервиса, или погоду из третьего, мы будем решать это на уровнях ApiUtil-ApiServise, а для всех репозиториев это будет выглядеть как будто мы получаем все данные из одного источника. В этом и заключается преимущество такого подхода.

Итак, мы подготовили всё необходимое для работы с API, пора переходить к репозиториям.

Готовим репозитории

Ранее мы определили на уровне бизнес-логики интерфейс репозитория DayRepository, теперь мы можем описать его конкретную реализацию. Для этого в каталоге data/api создадим папку repository и добавим в неё файл day_data_repository.dart со следующим содержанием:

day_data_repository.dart
import 'package:habr_flutter_clean_arch/data/api/api_util.dart';
import 'package:habr_flutter_clean_arch/domain/model/day.dart';
import 'package:habr_flutter_clean_arch/domain/repository/day_repository.dart';

class DayDataRepository extends DayRepository {
  final ApiUtil _apiUtil;

  DayDataRepository(this._apiUtil);

  @override
  Future<Day> getDay({double latitude, double longitude}) {
    return _apiUtil.getDay(latitude: latitude, longitude: longitude);
  }
}

Как видим, всё, что нужно нашему репозиторию, чтобы реализовать абстрактные методы класса DayRepository - это объект ApiUtil, который вернёт необходимые данные.

На данном этапе у нас должна получиться такая структура файлов в директории data:

Можно зафиксировать изменения и переходить к следующему слою, на котором мы будем осуществлять внедрение зависимостей.

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

Если взглянуть на наш код со стороны, то можно обратить внимание, что репозитории функционально зависят от ApiUtil, а тот, в свою очередь, от одного или нескольких ApiService (конкретно в нашем случае - от SunriseService). Начнем с ApiUtil.

В директорию internal добавим папку dependencies, в которой создадим файл api_module.dart со следующим содержанием:

api_module.dart
import 'package:habr_flutter_clean_arch/data/api/api_util.dart';
import 'package:habr_flutter_clean_arch/data/api/service/sunrise_service.dart';

class ApiModule {
  static ApiUtil _apiUtil;

  static ApiUtil apiUtil() {
    if (_apiUtil == null) {
      _apiUtil = ApiUtil(SunriseService());
    }
    return _apiUtil;
  }
}

Класс ApiModule содержит в себе статический метод apiUtil, который возвращает нам единственный экземпляр класса ApiUtil и создает его при необходимости. Используя этот модуль, мы можем поступить аналогичным образом и для репозиториев.

Добавим файл repository_module.dart и запишем в него следующий код:

repository_module.dart
import 'package:habr_flutter_clean_arch/data/repository/day_data_repository.dart';
import 'package:habr_flutter_clean_arch/domain/repository/day_repository.dart';

import 'api_module.dart';

class RepositoryModule {
  static DayRepository _dayRepository;

  static DayRepository dayRepository() {
    if (_dayRepository == null) {
      _dayRepository = DayDataRepository(
        ApiModule.apiUtil(),
      );
    }
    return _dayRepository;
  }
}

В классе RepositoryModule описываются статические методы, которые для каждого абстрактного репозитория из domain/repository создают объекты-наследники, реализующие методы этих репозиториев.

Если в каком-то месте нам потребуется репозиторий, то мы не будем создавать его сами, а обратимся за этим к RepositoryModule, который, по сути, является единственной точкой входа в каждый из репозиториев. В чем преимущество такого подхода? Если завтра нам потребуется использовать другую реализацию интерфейса репозитория, то будет достаточно изменить файл repository_module.dart, других изменений не потребуется.

Прежде чем мы начнём использовать репозиторий для получения информации о продолжительности дня в указанной точке, давайте зафиксируем изменения и подготовим простой UI нашего приложения.

Слой представления

У нас уже есть заготовка для экрана Home в папке presentation, давайте внесём в неё изменения.

Интерфейс будет очень простым: два поля ввода (для широты и долготы интересующей точки), кнопка для активации запроса и несколько строк текста для отображения результатов. Бедно, но мы ведь здесь не за этим собрались, верно? Никаких проверок валидности введённых данных тоже не будет, чтобы не усложнять код.

После внесения изменений, код экрана стал выглядеть следующим образом:

home.dart
import 'package:flutter/material.dart';
import 'package:habr_flutter_clean_arch/domain/model/day.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final _latController = TextEditingController();
  final _lngController = TextEditingController();

  Day _day;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: FocusScope.of(context).unfocus,
      child: Scaffold(
        body: _getBody(),
      ),
    );
  }

  Widget _getBody() {
    return SafeArea(
      child: Padding(
        padding: EdgeInsets.all(10),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _getRowInput(),
            SizedBox(height: 20),
            RaisedButton(
              child: Text('Получить'),
              onPressed: _getDay,
            ),
            SizedBox(height: 20),
            if (_day != null) _getDayInfo(_day),
          ],
        ),
      ),
    );
  }

  Widget _getRowInput() {
    return Row(
      children: [
        Expanded(
          child: TextField(
            controller: _latController,
            keyboardType: TextInputType.numberWithOptions(decimal: true, signed: true),
            decoration: InputDecoration(hintText: 'Широта'),
          ),
        ),
        SizedBox(width: 20),
        Expanded(
          child: TextField(
            controller: _lngController,
            keyboardType: TextInputType.numberWithOptions(decimal: true, signed: true),
            decoration: InputDecoration(hintText: 'Долгота'),
          ),
        ),
      ],
    );
  }

  Widget _getDayInfo(Day day) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Text('Восход: ${day.sunrise.toLocal()}'),
        Text('Заход: ${day.sunset.toLocal()}'),
        Text('Полдень: ${day.solarNoon.toLocal()}'),
        Text('Продолжительность: ${Duration(seconds: day.dayLength)}'),
      ],
    );
  }

  void _getDay() {
    // здесь получаем данные
  }
}

Обратите внимание на метод _getDay: уже сейчас мы могли бы создать там объект репозитория и получить с его помощью необходимые данные. Однако делать так не стоит: в этом случае экран, находящийся на слое представления, будет явным образом зависеть от объекта из слоя данных.

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

И тут нам приходят на помощь различные инструменты для управления состоянием приложения - такие как Redux, BLoC, MobX. Они могут довольно сильно отличаться в деталях, но идеологически суть их весьма близка: вы генерируете некое событие (например, нажатием кнопки), это событие инициирует изменение состояния (например, получив с бэкенда данные и поместив их хранилище), а изменение состояния приводит к изменению интерфейса.

Обычно для этих целей я использую BLoC, но сегодня хочу попробовать MobX - просто потому что никогда раньше его не использовал. Должна же быть польза и для меня от всей этой затеи!

Disclaimer: я не явлюсь специалистом по MobX, поэтому относитесь к моей реализации этого паттерна критически. Дайте знать, если я допустил ошибки.

Однако в рамках данной статьи это несущественно - вы можете заменить MobX на любой другой менеджер состояния, в глобальном смысле ничего не изменится.

Управление состоянием с помощью MobX

Итак, для начала нам потребуется добавить необходимые зависимости в наш проект:

dependencies:
        ...
  mobx: ^1.2.1+3
  flutter_mobx: ^1.1.0+2

Также добавим в dev_dependencies зависимости для генерации файлов, добавляющих возможность использовать аннотации @observable, @computed, @action:

dev_dependencies:
        ...
  mobx_codegen: ^1.1.1+1
  build_runner: ^1.10.0

Управление состоянием относится к слою бизнес-логики, поэтому давайте добавим в директорию domain папку state. В этом каталоге у нас будут классы, описывающие состояние экранов (а возможно - и других компонентов). Кажется разумным выделить для каждого из них свой подкаталог. В нашем примере экран всего один, поэтому давайте добавим подкаталог home.

Создадим в нём файл home_state.dart с таким содержанием:

home_state.dart
import 'package:mobx/mobx.dart';
import 'package:meta/meta.dart';
import 'package:habr_flutter_clean_arch/domain/repository/day_repository.dart';
import 'package:habr_flutter_clean_arch/domain/model/day.dart';

part 'home_state.g.dart';

class HomeState = HomeStateBase with _$HomeState;

abstract class HomeStateBase with Store {
  HomeStateBase(this._dayRepository);

  final DayRepository _dayRepository;

  @observable
  Day day;

  @observable
  bool isLoading = false;

  @action
  Future<void> getDay({
    @required double latitude,
    @required double longitude,
  }) async {
    isLoading = true;
    final data = await _dayRepository.getDay(latitude: latitude, longitude: longitude);
    day = data;
    isLoading = false;
  }
}

В целом он соответствует шаблону из примера по MobX, обсудим некоторые детали.

Поле day помечено аннотацией @observable, изменение значения этого поля будет отслеживаться на уровне представления и при необходимости перерисовывать экран.

Аналогичной аннотацией помечена и переменная isLoading - её мы будем использовать для определения момента, когда выполняется асинхронная операция и необходимо показать лоадер.

Также имеется метод, помеченный аннотацией @action, то есть то самое событие, инициирующее изменение состояния. В данном случае, мы будем вызывать его для того, чтобы получить данные из репозитория.

Теперь необходимо сгенерировать файл home_state.g.dart, для этого выполните команду:

flutter packages pub run build_runner build

У меня поначалу всё пошло не очень гладко: скрипт уходил в бесконечный цикл и наотрез отказывался генерировать необходимый файл. В одном из issue к mobx порекомендовали выполнить в этом случае команды

flutter clean
flutter pub get
flutter packages upgrade

Мне это помогло, после их выполнения предыдущий скрипт завершился успехом.

Итак, у нас есть класс HomeState, управляющий состоянием экрана Home, но ему требуется DayRepository репозиторий. А значит пора снова вернуться к слою внедрения зависимостей.

Добавим в директорию internal/dependencies файл home_module.dart со следующим содержанием:

home_module.dart
import 'package:habr_flutter_clean_arch/domain/state/home/home_state.dart';
import 'package:habr_flutter_clean_arch/internal/dependencies/repository_module.dart';

class HomeModule {
  static HomeState homeState() {
    return HomeState(
      RepositoryModule.dayRepository(),
    );
  }
}

Теперь всё необходимое у нас есть, и мы можем наконец-то организовать грамотное управление состоянием экрана Home.

Внесём изменения в файл presentation/home.dart:

home.dart
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:habr_flutter_clean_arch/domain/state/home/home_state.dart';
import 'package:habr_flutter_clean_arch/internal/dependencies/home_module.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final _latController = TextEditingController();
  final _lngController = TextEditingController();

  HomeState _homeState;

  @override
  void initState() {
    super.initState();
    _homeState = HomeModule.homeState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: FocusScope.of(context).unfocus,
      child: Scaffold(
        body: _getBody(),
      ),
    );
  }

  Widget _getBody() {
    return SafeArea(
      child: Padding(
        padding: EdgeInsets.all(10),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _getRowInput(),
            SizedBox(height: 20),
            RaisedButton(
              child: Text('Получить'),
              onPressed: _getDay,
            ),
            SizedBox(height: 20),
            _getDayInfo(),
          ],
        ),
      ),
    );
  }

  Widget _getRowInput() {
    return Row(
      children: [
        Expanded(
          child: TextField(
            controller: _latController,
            keyboardType: TextInputType.numberWithOptions(decimal: true, signed: true),
            decoration: InputDecoration(hintText: 'Широта'),
          ),
        ),
        SizedBox(width: 20),
        Expanded(
          child: TextField(
            controller: _lngController,
            keyboardType: TextInputType.numberWithOptions(decimal: true, signed: true),
            decoration: InputDecoration(hintText: 'Долгота'),
          ),
        ),
      ],
    );
  }

  Widget _getDayInfo() {
    return Observer(
      builder: (_) {
        if (_homeState.isLoading)
          return Center(
            child: CircularProgressIndicator(),
          );
        if (_homeState.day == null) return Container();
        return Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text('Восход: ${_homeState.day.sunrise.toLocal()}'),
            Text('Заход: ${_homeState.day.sunset.toLocal()}'),
            Text('Полдень: ${_homeState.day.solarNoon.toLocal()}'),
            Text('Продолжительность: ${Duration(seconds: _homeState.day.dayLength)}'),
          ],
        );
      },
    );
  }

  void _getDay() {
    // здесь получаем данные
    final lat = double.tryParse(_latController.text);
    final lng = double.tryParse(_lngController.text);
    _homeState.getDay(latitude: lat, longitude: lng);
  }
}

Здесь мы создаём объект класса HomeState с помощью HomeModule. Нажатие на кнопку инициирует событие getDay, а с помощью виджета Observer приложение отслеживает изменение состояния и перерисовывает экран.

Результат работы приложения представлен ниже.

Итак, мы разработали проект, который следует идеям чистой архитектуры. Такой проект имеет прозрачную структуру слоёв, что уменьшает когнитивную нагрузку и облегчает включение новых участников в проект.

Такой проект легче модифицировать - например, переезд с REST на GraphQL пройдёт безболезненно для слоёв бизнес-логики и представления. Вы также легко можете использовать их совместно или добавлять дополнительные сервисы. Можно вносить изменения в слой представления - например, подготовить разный дизайн UI для разных платформ и использовать единую бизнес-логику и данные.

Независимость слоёв также облегчает тестирование приложения.

Наконец, вы всегда можете заменить условный MobX на BLoC, Redux или что там вам по вкусу, и использовать эту архитектуру на полную катушку.

Исходный код проекта доступен на Github.

Let's block ads! (Why?)

[Перевод] Написать книгу: стоит ли игра свеч?.. От автора книги «Высоконагруженные приложения»

Привет, Хабр!

Сложно переоценить успех книги "Designing Data-Intensive Applications" которая вышла в русском переводе и неизменно допечатывается у нас под названием "Высоконагруженные приложения"

Не так давно автор разместил в своем блоге честный и подробный пост о том, как ему далась работа над этой книгой, сколько она позволила заработать, и чем кроме денег измеряется польза авторского труда. Публикация обязательна к прочтению для всех, кто хоть раз задумывался стать литературной суперзвездой нашим автором, но до сих пор не определился, а стоит ли браться за столь амбициозный проект.

Читаем с удовольствием!

Недавно была продана первая сотня тысяч экземпляров моей книги «Высоконагруженные приложения». В прошлом году моя книга занимала второе место по продажам во всем каталоге O’Reilly, пропустив вперед только книгу Орельена Жерона по машинному обучению. Несомненно, машинное обучение – очень горячая тема, поэтому второе место в данном случае меня весьма устраивает.

Я совершенно не ожидал, что книгу ждет такой успех; я ожидал, что она получится несколько нишевой, поэтому поставил для себя цель продать 10 000 экземпляров, пока книга не устареет. Вдесятеро превзойдя эту планку, я решил оглянуться назад и вспомнить, как это было. Пост не планировался чрезмерно нарциссическим; я ставил своей целью рассказать, какова бизнес-составляющая писательского труда.

Оправдан ли такой проект с финансовой точки зрения?

Большинство книг приносят совсем мало денег как автору, так и издателю, но иногда появляется книга вроде «Гарри Поттера». Если вы собираетесь писать книгу, настоятельно рекомендую исходить из того, что ваши будущие роялти окажутся близки к нулю. Все равно, как если собрать с друзьями музыкальную группу и надеяться, что вас ждет слава рок-звезд. Сложно спрогнозировать заранее, что станет хитом, а что провалится. Может быть, это касается технических книг в меньшей степени, чем беллетристики и музыки, но, подозреваю, даже среди технических книг хитов совсем мало, а большинство продается весьма скромными тиражами.
Учитывая вышесказанное, рад сообщить, что в ретроспективе моя книга оказалась финансово выгодным проектом. На графике показаны роялти, которые я получил с тех пор, как книга поступила в продажу:

Общая сумма роялти

Распределение роялти в помесячном выражении

На протяжении первых 2½ лет книга находилась в состоянии “early release” (черновиков): я все еще работал над ней, и мы реализовывали ее в неотредактированной форме, по главе по мере готовности, только в формате ebook. Затем в марте 2017 года состоялась официальная публикация книги, и печатное издание поступило в продажу. С тех пор продажи колебались месяц к месяцу, но в целом оставались удивительно стабильными. В какой-то момент я стал ожидать, что рынок вот-вот насытится (то есть, большинство тех, кто хотел купить книгу, ею обзаведутся), но пока этого, по-видимому, не произошло: более того, в конце 2018 года продажи заметно выросли (почему – не знаю). Ось x заканчивается в июле 2020 года, поскольку после продажи проходит пара месяцев, пока отчисления поступят на мой счет.

В соответствии с контрактом, я получаю 25% выручки издателя от продажи электронных книг, от онлайн-доступа и лицензирования, а также 10% выручки от продаж печатной книги и 5% роялти от переводов. Это процент от оптовой цены, уплачиваемой ритейлерами/дистрибьюторами издателю, то есть, в нем не учитывается розничная надбавка. Цифры, приведенные в этом разделе – это уплаченные мне роялти, полученные после того, как ритейлер и издатель забрали свою долю, но до вычета налогов.

С самого начала общие продажи составили (в долларах США):

  • Печатная книга: 68 763 экземпляра, роялти $161 549 ($2,35/экз.)
  • Электронная книга: 33 420 экземпляров, роялти $169 350 ($5,07/экз.)
  • Онлайн-доступ на сайте O’Reilly: роялти $110 069 (я не знаю, сколько раз книга была прочитана через данный канал)
  • Переводы: 5 896 экземпляров, роялти $8 278 ($1.40/экз.)
  • Другие виды лицензирования: роялти $34 600
  • Всего: 108 079 экземпляров, роялти $477 916

Куча денег, но сколько времени я в это вложил! Полагаю, что потратил около 2,5 лет полноценного фултайма на работу над книгой и сопутствующие исследования – в течение 4 лет. Из этого периода целый год (2014-2015) я полностью потратил на работу над книгой, без какого-либо дохода, а остальное время мне удавалось совмещать подготовку книги с частичной занятостью.

Теперь, в ретроспективе, понятно, что эти 2,5 года были потрачены не зря, так как доход, который принесла мне эта работа – того же порядка, что и зарплата программиста из Кремниевой Долины, которую я мог бы получить, если бы не ушел из LinkedIn в 2014 году ради работы над книгой. Но, конечно, я не мог этого предвидеть! Роялти вполне могли оказаться в 10 раз меньше, и такая перспектива была бы гораздо менее привлекательной с финансовой точки зрения.

Не роялти едиными

Отчасти успех моей книги может объясняться тем, что я потратил массу усилий на ее продвижение. С тех пор, как книга пребывала в состоянии early release, я прочитал почти 50 докладов на крупных конференциях, плюс у меня еще множество «приглашенных» выступлений в компаниях и университетах. В каждом из этих выступлений я хотя бы вскользь рекламировал мою книгу. Я действовал как рок-музыкант, отправляющийся в тур с презентацией нового альбома, и, подозреваю, именно благодаря этим выступлениям книга получила широкую известность. Весьма популярны оказались и пара постов в моем блоге, они, вероятно, также привлекли к книге внимание потенциальных читателей. В настоящее время я значительно меньше выступаю с лекциями, поэтому, полагаю, что информация о книге распространяется в основном по сарафанному радио (в соцсетях; читатели рекомендуют книгу коллегам).

Сочетая лекции и продвижение книги, а сумел стать узнаваемым в сообществе и наработать себе хорошую репутацию в этой области. Я получаю гораздо больше приглашений выступить на разных конференциях, чем реально могу принять. Сами по себе такие выступления не являются источником дохода (на хороших отраслевых конференциях докладчикам обычно оплачивают проезд и проживание, но сами выступления оплачиваются редко), однако, такая репутация полезна в качестве рекламы – к тебе обращаются как к консультанту.

Я совсем немного занимался консалтингом (и сегодня регулярно отклоняю такие запросы от разных компаний, так как основное внимание уделяю моим исследованиям), но, подозреваю, что в текущей ситуации мне не составило бы труда создать прибыльный консалтинговый и обучающий бизнес – связываться с компаниями и помогать им решать проблемы, связанные с инфраструктурой данных. Вас признают как авторитетного специалиста и эксперта в отрасли, а компании готовы платить хорошие деньги за консультации таких экспертов.

Я уделил столько внимания финансовой целесообразности авторского труда, поскольку считаю книги исключительно полезным образовательным ресурсом (подробнее об этом ниже). Я хочу, чтобы как можно больше людей писали свои книги, а значит, такой труд должен быть самодостаточным видом деятельности.

Я смог потратить немало времени на исследовательские поиски, связанные с книгой, поскольку мог позволить себе целый год жить без зарплаты, а многим такое удовольствие недоступно. Если бы люди могли получать достойную оплату за подготовку образовательных материалов, то хорошей литературы такого рода было бы все больше.

Книга – доступный образовательный ресурс

Книга не только может принести немалую финансовую пользу; у такой работы немало других достоинств.

Книга отличается универсальной доступностью: позволить себе купить книгу может практически кто угодно, во всем мире. Она несопоставимо дешевле университетского курса или корпоративного тренинга; чтобы воспользоваться книгой, не приходится ехать в другой город. Люди, живущие в сельской местности или в развивающихся странах, могут читать книги с той же отдачей, что и жители глобальных технологических центров. Книгу можно просто пролистать или проштудировать от корки до корки, как угодно. Для чтения книги даже не нужно соединения с Интернетом. Разумеется, в чем-то книга уступает университетскому образованию, например, не дает индивидуальной обратной связи, не позволяет налаживать профессиональные контакты, социализироваться. Но в качестве средства передачи знаний книга практически неоспоримо эффективна.

Разумеется, существует и множество других онлайновых ресурсов: Википедия, блоги, видео, Stack Overflow, документация API, исследовательские статьи, т.д. Они хороши в качестве справочного материала для ответа на конкретные вопросы (например, «каковы параметры функции foo?»), но, на самом деле, такая информация кусочная, и эти фрагменты сложно структурировать для полноценного образования. С другой стороны, в хорошо написанной книге предоставляется аккуратно подобранная и продуманная программа обучения, а также нарратив, который особенно ценен, когда впервые пытаешься осмыслить сложную тему.
Книга неизмеримо лучше масштабируется по сравнению с занятиями вживую. Даже если бы на протяжении всей оставшейся карьеры я читал лекции в самом большом амфитеатре моего университета, то не охватил бы занятиями и 100 000 человек. В случае индивидуальных занятий и занятий в небольших группах эта пропасть еще шире. Но книга позволяет охватить такую широкую аудиторию без особого труда.

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

Когда пишешь книгу, ты приносишь больше пользы, чем получаешь. Чтобы подтвердить это, попробую грубо оценить пользу, которую принесла моя книга.

Допустим, из 100 000 человек, уже купивших мою книгу, две трети собираются ее прочесть, но пока у них до нее не дошли руки. Далее допустим, что треть из уже прочитавших ее смогли применить некоторые из идей, изложенных в книге, а остальные прочли ее чисто ради интереса.

Итак, давайте возьмем консервативную оценку: 10% из тех, кто купил книгу, смогли извлечь пользу из нее.

Какова может быть такая польза? В случае с моей книгой такая польза заключается в основном в принятии верных архитектурных решений при создании хранилищ данных. Если как следует справиться с этой работой, то можно создавать еще более классные системы, а если ошибиться – то можно годами выпутываться из той неразберихи, в которую вы сами себя загнали.
Этот показатель сложно квантифицировать, но давайте допустим, что читатель, применивший идеи из моей книги, смог избежать неверного решения, на устранение которого потребовался бы реальный человеко-месяц. Следовательно, 10 000 читателей, применивших эти знания, высвободили примерно 10 000 человеко-месяцев или 833 человеко-года, которые удалось потратить на вещи куда более полезные, чем выпутывание из неразберихи.

Если я потратил на работу над книгой 2,5 года, чем сэкономил другим людям в общей сложности 833 года времени, то получил от своей работы более чем 300-кратную отдачу. Если предположить, что средняя зарплата программиста составляет $100k в год, то ценность, обеспеченная книгой, составляет $80m. Читатели потратили примерно $4m на покупку этих 100 000 книг, поэтому принесенная польза в 20 раз выше, чем приобретенная. Причем, еще раз отмечу, это очень осторожные оценки.

Книга приносит далеко не только ту пользу, о которой шла речь выше. Например, многие читатели признавались мне, что, благодаря моей книге успешно прошли собеседование, нашли работу мечты, обеспечили финансовую безопасность для своей семьи. Я не знаю, как измерить подобную ценность, но считаю, что она колоссальна.

Выводы

Написать техническую книгу непросто, но хорошая техническая книга:

  • ценна (помогает людям лучше справляться со своей работой),
  • масштабируется (пользу от книги может получать огромное количество людей),
  • доступна (практически каждому) и
  • экономически целесообразна (на этом можно хорошо заработать).

Эту работу было бы интересно сравнить с опенсорсной разработкой – еще одним видом деятельности, который приносит большую пользу, но почти не монетизируется. На этот счет у меня пока нет четкого мнения.

Необходимо отметить, что писать книгу реально сложно, как минимум, если вы хотите сделать это хорошо. Для меня это было сопоставимо по сложности с разработкой и продажей стартапа, и в процессе работы я пережил не один экзистенциальный кризис. Не могу сказать, что этот процесс благотворно сказался на моем душевном здоровье. Поэтому я не спешу приступать к следующей книге: шрамы от первой еще слишком свежи. Но шрамы постепенно сходят и, я надеюсь (возможно, немного наивно), что в следующий раз дело пойдет проще.

В сухом остатке я считаю, что писать техническую книгу – стоящее дело. Ощущение, что ты помог множеству людей, очень окрыляет. Также такая работа дает существенный личностный рост. Кроме того, нет лучшего способа выучить что-либо, чем объясняя это другим.

Let's block ads! (Why?)

Завтрак с легендарным геймдизайнером Американом МакГи: о новой Алисе, России и депрессии

Двадцать пятого сентября прошёл прямой фир с Американом МакГи — легендарным геймдизайнером, создателем American McGee’s Alice. Кроме Алисы, Американ также работал над ландшафтами в играх Doom и Quake с Джоном Кармаком и Джоном Ромеро.
Делимся с вами расшифровкой и записью интервью.

Сегодня мы говорим с легендарным гейм-дизайнером Американом Макги. Спасибо, что пришли! Как дела?


Всё хорошо. Спасибо, что пригласили.

Как вы переживаете пандемию? Как к ней относитесь?


Как вы, наверное, знаете, я сейчас в Китаев, в Шанхае. И дела в Китае, если честно, снова в норме. Я знаю, что остальной мир всё ещё страдает и переживает локдауны, но в Китае всё выглядит так, словно бы мир вернулся на круги своя.
Я бы сказал, что в начале у нас были очень агрессивные локдауны и люди должны были оставаться дома. Но как только это закончилось, всё стало нормально. Так что у нас всё неплохо.

Это отлично. Это как-то влияет на вашу работу? Что-то изменилось?


Да, это интересный вопрос. На самом деле, наша команда общается в виртуале. У нас один человек в Израиле, один в Австралии, один в Канаде, один в Китае — люди по всему миру, в США. Все работают онлайн, так что мы виртуальная команда, мы всё делаем через командные онлайн-инструменты. Всё управление задачами, встречи и так далее проходят онлайн.
И когда всё началось, то это не так уж сильно повлияло на нас, ведь мы не ходим в офис каждый день. Место, которое вы сейчас видите, это моя домашняя студия. И отсюда я работаю со своей командой. Отсюда мы проводим стримы, и здесь же отправляем товары из нашего онлайн-магазина и другие вещи. Большая часть нашего бизнеса и так онлайн, в итоге изменений не было почти никаких.

Вероятно, это значит, что работа над новой Alice продвигается хорошо.


Ну да. Любопытно, что это нас и не замедлило. На самом деле мы совсем недавно начали говорить с новым издателем, который заинтересован в том, чтобы профинансировать разработку новой игры про Алису. А ещё может быть профинансируют новую вариацию «Волшебника страны Оз» и помогут нам основать студию. И они в том числе сказали, что понимают, что команда разработки может быть удалённой, теперь никто не обязан сидеть в одном офисе. А причина, по которой они это стали понимать, в пандемии и в том, что многих их коллег пандемия застала вне Китая, так что они не могли вернуться. Но тем не менее они всё равно могли продолжать работать.
Я думаю, что в каком-то смысле это научило многих, что система, при которой все ходят в один офис, чтобы закончить проект, не обязательна. И на самом деле, это странным образом это может быть полезном нам и нашей работе над проектом.

Рад это слышать. Вы можете рассказать, на каком этапе сейчас работа над проектом?


На самом деле на том же этапе, на котором он был, когда мы начали про него говорить. В том смысле, что мы всё ещё общаемся с EA по поводу получения лицензии и всё ещё пытаемся найти финансирование для разработки. Это то, что происходит на стороне бизнеса.
С точки зрения творчества, за последние два года мы вложили невероятное количество сил в художественную часть, гейм-дизайн, нарратив и все прочие аспекты, которые в конечном счёте создадут финальный дизайн игры. Мы заносим всё в то, что можно назвать библией дизайна. Проще говоря, это вся игра, от начала до конца: как дизайн-документ, только с ещё бо́льшим количеством деталей. Сейчас мы начинаем работать над тем, чтобы добавлять контент в библию дизайна, и я думаю, что в следующие месяцев шесть-восемь у нас будет завершенная библия дизайна. К тому моменту, я надеюсь, у нас уже будет финансирование и всё, что нужно, чтобы основать новую студию. Тогда мы уже начнём двигаться в сторону разработки.

А как отличается работа над игрой сейчас от работы над первой Alice и над сиквелом, с точки зрения бизнеса, процессов разработки и всего остального?


Ну, на первой игре я был наемным сотрудником в Electronic Arts, когда они предложили мне сделать новую игру. В этом смысле всё было совсем по-другому, потому что это они пришли ко мне с предложением. Это всё равно заняло какое-то время, кажется, с момента предложение до момента начала разработки больше года. Во второй раз прошло два года с момента, когда мы начали обсуждать игру и до начала разработки. И в тот момент у них был интерес. Они хотели сделать несколько другую схему финансирования в сравнении с тем, как они работали раньше. Так что нам пришлось делать студию, чтобы начать работать.

В общем, мне кажется, что сейчас, в третий раз, всё очень похоже на то, как мы работали над сиквелом. С той разницей, что теперь EA, наверное, не будет издавать эту игру, и, следовательно, они они не очень заинтересованы в том, чтобы быстро закрыть сделку по лицензии. Я думаю, что, возможно, они считают, что их вовлеченность в проект не так уж полезна, так что для них нет большого смысла решать этот вопрос быстро. Но процесс идёт. Просто, когда работаешь с корпорациями, даже в том случае, когда у них есть желание и они действительно хотят что-то сделать, они всё равно медленные. Так что в этом случае, я бы сказал, они двигаются примерно с той скоростью, с которой мы и ожидали.

И, повторюсь, что я надеюсь, что скоро у нас будет лицензия, а потом появится финансирование, а потом мы сможем начать работать. Если смотреть со стороны, то я могу сказать, что ещё одно отличие в разработке, это то, что у вас сейчас есть Patreon. Конечно, сейчас вы как инди-разработчик и не работаете в большой корпорации, но ещё у вас есть Patreon, где, я вчера проверил, больше 3000 человек поддерживают вас. Я думаю, что это замечательно, и это сильно отличается от того, что было раньше. Потому что сейчас вы можете как бы почувствовать эту связь со своими фанатами, а они могут финансово поддержать вас, чтобы вы сделали что-то, что они от вас ждут.

Я думаю, что одна из самых главных вещей на Patreon, это то, что фанаты привлекаются к работе. Мы сейчас делаем такую вещь под названием называется крауд-дизайн, то есть мы собираем отзывы фанатов на весь дизайн, арт и всё, что мы делаем, а потом мы прислушиваемся к ним. Я вообще начинаю думать, что в этом будет будущее разработки игр, или по крайней мере должно им быть. Опять же, мы недавно встречались с одними издателями, и я бы рад услышать, что они тоже считают, что сейчас появляется новая модель разработки, когда ты комбинируешь саму разработку и маркетинг игры с аудиторией, которая погружена в эти процессы. Когда ты вскрываешь карты пораньше, что-то вроде модели раннего доступа, когда ты приглашаешь фанатов в проект с самого начала. Знаете, в отличие от обычной ситуации, когда игру разрабатывают уже два года, вы видели пару скриншотов тут и там, но вовлечение фанатов и маркетинг начинается где-то месяца за три до выхода игры. Внезапно на маркетинге делается огромный акцент, но в этот момент фанаты получают по сути кота в мешке.

Так что мне кажется, часто бывают ситуации, когда фанаты хотят, чтобы у них было больше права голоса в отношении контента в игре, и они хотели бы видеть процесс разработки, а не только маркетинг, который и рассказывает им о том, что внутри чёрного ящика. Ведь очевидно, что маркетинг часто бывает весьма лукавым. Так что я думаю, что в этой новой модели мы прозрачны, то есть аудитория лучше понимает, что они получают, а ещё у них есть вовлечение в процесс разработки.

Я думаю, что крауд-дизайн звучит как крутая идея, но несколько утопичная. Знаете, когда пытаешься получить решение от большой толпы людей, иногда это приводит к хаосу, ведь всех хотят что-то своё. С какими творческими трудностями вы сталкиваетесь из-за этого?


Ну, я думаю… Я раньше тоже пробовал так делать, и я обнаружил кое-что в отношении Patreon. Там дела обстоят по-другому, потому что тебе нужно вложиться, чтобы твой голос был услышан. Ты должен потратить доллар или пять долларов в месяц или даже больше. И мне кажется, что это создает барьер для троллей. То есть тролли любят троллить до тех пор, пока они могут это делать бесплатно – просто пойти на Twitter или форум или ещё куда-то. Но когда троллю нужно указать своё реальное имя и реальную банковскую карту на платформе, это их тут же отпугивает. Они не хотят этого делать, так ведь?

То есть мне кажется, что особенность Patreon в том, что люди платят за то, чтобы быть услышанными. И это исключает множество людей, которые бы просто создавали проблемы. По нашему опыту за последние два года, я бы сказал, что у нас не было никого, кто бы пришёл на Patreon и попытался использовать систему крауд-дизайна так, чтобы создать нам проблемы. Так что это довольно хорошо.

Другой момент, что я честен со своими подписчиками (мы их называем «сумасшедшими детьми»), это демократическая диктатура. Иначе говоря, я знаю, когда сказать, что у меня нет большого желания пробовать какое-то решение или идею, или что я не хочу, чтобы это решение принимали они. Иногда я говорю, что, вне зависимости от того, что они скажут мне, я всё равно приму решение сам. И определённая группа моих подписчиков согласна или принимает моё решение. Но знаете, у нас ещё не было большого количества таких решений. И я думаю, что это отчасти потому, что когда делаешь уже третью часть в такой серии, как Alice, аудитория довольно хорошо понимает, чего ждать от этой вселенной.

Не бывает, что мы зовём кого-то поговорить про дизайн, и он говорит: «А знаете, что бы сделало эту игру крутой? Динозавры!». То есть мы не получаем идеи, которые берутся абсолютно с потолка и не имеют ничего общего со вселенной, потому что эта вселенная уже довольно хорошо устоялась. Этот… Этот фактор, что мы работаем с чем-то, что уже устоялось, возможно, очень удачно подходит к крауд-дизайну. Возможно, он бы не работал так хорошо с новой франшизой, где ещё многое не ясно, но по крайней мере сейчас мы работаем над чем-то хорошо знакомым.

Говоря о вселенной игр Alice, знаете, я думаю, что она весьма уникальна. Но в то же время «Алиса», в смысле книги о ней, служила вдохновением для бесчисленных игр, фильмов, других книг и так далее. Как вы думаете, почему она стала таким богатым первоисточником для того, чтобы взять эту идею и трансформировать её во что-то своё?


Я об этом размышлял недавно из-за того, что у нас была встреча с издателем и я говорил с одним финансовым консультантом, и он советовал нам представить инвесторам Alice и ещё какую-нибудь другую идею. Потому что таким образом это бы повышало шансы на сделку в целом.

Когда человеку даёшь на выбор два варианта, то он скорее примет решение.


И тут я осознал, что «Алиса» очень уникальна тем, что она рассказывает о персонаже в мире, которым мы можем манипулировать и который можно менять, из которого можно сделать почти что угодно. Это как место из Star Trek, знаете, как голопалуба. В то время, как в других вселенных существует много ограничений на счёт того, что можно показывать на экране, в Стране чудес нет ограничений. Есть правила, есть какие-то вещи, которые вы там не можете увидеть – например космический корабль. Но в реальности воображения Алисы вы можете представить много-много разных вещей, различных созданий и ситуаций. Может быть магия, может быть механическое оружие. В общем, это очень гибкая вселенная с точки зрения того, какую можно рассказывать историю.

И в то время, как я думал над другими известными сказками, которые мы могли бы использовать, я обнаружил в них множество ограничений. Они совсем не подходили для того сюрреалистичного стиля и историй. Я думаю, что в этом, вероятно, и есть привлекательность «Алисы» как вселенной для разного рода создателей.

Вы делаете игры уже почти 30 лет. Это огромное время для того, чтобы работать в одной индустрии. Что вдохновляет вас все эти годы? Вы находите вдохновение в фильмах, музыке, может быть других играх?


Хотя я и проработал в одной индустрии уже три десятка лет, моя роль в индустрии серьезно менялась несколько раз. Когда я начинал, я был дизайнером уровней. После я стал креативным директором и гейм-дизайнером. После этого я стал больше продюсером, а когда основал свою студию, то стал её директором. И после каждого перехода я учился чему-то новому, начинал решать новые задачи. Это одна из тех вещей, которая не даёт мне почувствовать, что я занимаюсь одним и тем же, потому что я всегда добавляю что-то новое к тому, что считаю своей работой.

И к тому же пятнадцать лет назад я уехал из США и перебрался в Китай. И я попал в Китай в то время, когда это стало наиболее динамичным и наиболее интересным периодом. Китай — это, возможно, самое интересное место в мире сейчас. То есть на планете никогда не происходило ничего подобного, что происходило в последние 20 лет в Китае. Вот это вторая вещь, которая разжигает во мне интерес.

Мы сейчас делаем много вещей, которые выходят за рамки игр и связывают их с производством, например мы делаем мерчендайз. Или вещи, которые связаны с регионом, к примеру, я делаю гейм-джем в Таиланде, называется Pirate Jam. И это связано с моей страстью к мореходству и с тем, что мне нравится путешествовать в Таиланд и делать там мероприятие. Здесь много чего происходит, в том числе для меня лично, что помогает расти, делать разные задачи. Но в то же время здесь многое происходит и в самом Китае и рядом. И вот это меня интересует и очень вдохновляет.

Вы прожили в Китае уже больше 10 лет и, кажется, не собираетесь уезжать. Каково это, жить в Китае американцу? Вы говорите по-китайски?


Я женат на китаянке, и недавно у нас родился ребёнок, всего год назад. Я уже не был в Штатах где-то три, да, я думаю уже три года. И когда я включаю новости сегодня, то думаю, что я и не очень-то хочу возвращаться.

Каково американцу жить в Китае и видеть, как американские медиа освещают страну, в которой вы сейчас живёте?


Я часто об этом говорю со своими местными друзьями, потому что мы видим то, как американские медиа освещают США, мы также видим, как они освещают Россию. Я думаю, что медиа в США просто сошли с ума, если быть откровенным. Я же вижу людей здесь в Китае, я бывал в России, и куда бы ты ни поехал, везде люди — это люди. Народ страны — это не правительство, и, в большинстве случаев, правительство — это тоже не зло, которое пытается завоевать мир. Я нахожу иронию в том, что США постоянно тычут пальцем в страны типа Китая или России, заявляя, что они пытаются распространить влияние и захватить мир. И в то же время именно у США полно военных баз по всему миру, и у них есть интересы в политике всего мира, и они разжигают революции везде — от Украины до Гонконга и так далее.
19:28 Как американец, который живёт не в США, оглядываться на США — это как смотреть на эдакий шар безумия. Очень сложно хоть понять это, ведь когда-ты бывал в России или жил в Китае, то ты знаешь – то, что говорят по ТВ и что ты слышишь от правительства, совершенно безумно. Это не имеет никакого отношения к реальности. Это открывает глаза, и это причина, по которой спустя столько лет, я решил, что останусь здесь и это будет моим домом. Я собрался здесь остаться и пустить корни, потому что я не чувствовал, что мне было интересно то, что происходит дома.

Последний вопрос о Китае. Одна вещь, которая не даёт мне покоя. Мы все знаем историю, откуда у вас такое имя, по крайней мере читали на «Википедии». У вас была мать-хиппи, у которой была подруга, чью дочь звали Америка, и она решила назвать вас Американ. Но каково жить с именем Американ в Китае? Как часто вы слышите дурацкие шутки?


Это очень смешно. Когда в Китае рождаются дети, на их свидетельствах о рождении, очевидно, пишут имя, и оно всегда на китайском. Когда у нас родился ребёнок, то в его свидетельстве указали три китайских иероглифа, один — это имя, Чжан, а два других — фамилия, Цзи Ка. То есть у него нет английского в его свидетельстве о рождении. Люди получают английские имена, потому что они сами себе их придумывают в школе, обычно в старшей, или даже в университете. Им говорят, чтобы они придумали себе английское имя, но здесь нет никаких правил, каким именно должно быть имя.
В нашей студии Spicy Horse у нас был сотрудник, которого звали Led Zeppelin. Другого хвали Real Alien (Реальный Пришелец). У нас был один художник, который рисовал очень быстро и хорошо, и его имя на английском — и нам надо было его называть именно так, а не то он обижался – было Speed Shit (Скоростное Дерьмо). И вы спрашиваете меня, не странное ли имя «Американ»? Да на меня работал сам Led Zeppelin! Так что я не был с самым странным именем.

Звучит как очень здоровая система, когда ты выбираешь имя для мира, когда вырастаешь. Похоже на то, когда ты выбираешь никнейм. Ты же не получаешь никнейм одновременно с рождением. Ты как бы вырастаешь и выбираешь в какой-то момент, что вот так ты будешь представляться миру.


Но в целом, я думаю, что ваш вопрос больше о том, каково это быть американцем в Китае сейчас. И знаете, что забавно? Я снимаю дом у китайца, вот этот дом, и он мне вечно посылает сообщения в WeChat про отношения между США и Китаем. И он очень волнуется из-за них, потому что ему кажется, что мы скоро начнём воевать. И он всегда пишет мне, чтобы я рассказал американцам, что Китай – это друг США, и что мы не должны воевать.

Я очень часто слышу это от местных таксистов или просто людей, которых я встречаю. Все китайцы не понимают, вообще не понимают, почему американские медиа так зациклены на том, чтобы показать их в негативном свете. Все, кого я встречал, любят американцев и Америку. Они всё ещё считают, что это страна свободы и возможностей. И иногда мне хочется сказать им, что у них больше свободы и уж точно больше возможностей здесь в Китае, чем в США. Но это очень сложно убедить их, ведь они всё ещё верят в американскую мечту, они всё ещё смотрят и восхищаются некоторыми концепциями, которые произошли из Америки. Так что я никогда не сталкивался с чем-то негативным, что было бы связано с моим именем или с тем, что я из Америки. Никогда.

Вы немного говорили про Россию, и я знаю, что вы туда ездили. Кажется, это было лет десять назад. Я общался с несколькими людьми, которые были рядом, когда вы были в России, и они мне рассказали всяких смешных вещей, которые я не буду цитировать. Может быть вы поделитесь воспоминаниями о путешествиях или просто смешными моментами?


Было очень весело. Я был в Испании в то время, и вдруг приходит имейл о том, что надо ехать в Россию на встречу с издателем. Они собирались издавать то ли Bad Day L.A., то ли Scrapland.

Для наших российских зрителей, я думаю, что речь идёт об «Акелле».


Да, точно.
Было весело. Куда бы мы ни пошли, машины неслись по улицам. Где бы мы ни были, люди много пили. Еда была очень интересной. И я был просто поражён, когда гулял по Красной площади, смотрел на Кремль и все эти места, которые я видел только в фильмах, и станции метро были невероятными. Куда бы мы ни пошли, люди были очень милыми, всегда происходило что-то интересное и было ощущение полной свободы. Было так, что куда бы мы ни пошли, было чувство, что люди делали, что хочется, говорили, что хочется, и не волновались, что они могут кого-то задеть или что у них будут неприятности. И мне кажется, что это же верно и в отношении Китая, сама концепция свободы. Она очень гибкая, и люди любят болтать о ней, но когда ты ездишь куда-то и встречаешься с людьми, то ты понимаешь, что есть такое отношение к жизни, такое счастье или персональная свобода. И в России я заметил это безумное ощущение свободы.

Я путешествовал со своей тогдашней девушкой, я сказал «Акелле», что это моя ассистентка. В общем, они меня поселили в специальный отель, который не очень-то понравился моей девушке. И нам пришлось переехать. Я думаю, что они просто хотели, чтобы я получил удовольствие от поездки, но это было не то удовольствие, которое бы моя девушка хотела, чтобы я получил. Как бы то ни было, это была отличная поездка и хорошее время.

Говоря о Bad Day L.A., я всегда любил эту игру, несмотря на средние отзывы. Я думаю, что ее можно назвать культовой, в то время она была моим эдаким предосудительным удовольствием. Как к вам пришла такая странная идея?


Забавно. Когда смотришь сейчас на США, на все расовые трения и насилие на улицах, как происходит катастрофа за катастрофой, и медиа тебе говорят, что ты живешь в страхе и должен жить в страхе. И в этом и был наш слоган. Причины, по которым я решил делать эту игру, были связаны с катастрофой 11 сентября и с войнами, которые США вели в Ираке и Афганистане. И которые не имели ничего общего с 11 сентября, и культура, при которой миллионы людей выходили на улицы и протестовали против войны, а правительство всё равно продолжало это делать. И все продолжали снимать жестокие фильмы. И продолжали происходить преступления и другие проблемы. И все говорили только о террористических угрозах и что ты можешь умереть в любой момент. И вот в то время я решил, что хочу уехать из США. Я сказал себе, что не хочу быть в США и не хочу больше этих проблем.
И компания, которая финансировала игру, попросила меня придумать какую-то оригинальную идею. Я очень старался убедить их сделать простую игру, потому что это то, на что они могли бы сделать. Но они требовали сюжетный экшен, а у меня уже накипело от проблем в США, так что я вылил всё это в Bad Day L.A. А самое удивительное здесь то, что если посмотреть на Bad Day L.A. сейчас и сравнить ее с ситуацией в США, то я будто Нострадамус от видеоигр или типа того. Это почти как волшебное предсказание событий в Штатах.

Знаете, говоря про стиль этой игры, мне кажется, что мы потеряли это тонкое искусство дурашливых и мрачных игр, вроде Stubbs the Zombie, Bad Day L.A. и других, которые были одновременно и мрачными, и смешными. Сейчас ты должен выбрать, либо мрачное, но серьёзное, либо веселое, но легкое и яркое. Думаете, сегодня можно сделать игру, подобную Bad Day L.A.?


Ни за что. У меня было бы столько проблем. Вот об этом я и говорю, когда мы упоминаем свободу, понимаете? Свобода – как возможность нам создавать и не волноваться, что это постараются «отменить». Свобода — это также и обратная ситуация, когда ты можешь показать людям что-то, что ты создал, а они могут выключить это, отвернуться или уйти. Они же не обязаны вникать во что-то, что им не интересно. Вот этого сейчас в культуре США нет. Есть такое высказывание Кристофера Хитченса, что люди в США и Британии сейчас так скучают из-за отсутствия проблем в своём доме, что им приходится заглядывать через забор к соседу и искать проблемы там.

Меня это очень бесит. Вот как вы сказали, иногда хочется сделать игру с очень черным юмором, но существует целая группа людей, которая только и ждет, чтобы напасть на тебя и «отменить» тебя. Мне кажется, что в политкорректности что-то потерялось. Чего-то не хватает в спектре историй, которые мы можем рассказывать, в спектре искусства, которое мы можем создавать.

Говоря об «Акелле» и России, вы когда-нибудь играли в российские игры того времени? Мне кажется, что у нас была похожая атмосфера, то есть это был Дикий Запад с точки зрения творчества. Можно было реализовать очень странные идеи, и игры получались не идеальными по техническим стандартам даже того времени, но зато были очень любопытные идеи, которые нельзя было встретить на других рынках.


Не могу сказать, что я когда-то играл в российские игры, но я не удивлён, ведь раньше у нас было больше свободы делать подобное.

Ладно, тогда я вам назову несколько игр после интервью, чтобы вы поиграли в свободное время. А какая была ваша любимая игра с точки зрения процесса? Что вам больше всего понравилось делать?


Это очень сложный вопрос, потому что, как я уже говорил, каждый раз, когда я делал игры, моя роль менялась тем или иным образом. Так что если вы меня спросите, какую игру было приятней всего делать как дизайнеру уровней, то я назову Quake. Если как гейм-дизайнеру или креативному директору, то, наверное, Alice Madness Returns. Она же была бы самой любимой в качестве директора студии. Ещё было очень классно делать Grimm в Spicy Horse, пожалуй, вот её я бы назвал в качестве любимой игры с точки зрения директора студи и. А Alice Madness Returns, пожалуй, лучшая в качестве креативного директора, потому что у нас была большая команда, большой бюджет, и мы могли делать многое из того, что не могли раньше. Так что нелегко указать на одну игру и сказать, что она была самой приятной с точки зрения процесса, так как роли в проектах всегда были разными.

Окей, а какая ваша любимая игра как результат?


Вы имеете в виду как финальный продукт, законченная игра?

02 Ну да, в какую вам самому больше всего понравилось играть?


Из игр, которые я сделал? Ох, это тоже сложный вопрос, потому что они очень разные. Я ведь занимался всем – от экшенов от третьего лица до мультиплеерных шутеров и данжн-кролеров, и чего только не делал. Если иметь в виду то, во что бы мне нравилось сесть и поиграть, то мне все еще очень нравятся Doom и Quake. Если я хочу выпустить пар, побегать и сыграть deathmatch, то я бы назвал что-то вроде Quake. Потому что, если говорить обо всех вещах, к которым я приложил руку, то Quake лучше всего подходит для отдыха, самая захватывающая и веселая с точки зрения геймплея.

А вам нравятся новые версии Doom? Я имею в виду Doom Eternal и предыдущую часть?


Я попробовал сыграть в Doom Eternal, мне показалось, что он очень классный, но много времени на игры у меня сейчас нет. Как я говорил, у нас родился ребенок год назад, и не в курсе, знаете ли вы, каково это, но дети требуют очень много времени. Последнее, во что я играл, был Red Dead Redemption или какая-то часть Hitman, и это было год назад.

Я это спрашиваю про Doom, потому что игру все еще делает id Software. А вы были одним из тех, кто работал в начале компании, не у самых истоков, но тем не менее. Мне кажется, что id Software была кузницей профессионалов, которые позже стали известными разработчиками, дизайнерами, программистами и так далее. Как думаете, у каких еще компаний была похожая роль?


Да, конечно! Я даже видел карты, на которые нанесены компании, типа Microsoft, Bungie, Valve в Сиэттле, или EA и NCSoft в Остине, или далласские разработчики, вроде id Software, Ion Storm и 3D Realms. И, в общем, эти карты, выглядят будто распространение вируса. Будто id Software разбросала семена, а потом люди основали новые компании, а эти компании привели к другим компаниям. Не помню уже, где я видел эту карту, но это очень интересно, так как видно, что игры одних жанров и люди из одних компаний создавали эдакое взаимоопыление. То есть одна студия приводит к тому, что появляется ещё пять, а потом от них ещё и еще. Мне кажется, что многие индустрии похожи на это. Не помню, где видел эту карту, но её стоит поискать.

Я спрашиваю, потому что, знаете, масштаб разработки серьезно изменился. Двадцать или тридцать лет назад у вас было пара десятков человек, которые работали в команде над одной игрой. То есть каждый человек был важен, а его вклад заметен. А также они приобретали огромный опыт, который позже они могли использовать, чтобы сделать собственный проект. Думаете, есть подобные компании сейчас? Которые меняют людей навсегда, как только они в них поработают.


Да, конечно, есть. То есть с точки зрения того, что ты мог прийти в компанию и работать в маленьком коллективе и многому научиться, это так, но навыки в видеоиграх стали намного более специализированными и в каком-то смысле более сложными. То есть сейчас сложно быть одновременно хорошим программистом, хорошим аниматором и хорошим художником по текстурам, так ведь? А раньше игры были проще, и ты мог одновременно быть и программистом, и художником по текстурам, и может быть ещё и звуковиком в рамках одной работы. Но я вижу, что на инди-сцене полно игр, которые сделаны одним или двумя людьми, и их игры могут быть очень успешными. Не забывайте, что тот же Minecraft, который купили за миллиард долларов и который, вероятно, стал самой успешной игрой в мире, изначально был сделана одним человеком в качестве хобби.

Я думаю, что не стоит фокусироваться на крупных играх для консолей, ведь вы тогда упустите факт наличия огромного количества инди-игр и игр от одного разработчика, которые создают массу контента. И эти разработчики как бы просачиваются в индустрию и начинают работать над большими проектами. То есть есть, разумеется, технические изменения и команды разработки теперь выглядят по другому, но с точки зрения того, как люди попадают в индустрию и перемещаются в ней и как можно самому научиться делать игры, я не думаю, что что-то сильно изменилось. Сейчас намного больше ресурсов, где можно научиться делать игры, начиная с YouTube. Можно просто взять и скачать движок Unreal бесплатно и научиться всему, что делают профессиональные разработчики игр, просто смотря видео.

Давайте вернёмся к вашим играм. Мне кажется, что все они имеют схожий стиль: мрачноватые, необычный юмор, много аллюзий на сказки. Если проводить параллели с фильмами, то мне всегда представлялось, что вы как Тим Бёртон от мира игр. Вы бы согласились с этим?


Я уже слышал это раз сто. Я никогда не был с ним знаком, но я бы принял это за комплимент. В основном потому, что мне нравятся его фильмы и я считаю, что он более плодовит и хорош как создатель фильмов, чем я как создатель игр. Не знаю, хотел ли бы он, чтобы его называли «Американ Макги от мира фильмов», мне кажется, что мы на несколько разных уровнях. Но это нормально, я понимаю, почему люди делают такое сравнение. Так мало людей делают такие мрачные странные игры с атмосферой волшебной сказки, и так же мало людей делают подобные фильмы. Факт того, что мы оба специализируемся в чём-то похожем, как бы в одном и том же жанре, но в своих сферах, обусловливает это сравнение.

А если подумать о ваших любимых создателях игр и фильмов, то вы бы могли провести подобные параллели?


Не думаю, что я до конца понял вопрос. Вы имеете в виду, напоминают ли какие-то создатели игр мне режиссёров? А, хм. Я об этом не думал раньше, наверное… Да, я не хотел бы сейчас приводить в пример кого-то и потом узнать, что я обидел этого человека. Так что лучше не буду отвечать.

У меня такой вопрос, потому что — говоря про имена — мне всегда нравилось, как вы в каком-то смысле превратили Американа Макги в бренд, когда добавляли его в названия игр. Можете вспомнить, как к вам пришла эта идея?


Ну, эта идея пришла не ко мне. Это предложили сделать EA. Я уже рассказывал когда-то об этом. В общем, когда я работал над первой игрой Alice, и мы поехали в Техас и начали работать с Rogue Entertainment, они разрабатывали, а я помогал с дизайном. В общем, я к ним ездил и помогал работать, а еще встречался с юридическим отделом EA, у которых были проблемы с названием. Потому что название должно было быть таким, чтобы его можно было защитить и зарегистрировать как торговую марку. Одна из проблем была в том, чтобы найти свободное название сайта. А в этой сфере торговые марки уже были или заняты другими фильмами, книгами и т.д., или же слишком похожи на то, что нам нравилось. В общем, у EA не получалось найти что-то уникальное.

В какой-то момент они позвонили мне, когда я был в Техасе, и сказали, что собираются назвать игру American McGee's Alice. К тому моменту, я уже подписал кое-какие бумаги насчет своего имени, потому что они думали над этой идеей и ещё над другими идеями… Короче, когда я рассказал это команде, они не были этому рады. Так что я вернулся к юристам EA и сказал: «Слушайте, разработчики недовольны этим. И это справедливо, я же не один работаю над игрой». Они сказали, что перезвонят и что-то придумают. Потом перезвонили и сказали, что, мол, ладно, мы не будем называть игру American McGee's Alice. Я сразу же побежал к команде и сказал: «Ура, сработало! Они послушались меня, и назовут игру по-другому». Так что все стали работать над игрой дальше, а когда игра уже практически закончена – кажется, уже делали коробки или типа того, — мне снова позвонили и сказали: «Мы изменили свое решение. Игра все же будет называться American McGee's Alice». Пришлось идти к команде и говорить: «Ребята, простите, но они все же в итоге решили сделать так». И они были не очень рады. Но очевидно, что для меня лично, дальше это сыграло положительную роль. То есть я не могу сказать, что это было правильным решением для команды, но для меня лично это было полезно все эти годы.

А почему новая игра тогда не называется American McGee's Alice Asylum? По причине того, что это зарегистрированная торговая марка, или по той же причине командной работы?


Нет. Потому что, когда я контролирую это, я не ставлю свою имя на коробку. Этого хотят другие люди. Все игры, которые мы выпускали в Spicy Horse и которые мы контролировали, не называются «American McGee's что-то там». Ни одна из них. Когда я принимаю решение сам, я не ставлю имя на упаковку. Просто посмотрите на все игры, которые выпустила Spicy Horse. Но это меняется, когда другие люди финансируют разработку, к примеру Grimm от Gametap.

В общем, Gametap пришли и говорят: «Мы хотим дать вам денег, чтобы вы сделали игру». Я отвечаю: «Отлично, поехали!». Они говорят: «Но с одним условием. Она должна называться „Американ Макги представляет…“ и дальше остальное название». И что я должен ответить? «Нет, не хочу ваших денег, не дам вам это сделать» или «Окей, мы напишем имя на коробке»? В общем, это никогда не было моим решением, всегда это решали люди, которые финансируют проекты. И причина, по которой Alicy Asylum не называется American McGee's Alice Asylum, это то, что пока что никто игру не финансирует. Если тот, кто будет финансировать разработку, скажет мне назвать игру «Американ Макги представляет…» или ещё как-то, и это будет частью сделки, от которой будет зависить, получим ли мы деньги, то окей.

Я немного не согласен с вами в этом отношении. То есть я понимаю причины, но всё ещё считаю, что ставить своё имя в название очень важно сейчас. Ведь не так много людей знают создателей своих любимых игр. И мне кажется, что это проблема в индустрии игр.


Не знаю. Что касается меня, то я не прочь быть немного загадочным в этом отношении. Знаете, как Стивен Кинг, который начал писать под псевдонимом. Он взял другое имя.

Вы говорите, что Стивен Кинг использовал псевдоним, но он же его использовал, когда начинал. И очевидно, что это не ваш случай.


А, нет, нет! Он использовал фальшивое имя уже после того, как стал известным автором. Он писал о том, что он хотел проверить, будут ли его книги принимать литературные агенты уже после того, как он стал знаменит. То есть ему было любопытно, литературные агенты или издатели покупают книги, потому что они интересные или потому что его имя стоит на обложке. Потому что книга с именем Стивен Кинг на обложке продастся определенным тиражом в любом случае, это прямо гарантировано. Так что в какой-то момент своей карьеры, это он описывает в своей работе «Как писать книги», он стал отправлять рукописи издателям под другим именем, чтобы проверить, возьмут ли они их.

В общем, причина в том, что я как создатель, не хочу, чтобы игры покупали только потому, что их сделал я. Я хочу проверить, хороши ли они сами по себе. Вторая большая причина, по которой в Spicy Horse я не называл игры своим именем, это то что над играми работает большое количество людей. И часто я чувствую, что было бы неискренне писать только моё имя на упаковке.

Ну да. С другой стороны, как игру не назовёшь, то ваши игры всегда узнаются среди прочих, их не перепутать с играми других людей.


Да, это правда.

А можете назвать других создателей игр, которые тоже были бы так же узнаваемы? То есть у нас есть Сид Мейер и его «Цивилизация», но помимо вас, я думаю, это единственный пример «имени на коробке».


Еще, кажется, Уилл Райт ставил свое имя на коробки. Но знаете, игры Уилла Райта такие, что если вы поставите рядом SimCity и The Sims, то, несмотря на то, что в названии обеих игр есть слово Sim, вы можете и не понять, что их сделал один человек. Настолько они разные. Я об этом особенно не задумывался. Как я сказал, я сам не ставлю имя на игры. Вот, к примеру, сейчас мы делаем логотип по новой игре по «Стране Оз», и один из художников сделал логотип, на котором написано «Американ Макги представляет…». Но мне кажется, что он это сделал просто с точки зрения баланса композиции и шрифтов, потому что это ему очень важно. В общем, у всех свои причины делать это, и если у кого-то есть причины настаивать на таком, то и ладно, но если решение за мной, то мне наплевать.

Давайте немного пофантазируем. Как думаете, как бы сложилась ваша жизнь и карьера, если бы вы не сделали оригинальную Alice?


Я думаю, что лучше спросить, как бы пошла моя жизнь, если бы я не встретился с Джоном Кармаком. Потому что я пришел в индустрию тогда, когда я встретил Джона Кармака. Меня выгнали из старшей школы, я работал над машинами и подумывал стать механиком. В общем, перспективы у меня были так себе. И я часто задумываюсь, где бы я оказался, если бы я не встретил Джона. И думаю, что это было бы не очень хорошее место.

Знаете, я такой человек, в котором очень много творческого. Но еще я страдаю от депрессии, и если бы у меня не нашлась такая творческая отдушина, которая одновременно стала моей работой, то жизнь была бы намного хуже. Со всякими вещами вроде злоупотребления наркотиками и алкоголем, разными психологическими и эмоциональными проблемами. И я так говорю, потому что многие люди в моей семье страдали от этого. И часто это было наследственное. Но они все не в том же положении, что и я, ведь у меня есть способ выпустить пар через творчество. В результате они несчастны или в некоторых случаях страдают от зависимости или ещё хуже. Как, например, моя сестра, которая пропала без вести и теперь считается погибшей. Для меня это наглядная иллюстрация того, по какой дорожке я мог бы пойти, если бы мне не повезло встретить Джона Кармака. Я считаю, что он спас мне жизнь. Вот так просто: спас мне жизнь.

Ух! Кажется, что сейчас, ближе к концу интервью, самое время рассказать нашим слушателям, как они могут помочь вам сделать Alice Asylum. Рассказать, где они могут поддержать, подписаться и следить за обновлениями.

Конечно. Все очень просто. Как вы говорили про имя на коробке, у меня есть сайт americanmcgee.com. И если вы зайдете на него, там есть целый список того, что можно сделать, чтобы поддержать разработку. Можете просто подписаться на рассылку или на Patreon, или поставить лайк на Facebook, Twitter, YouTube и других местах. Или даже можете зайти в онлайн-магазин, которым я управляю со своей женой. Все эти вещи помогут нам. Просто пролистайте список с начала до конца и выберите одну вещь или сделайте все.

Да, лучше сделайте весь список. Еще раз спасибо, что присоединились к нам сегодня. Было очень любопытно услышать ваши мысли о карьере, других играх и обо всем остальном. Для меня это был самый интересный разговор за последние месяцы.


Да ладно. Я видел другие интервью, у вас были очень крутые гости. Но я очень благодарен за приглашение. Было очень интересно, и я рад знать, что у меня столько фанатов в России – передаю им привет!

И привет ребятам из «Акеллы» того времени.


Да, точно.

Спасибо, что пришли, и до свидания.


До свидания.

Что было ранее


  1. Илона Папава, Senior Software Engineer в Facebook — как попасть на стажировку, получить оффер и все о работе в компании
  2. Борис Янгель, ML-инженер Яндекса — как не пополнить ряды стремных специалистов, если ты Data Scientist
  3. Александр Калошин, СEO LastBackend — как запустить стартап, выйти на рынок Китая и получить 15 млн инвестиций.
  4. Наталья Теплухина, Vue.js core team member, GoogleDevExpret — как пройти собеседование в GitLab, попасть в команду разработчиков Vue и стать Staff-engineer.
  5. Ашот Оганесян, основатель и технический директор компании DeviceLock — кто ворует и зарабатывает на ваших персональных данных.
  6. Сания Галимова, маркетолог RUVDS — как жить и работать с психиатрическим диагнозом. Часть 1. Часть 2.
  7. Илья Кашлаков, руководитель фронтенд-отдела Яндекс.Денег — как стать тимлидом фронтендеров и как жить после этого.
  8. Влада Рау, Senior Digital Analyst в McKinsey Digital Labs — как попасть на стажировку в Google, уйти в консалтинг и переехать в Лондон.
  9. Ричард «Левелорд» Грей, создатель игр Duke Nukem 3D, SiN, Blood — про личную жизнь, любимые игры и о Москве.
  10. Вячеслав Дреер, гейм-дизайнер и продюсер игр с 12-летним стажем — про игры, их жизненный цикл и монетизацию
  11. Андрей, технический директор GameAcademy — как видеоигры помогают прокачивать реальные навыки и найти работу мечты.
  12. Александр Высоцкий, ведущий PHP-разработчик Badoo — как создаются Highload проекты на PHP в Badoo.
  13. Андрей Евсюков, заместитель CTO в Delivery Club — про найм 50 синьоров за 43 дня и о том, как оптимизировать фреймворк найма
  14. Джон Ромеро, создатель игр Doom, Quake и Wolfenstein 3D — байки о том, как создавался DOOM
  15. Паша Жовнер, создатель тамагочи для хакеров Flipper Zero — о своем проекте и другой деятельности
  16. Татьяна Ландо, лингвист-аналитик в Google — как научить Google-ассистента человеческому поведению
  17. Путь от джуна до исполнительного директора в Сбербанке. Интервью с Алексеем Левановым
  18. Как Data Science продает вам рекламу? Интервью с инженером Unity
  19. Как я переехал в Лондон c Revolut

Let's block ads! (Why?)

[Перевод] Что такое хорошо, что такое плохо: будет ли совесть у искусственного интеллекта


Сможет ли искусственный интеллект изучить моральные ценности человеческого общества? Сможет ли принимать решения в ситуациях, когда необходимо взвесить все за и против? Сможет ли развить чувство правильного и неправильного? Короче говоря, будет ли у него совесть?

Эти вопросы могут показаться неуместными, учитывая что современные системы ИИ способны выполнять довольно ограниченное число задач. Но по мере развития науки его возможности все больше расширяются. Мы уже видим, как алгоритмы искусственного интеллекта применяются в областях, где границы «хороших» и «плохих» решений трудно определить, — например, в уголовном правосудии или отборе резюме.

Мы ожидаем, что в будущем ИИ будет заботиться о пожилых людях, обучать наших детей и выполнять множество других задач, требующих человеческой эмпатии и понимания норм морали. Поэтому вопрос осознанности и добросовестности ИИ становится все более острым.
С этим запросом я начал искать книгу (или книги), которая объясняла бы, как у людей формировалась совесть. И дала бы подсказку, какие знания о мозге человека могут помочь в создании совестливого искусственного интеллекта.

Друг предложил мне изучить книгу «Совесть: истоки нравственной интуиции» доктора Патриции Черчленд, нейробиолога, философа и почетного профессора Калифорнийского университета в Сан-Диего. Книга доктора Черчленд и личная встреча с ней дали мне хорошо понять, каковы масштабы и ограничения науки о мозге. «Совесть» показывает, как далеко мы продвинулись к пониманию связи между физиологией и работой мозга и моральными качествами людей. Также книга проливает свет на то, какой путь нам еще предстоит пройти, чтобы по-настоящему понять, как люди принимают моральные решения.

Книга написана доступным языком и понравится тем, кто заинтересован в изучении биологической основы сознания и размышляет на тему «человечности» искусственного интеллекта.

Ниже очень краткое изложение того, что «Совесть» рассказывает о развитии морального выбора в человеческом мозге. Поскольку именно с него списана модель ИИ, больше знаний о совести поможет нам понять, что необходимо искусственному интеллекту для изучения моральных норм.

Система обучения


«Совесть — это индивидуальное суждение человека о том, что является правильным или неправильным. Обычно, но не всегда это суждение отражает мнение группы, к которой человек себя причисляет», — пишет доктор Черчленд в книге.

Но как люди развили способность понимать, что правильно, а что нет? Чтобы ответить на этот вопрос, доктор Черчленд переносит нас в прошлое, когда появились наши первые теплокровные предки.

Птицы и млекопитающие — эндотермы: их тела могут сохранять тепло. В то время как у рептилий, рыб и насекомых, иных холоднокровных организмов тело приспосабливается к температуре окружающей среды.

Большое преимущество животных-эндотермов — способность собирать пищу ночью и выживать в более холодном климате. Но таким существам нужно гораздо больше пищи для выживания. Это привело к ряду эволюционных шагов в мозге теплокровных млекопитающих, которые сделали их умнее. Наиболее заметное изменение — развитие коры головного мозга.

Кора головного мозга может интегрировать сенсорные сигналы и формулировать абстрактное представление о событиях и вещах, относящихся к выживанию и производству потомства. Она учится, обобщает новые знания, вспоминает и продолжает обучение.

Кора позволяет млекопитающим быть более гибкими и не чувствительными к изменениям погоды и ландшафта. В отличие от насекомых и рыб, которые очень зависят от стабильных условий окружающей среды.

Но, опять же, способность к обучению компенсируется тем, что млекопитающие рождаются беспомощными и уязвимыми. В отличие от змей, черепах и насекомых, которые после вылупления способны бегать и полноценно функционировать, млекопитающим нужно время на развитие навыков выживания.

Кроме того, их выживание зависит друг от друга.

Развитие социального поведения



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

«В ходе эволюции чувства удовольствия и боли, помогающие выживать, были переориентированы, чтобы развить аффилированное поведение, — пишет Черчленд. — Самолюбие распространилось на родственную, но новую сферу — любовь к ближнему».

Основной причиной этого изменения стали потомки. Эволюция вызвала трансформации в мозге млекопитающих, чтобы поставить на первое место заботу о детях. Матери, а у некоторых видов оба родителя, готовы пойти на все, чтобы защитить и прокормить свое потомство. Даже если лично для них в этом нет выгоды.


В книге «Совесть» автор описывает эксперименты по определению биохимических реакций мозга различных млекопитающих, которые поощряют социальное поведение, в том числе заботу о потомстве.

«Социальная жизнь млекопитающих качественно отличается от жизни других социальных животных, у которых отсутствует кора головного мозга, — например, пчел, термитов и рыб, — пишет Черчленд. — Мозг млекопитающих более гибкий, меньше завязан на рефлексах, более восприимчив к изменениям в окружающей среде. Он склонен как к долгосрочным, так и к краткосрочным суждениям. Социальный мозг млекопитающих позволяет им ориентироваться в мире, чтобы понимать, что намерены сделать или ожидают от тебя другие члены общества».

Человеческое социальное поведение


Из млекопитающих у человеческого мозга самая большая и сложная кора. Мозг homo sapiens в три раза больше мозга шимпанзе, с которыми у нас был общий предок 5-8 млн лет назад.

Большой мозг, естественно, делает нас умнее, но также требует более высоких энергозатрат. Так как же мы стали оплачивать этот калорийный счет?

«Умение готовить еду на огне, скорее всего, было решающим поведенческим изменением, которое позволило мозгу гоминина развиться за пределы мозга шимпанзе и довольно быстро продолжить эволюцию», — пишет Черчленд.

Научившись удовлетворять потребности организма в энергии, гоминины стали способны в итоге выполнять более сложные задачи. Например, развивать социальное поведение и строить общественные иерархии.

Получается, наше поведение, включая соблюдение моральных норм и правил, — это результат борьбы за выживание и необходимость получать необходимое число калорий.

«”Тривиальная потребность в энергии” звучит не достаточно глубоко, конечно, но, тем не менее, это реальная причина», — пишет Черчленд в книге «Совесть».

Наша генетическая эволюция благоприятствовала развитию социального поведения. Моральные нормы возникли как ответы на наши потребности. А мы, люди, как и любые другие живые существа, подчиняемся законам эволюции, которые Черчленд описывает как «слепой процесс, который без какой-либо цели возится с уже существующей структурой». Строение нашего мозга — результат бесчисленных экспериментов и корректировок.

«Между частью мозга, отвечающей за заботу о себе, и той, что усваивает социальные нормы, как раз и кроется то, что мы называем совестью, — пишет Черчленд. — В этом смысле наша совесть — это “конструкт” мозга, посредством которого инстинкты самосохранения и других преобразуются в конкретные формы поведения посредством развития, имитации и обучения».

Это очень деликатная и сложная тема, и, несмотря на все достижения науки о мозге, многие загадки человеческого разума и поведения остаются открытыми.

«То, что важную роль в происхождении человеческой морали сыграла простая необходимость в пище, не означает, что порядочность и честность нужно обесценивать. Эти добродетели по-прежнему достойны восхищения и очень важны для нас, независимо от их скромного происхождения. Именно они делают нас людьми», — пишет Черчленд.

Искусственный интеллект и совесть


Источник: Depositphotos

В книге «Совесть» Черчленд обсуждает и другие темы, в том числе роль обучения с подкреплением в развитии социального поведения и способность коры головного мозга человека учиться на собственном опыте, размышлять над контрфактическими суждениями, разрабатывать модели мира, проводить аналогии и другое.

По сути, мы используем ту же систему вознаграждения, которая позволила нашим предкам выжить, и опираемся на особенности нашей многоуровневой коры головного мозга, чтобы принимать сложные моральные решения.

«Моральные нормы возникли в контексте социальной напряженности и закрепились на биологической почве. Изучение социальных практик основывается на системе положительного и отрицательного вознаграждения мозга, а также на его способности решать проблемы», — пишет Черчленд.

После прочтения «Совести» у меня возникло много вопросов о роли этого морального компаса в ИИ. Станет ли совесть неотъемлемой частью искусственного интеллекта? Если к выработке социальных норм и морального поведения нас подтолкнули физические ограничения, необходимы ли подобные требования для ИИ? Играют ли физический опыт и сенсорное восприятие мира решающую роль в развитии интеллекта?

К счастью, после чтения «Совести» у меня была возможность обсудить эти вопросы с доктором Черчленд лично.


Требуется ли физический опыт для развития совести в искусственном интеллекте?


Что очевидно из книги доктора Черчленда (и других исследований биологических нейронных сетей), физический опыт и ограничения играют важную роль в развитии интеллекта и, соответственно, сознания у людей и животных.

Но сегодня, когда мы говорим об искусственном интеллекте, мы имеем в виду программные архитектуры, такие как искусственные нейронные сети. ИИ в актуальной форме — это в основном бестелесные строки кода, которые выполняются на компьютерах и серверах и обрабатывают данные. Будут ли физический опыт и ограничения необходимыми для разработки действительно человеческого ИИ, способного ценить и соблюдать моральные нормы общества?

«Трудно понять, насколько гибкой может быть работа ИИ, учитывая, что анатомия машины сильно отличается от анатомии мозга, — рассказала доктор Черчленд в нашей беседе. — В случае биологических систем решающее значение имеет система вознаграждения, система обучения с подкреплением. Ощущения положительного и отрицательного вознаграждения необходимы для познания окружающей среды. Это может быть не так в случае искусственных нейронных сетей. Мы просто об этом не знаем».

Доктор также отметила, что мы до сих пор не знаем, как думает мозг.

«С этим знанием нам, возможно, не потребовалось бы копировать абсолютно все особенности биологического мозга в искусственном интеллекте, чтобы добиться похожего поведения», — добавила она.

Черчленд напомнила, что изначально сообщество разработчиков ИИ отвергало нейронные сети. Но в итоге признало их довольно эффективными, когда нейронные сети показали свой потенциал в исполнении вычислительных задач. И хотя современные нейронные сети серьезно уступает возможностям человеческого мозга, в будущем нас могут ждать сюрпризы.

«Мы знаем, что млекопитающие с развитой корой головного мозга, системой вознаграждения и биологическими нейронными сетями могут учиться и структурировать информацию без огромного количества данных, — сказала она. — На сегодняшний день искусственная нейронная сеть может быть настолько хороша для распознавания лиц, насколько бесполезна при классификации млекопитающих. Дело может быть просто в числах».

Нужно ли нам воспроизводить тонкие физические различия мозга в ИИ?


Один из выводов, что я сделал после прочтения «Сознания», заключался в том, что люди обычно соглашаются с социальными нормами общества, но время от времени бросают им вызов. И уникальное строение человеческого мозга, и гены, которые мы унаследовали от родителей, и опыт, который мы приобретаем, позволяют нам заниматься тонкой настройкой моральных ориентиров. Люди могут переосмысливать ранее установленные моральные нормы и законы, а также придумывать новые.

Одна из самых растиражированных особенностей искусственного интеллекта — его воспроизводимость. Когда вы создаете алгоритм ИИ, вы можете реплицировать его бесчисленное количество раз и развертывать на любом количестве устройств. Все они будут идентично работать по последним настройкам нейронных сетей. Теперь возникает вопрос: если все ИИ равны, будут ли они статичны в своем социальном поведении и потому лишены той гибкости, которая определяет динамику социального прогресса общества?

«Пока у нас не будет более глубокого понимания того, как работает мозг, на этот вопрос ответить будет трудно, — сказал Черчленд. — Мы знаем, что для того, чтобы получить сложный результат с помощью нейронной сети, в ней не обязательно должны быть такие биологические элементы, как митохондрии, рибосомы, белки и мембраны. Сколько еще в нем не должно быть? Мы не знаем…. Без данных я просто очередной человек, высказывающий мнение. А у меня нет данных, которые бы сказали: вам нужно имитировать такие-то схемы в системе обучения с подкреплением, чтобы создать более человечную нейронную сеть».

Нам еще многое предстоит узнать о человеческой совести. Еще больше о том, применимо ли это к технологиям искусственного интеллекта и как именно.

«Мы не знаем точно, что делает мозг, когда мы учимся сохранять баланс в стойке на голове, — пишет Черчленд в журнале «Conscience». — Еще меньше мы знаем о том, что делает мозг, когда учится находить баланс в социально сложном мире».

Но по мере изучения и раскрытия секретов мозга, будем надеяться, мы будем все более оснащены для создания ИИ, который послужит на благо человечества.

Let's block ads! (Why?)