Как создавался «Кинопоиск» для Windows Phone

    Не так давно в российском Marketplace появился официальный клиент сайта «Кинопоиск», который на ура был воспринят пользователями Windows Phone и сейчас бьёт все рекорды популярности среди бесплатных приложений. Конечно же, мы не могли не взять интервью у Григория Никонова (Anadale), разработчика этого приложения.

    Григорий является сооснователем крупнейшего в России диджитал-агентства Actis Wunderman и главным техническим гуру компании. Кроме того, Григорий сотрудничал с ATM Forum European Marketing Awareness Committee и стал одним из авторов монографии, посвященной ATM-сетям. В совокупности его опыт работы в сфере IT составляет более двадцати лет.

    Под катом вы сможете почитать мнение Григория Никонова о платформе Windows Phone и конкурирующих мобильных операционных системах (как со стороны разработчика, так и пользователя), о проблемах разработки под мобильные ОС, и, непосредственно о проектировании и разработке «Кинопоиска».



    — Чем разработка под Windows Phone отличается от разработки под другие платформы?

    С точки зрения разработчика, iOS имеет очень хорошее API, позволяющее реализовать практически всё, что может потребоваться, и содержит отличную документацию. Однако при разработке под iOS есть один минус, который так или иначе напрягает: разработка ведётся на Objective-C — чудесном языке, который пытались дотянуть до языка высокого уровня. К сожалению, на нем вы тратите массу времени на подробное объяснение того, что нужно сделать, чтобы показать ваши данные, вместо того, чтобы сказать «вот мои данные – покажи их». Ну и, конечно, приходится помнить о таких вещах, как утечка памяти, управление счетчиками ссылок и подобных вещах.

    Если же говорить про пользовательские интерфейсы, то в силу огромной гибкости iOS, разработчики пытаются выделиться как могут. В результате этого все приложения под iPhone и iPad делятся на две большие категории: либо все приложения сделаны абсолютно одинаково, по шаблону, либо это «цыганский табор», когда каждый пытается сделать то, что он хочет, и, более того, ему это удаётся. Проблема в том, что кому-то это удаётся не очень хорошо. Если подводить какую-то оценку разработке под iOS, то я ставлю твёрдую четвёрку.

    Вторая широко известная платформа — это Android. Данная платформа тоже поражает своей гибкостью в большинстве мест. К тому же, под Android разработка ведётся на Java — более современном и удобном языке, нежели Objective-C. Java упрощает разработку в силу своей объектно-ориентированности и того, что это «управляемый» язык, то есть существует виртуальная машина, которая теоретически управляет за тебя памятью и всем остальным. Но и здесь есть свои нюансы. Во-первых, преимущественно средой разработки является Eclipse, и хотя она хороша для разработчика сама по себе, она никак не помогает рисовать интерфейсы и делать другие вещи. Кроме того, писать на Java под Android, как оказалось, сложнее, чем под iOS. При разработке под iOS в Xcode есть хоть какая-то визуальная помощь, в Eclipse такого нет. Вообще, Android замечательный и гибкий, разрабатывать для него — это как «идти в разведку в джунглях»: ты много тащишь всего на себе, это всё тоже нужно знать; есть масса нюансов, про которые можно и не догадываться, пока они тебя не ударят по голове.

    После всего этого разработка под Windows Phone оказалась «чистой радостью ребёнка в песочнице». Во-первых, у Microsoft на сегодняшний день самые сильные средства для разработчика. Лучше Visual Studio ничего не придумано. Apple с Xcode только сейчас подошёл к VS пятилетней давности, а Eclipse хоть и имеет очень сильные инструменты для работы с текстом, в ней нет всех тех «визуальных обёрточек», которые часто нужны. Зато это есть при разработке под Windows Phone: ты сразу видишь код, который ты пишешь, и сразу видишь, как всё это выглядит на экране. К тому же C# — язык поновее, чем Java, и наученный на ошибках Java. На нём просто хорошо и приятно писать.

    У Windows Phone нет такой гибкости, которая есть у iOS и Android. Ребята из Microsoft честно подошли к Metro-концепции, сказав, что мы имеем дело с мобильным телефоном, и, что у телефона не может быть всех этих текстур дерева и выпуклых кнопок, которые все так пытаются сделать на iOS и Android. В Microsoft говорят, что это телефон, это экран, тут всё должно быть просто и нужно концентрироваться на контенте. Они представили массу шаблонов и «принципов дизайна», которые трактуют, как должно выглядеть Metro-приложение. Несмотря на то, что, с одной стороны, кажется, будто Microsoft загоняет разработчиков в рамки шаблонов, практика показывает, что внутри этих шаблонов столько свободы, что сделать можно всё, что угодно. А самое главное, что приложения, которые получаются — если их, конечно, правильно писать, — не выглядят скопированными под кальку. Так что с точки зрения принципов подхода к дизайну Windows Phone очень способствует концентрации на том, что ты хочешь представить пользователю, а не на том, как ты хочешь это представить. Когда мы делали «Кинопоиск», мы провели безумное число часов за спорами, как приложение должно выглядеть, и проиграли перед собой несколько десятков сценариев взаимодействия пользователя с приложением.



    Возвращаясь к разработке, хочется сказать, что C# является лучшим языком программирования широкого профиля, и, что самое главное, очень нравится, в каком направлении этот язык продолжает развиваться. Стоит сказать, что мы немножко схитрили, используя не тот «голый» язык в той версии, которая доступна всем, а применяли некоторые свойства для упрощения асинхронной работы с данными, которые только появятся в следующей версии языка. А для мобильных устройств это штуки, без которых жить просто нельзя. Этих вещей ни в iOS, ни в Android нет, и как только ты на этих платформах ввязываешься в асинхронную работу с данными, ты сразу погрязаешь в куче непонятных вещей, которые реально сносят мозг.

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

    При этом в C# компилятор языка автоматически умеет раскладывать всё это на тысячи методов. Для программиста это выглядит так, будто весь процесс проходит линейным потоком, а компилятор за него разбирает весь код на необходимые методы. Эта особенность компилятора сэкономила нам в разработке «Кинопоиска» примерно две недели. Несмотря на то, что «Кинопоиск» не является большим приложением, даже на его разработке мы сэкономили столько времени благодаря C#. И страшно представить, сколько мы бы затратили времени на поиск и отладку тех ошибок, которые бы могли возникнуть, если бы это всё разрабатывалось под Android или iOS.

    — Какие трудности ожидают людей при разработке мобильных приложений?

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

    С другой стороны, помимо желания быстро что-то показать пользователю, есть жестокое ограничение — канал передачи данных. Далеко не всегда пользователи пользуются Wi-Fi или хотя бы 3G, а значит нужно заниматься оптимизацией сетевого трафика. Помимо оптимизации трафика нужно оптимизировать и интерфейс мобильных приложений: на небольшой площади экрана нужно разместить максимум информации и соблюсти все зоны, куда пользователь попадает пальцем. У кого-то пальцы меньше, а у кого-то больше; и тут встречается очень распространённая ошибка, когда программисты считают, что кнопка должна быть такого же размера, что и её изображение, а ведь на самом деле «touch zone» правильной кнопки многим больше, чем она нарисована. Нужно считать, сколько приложение потребляет процессорной мощности и сколько оно занимает места в памяти и на диске. Эта оптимизация знакома программистам старой закалки, но неизвестна новым разработчикам. При разработке «Кинопоиска» мы изначально планировали по-максимуму кешировать данные, чтобы при отсутствии сети пользователь мог посмотреть какую-то информацию, но мы столкнулись с проблемой, когда скачать изображение из интернета по 3G получается быстрее, чем прочитать её из внутреннего хранилища — о таких проблемах изначально очень сложно догадаться. В первых версиях «Кинопоиска» мы сначала искали изображения в кеше, и если их там не было, сперва скачивали их и загружали в кеш, а потом показывали из кеша. Сейчас мы кешируем только те изображения, которые появляются на первом экране — все остальные материалы сразу грузятся из Сети.

    — «Кинопоиск» — это приложение-панорама (Windows Phone Panorama Application). Какое впечатление сложилось о Metro UI? Вызывал ли новый интерфейс трудности в проектировании?

    У нас ушло приблизительно три недели на проектирование и понимание того, как разложить все данные, отображающиеся в приложении, на правильный Metro-интерфейс, чтобы вся информация вместилась и чтобы приложение не было копией iPhone-версии «Кинопоиска». К сожалению, последней проблемой страдают очень многие приложения в Marketplace, чьи разработчики не потрудились адаптировать их под новую платформу, а просто стянули дизайн с существующей версии под iPhone или Android.



    В «Кинопоиске», конечно же, мы использовали панорамы. Всё приложение устроено таким образом, что в любой панораме самая важная информация отображается на первом экране, информация, чуть меньшая по важности, всегда отображается при одном скролле вправо, и ещё чуть меньшая по важности — при одном скролле влево. И в этом огромный плюс панорам и Metro UI. Такого нет ни в iOS, ни в Android.

    — Были ли при разработке использованы какие-нибудь хинты, о которых можно рассказать и которыми хотелось бы поделиться?

    Какое-то время мы потратили на создание правильной инфраструктуры для разработки приложений — некоторой нашей внутренней базовой платформы по тому, как строить мобильный софт. Есть такой архитектурный паттерн Model-View-ViewModel, и существует несколько разных его реализаций в виде базовых библиотек. Мы на них посмотрели и написали свой шаблон MVVM. Сделали мы это потому, что у нас уже был некоторый набор базовых библиотек, с которыми мы привыкли работать, и на эти библиотеки концепция MVVM очень хорошо ложилась. В результате мы не думали, как, например, описать получение данных и ещё что-то — в основном работа шла над представлением.

    — Как устроен API, были ли с ним какие-то проблемы? Если были, то как решались?

    Для нашего приложения «Кинопоиск» написал отдельный API, отличный от оного для собственного iOS-клиента. По-хорошему, API разрабатывается под нужды клиента, и нам не были нужны вызовы, использующиеся в iOS-клиенте «Кинопоиска». Дело в том, что версия под iPhone использовала отдельные вызовы для каждого экрана — список популярных на сегодня фильмов, список популярных людей на сегодня, лента новостей и так далее. Нам же, в панорамах, все эти данные были нужны вместе, поэтому для «Кинопоиска» под Windows Phone часть запросов была переделана для более удобного, быстрого и компактного получения необходимых нам данных.

    — Как происходило взаимодействие с Microsoft Marketplace? Сразу ли допустили приложение в магазин?

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



    — Что можно посоветовать начинающим разработчикам приложений под Windows Phone?

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

    Второй совет: используйте сторонние системы управления ошибками. Есть один замечательный сервис с названием BugSense — это единая система сбора и обработки ошибок, которые возникают при работе приложения. Сервис доступен не только для Windows Phone, но и для iOS и Android. При возникновении какой-либо ошибки BugSense показывает пользователю окно о проблеме, а на сайт отправляет данные о самой ошибке и всю техническую информацию о состоянии смартфона, при котором эта ошибка возникла. В итоге на сайте вся эта информация собирается и обрабатывается, позволяя быстро реагировать на возникающие проблемы. Данный сервис гораздо удобнее того, что предлагает Microsoft в своём App Hub. Сервис платный, но имеет и бесплатную версию подписки с рядом ограничений, которой, впрочем, вполне хватает.
    Microsoft Lumia
    0.00
    Company
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 36

      –7
      Отличная статья! Эх если бы я мог за не проголосовать ;)
        –9
        Чудесно, пришли мои почитатели и заминусовали насрав в карму :) Да здравствует хабр и крысы, которые трусливо им правят :)
        +5
        скачать изображение из интернета по 3G получается быстрее, чем прочитать её из внутреннего хранилища — о таких проблемах изначально очень сложно догадаться.

        Почему так? Расскажите подробнее.
          0
          насколько я понял, вместо просто загрузки из сети идет просмотр всего кэша на наличие, потом загрузка из сети в кэш, потом загрузка из кэша. потому и дольше
            0
            Это понятно, но интересно что в этой цепочке тормозит:
            — если поиск в кэше — можно построить индекс в локальной БД.
            — после загрузки из сети можно сразу это изображение использовать, а в кэш сохранять в фоне.
              +1
              Поиск в кеше проходит достаточно быстро, а с загрузкой было сделано так — сначала изображение загружалось в кеш, а потом из кеша показывалось, то есть происходил двойной доступ к хранилищу, но экономился траффик пользователя. Конечно есть вариант сначала загрузить все изображение в память, а потом уже декодировать его в рисуемый объект и сохранять его в хранилище, однако это повышает пиковое использование памяти, что критично в некоторых ситуациях. Так вот, эта двойная операция обращения к хранилищу оказалась на удивление медленной, поэтому сейчас такое кеширование оставлено только для изображений главной панорамы, а все остальные изображения грузятся напрямую и не кешируются. Кстати, очень нехватает возможности определить сколько места занято под кеш, из за этого приходится изобретать хитрый скавенджер :(
          +3
          Приложение на самом деле получилось очень хорошим, спасибо :-)
          • UFO just landed and posted this here
            • UFO just landed and posted this here
              0
              >Стоит сказать, что мы немножко схитрили, используя не тот «голый» язык в той версии, которая
              >доступна всем, а применяли некоторые свойства для упрощения асинхронной работы с данными,
              >которые только появятся в следующей версии языка.
              Вы про async await?
              Можете расказать подробнее, как из можно использовать уже?
                +3
                С помощью Async CTP. Скачать можно по ссылке msdn.microsoft.com/en-us/vstudio/gg316360
                  +1
                  Крайне удобная вещь, я в своем приложении переписал под Async CTP 3, код получился раза в 2 короче и читабельнее.
                  Еще бы сделали HttpContent, как в WinRT, цены бы не было!
                  +1
                  Только сейчас заметил, что установленное у меня приложение Кинопоиск.Ru — неофициальное, а в Маркетплейсе есть еще одно — Кинопоиск :)
                  Официальное приложение гораздо лучше!
                  Ну и за статью — отдельное спасибо! ;)
                    +7
                    Приложение получилось довольно хорошим, но есть несколько замечаний.

                    Первое — производительность. Скроллинг панорамы заметно тормозит. Проверьте показатели FPS для compositor thread и fill rate. Навигация с какого-нибудь экрана обратно на главную страницу также занимает довольно много времени. Вероятно, какой-нибудь «тяжёлый» код выполняется в OnNavigatedTo/OnNavigatingFrom.

                    Второе — отступы в разделе «кино!» на стартовой панораме. Можно заметить, что у заголовка и контента разный margin слева. Стандартное значение — 24 пикселя

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

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

                      Жаль, пополнение Marketplace программами такого уровня идёт сильно медленнее, чем хотелось бы.
                      К моменту, когда все приятные и привычные по iOS и Android программы наконец появятся, уже WP8 успеет выйти.

                      Спасибо за статью :)
                        +3
                        Вот чего я понять не могу: есть приложение от facebook, которое работает так же плавно, как и сама система. Почему у подавляющего большинства других приложений, которые что-то грузят из сети, такие ужасные задержки и тормоза?

                        Кинопоиск тому пример. Было бы отлично, если бы это чудо-приложение не фризилось при загрузке данных из сети. А прокрутка панорамы — вообще отдельная песня.
                          +2
                          Делают много работы в UI-потоке.
                          +2
                          Отличное приложение, но над производительностью стоит поработать. Помните, что устройства первой волны имеют Adreno200 вместо Adreno205.
                            –4
                            Видимо этот разработчик давно под iOS не писал, с xcode 4 и iOS 5 стало еще проще и приятнее. Да и под андроид интерфейсы рисовать можно.
                              +6
                              Уважаемые хаброжители! Прежде всего хочу сказать спасибо за добрые отзывы и конструктивную критику — и того, и другого так мало стало в современных интернетах :-) Мы продолжаем улучшать Кинопоиск ориентируясь, в том числе, и на ваши пожелания и замечания. Большая часть проблем, связанных с производительностью, была решена в версии 1.3, отдано мы не остановимся на достигнутом.

                              Одной из причин, по которой возникают задержки, является большое количество графики, которую приложение загружает из интернета. Вся загвоздка в том, что финальное декодирование изображения производится в потоке пользовательского интерфейса (сама загрузка идет в фоне) — и вот тут-то начинаются притормаживания. К сожалению элегантного способа решения проблемы мы пока не нашли, а уж совсем откровенных «гнусных хаков» делать не хочется, так что продолжаем борьбу на этом фронте :-)

                              @andrew_kane: В обработчиках
                                +4
                                Нажал не ту кнопку и улетел недописанный текст :-(

                                @andrew_kane: В обработчиках ничего такого нет, а за пиксели спасибо, проверю шаблон. Да и кнопки действительно можно сделать побольше. Наверняка поправим в одном из ближайших релизов.
                                +3
                                Эмма прекрасна!
                                  0
                                  Уважаемый Anadale, спасибо за интервью, оно очень интересное. Но Ваше сравнение разработки под Android и WP7 не выдерживает никакой критики. Особенно часть про асинхронное программирование.
                                    +5
                                    А я не сравнивал именно асинхронное программирование у WP7 и Android. Я говорил про общую дружелюбность платформы к разработчику. Да, Android очень гибок и позволяет очень много сделать. Мне ужасно нравится сама концепция общения между приложениями в Android — у WP7 этого пока нет. Да и сама платформа постарше (в смысле зрелости). Однако то, что в VisualStudio для WP7 делается за минуту, на Android нужно тщательно описывать. Про это я и говорил. А еще при разработке под Android ужасно нехватает свойств (C# properties), LINQ, связывания и ах да! async/await, но тут я, пожалуй, остановлюсь иначе начнется холивор :)
                                      0
                                      1) Java vs C# != Android vs WP7. Хотите C# под Andriod? Есть MonoDroid в конце концов.
                                      2) Про удобство согласен, но это дело вкуса.
                                      3) … применяли некоторые свойства для упрощения асинхронной работы с данными, которые только появятся в следующей версии языка C#Этих вещей ни в iOS, ни в Android нет. Что Вы имеете ввиду? Если, Вы говорите про async/await (опять к Android не имеет отношения это чистый C#), то вводите неопытных читателей в заблуждение. Конкретной реализации async/await в java нет и, возможно, не будет, но асинхронные вычислительные операции возможны, и конечно работают очень неплохо.
                                      Спасибо.
                                        +3
                                        1) Хочу C# под Android! Но MonoDroid, по рассказам очевидцев, пока недостаточно зрелый, что ли. Сам не пробовал, поэтому врать не буду. Хотя в большинстве случаев, кстати, Android == Java && iOS == ObjectiveC.
                                        2) Да к этому удобству так привыкаешь быстро…
                                        3) Еще раз, я не спорю, что асинхронные паттерны (begin/callback/end) есть сейчас в любой мобильной платформе. Я говорю именно про конкретную реализацию в том инструменте, который наиболее часто используется для разработки под конкретную платформу. Вот у VS/C# есть async/await который, согласитесь, уж всяко лучше тех конструкций, которые придется писать на Java || Objective C. Да, мы Челябинские металлурги олдскульные хардкорщики, не обломимся и напишем таки 4 экрана коллбеков и при этом не запутаемся в них. Но этот гадский инструмент VS лишает нас этого удовольствия и заставляет писать коротко и понятно :)
                                          0
                                          1) Ok. Закрыли.
                                          2) Ok. Закрыли. LINQ наше всё)
                                          3) Вот у VS/C# есть async/await который, согласитесь, уж всяко лучше тех конструкций, которые придется писать на Java. Конечно, всё зависит от решаемой задачи. Не факт, что эта конструкция будет лучше работать.
                                          3.1) писать коротко и понятно. Не соглашусь, что коротко и понятно можно связывать. И вообще коротко не значит лучше. Как пример приведу слово lock из C#! Так что посмотрим на итоговую реализацию и подводные камни, которых скорее всего будет навалом.
                                          По итогу 3) Ok. Закрыли.
                                          Спасибо ещё раз.
                                            0
                                            позвольте вторгнуться в ваш холивар.

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

                                            я не разбираюсь в механизме async/await, но мне интересно было бы сравнение, если вы конечно сталкивались с тем, что я описал
                                              +1
                                              Тут разговор шел, в основном, о синтаксическом сахаре паттерны Asynchronous Callbacks, который предоставляет компилятор C#. Если коротко, то код, который на «чистом» C# выглядит как цепочка методов (начало обработки/завершение обработки) с использованием Async CTP превращается (для разработчика) в один метод. А «на самом деле» компилятор сам пишет те самые «начало обработки» и «завершение обработки». В простых ситуациях это само по себе приятно, а особенно это приятно, например, когда по результатам одной асинхронной операции нужно запустить еще несколько. Такой сценарий, кстати, часто встречается — например мы получаем от сервера информацию о фильме и стартуем загрузку кадров из фильма.
                                                0
                                                понятно, спасибо
                                          0
                                          Вы использовали async/await в проекте? В VS11 разрабатывали?
                                            +2
                                            Нет, к сожалению VS11 не поддерживает разработку под Windows Phone 7. Это была VS2010 & Async CTP 3.
                                        +1
                                        Очень не хватает функционала выбора кинотеатра и показа идущих уже в нем сеансов, а не наоборот, как сделано сейчас(сначала фильм, а потом уже кинотеатры)
                                          +5
                                          (записывает в блокнотик)
                                            0
                                            А TODO для фильмов будет? (что хочу посмотреть, и галочки когда посмотрел, и история что смотрел,… =)
                                          +1
                                          Будет обязательно, но, к сожалению, не могу пока сказать дату релиза. Прошу отнестись с пониманием — www.kinopoisk.ru — это большой, удивительно мощный проект, с большим количеством функционала. Хочется аккуратно переводить его в мобильный вид, чтобы с одной стороны представить все функции, а с другой — не сделать приложение чересчур громоздким и выбивающимся из экосистемы. Так что «семь раз отмерь — один раз запрограммируй».

                                          Only users with full accounts can post comments. Log in, please.