Развитие Android глазами разработчика

в 9:01, , рубрики: android, android studio, ant, asynctask, dagger, eclipse, eventbus, netbeans, история разработки, мобильная разработка

Меня зовут Андрей Данилов, под Android начал разрабатывать в далеком 2012 году. Успел поработать примерно везде — в крошечном стартапе, маленькой продуктовой компании, аутсорсах и крупных компаниях, таких как Авито, Ситимобил, Яндекс. Успел выступить примерно на десятке митапов и конференций. Сейчас член Программного комитета конференции Apps conf X. В данный момент руковожу парой команд в Т-Банке.

Развитие Android разработки глазами разработчика

Довольно много времени прошло с 2007 года, когда Android стал доступен для разработчиков. С тех пор прошло почти 18 лет. За это время изменилось примерно все: железо стало мощнее, интернет быстрее, IDE умнее, а проекты сложнее. Предлагаю оглянуться назад и посмотреть, что же именно изменилось с тех пор для разработчиков. 

Развитие Android глазами разработчика - 1

Ранний Android 2007 - 2014

Система сборки Ant

Развитие Android глазами разработчика - 2

Первое, что бросилось бы в глаза современному разработчику — это отсутствие Gradle для сборки. Вместо нее использовался Ant. В те времена вообще можно было подумать, что для Android используется XML driven development. Вся верстка в XML, скрипт сборки в XML, строки и ресурсы в XML и даже сохраненные настройки (SharedPreferences) под капотом все тот же XML. Часть использования XML, конечно, дожила и до наших дней, но от части все же удалось избавиться, спасибо и на этом.

Использование Ant выглядело примерно так — в проекте был build.xml, и все задачи сборки (в Ant они называются targets) нужно было прописывать в нем:

<?xml version="1.0" encoding="UTF-8"?>
<project name="HelloWorld" default="help">
    <!-- Определяем свойства проекта -->
    <property name="sdk.dir" location="/path/to/android/sdk" />
    <property name="build.target" value="android-19" />

    <!-- Настраиваем путь к исходным файлам -->
    <path id="source.path">
        <fileset dir="${src.dir}">
            <include name="**/*.java" />
        </fileset>
    </path>

    <!-- Путь к ресурсам -->
    <path id="resource.path">
        <fileset dir="${res.dir}">
            <include name="**/*" />
        </fileset>
    </path>

    <!-- Включаем библиотеки и внешние JAR файлы -->
    <path id="lib.path">
        <pathelement path="${sdk.dir}/platforms/${build.target}/android.jar" />
     </path>

     <!-- Задача для компиляции исходного кода -->
     <target name="compile">
         <javac srcdir="${src.dir}" destdir="${bin.dir}" includeantruntime="false">
             <classpath>
                 <path refid="lib.path" />
             </classpath>
         </javac>
     </target>

     <!-- Задача для создания ресурсов -->
     <target name="create-resources">
         <aapt executable="${sdk.dir}/build-tools/${build.target}/aapt.exe"
               ignoreAssets="true" verbose="true">
             <res path="${res.dir}" />
         </aapt>
     </target>

     <!-- Задача для упаковки APK файла -->
     <target name="package-apk">
         <jar jarfile="${out.dir}/${ant.project.name}.apk" basedir="${bin.dir}"/>
         <zipalign executable="${sdk.dir}/build-tools/${build.target}/zipalign.exe" 
           verbose="true" outfile="${out.dir}/${ant.project.name}-aligned.apk" 
           inputfile="${out.dir}/${ant.project.name}.apk"/>
     </target>
</project>

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

IDE - Eclipse and NetBeans

Развитие Android глазами разработчика - 3

Конечно, к современной среде разработки пришли не сразу. До Android Studio, сделанной на базе Intellij IDEA, вся разработка под Android (так же, как и под Java, к слову) велась либо в Eclipse, либо в NetBeans. Обе IDE вполне успешно могут работать с Android проектами до сих пор, конечно же, при условии разработки на Java — Kotlin-плагины уже не поддерживаются. Разница между ними была примерно как между Coca Cola и Pepsi — чисто вкусовщина. NetBeans предоставлял чуть более дружелюбный и не перегруженный интерфейс, Eclipse имел большее количество плагинов. Из минусов этих IDE — отсутствие хороших инструментов вроде умного рефакторинга, анализатора кода, а также прямой поддержки Google.

Fun Fact

Первые версии Intellij IDEA и Eclipse появились в 2001 году. Чтобы для Android разработки обойти по популярности Eclipse, Intellij IDEA понадобилось 7 лет, причем не без помощи поддержки Google. И 15 лет, чтобы обойти Eclipse по популярности в Java.

RoboGuice

Развитие Android глазами разработчика - 4

RoboGuice был, по сути, первым по популярности фрэймворком для Dependency Injection до Dagger и даже местами соответствовал JSR-330. Работал с View, ресурсами и кастомными классами. Но выглядел он максимально странно:

@ContentView(R.layout.main)
class RoboWay extends RoboActivity { 
    @InjectView(R.id.name)             TextView name; 
    @InjectView(R.id.thumbnail)        ImageView thumbnail; 
    @InjectResource(R.drawable.icon)   Drawable icon; 
    @InjectResource(R.string.app_name) String myName; 
    @Inject                            LocationManager loc; 

    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        name.setText( "Hello, " + myName ); 
    } 
} 

Да, какие-то строчки кода это экономило, но только за счет кодогенерации. Получалось, что для маленьких проектов он добавлял экономию на спичках — экономию 1-2 строки для каждой сущности, что совсем незначительно. Зато для крупных проектов RoboGuice добавлял минуты холодной сборки. Страшно подумать, что было бы сейчас в случае с проектами, состоящими из многих сотен экранов. В общем, уже к 2013 году проект по факту перестал поддерживаться, а вскоре и использоваться.

ActionBarSherlock

Развитие Android глазами разработчика - 5

В древние времена, когда 4 андроида еще не существовало, сделать приличный Action Bar было довольно тяжко. В общем-то, ActionBarSherlock решал эту проблему и при этом использовал нативный ActionBar в 4 андроиде, так что в какой-то момент использовался почти повсеместно.

AsyncTask

Развитие Android глазами разработчика - 6

AsyncTask был частью стандартного SDK, но поистине легендарной частью. Основная проблема была в том, что из-за обилия неопытных разработчиков, засилья именно Async Task во всевозможных курсах и гайдах по андроид разработке, а также отсутствия хороших архитектурных практик по разделению слоев (привет Clean Architecture) сами Async Tasks создавались, как и все остальное — прямо в коде Activity. Это приводило к созданию анонимных внутренних классов с неявной ссылкой на Activity и дальнейшим утечкам памяти или даже падениям приложения. Например, в случае переворота экрана. Выглядело это так:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         textView.setText(“Progress ” + progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

Стоило перевернуть экран — textView переставал существовать, но сам Async Task продолжал работу и при попытке поменять текст сразу клал все приложение на лопатки.

Масштабы безумия были столь массовыми, что на долгое время этот кейс внесли в вопросы на собеседованиях Android разработчиков. К счастью, с 30 API уже Deprecated.

EventBus

Развитие Android глазами разработчика - 7

Из-за отсутствия адекватных, сравнительно простых и удобных механизмов обновления UI появилась библиотека EventBus. Концепция была простой, как пробка:

Надо было просто зарегистрировать прием события:

@Subscribe(threadMode = ThreadMode.MAIN)  
public void onMessageEvent(MessageEvent event) {
      // Do something
}

Зарегистрировать прием сообщений:

@Override
public void onStart() {
      super.onStart();
      EventBus.getDefault().register(this);
}

И в любом месте дергать его отправку:

EventBus.getDefault().post(new MessageEvent());

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

Архитектура MVC

Развитие Android глазами разработчика - 8

Если не брать в расчёт проекты с God Object Activity, которые отвечали примерно за все вообще, то основной архитектурой был MVC. По разбивке на слои выглядел он так:

Model — логика, данные и т.д.

View — XML с версткой

Controller — Activity / Fragment 

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

Эра бурных перемен 2014 - 2018

Android Studio

Развитие Android глазами разработчика - 9

Android Studio появилась в 2014 году и используется активно до сих пор. Да, первые версии были настолько кривыми и косыми, что после нескольких дней использования мне пришлось пересесть на Eclipse. Тем не менее спустя полгода после релиза проблемы были починены, а позиция основной IDE для Android разработки стала нерушимой.

Gradle

Развитие Android глазами разработчика - 10

Первая версия Gradle появилась еще в 2009. Основным языком выбрали Groovy, так как он, с одной стороны, привязан к JVM, с другой стороны — с динамической типизацией, что удобно для скриптов и довольно понятно Java-разработчикам. Это было особенно важно, учитывая, что для рядового разработчика с Ant и Maven работать было сложнее. Помимо этого, Groovy на тот момент был весьма модным языком, так что классический hype driven development имел место быть.

Для Android плагин вышел в 2013, но быстро приобрел популярность уже в 2014 году, после чего про Ant практически полностью забыли.

Material Design

Развитие Android глазами разработчика - 11

Уже мало кто помнит, но до Material Design был HOLO, который был сосредоточен на минимализме и выглядел примерно так:

Развитие Android глазами разработчика - 12

В те времена очень часто можно было услышать что-то типа «вот Apple заботится о разработчиках и пользователях, сделали нормальный дизайн дефолтных компонентов, а на Android все выглядит в стиле сайтов 90х». И в какой-то степени это было правдой. До Material Design стили были максимально простыми и некрасивыми. Разумеется, в этом были и технические причины — темные цвета способствовали чуть более долгой работе аккумулятора, а отсутствие наворотов положительно сказывалось на скорости рендеринга элементов. Material Design появился, когда телефоны уже худо-бедно стали справляться с большей нагрузкой. Хотя первое время некоторые элементы Material Design, например, тени, могли провоцировать сокращение фрэймов. Выглядел Material Design тогда так:

Развитие Android глазами разработчика - 13

RxJava

Развитие Android глазами разработчика - 14

Асинхронных запросов год к году меньше не становилось. Дошло до того, что в некоторых компаниях умудрились столкнуться с ограничением GCD в 64 треда на iOS. Учитывая, что дефолтные механизмы, такие как AsyncTasks, Threads, Loaders были довольно ущербными в итоге пришли концепции реактивного программирования и ее Java имплементации — RxJava.

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

public static <A, B> Observable<CombinedResult<A, B>> combineObservablesParallel(Observable<A> observable1, Observable<B> observable2) {
	return observable1.flatMap(new Function<A, ObservableSource<CombinedResult<A,B>>>() {
    	@Override
    	public ObservableSource<CombinedResult<A,B>> apply(A a) throws Exception {
        	return Observable.just(a).zipWith(observable2, new BiFunction<A, B, CombinedResult<A, B>>() {
            	@Override
            	public CombinedResult<A, B> apply(A a, B b) throws Exception {
                	return new CombinedResult<>(a,b);
            	}
        	});
    	}
	});
}

Этот кусок со Stackoverflow просто объединял результат 2 observables в 1. Да, сейчас он бы точно выглядел иначе, но тогда это было так.

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

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

Volley

Развитие Android глазами разработчика - 15

Библиотека Volley, на мой взгляд, была вечным, всегда вторым номером после Retrofit. Да, это было точно лучше, чем HttpUrlConnection, но до Retrofit не дотягивала. Основных причин две: проблемы с производительностью тяжелых запросов и не самый удачный API. В нем не было ни поддержки работы с RxJava и корутинами, ни удобства написания сложных запросов, а в какой-то момент большинство запросов стали именно такими.

Retrofit

Развитие Android глазами разработчика - 16

Основным инструментом для работы с сетевыми запросами как был, так и остается Retrofit. Появился он еще в далеком 2013 году, но популярность приобрел спустя несколько лет и стал стандартом индустрии. Причины популярности — OkHTTP под капотом, который также стал стандартом. Благодаря ему Retrofit успешно справлялся с сетевыми запросами любого объема, а также в целом был удобный и простой API с парсингом сразу в POJO, поддержкой RxJava и корутин.

Архитектуры MVP / MVVM

Развитие Android глазами разработчика - 17
Развитие Android глазами разработчика - 18

После роста размера приложений стало очевидно, что MVC крайне печально справляется с задачей построения расширяемой архитектуры. Так что с 2015 комьюнити стало искать новые варианты. Сначала был Model View Presenter с Mosby, а потом с Moxy. Доклады про архитектуру заполонили все конференции, и вплоть до 2018 года включительно можно было прийти и в 100500 раз послушать, как кто-то переехал на новую архитектуру в %company_name%.

В 2017 году на Google IO появились Google Architecture Components с LiveData и ViewModel. Проблем и возни с ними было значительно меньше, чем с MVP. И все радостно переехали на Model View ViewModel.

Dagger 2

Развитие Android глазами разработчика - 19

Dagger 2 вышел еще в далеком 2015 году и довольно быстро завоевал популярность, став стандартом на многие годы. Да, порог входа был довольно высоким. Да, кодогенерация проекта отжирала все больше времени сборки. Но все это с лихвой компенсировалось проверкой корректности графа во время компиляции и хорошим уровнем экспертизы в комьюнити. Периодически появлялись альтернативы — сначала Toothpick, а с приходом Kotlin еще Koin и Kodein, но чем-то настолько же массовым, они так и не стали.

Kotlin

Развитие Android глазами разработчика - 20

Kotlin, вообще говоря, появился раньше, в 2011, но полноценно использовать под Android его стали с 2015-2016. Google IO 2017 года только закрепил его статус, сделав третьим официально поддерживаемым языком на Android (после Java и С++). А в 2019 году Google даже объявили Kotlin-first подход. Причины всем понятны — Kotlin удобнее, короче, гораздо быстрее развивается, тогда как Java погрязла в поддержке обратной совместимости легаси проектов и довольно консервативном комьюнити.

По большей части Android разработчики массово перешли на Kotlin с 2017. Однако в «кровавом энтерпрайзе» процесс был медленнее — сначала оценивали риски, потом вырабатывали процесс обучения сотрудников. Кое-где даже надо было сдать экзамен, чтобы разрешили писать на Kotlin. Так или иначе, к настоящему времени абсолютное большинство Android проектов использует именно этот язык.

Современность 2018 - 2025

Coroutines + Flow

Развитие Android глазами разработчика - 21

Сами по себе корутины появились еще в 2017, но съезд с RxJava был затруднен из-за отсутствия всех необходимых операторов. Однако чуть позже, с появлением Flow, все эти проблемы сошли на нет.

Плюсы миграции были всем очевидны.

Во-первых, с корутинами и Flow было легче работать, был меньше порог входа.

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

Примерно с 2020 началась массовая миграция с RxJava на Coroutines и с тех пор корутины стали нерушимым стандартом.

Gradle Kotlin DSL

Развитие Android глазами разработчика - 22

До 2018 года в Gradle безраздельно властвовал Groovy. Да, можно было какие-то части написать на Java, например, плагины, но это было скорее редкостью и исключением из правил.

Я думаю, поддержка Kotlin DSL в Gradle — это самый недооцененный пункт из всех, что здесь есть. Посудите сами, если раньше разработчик, залезая в build.gradle, наблюдал там Groovy, а также полное отсутствие мотивации лишний раз копаться в премудростях незнакомого для себя языка, то сейчас там Kotlin — тот же самый язык, на котором пишется код. Это важно, так как разработка не становится проще, а ситуация, в которой работа типичного Android разработчика с Gradle строилась по принципу карго-культа (что нагуглил по теме, то и скопировал, не задумываясь, как оно вообще работает), наконец-то сходит на нет.

Jetpack Compose

Развитие Android глазами разработчика - 23

Анонсированный буквально за месяц до SwiftUI (Совпадение? Не думаю!) в мае 2019 года Jetpack Compose доехал до состояния production ready только в 2021 году. Однако простота внедрения и разработки, а также поддержка древних версий Android сделали свое дело, и внедрение пошло довольно быстро, в первую очередь за счет новых проектов в стартапах и аутсорсе, а также прогрессивных крупных компаний.

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

Архитектура MVI

Развитие Android глазами разработчика - 24

Однонаправленная архитектура Model View Intent по факту появилась еще в 2016, но массового применения не нашла. Она была довольно сложной в применении, с довольно узкими кейсами эффективного использования. В основном использование ограничивалось сложными экранами вроде чатов, где довольно много обновления UI, а также много источников данных, хотя некоторые компании вроде Badoo строили на MVI всё приложение целиком.

С выходом Jetpack Compose архитектура MVI приобрела чуть больше смысла. Хотя бы потому, что сущность State уже в любом случае существовала в явном виде. В целом из-за все более сложных экранов и все большего количества состояний на них архитектура в данный момент имеет все больше смысла.

Итоги

Сейчас Android разработка стабилизировалась. Это уже далеко не молодая область, в которой часто меняются подходы к разработке, часто выходят новые фреймворки и библиотеки, меняющие всё. Сами посудите — с 2014 по 2018 год изменений было кратно больше, чем за предыдущие 7 лет. В какой-то мере можно сказать, что мы пришли к стагнации — имеющиеся технологии как-то развиваются, но ничего принципиально нового не происходит. Чтоб не пропустить новые тренды и не утонуть в рутине покраски кнопок, приходите на AppsConf 2025. Вместе посмотрим, все ли настолько плохо как кажется, и сможет ли AI что-то изменить в текущей парадигме.

Автор: DEADMC

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js