<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Рассказы о своих проектах</title>
    <description>Любой наш подписчик, в том числе и вы, может поделиться опытом создания собственного интересного проекта. Рассказы наших читателей публикуются в этой рубрике.</description>
    <link>https://tproger.ru/projects</link>
    <atom:link href="https://tproger.ru/projects/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Tue, 06 Oct 2026 02:43:22 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Рассказы о своих проектах</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Мой pet-проект: видеоплеер с переводимыми субтитрами LinguaPlayer</title>
      <link>https://tproger.ru/projects/moj-pet-proekt-videopleer-s-perevodimymi-subtitrami-linguaplayer</link>
      <comments>https://tproger.ru/projects/moj-pet-proekt-videopleer-s-perevodimymi-subtitrami-linguaplayer?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[barinbritva]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/moj-pet-proekt-videopleer-s-perevodimymi-subtitrami-linguaplayer</guid>
      <description><![CDATA[<p>История видеоплеера, который переводит слова и целые фразы прямо во время просмотра фильма: идея выросла из изучения английского по оригиналам.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/moj-pet-proekt-videopleer-s-perevodimymi-subtitrami-linguaplayer">Мой pet-проект: видеоплеер с переводимыми субтитрами LinguaPlayer</a>»</p>]]></description>
      <category><![CDATA[Пост пользователя]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 17 Feb 2021 07:16:22 GMT</pubDate>
      <content:encoded><![CDATA[<p>У меня было достаточно много pet-проектов разной степени готовности. Среди них: социальная сеть для писателей, генератор CSS-спрайтов, Телеграм бот для знакомств по интересам и многое другое. Сегодня речь пойдёт о моей последней разработке.</p><p>Как многие в наши дни, я учу английский. Думаю, так же многие знают, что эффективным подходом в этом деле является максимальное погружение в среду. Интерфейс телефона на английском, записи в блокноте на английском, смотреть кино на английском с английскими субтитрами. Смотря кино в оригинале, рано или поздно возникает потребность перевести то или иное слово или фразу, которые мелькают на экране каждые несколько минут. Без них вообще ничего не понятно.</p><h2>Идея проекта</h2><p>Так у меня и родилась идея видеоплеера с переводимыми субтитрами. Приложение позволяет переводить слова и целые фразы прямо во время просмотра кино. С ним отпадает необходимость переключаться между приложениями или брать в руки смартфон. Знакомьтесь – <a href="http://linguaplayer.barinbritva.com/">LinguaPlayer</a>.</p><p>Схема работы простая. Пользователь открывает файл с фильмом и файл субтитров. Смотрит фильм как обычно. Однако теперь в его распоряжении помимо стандартных горячих клавиш есть клавиши для перевода каждого слова по отдельности, перевода целых предложений, перемотки от реплики к реплике. Также присутствует перевод посредством наведения курсора мыши на слова или выделения нужного куска текста. Приложение доступно для Windows и MacOS. Все подробности можно почитать <a href="https://linguaplayer.barinbritva.com/">на страничке приложения</a>.</p><h2>Технологический стек</h2><p>Плеер реализован на платформе <a href="https://www.electronjs.org/">Electron</a>, т. е. по сути это браузер Chromium внутри которого бежит обычное веб-приложение. На этой технологии построено большое количество различных приложений – удачных и не очень. Наиболее известные примеры это Visual Studio Code, Skype, Slack. Electron предоставляет некоторые системные API, которые недоступны JavaScript, запущенному в обычном браузере. Это позволяет делать приложения более функциональными и близкими по возможностям и пользовательскому опыту к нативным. Что касается всего остального – разработчику доступен абсолютно любой стек, применимый в вебе. Будь то чистый JavaScript, Angular, jQuery, Vue – что угодно.</p><p>Для LinguaPlayer я выбрал привычный стек, с которым работаю каждый день: TypeScript, React, MobX, Webpack. Я планировал сделать прототип за вечер, так как задача выглядела легко: дал приложению файл с видео и файл с субтитрами, прикрутил переводчик и готово. С этой частью проблем не возникло. Однако, как оказалось, встроенный в браузеры движок отображения субтитров не имеет никаких средств взаимодействия с текстом реплик. Что я имею в виду. Реплики титров хоть и появляются поверх видео, но в DOM никаких упоминаний о них нет. Другими словами, нет возможности распарсить текст, разбить его по словам и предложениям, повесить обработчики нажатий клавиш или зарегистрировать события мыши.</p><h2>Решение интересных задач</h2><p>Таким образом, мне пришлось решить две задачи. Первая — это парсинг srt-файлов с титрами с последующей синхронизацией реплик с видеопотоком. Вторая – разбивка реплик на токены, чтобы была возможность взаимодействовать с каждым словом и предложением по отдельности.</p><p>Для парсинга титров я взял библиотеку <a href="https://github.com/osk/node-webvtt">node-webvtt</a>. Для синхронизации титров изначально я написал логику «в лоб». Подписавшись на событие video-элемента «<a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/timeupdate_event">timeupdate</a>», я просто ходил по массиву реплик и сравнивал текущее время видео с временем реплик. Однако, событие «timeupdate» срабатывает четыре раза за секунду, а реплик в среднем фильме несколько тысяч. Всё это дело жутко тормозило.</p><p>Для оптимизации данного процесса я сделал простой hash map. Его ключом является секунда (целая, без миллисекунд), а значением – массив номеров реплик, которые должны быть показаны в эту секунду. Выглядело это примерно так:</p><p>В каждой секунде может быть от 0 до примерно 4 реплик — человек имеет ограничения и вряд ли сможет прочитать большее количество текста за секунду. Таки образом, при обновлении времени воспроизведения, всё что необходимо сделать, это выделить из него целую часть и обратиться с этим значением к hash map. Если на этой секунде реплик нет, значит ничего больше не делаем. Если на этой секунде есть реплики, то итерируемся по вернувшемуся массиву и ищем, какая именно реплика должна быть показана сейчас. Так как на секунду может быть до 4 реплик, то цикл завершается быстро. Возможно, многим будет проще воспринять описанный алгоритм в виде кода:</p><p>Таким образом, вместо того, чтобы 4 раза в секунду обходить массив из тысяч элементов, необходимо лишь сделать одно обращение по индексу, и пройтись по массиву длинной от 1 до 4.</p><p>Перед тем как выводить получаемые реплики я разбивал их на предложения и на слова с помощью библиотеки <a href="https://github.com/parmentf/node-sentence-tokenizer">node-sentence-tokenizer</a>. Всё это дело я оборачивал в элементы div с классами sentence и word соответственно, чтобы иметь возможность вешать на них события в дальнейшем и выполнять перевод. Вот так выглядит код:</p><p>Далее я прикрутил <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/translator/">Microsoft Translator</a> для осуществления перевода, и плеер для изучения английского был готов.</p><h2>Чего не хватает проекту, чтобы развиваться</h2><p>Конечно, на данный момент плеер даже не является MVP, это скорее proof of concept. И у меня есть множество идей по развитию данного проекта. В первую очередь хочется добавить поддержку словарей, например английского и англо-русского, а также интегрировать Urban Dictionary для распознавания сленга, а также различных современных слов и фраз. Во вторую очередь есть мысль реализовать интеграции с сервисами по изучению иностранных языков, такими как <a href="https://lingualeo.com/">LinguaLeo</a> или <a href="https://skyeng.ru/">Skyeng</a>. Это позволило бы добавлять незнакомые слова в персональный словарь на сервисе и учить их позже. Или же импортировать свой словарь в <a href="https://apps.ankiweb.net/">Anki</a>. Также можно было бы добавить поддержку изучения других языков.</p><p>Но, прежде чем приступить к реализации задуманных функций, необходимо решить ряд технических и концептуальных проблем. Моя изначальная идея заключалась в том, чтобы можно было смотреть свои старые и излюбленные фильмы, пылящиеся на жёстком диске. И здесь возникает серьёзная техническая проблема, а именно – слабая поддержка кодеков в браузере Chromium. Глядя на <a href="https://www.chromium.org/audio-video">список поддерживаемых форматов</a>, можно заметить, что по факту в приложении можно проиграть лишь файлы с видеокодеком H.264 и аудиокодеком FLAC либо MP3. Нужно очень постараться чтобы найти именно такой файл. Да никто и не будет заниматься подобным – сейчас все избалованы стриминговыми<br />сервисами. Не говоря уже о вопросах лицензирования, что является большой, концептуальной проблемой.</p><p>Таким образом, главный блокирующий фактор сейчас – это контент. Он должен без проблем играть в приложении, должна быть возможность легко и быстро его получать, а также, он не должен нарушать лицензии и авторские права. Как только удастся решить вопрос с контентом, я с радостью продолжу работу над проектом. А пока предлагаю всем энтузиастам <a href="https://linguaplayer.barinbritva.com/">скачать и попробовать</a> концепт-версию приложения.</p>]]></content:encoded>
    </item>
    <item>
      <title>Мой pet-проект: создание турнирных таблиц</title>
      <link>https://tproger.ru/projects/moj-pet-proekt-sozdanie-turnirnyh-tablic</link>
      <comments>https://tproger.ru/projects/moj-pet-proekt-sozdanie-turnirnyh-tablic?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/moj-pet-proekt-sozdanie-turnirnyh-tablic</guid>
      <description><![CDATA[<p>GitHub1s открывает репозиторий в онлайн-версии VS Code после добавления «1s» к слову github в адресе; для Chrome также доступно расширение.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/moj-pet-proekt-sozdanie-turnirnyh-tablic">Мой pet-проект: создание турнирных таблиц</a>»</p>]]></description>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 11 Feb 2021 13:22:58 GMT</pubDate>
      <content:encoded><![CDATA[<p>Мы в Ижевске регулярно проводим турниры по шахматам и шашкам. Обычно турнир у нас растягивается на несколько дней и нужно где-то хранить результаты. Для круговых турниров мы создавали файл в гугл-таблицах. Для швейцарских пробовали разные веб-сервисы и программы. И всегда сталкивались с какими-нибудь недостатками.</p><p>Приложения для компьютера неудобны для публикации результатов и крайне сложны. Онлайн-сервис имел неудобный интерфейс. Несколько раз приходили мысли написать свой веб-сервис. И вот наконец идея воплотилась в реальность. В конце 2018 года был создан сайт <a href="https://swisssystem.org/">SwissSystem</a>.</p><h2>Как работает сервис</h2><p>На сайте можно прочитать, какие возможности предоставляет сервис, поэтому тут опишу технические особенности реализации.</p><p>Использованные технологии: ASP.NET Core 2.1, Entity Framework, Bootstrap, Maria DB, Nginx, Linux.</p><p>Я впервые размещал ASP.NET приложение на Linux и это было интересно. В остальном же были использованы достаточно стандартные для ASP.NET решения. Из коробки можно было использовать авторизацию по логин-паролю и через социальные сети.</p><p>Основная сложность была в алгоритмах. Помню, в шахматной школе не каждый тренер мог провести жеребьевку по швейцарской системе. Это именно жеребьевка, поскольку есть элемент случайности. К счастью, я нашел в интернете движок по жеребьевке на JAVA. Это очень помогло, но не до конца. Нужно было уметь правильно подсчитывать очки и тут есть определенные сложности и варианты подсчета (связано с <a href="https://chess.stackexchange.com/questions/24915/how-is-buchholz-score-calculated-in-a-swiss-tournament">правилами</a> ФИДЕ по подсчету коэффициента бухгольца).</p><p>Данные хранятся достаточно просто. Весь турнир сохраняется в виде JSON. Для обеспечения многопоточного изменения поддержана версионность. Операция изменения применяется если прочитанная версия равна версии данных в базе. Если версия изменилась, то данные пересчитываются и применяются еще раз.</p><h2>Как сервис стал популярным у иностранных шахматистов</h2><p>Первое время я пробовал раскручивать сайт и потратил где-то 2000 рублей. Было впечатление, что шахматная жеребьевка мало кому интересна. Статистика по ключевым словам в Google это подтверждает. В итоге решил прекратить раскрутку.</p><p>Но каким-то образом раскрутка дошла до Бразилии. Одна девушка пользовалась моим сайтом, но ее печалило, что  интерфейс не на ее родном языке. Друг этой девушки решил ее удивить и написал мне, что хочет перевести мой сайт. Так появился португальский язык на SwissSystem.org. Думаю, ребята поженились, жили долго и счастливо. ?</p><p>Осенью 2019 внезапно на меня вышел Мато Джелик (Mato Jelic) из Австралии, который хотел купить компоненту и встроить ее в свой сайт на вордпрессе. Я ему долго объяснял, что это практически невозможно и нужно будет покупать нормальную виртуальную машину, а не хостинг на PHP. В итоге мы всё-таки договорились и была создана <a href="https://swissonlinetournament.com/">копия сайта</a>. Это был единственный существенный доход, который покрыл расходы на хостинг на много лет вперед.</p><p>За последний год в среднем сайт посещает около 500 человек в месяц. В январе 2021 года преимущественно посещают игроки из Великобритании, Индии и США. Организатор турниров в Великобритании пару раз давал пожертвования в виде пары десятков фунтов. Есть идея переписать сайт на ReactJS и выпустить мобильное приложение, но всегда находятся какие-то другие дела.</p>]]></content:encoded>
    </item>
    <item>
      <title>Мой pet-проект: сервис по сбору и категоризации объявлений о продаже телефонов</title>
      <link>https://tproger.ru/projects/moj-pet-proekt-servis-po-sboru-i-kategorizacii-objavlenij-o-prodazhe-telefonov</link>
      <comments>https://tproger.ru/projects/moj-pet-proekt-servis-po-sboru-i-kategorizacii-objavlenij-o-prodazhe-telefonov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/moj-pet-proekt-servis-po-sboru-i-kategorizacii-objavlenij-o-prodazhe-telefonov</guid>
      <description><![CDATA[<p>Ведущий Fullstack-разработчик Михаил Альфа вспоминает свой pet-проект, написанный преимущественно на PHP, и обстоятельства, с которых началась его история.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/moj-pet-proekt-servis-po-sboru-i-kategorizacii-objavlenij-o-prodazhe-telefonov">Мой pet-проект: сервис по сбору и категоризации объявлений о продаже телефонов</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 05 Feb 2021 07:14:44 GMT</pubDate>
      <content:encoded><![CDATA[<p>Добрый день! Меня зовут Михаил Альфа, я являюсь ведущим разработчиком. Сам себя определяю как Fullstack-разработчик, т. к. писал и пишу практически все, что сейчас популярно писать — Frontend, Backend и Mobile. Мой технологический стек, возможно, не слишком обширен:</p><ul><li>Frontend на Vue или React;</li><li>Backend: Node.js, особенно нравится в сочетании с Nest.js;</li><li>Mobile: Flutter — one love;</li><li>Ну и, конечно, все это (кроме mobile) — обмазано TypeScript, без него точно никуда​.</li></ul><p>Еще я посматриваю на таких кракенов, как Rust, но глаза пока боятся нырять в эту нору. Когда-то раньше я писал и на PHP. Это было на Symfony 3 и 4 версий (даже и 2 иногда). И эта история будет об одном моем pet-проекте, написанном, в основном, на PHP. Прежде, чем начать выкладывать сей опус я пытался найти его исходники в своих репозиториях. К сожалению — безуспешно. Вероятно, в очередном приступе синдрома самозванца, ночью, после трудового будня я решил, что пора избавиться от гнетущего наследия, взглянуть на которое без слез было бы нельзя. И удалил все, что мне казалось когда-то важным, перспективным, на что я тратил время, огромное количество времени, возможно, и душу.​ Но хватит лирики, едва ли эта статья будет интересной, если в ней и будет, что только моя рефлексия. Давайте сменим настроение (я сменю) и помчимся вперед!​</p><h2>Предыстория</h2><p>​Путь к данной истории начался в 2014-м году, я учился в вузе и был вынужден уйти в академический отпуск из-за финансовых трудностей, появившихся в моей семье. Устроившись на неплохую работу, я начал зарабатывать первые в своей жизни существенные суммы (существенные, разумеется, для вчерашнего студента, единственным заработком которого до этого была стипендия и редкие подработки, да помощь с выполнением различных задач из вуза одногруппникам — за ?, разумеется). Работа спорилась, время шло и наступил долгожданный момент, когда можно было снова вернуться к учебе.​</p><p>Было очень тяжело терять то, к чему успел привыкнуть, привязаться, что стало таким родным и близким. И нет, я говорю не о радушных и прекрасных коллегах, я говорю — о денежках.​ Так повелось, что я всю жизнь интересовался мобильными телефонами / смартфонами, эдакий техно-гик. И разбирался я в них отлично, пользовался, конечно, далеко не флагманскими моделями, но самым лучшим, что только можно было купить за те финансы, которые у меня пели романсы. Тут-то и появилась идея — применить свои знания на практике. Кто-то задастся вопросом — как применить такие знания на практике? Идти в какой-нибудь магазин электроники, да продавать телефоны? А вот и нет! Идея, действительно, была в том, чтобы продавать телефоны, да только не чьи-то, где-то, генерируя чью-то прибыль, а продавать свои. ​Неосознанно я занимался этим и раньше, только не придавал этому какого-то особенного значения. Например, мне удалось через цепочку обменов, продаж и покупок, без дополнительных денежных вливаний превратить свой старенький Sony Xperia Neo в Sony Xperia Z1.​</p><p>​​​​​​Провернуть эти операции я смог за пару месяцев, и был несказанно счастлив, хоть в тот момент, когда это и произошло, флагманом был Sony Xperia Z2, а вот-вот должен был выйти и Z3, но я утешал себя тем, что и Z3 будет практически таким же, как мой Z1, да и вообще, до этого у меня был Neo.​ Так вот, вполне простая идея начала воплощаться в реальность. В народе таких людей принято называть перекупщиками. И мне пришлось стать таким. Алгоритм данной деятельности был довольно простым — ищешь телефон с лучшими на данный момент характеристиками, как можно дешевле покупаешь (нередко еще и неплохо сбивая цену), затем выставляешь объявление и продаешь. Разницу — в карман. Безусловно, есть и риски и весьма немаленькие. Я покупал и дефектные смартфоны, и такие, которые становились дефектными спустя буквально пару дней, и это все приносило существенные убытки.​ Скажу честно, однажды я даже купил по почте топорную подделку iPhone 5S, поведясь на красивую историю о том, что человеку срочно были нужны деньги на какое-то важное дело (на самом деле я повелся на низкую цену, а алчность просто застилала мои глаза). И каково же было мое удивление, когда я прямо на почте, дрожащими, мокрыми от волнения и страха ладошками открывал коробку с посылкой, и увидел внутри … не iPhone 5S ?. Посылка была с наложенным платежом и почтальон лишь сочувственно пожала плечами.​</p><p>Мы ничего не можем сделать. Посылка получена, деньги мы вернуть не можем. А ведь я «подстраховался» — попросил продавца отправить посылку с описью. Ну, опись действительно была:</p><ul><li>телефон;</li><li>кабель для зарядки;</li><li>коробка;</li><li>зарядка​.</li></ul><p>Не прикопаешься в общем.​Что было дальше — история на еще один рассказ, но кратко — я приобрел опыт. Как известно, опыт — это то, что мы получаем вместо того, что хотели получить.​</p><h2>Ближе к делу</h2><p>​Дни летели, я учился. Кодил учебные проекты на самые разные темы, совершенно никак не связанные с тем, что предстоит делать в реальном мире на реальной работе. По-прежнему перепродавал телефоны, еще и ноутбуки пошли в копилку. И что-то у меня в голове щелкнуло:​ надо автоматизировать свою деятельность.​ По крайней мере настолько, насколько это возможно. Идея была такой — весь алгоритм, который мне нужно было реализовывать, чтобы называть эту деятельность успешной, был весьма прост. Нашел лучшее по минимальной цене, сторговался, продал дороже. Нюансы начинаются в том, как понять — что есть лучшее за эту цену? К примеру, когда на рынке iPhone 5S уже не являлся «крутым» телефоном, его ценник на рынке досок объявлений был, условно, 15 000₽ за версию на 16Gb. Соответственно, мне было нужно найти эту модель за сумму, меньшую, чем 15 000₽. При этом средний срок продажи телефона составлял от недели до двух (это сильно зависело от модели, производителя, хайпа вокруг марки). А за это время, особенно в преддверии анонсов новых моделей, цена конкретного устройства могла упасть настолько, что ни о какой прибыльности и речи идти не могло.​</p><h2>Проект</h2><p>​Что я сделал? Первым делом было нужно собрать данные, которые были необходимы для анализа. Для этого я начал писать grabber — некоего паука, который ходил по доскам объявлений и искал интересующие меня категории продаваемых товаров, а именно: смартфоны и ноутбуки. Забегу вперед и скажу, что все, что я делал — использовал только в личных целях, никому эти данные не передавал, да и не захотел бы этого никогда делать, уж сильно они казались мне ценными.​</p><p>Затем все найденное добро, а это были буквально html-страницы, очищалось от шелухи, старательно сохранялось в базу данных и структурировалось. Было интересно все: фотографии устройств, текстовое описание, название объявления, категория, ссылка на страницу, цена, ну и контакты продавца. С последним было немного тяжело, некоторые из площадок не отдавали номера мобильных телефонов продавцов напрямую, при запросе номера — он возвращался в виде картинки, она была чистой, и можно было бы прикрутить OCR, но в тот момент моего скила было недостаточно для таких излишеств, зато в избытке было изобретательности. Поэтому я нашел лазейку в мобильной версии у одной из досок объявлений — там номер телефона возвращался строкой и прекрасно пополнял мою персональную коллекцию.</p><p>У другого источника информации API вообще было открытым, чему я был несказанно рад — намного приятнее работать с JSON, чем вычленять нечто селекторами из HTML, да еще и на PHP. А верстка, как оказывается, менялась с завидной регулярностью, но обычный пользователь этого не увидит.​ Дальше больше — вот у меня есть свое злато, а что с ним делать? Нужно же как-то понять, что из этого мне может быть полезно, а что — совершенно точно нет. Для начала предстояло решить новые задачи.​</p><h2>Новые задачи</h2><p>​Как оказалось, пользователи, выкладывающие свои объявления на площадках, могут называть свои устройства абсолютно как угодно. К примеру, вот вариации того же злополучного iPhone 5S:</p><ul><li>Продается iphone 5s;</li><li>IPHONE 5S;</li><li>Айфон 5с;</li><li>Продается телефон;</li><li>5S на 32​;</li></ul><p>И так далее…​ Вариаций — великое множество, но и это еще не все. В примере выше проскользнула еще одна деталь: 32. 32, Карл! Оказывается, что iPhone 5S может быть как на 16Gb, так и на 32, а еще и на 64Gb! Есть, конечно, и цвета, но они, к счастью, не слишком влияют на цену. Но памяти оказалось достаточно. И она влияет сильно. Как вы понимаете — второй задачей после сбора информации стала категоризация всего собранного каталога. Площадки предоставляли малую толику информации, например, я мог быть почти уверен, что если телефон был получен из категории устройств iPhone — то это, скорее всего, iPhone. Конечно, не всегда, некоторые люди отчаянно запихивали свои товары в чужие категории, видимо, очень не хотели расставаться со своими любимыми игрушками, но в большинстве случаев на эту кроху полезности можно было положиться.​</p><p>Тут, возможно, найдутся люди, которые закидают меня тряпками (а я буду рад, т. к. в данный момент у меня решается такая же проблема, но в другой предметной области), и скажут — что так как я, делать не стоило, а стоило вот так! (Как, кстати? А кроме нейронок?) ​Ну а я решил эту задачу таким способом: сначала было необходимо полностью очистить названия от всех посторонних символов — специальные знаки, эмодзи, пробелы, кириллица. Был составлен словарь, который постоянно пополнялся, благодаря которому можно было преобразовывать «афон» в «iPhone». Затем эта очищенная строка сравнивалась со всеми остальными имеющимися строками в базе, которые еще не были в сравнении с текущий, так же очищенными от всякого… ну вы поняли.</p><p>Сравнение было не простым, а с использованием алгоритма схожести строк — расчетом <a href="https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D1%81%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D0%B5_%D0%9B%D0%B5%D0%B2%D0%B5%D0%BD%D1%88%D1%82%D0%B5%D0%B9%D0%BD%D0%B0">расстояния Левенштейна</a>. Это было весьма долго и неэффективно. ​​Данных было очень много (для моего домашнего компа) — сотни тысяч записей, и все их нужно было кластеризировать. Но в итоге у меня начали образовываться группы объявлений, которые были похожи друг на друга. Точность на этом моменте была относительно невысокой — порядка 60–70%, но и это было неплохо. Затем в ход пошли не только заголовки объявлений, но и описания. Довольно часто «Айфоны на 32 гига» в описании назывались нормальным именем (в основном благодаря тому, что люди могли просто копировать описания телефонов из магазинов и использовать в своих объявлениях), благодаря этому точность удалось повысить до стабильных 70–75%. Но мало, мааало!</p><p>Дальше пошли эксперименты (за утерю которых мне сейчас очень обидно) — я разбивал эти строки на некие токены определенной длины, с перекрытием в несколько символов, и сравнивал уже их, считал количество совпадений, выделял определенные токены и назначал им веса, ведь важность совпадения «ipho» в двух строках выше, чем какой-нибудь «e32gb», время обработки росло все быстрее и быстрее, но росла и точность. Насколько я помню, у самого успешного варианта была точность &gt; 85% в среднем!​ После этого качеством категоризации можно было гордиться и у данного проекта появилась хоть какая-то практическая ценность — можно было находить интересные модели смартфонов и сравнивать их по ценам, по прежнему вычитывая описания и просматривая фотографии. Ведь наш айфон может стоить на 10% ниже рынка не только потому, что продавцу срочно нужны деньги, но и потому, что в описании указано «пару раз падал, но выглядит как новый», ага.​</p><p>Следующая задача — нужно как-то понять, стоящий ли перед нами аппарат — вернее, стоит ли он своих денег в конкретный момент времени. Тут начинается полное безумие — нейронные сети на PHP.​​ Я даже помню имя этого безумия — <a href="https://www.php.net/manual/ru/book.fann.php">FANN</a>. Решение было таким: сначала я, как представитель экспертной группы «людей, разбирающихся в том, стоит ли данный телефон своих денег», прочитал несколько тысяч описаний к самым разным телефонам, оценив, насколько хорошим является данный экземпляр. Для этого была даже создана специальная мини-страничка с оцениванием — там было название телефона, описание и 10 кнопок от 1 до 10. Нажал кнопку — оценка записана, читай следующее объявление. Заняло это около недели. Чтиво было занятным ?. А затем, я просил своих товарищей, одногруппников (про толоку я тогда не знал, или ее еще даже не было, не помню), чтобы и они оценили то, что оценил я. Для этого им в случайном порядке предлагалось оценить по той же шкале те объявления, что и оценивал я. Задача звучала примерно так: «Насколько бы вам захотелось купить этот телефон, если бы у вас точно были на него деньги?».​ Каким-то образом удалось собрать более-менее приемлемое количество дополнительных оценок, после чего была благополучно написана и обучена нейронка (я специально опускаю технические подробности сего аспекта, т.к. мои воспоминания об этом примерно такие: «Боже, что за чушь я тогда писал»).</p><p>Но самое интересное — она работала! Работала на таком уровне, что я смог начать ее использовать. То есть я действительно мог, к примеру, отсортировать список телефонов по данной оценке, и те из них, что были с 8+ оценкой — можно было покупать хоть сейчас! Да, точность не всегда была на высоте, например: кто-то мог выставить на продажу какой-нибудь ZTE Axon, статистики по которому совсем немного, и продается данный аппарат раз в месяц. И вот человек, который его выставляет, решает, что можно было бы его не только продать за 12 000₽, но и поменять на iPhone 5S 32Gb Space Gray. Вау! К сожалению, таких всплесков тоже было немало, и отлавливать их приходилось вручную. Но, как вы понимаете, вместо заветного айфончика в топе мог быть и аксон, который купить-то можно быстро, но продавать его будешь полгода :)​ Но в целом система работала и очень сильно помогала!</p><p>Но и это еще не все, с учетом того, что работала она к этому моменту, как минимум в качестве сборщика информации, больше полугода — было накоплено и просто много информации для статистики. Например, теперь можно было строить примерные прогнозы того, как сильно и как часто опускается цена на каждый из имеющихся на рынке телефонов. Можно было иметь представление о том, как долго продается каждая конкретная модель. К слову, считалось это так: когда объявление впервые попадало в базу данных сервиса — это был день, с которого начинался отсчет времени, необходимого на продажу. Затем, когда это объявление исчезало из выдачи, происходила проверка — переход на страницу конкретного объявления, и если эта страница не была страницей активного объявления, значит устройство, скорее всего, продано. Вот эту дату мы и запишем как дату продажи, и сможем понять, что наш айфоша продается по такой цене — неделю, по такой — две, а вот по такой — 3 дня.</p><p>Правда тут тоже были подводные камни — некоторые объявления блокировались, т. к. оказывались мошенническими, и какой-то набор данных сервиса был таким образом испорчен, но после обработки всех критических ситуаций и данная информация начала приносить очень большую пользу. Все что оставалось — это следить за появлением новых объявлений, убеждаться, что они действительно стоящие, а затем постараться купить заветный товар раньше других людей.</p><p>​Еще одним плюсом от использования данного сервиса являлось то, что информацию о таких товарах удавалось получать практически в реальном времени. После того как все группы товаров были созданы, для анализа одной (или нескольких) новых записей требовалось совсем немного времени, поэтому, как только объявление появлялось на площадке — оно в течение пары минут оказывалось и в аналитическом сервисе.​</p><p>Эта история — история пути, а не цели, к которой я стремился. А планы были грандиозными — хотелось сделать рекомендательный сервис по подбору устройств на б/у рынке, хотелось расширить технологический парк — анализировать не только смартфоны, но и множество других видов техники. К слову, в те же ноутбуки я пытался углубиться, но основной фокус был именно на телефонах. Но с течением времени, данная деятельность перестала помещаться в ограниченное время дня — даже для того, чтобы ездить за телефонами, нужно много времени, а если учесть, что действительно интересные варианты могут покупать в течение считаных часов и нужно быть всегда на подхвате, основная работа начинает немного мешать. Поэтому, перестав заниматься перепродажей телефонов я и потерял интерес к конкретному проекту, но тот опыт, что я получил, создавая его, останется со мной.​</p><p>Что же, кажется, пора подводить итоги. Делать выводы. Ну или нет ?. Шутка. А вывод, собственно, такой — если разработчик имеет в своем арсенале некие домашние проекты, то он может обстреливать на них самые новые технологии, использовать самые смелые идеи, а также делать то, что в продакшене делать бы точно никогда не стал. Pet’ы позволяют существенно расширить кругозор, улучшить навыки, сменить стек, в конце концов, если ваш текущий вам надоел, а опыт на новом где-то набивать надо. Поэтому я однозначно советую всем писать код не только на работе, за деньги, но и дома — для себя! В итоге, новые навыки, знания и опыт только делают вас ценнее, а значит и дороже на рынке, а значит — домашние питомцы тоже приносят вам доход. Всем удачи!</p>]]></content:encoded>
    </item>
    <item>
      <title>Использование паттерна data access object в клиентском приложении</title>
      <link>https://tproger.ru/projects/pattern-data-access-object</link>
      <comments>https://tproger.ru/projects/pattern-data-access-object?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Vladimir Gabrinevski]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/pattern-data-access-object</guid>
      <description><![CDATA[<p>Паттерн Data Access Object организует доступ к данным Android-приложения: пользователи, шаблоны и осмотры работают через отдельные интерфейсы API сервера.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/pattern-data-access-object">Использование паттерна data access object в клиентском приложении</a>»</p>]]></description>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 24 Jul 2017 11:54:07 GMT</pubDate>
      <content:encoded><![CDATA[<p>Рассказывает Стенли Винтергрин, наш подписчик</p><p>Всем привет! В этой статье я поделюсь своим опытом по работе с базой данных в приложении для Android. Это будет один из вариантов реализации паттерна <a href="https://ru.wikipedia.org/wiki/Data_Access_Object">data access object</a> на языке Java.</p><h2>Постановка задачи</h2><p>Заказчик, который занимается предстраховыми осмотрами автомобилей, хочет автоматизировать рабочий процесс. Задача приложения — собирать и передавать на обработку данные об автомобиле.</p><p>Проектирование показало, что у приложения будет 3 модуля:</p><ol><li>Авторизация.</li><li>Проведение осмотра.</li><li>Синхронизация.</li></ol><h2>Сущности</h2><p>Есть сущности, которыми мы будем оперировать в коде, опираясь на техзадание этого проекта и API сервера: пользователи, шаблоны и осмотры. Пользователи получают от сервера шаблон сценария и проводят осмотр. Составленный на основе полученной информации готовый осмотр отправляется на сервер.</p><h2>Доступ к данным</h2><p>Выделим для этих сущностей 3 вида доступа. В данном случае это будут следующие интерфейсы:</p><ul><li>UsersAccess — для пользователей;</li><li>ScenariosAccess — для шаблонов сценариев;</li><li>InspectionsAccess — для осмотров.</li></ul><p>Далее создадим data access object, который предоставляет доступы. Этот интерфейс будет выглядеть так:</p><p>Теперь у нас есть все необходимые виды доступа, но пока они не запрашивают и не изменяют данные.</p><h2>Модели данных</h2><p>Создадим модели, которые будут описывать необходимые операции с сущностями. Начнём с пользователей. Что в данном проекте нужно с ними делать? В техзадании сказано, что одним устройством могут пользоваться разные люди, поэтому нужно хранить список пользователей. Также известно, что пользователи ничего не будут знать друг о друге. В таком случае можно создать модель:</p><p>Очевидно, что у нас также должны быть модели ScenariosModels и InspectionsModels. Они будут оперировать несколькими сущностями. Шаблон будет состоять из типов этапов осмотра, а типы этапов из типов элементов. Нужно организовать возможность добавлять данные в базу, получать шаблон по уникальному ключу и строить список типов этапов по ссылке на шаблон и список типов элементов по ссылке на тип этапа:</p><p>Готовый осмотр будет состоять из элементов, а элементы из данных. Нужно реализовать возможность получения осмотра по ключу, построение списка черновиков осмотров, списка готовых осмотров, а также возможность удалить осмотр. Таким образом, для всех подсущностей осмотра создадим модели:</p><p>Теперь передадим доступам их модели:</p><p>Теперь наш data access object готов.</p><h2>Использование data access object</h2><p>У нас есть три модуля. Каждый из них получит доступ только к той области базы данных, которая необходима для выполнения его задач.</p><p>При авторизации будет происходить работа только с пользователями. Поэтому модуль авторизации получит интерфейс UsersAccess. Поскольку необходимы операции только с одной сущностью, можно оставить этой модели доступ только к таблице Users.</p><p>При прохождении осмотра нужно опираться на шаблон и на его основе составлять объект осмотра. Придется определять, как отображать этапы осмотра и его элементы, т. е. в этом случае необходим полный доступ ко всем сущностям шаблона и сущностям осмотра. Этому модулю можно передать ScenariosAccess вместе с InspectionsAccess.</p><p>Во время синхронизации необходимо получать информацию о готовых осмотрах для передачи на сервер со всеми элементами и прикреплёнными данными. В этот модуль стоит передать только InspectionsAccess.</p><p>Для сравнения посмотрите на код, который используется для получения данных, если не использовать DAO:</p><p>Обратите внимание, что класс неявно получает зависимость от конкретной реализации SQLite. Более того, он получает доступ ко всем частям базы данных, хотя не должен иметь возможности читать, изменять и удалять данные вне его круга задач. А вот как выглядит реализация аналогичной задачи с применением DAO:</p><p>Теперь класс явно зависит только от модели Users и от модели Inspections. Стоить заметить, что SQLite нигде не упоминается.</p><h2>Тестирование</h2><p>У нас уже описана логика по работе с базой данных. Мы используем её в модулях, хотя реализации работы с данными пока нет. Однако, мы уже можем написать тесты для всех доступов и моделей. Итак, DAO должен успешно передавать доступы (не null). Точно так же для доступов: они не производят никаких действий, а только передают данные. А вот для моделей можно написать тесты. Например, модель Users изначально ничего не возвращает по ключу, но после добавления объекта станет возвращать новый объект со всеми полями в таком же виде, в котором он был добавлен в базу. По такому же принципу нужно покрыть тестами все модели.</p><h2>Реализация</h2><p>Теперь осталось выбрать, с помощью чего реализовать обработку данных для нашего data access object – например, это может быть <a href="https://developer.android.com/reference/android/database/sqlite/package-summary.html">SQLite</a>. Удобство DAO в том, что мы сможем изменить реализацию логики работы приложения, не затрагивая при этом блок по работе с базой данных. Например, в проекте <a href="https://github.com/kepocnhh/MyM1yClean">MyM1y</a> (система учёта финансовых операций) с самого начала для хранения данных был выбран <a href="https://developer.android.com/reference/android/database/sqlite/package-summary.html">SQLite</a>. В процессе работы над проектом было решено заменить реализацию на более легковесную. Была выбрана другая библиотека — <a href="https://github.com/StanleyProjects/Boxes">Boxes</a>, и реализация работы с базой данных в проекте была полностью заменена. Это можно наблюдать в коммите <a href="https://github.com/kepocnhh/MyM1yClean/commit/ea5d973701bc9275ba67d09a9784aaa716a7c991">painless jump from sqlite to custom nosql orm</a>. Класс <a href="https://github.com/kepocnhh/MyM1yClean/commit/ea5d973701bc9275ba67d09a9784aaa716a7c991#diff-76e7ccade888287fc2dc611c37e64cbb">stan.mym1y.clean.db.SQLite.java</a> был полностью вырезан со всеми зависимостями и заменён на <a href="https://github.com/kepocnhh/MyM1yClean/commit/ea5d973701bc9275ba67d09a9784aaa716a7c991#diff-2e8288f7b39e3d93f1ec346269835d9f">stan.mym1y.clean.boxes.Boxes.java</a>. Обратите внимание, что это было сделано без изменения модулей по взаимодействию с базой данных.</p><h2>Заключение</h2><p>Используя DAO, можно удобно разделять уровни доступа при работе с базой данных, чётко видеть эти уровни доступа и легко оперировать ими, не привязываясь к конкретной реализации хранения данных. Это позволяет применять такой подход вместе с TDD и точнее настраивать реализацию работы с БД (без изменений в других модулях) или полностью заменить одну реализацию на другую.</p>]]></content:encoded>
    </item>
    <item>
      <title>Борьба за безопасность при создании менеджера паролей под Android</title>
      <link>https://tproger.ru/projects/security-password-manager-android</link>
      <comments>https://tproger.ru/projects/security-password-manager-android?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Елена Брызгалова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/security-password-manager-android</guid>
      <description><![CDATA[<p>Создание PassData для Android началось с поиска менеджера без лишней регистрации, обязательной облачной синхронизации и ограничений на скрытие полей.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/security-password-manager-android">Борьба за безопасность при создании менеджера паролей под Android</a>»</p>]]></description>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 08 Jul 2017 16:35:42 GMT</pubDate>
      <content:encoded><![CDATA[<p>Рассказывает Михаил Иванов, наш подписчик</p><p>Приветствую всех! Хочу поделиться историей создания своего первого проекта под Android, а также рассказать об основных проблемах, которые возникли при работе над отдельными его компонентами.</p><h2>Зачем нужен еще один менеджер паролей?</h2><p>В Play Market достаточно приложений для хранения паролей и заметок в зашифрованном виде, но для себя я так и не нашел сочетания всех необходимых функций в одном приложении.</p><p>В принципе, с хранением логинов и паролей различных интернет-сайтов отлично справляется любой браузер, в том числе и на телефоне. Проблемы начинаются, когда, например, по работе нужно сохранить в безопасном месте пароли от компьютеров, маршрутизаторов или другого оборудования. В таком случае придется искать надежное и удобное место для всего этого добра, и телефон подойдет как нельзя лучше.</p><h2>Анализ существующих приложений</h2><p>Что мне не понравилось во многих самых популярных приложениях, так это необходимость регистрировать еще один аккаунт, собственно, для самого приложения. Еще не всегда в приложении есть возможность отказаться от синхронизации с облаком, а в редких случаях нельзя даже редактировать данные, находясь оффлайн.</p><p>Зачастую в менеджерах паролей присутствует еще один существенный недостаток: невозможность сделать скрытыми несколько полей, например, пароль и пин-код или пароль и ответ на секретный вопрос. Тогда приходится выбирать, что важнее спрятать от несанкционированного доступа. Неудобства часто доставляет и ограниченное количество полей, которые можно добавить в запись, или когда их количество вообще статично и нельзя убрать незаполненные поля.</p><p>Различные комбинации этих недостатков в существующих приложениях и побудили меня к созданию собственного менеджера паролей.</p><h2>Особенности менеджера паролей PassData</h2><p>Ключевые фишки моего приложения:</p><ul><li>возможность создания нескольких независимых хранилищ (аккаунтов). Каждому хранилищу в приложении можно назначить свое имя, иконку, и, что самое главное, — свой мастер-пароль. Я не нашел в Play Market ни одного офлайн-менеджера паролей, где это можно сделать, возможно, потому что это не очень востребовано, но для кого-то при выборе этот момент может стать решающим;</li><li>возможность создания неограниченного количества собственных категорий (папок) для группирования записей. Очевидный функционал, который, тем не менее, отсутствует в некоторых приложениях, ограничиваясь небольшим количеством предусмотренных разработчиком категорий;</li><li>создание неограниченного количества полей (логин, пароль и т. д.) для каждой записи, возможность настройки видимости полей и их произвольной сортировки;</li><li>каждому полю в записи можно присвоить один из типов, которые могут быть представлены логином, паролем, ссылкой, email, комментарием или обычным полем. У полей, которые имеют тип ссылки или email, появится кнопка для быстрого перехода или отправки письма. Поле комментария больше остальных, поэтому позволяет вводить многострочный текст;</li><li>большой набор иконок для записей;</li><li>возможность быстрого создания новой записи и набора полей для нее;</li><li>приложение полностью офлайновое. Такое решение было принято из-за того, что для синхронизации данных между устройствами или облачного хранения нужен свой backend, а это в данный момент не входит в мои планы. Плюс в том, что отсутствие доступа к интернету прибавляет доверия к приложению. Одна из проблем, которая при этом возникла, — это трудности при сборе аналитики и отчетов об ошибках.</li></ul><figure><img src="https://media.tproger.ru/uploads/2017/06/4-screens-1024x493.png" alt="" /></figure><h2>О разработке</h2><p>Сначала разработка велась во фрагментах/активити. Это основные компоненты Android SDK, используемые при разработке приложения. Однако размещать весь код в них, смешивая бизнес-логику и работу с операционной системой, — не очень хорошая практика, которая грозит ситуацией, когда исправить что-то или добавить новый функционал становится практически невозможно. К счастью, я вовремя столкнулся с аббревиатурой MVP.</p><p><a href="https://ru.wikipedia.org/wiki/Model-View-Presenter">Model View Presenter</a> — архитектурный подход, который предполагает разделение всех классов программы на три основных слоя, каждый из которых выполняет строго свои обязанности. Пока было еще не совсем поздно, я все переписал, что однозначно того стоило и окупило себя многократно. Такой подход значительно упрощает внесение изменений в код и в целом облегчает понимание логики работы программы.</p><p>Основные технологии и подходы, которые я использовал во время разработки:</p><ul><li>уже упомянутый MVP как основу архитектуры приложения;</li><li><a href="https://ru.wikipedia.org/wiki/Внедрение_зависимости">Dependency Injection</a> (DI) — набор паттернов и принципов разработки, которые позволяют писать слабосвязанный код. Google для их внедрения даже создал собственную библиотеку – <a href="https://github.com/google/dagger">Dagger 2</a>, именно ей я и воспользовался;</li><li>MVP и DI позволяют писать легко тестируемый код. Благодаря разбиению на слои и слабой связанности компонентов системы, можно легко тестировать отдельные ее части. Такие тесты называются <a href="https://ru.wikipedia.org/wiki/Модульное_тестирование">«Unit tests»</a>, и ими покрыта вся бизнес-логика в приложении;</li><li><a href="https://ru.wikipedia.org/wiki/Система_управления_версиями">система контроля версий</a> (далее VCS) — еще один must have при разработке. Системы контроля версий позволяют хранить всю историю изменения исходного кода программы и возвращаться к любой его версии при необходимости. VCS предоставляет огромное количество различных инструментов, которые значительно упрощают разработку. Есть множество различных систем контроля версий, в своей работе я использовал Git, которая является наиболее распространенной и удобной;</li><li>все данные, введенные пользователем в приложение (пароли, логины и т. д.), хранятся в <a href="https://www.zetetic.net/sqlcipher/">SQLCipher</a> базе данных.</li></ul><h2>Реализации безопасности в приложении</h2><p>Обеспечение безопасности хранения данных в подобных приложениях стоит на первом месте, поэтому я хочу рассказать, каким образом хранятся данные в приложении и как происходит авторизация пользователя. Также я расскажу о проблемах, которые возникли в ходе разработки.</p><p>Получить доступ к данным, хранящимся в приложении, можно двумя способами: введя мастер-пароль, заданный при создании хранилища, или воспользовавшись сканером отпечатков пальцев.<br />Вход в приложение c помощью мастер-пароля реализован достаточно просто: при создании хранилища пароль от него хешируется (соль + пароль), и этот хеш хранится в приложении. При последующем входе введенный пароль хешируется с той же солью и сравнивается с хранящимся хешем. Если они совпадают, то введенный пароль используется для доступа к SQLCipher базе данных.</p><h3>Вход по отпечатку пальца</h3><p>Со входом по отпечатку пальца все гораздо сложнее, особенно если учесть все нештатные ситуации. В простом виде это выглядит примерно так:</p><ol><li>На экране логина проверяем, поддерживается ли сканер отпечатков и включен ли он в настройках приложения.</li><li>Проверяем, зарегистрирован ли в системе хотя бы один отпечаток пальца.</li><li>Если все нормально, ждем от системы ответа об успешной аутентификации.</li><li>Расшифровываем мастер-пароль и используем его для доступа к SQLCipher базе данных.</li><li>Подробный алгоритм работы при входе по отпечатку показан на схеме:</li></ol><figure><img src="https://media.tproger.ru/uploads/2017/07/Fingerprint-login-Diagram-1024x588.png" alt="" /></figure><p>Весь этот функционал в приложении возложен на два класса с говорящими названиями: FingerprintAuthenticator и Cryptographer. Они представляют собой удобные обертки над классами FingerprintManagerCompat и KeyStore/Cipher.</p><p>Код к шагам 1-3:</p><p>Метод, вызываемый при успешной аутентификации с помощью сканера отпечатков:</p><p>Первые проблемы в данной части начинаются с аутентификации при помощи сканера отпечатков пальцев. Дело в том, что даже если сканер отпечатков доступен, у нас может не получиться начать прослушивать его из-за проблем в работе KeyStore и Cipher. Именно поэтому я получил свои первые отзывы с одной-двумя звездами от устройств Xiaomi/Meizu из-за падений приложения. Эти случаи я стал обрабатывать отдельно (mFingerprintAuthenticator.startListening() возвращает false, если что-то пошло не так, и просто отключается вход по отпечатку).</p><p>На некоторых смартфонах, в основном китайских производителей, возникает еще одна проблема: у устройства с физическим наличием сканера отпечатков пальцев и версией Android’a 6.0+ стандартные методы для проверки его доступности из класса FingerprintManagerCompat (isHardwareDetected() и hasEnrolledFingerprints()) говорят, что сканер <a href="https://issuetracker.google.com/issues/37132365?pli=1">не поддерживается</a>. Это подтверждается и проверкой через PackageManager.getSystemAvailableFeatures, в списке результатов которой нет поддержки сканера отпечатка пальцев. Найти решение этой проблемы мне пока, к сожалению, не удалось (хотя в других приложениях, например банковских, разработчикам удалось заставить работать сканер отпечатков), поэтому приходится мириться с некоторыми негативными отзывами от пользователей.</p><h3>Шифрование и хранение мастер-пароля</h3><p>С шифрованием/расшифровкой мастер-пароля, как уже было упомянуто выше, тоже не все в порядке. Общая логика работы следующая:</p><ol><li>При первом запуске приложения, если версия android 6.0+ и есть сканер отпечатков, создаем пару ключей для шифрования/расшифровки и прячем их в KeyStore. Если условия не соблюдены, то нет никакой необходимости хранить и шифровать мастер-пароль.</li><li>Далее, при создании пользователем нового хранилища, мы шифруем введенный пароль, используя Cipher, и в зашифрованном виде храним в базе данных.</li><li>Если аутентификация с помощью сканера отпечатка пальца прошла успешно, тогда достаем из KeyStor наши ключи и при помощи Cipher расшифровываем мастер-пароль, который используем для доступа к базе данных.</li></ol><p>В идеальных условиях все так и будет происходить, но на деле ситуаций, которые нужно обрабатывать, гораздо больше.<br />Если при первом запуске устройство не защищено пин-кодом или другим способом, то ключи не будут созданы, или с ними невозможно будет работать (метод setUserAuthenticationRequired()).</p><p>Поскольку в Android нет достаточно надежного места для хранения произвольной информации, но предоставлены инструменты для надежного хранения ключевой пары, к которой будет доступ только у нашего приложения, я формирую секретный и публичный ключи. Публичный ключ используется для зашифровки мастер-пароля, когда пользователь создает новое хранилище. Секретный (приватный) ключ используется для расшифровки этого пароля, когда пользователь входит в приложение по отпечатку пальца и, соответственно, не вводит сам пароль, который потом используется для доступа к базе данных.</p><p>Код формирования пары ключей:</p><p>В качестве решения во время запуска приложения при создании Cryptographer мы получаем KeyStore и проверяем наличие ключей, а если их нет, то еще раз пробуем их создать.</p><p>Во время шифрования или расшифровки пароля тоже могут возникнуть проблемы. Например, мне пришло несколько crash report с устройств Xiaomi, на которых метод CipherOutputStream.close() выбрасывал IOException в процессе расшифровки пароля. Дело в том, что при любом исключении методы расшифровки и шифрования пароля возвращают пустую строку, а при входе по отпечатку расшифрованный пароль хешируется и сравнивается с сохраненным хешем, как и при обычном входе. При сравнении пустой строки и хеша и возникало исключение. Если же ошибка не возникла, тогда пускаем пользователя дальше, если нет — сообщаем ему о проблеме и предлагаем войти по мастер-паролю, при этом заново пересоздаем ключи и шифруем введенный пароль.</p><p>Значительно усложняет борьбу с этими проблемами отсутствие у приложения разрешения на доступ к интернету, отсюда невозможность автоматически собирать данные о сбоях и всю интересующую нас информацию о работе приложения. Выход из ситуации есть: пользователь имеет возможность сформировать отчет в приложении и отправить его по email разработчику, а если не хочется реализовывать это самому, тогда можно воспользоваться сторонними библиотеками (например, <a href="https://github.com/ACRA/acra">ACRA</a>).</p><p>Теперь перейдем к тому, как непосредственно хранится введенная пользователем информация. Для этих целей я воспользовался довольно популярной и проверенной временем библиотекой <a href="https://www.zetetic.net/sqlcipher/about/">SQLCipher</a>. Она является расширением обычного SQLite и шифрует страницы базы данных перед тем, как их записать, а при чтении расшифровывает. В процессе этого используется алгоритм шифрования AES-256. Работа с данной библиотекой ведется точно так же, как и с обычным SQLite, никаких проблем при этом у меня не возникало.</p><h2>Релиз</h2><p>В Play Market я решил выложить сначала бета-версию приложения, надеясь, что смогу отловить и исправить основные проблемы, при этом не получив отрицательных отзывов. Но, к моему сожалению, его просто никто не скачивал. Да, не было никакой рекламы и пиара даже в социальных сетях, но я надеялся хотя бы увидеть свое приложение в поиске Play Market, и на 5-10 установок в неделю. Возможно, причина этого в тематике приложения: никто не хочет доверять важную информацию приложению от неизвестного разработчика.</p><p>Польза от функции бета-тестирования в консоли разработчика Google play в любом случае есть. Все обновления я сначала выкладываю в закрытом бета-тесте, а полномасштабное обновление даю в открытый доступ только после тестирования на своем устройстве.</p><h2>Заключение</h2><p>В итоге получилось довольно интересное приложение, сочетающее в себе уникальный набор функций. Далее я планирую активно развивать его, повышая стабильность, улучшая производительность и добавляя новые возможности.<br />Всем спасибо за внимание, делитесь своим мнением в комментариях!</p>]]></content:encoded>
    </item>
    <item>
      <title>Проект нашего подписчика: Codelobster PHP Edition&nbsp;— бесплатный PHP, HTML, CSS, JavaScript редактор</title>
      <link>https://tproger.ru/projects/codelobster-php-edition</link>
      <comments>https://tproger.ru/projects/codelobster-php-edition?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Лапа]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/codelobster-php-edition</guid>
      <description><![CDATA[<p>Функциональный и простой редактор кода с поддержкой PHP, HTML, CSS и JavaScript — бесплатная альтернатива платным продуктам для создания сайтов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/codelobster-php-edition">Проект нашего подписчика: Codelobster PHP Edition&nbsp;— бесплатный PHP, HTML, CSS, JavaScript редактор</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 19 Dec 2016 19:49:07 GMT</pubDate>
      <content:encoded><![CDATA[<p>Для полноценной работы по созданию сайтов вам обязательно необходим хороший удобный редактор. Есть очень много платных продуктов для этого, но нам бы хотелось выделить бесплатный очень функциональный и в то же время простой в использовании редактор — <a href="http://www.codelobster.com/">Codelobster PHP Edition</a>.</p><figure><img src="https://media.tproger.ru/uploads/2016/12/1.png" alt="" /></figure><p>Давайте расскажем о некоторых важных возможностях и преимуществах этой программы:</p><ul><li>Весь код подсвечивается разными цветами в зависимости от типа, причем поддерживается также смешанный код, когда в одном и том же файле участок HTML будет подсвечен как HTML, PHP — как PHP, а JavaScript — как JavaScript. Существуют возможность выбора из нескольких цветовых схем, включая схемы из популярных IDE.</li><li>Мощное автодополнение для HTML, PHP, CSS и JavaScript, включая HTML5 и CSS3. Для PHP полностью распознается структура проекта, выпадает полный список методов в соответствующих местах.</li><li>HTML/CSS инспектор по типу FireBug, который позволяет легко сопоставлять выделенные элементы страницы с кодом и соответствующим стилем.</li><li>Контекстная помощь по всем поддерживаемым языкам. По нажатию клавиши F1 происходит открытие страницы с полный описанием текущего тега, атрибута, функции и т.д. с соответствующих официальных сайтов.</li><li>PHP-отладчик. Позволяет пошагово выполнять PHP скрипты, отслеживая значения всех переменных в каждой строчке.</li><li>SQL-менеджер позволяет производить все необходимые действия с базой данных — добавлять, удалять, редактировать структуру и записи в таблицах, экспортировать данные, выполнять SQL-запросы. Для SQL-файлов работает подсветка и автодополнение.</li><li>Поддержка FTP позволяет работать напрямую с удаленным сервером и делать все необходимые изменения с предварительным просмотром результата.</li><li>Опция Portable позволяет использовать редактор без предварительной установки.</li><li>Остальные полезные фичи: парная подсветка, возможность выделения блоков, коллапсинг, тултипы, навигация по описаниям функций и подключаемым файлам при удержании клавиши CTRL, просмотр структуры файла и проекта, превью в браузере, закладки и все остальные стандартные возможности для работы с кодом.</li></ul><p>Также существуют специальные плагины для работы с:</p><ul><li>CMS: Drupal, Joomla.</li><li>PHP фреймворками: CakePHP, CodeIgniter, Symfony, Yii, Laravel.</li><li>Движком для блогов WordPress.</li><li>JavaScript-библиотекой JQuery.</li><li>Шаблонизатором Smarty, Twig.</li></ul><h4>Информация</h4><p>Разработчик: <a href="http://www.codelobster.com/">Codelobster Software</a></p><p>Поддерживаемые языки: Английский, Русский, Немецкий, Испанский, Французский.</p><p>Поддерживаемые системы: Windows XP, Windows Vista, Windows 7, Windows 8, Windows 10.</p>]]></content:encoded>
    </item>
    <item>
      <title>ASP .NET роутинг в JavaScript</title>
      <link>https://tproger.ru/projects/asp-net-routing</link>
      <comments>https://tproger.ru/projects/asp-net-routing?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Иван Бирюков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/asp-net-routing</guid>
      <description><![CDATA[<p>Способ подключить к JavaScript роутинг с backend на ASP .NET, чтобы не указывать URL вручную при каждой отправке данных формы через AJAX.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/asp-net-routing">ASP .NET роутинг в JavaScript</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 29 May 2016 23:11:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Наш читатель поделился с нами удобным способом обработки запросов на JavaScript в ASP .NET.</p><p>Я — студент 2-го курса, в свободное от учебы время пилю для себя небольшой сайтик на ASP .NET. И в какой-то момент, при написании очередной формы, которая отправляет данные при помощи AJAX, я поймал себя на мысли, что мне надоело снова и снова указывать URL для отправки запроса, и было бы неплохо подключить к JavaScript’y роутинг, который есть у меня на backend’е.</p><h3>Выбор способа реализации</h3><p>Немного подумав и спросив на StackOverflow (и не получив ответа), я пришел к выводу, что у меня есть два простых пути реализации этого:</p><ul><li>через URL вида route/{routename} c последующим редиректом;</li><li>через реплейсмент-тег вида «[Route:%route_name%]», который при отдаче файла будет заменяться на URL cамого роута.</li></ul><p>Первый вариант практически сразу был отброшен как слишком скучный, и я приступил к реализации задуманной функциональности.</p><h3>Реализация</h3><p>Немного почитав про то, как ASP .NET обрабатывает реквесты, я решил, что мне следует написать кастомный HttpHandler, который будет по регулярному выражению искать в файлах *.js строку вида «[Route:%route_name%]» и заменять ее на искомый URL.</p><h3>Итоговый код:</h3><p>После регистрации этого хэндлера в web.config’e все заработало, как нужно.</p><p>Файл, который был запрошен:</p><p>Файл, который был получен:</p><p>Надеюсь, кому-либо сможет помочь данный очерк. Спасибо за внимание!</p>]]></content:encoded>
    </item>
    <item>
      <title>История создания Blank — необычного мессенджера реального времени</title>
      <link>https://tproger.ru/projects/blank</link>
      <comments>https://tproger.ru/projects/blank?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/blank</guid>
      <description><![CDATA[<p>Пётр Лобанов из Санкт-Петербурга рассказывает, как команда из трёх человек без инвестиций и с разработкой на аутсорсе делала мессенджер Blank.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/blank">История создания Blank — необычного мессенджера реального времени</a>»</p>]]></description>
      <category><![CDATA[Мобильная разработка]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 26 May 2016 21:35:29 GMT</pubDate>
      <content:encoded><![CDATA[<p>Наш читатель прислал рассказ о разработке мессенджера реального времени. Передаём ему слово.</p><p>Здравствуйте! Меня зовут Пётр Лобанов, мне 28 лет, я живу в Санкт-Петербурге. У меня есть основной бизнес в оффлайне — сеть бургер-баров. Совсем недавно я ничего не знал о стартапах и мире IT.</p><figure><img src="https://media.tproger.ru/uploads/2016/05/team.png" alt="" /></figure><p>Однажды мы решили сделать мобильное приложение. Самое бредовое, что мы решили делать мессенджер, которых и так полно. В команде у нас всего три человека: два основателя и маркетолог. В проект не привлекались сторонние инвестиции, все делали на собственные средства. Вся разработка ведется на аутсорсе, с чем мы в свое время дико намучились. Ниже станет понятно, почему.</p><p>Мы – школьные товарищи. История Blank началась с того, что одному из нас в канун 2015 года пришла идея про новый способ переписки, когда нет привычной кнопки «Отправить», а человек просто видит, как собеседник набирает текст по буквам, и абсолютно таким же способом отвечает ему в режиме реального времени. Подумали – по логике это похоже на телефонный разговор, поэтому решили дополнить продукт фичей с исчезновением текста: переписка у нас нигде не хранится. Идеей загорелись моментально, и уже на следующий день мы обсуждали, как продукт будет выглядеть вживую. На самой заре проекта у нас был суровый, но интересный концепт: можно было общаться, только если вы и ваш собеседник находитесь онлайн, а перед беседой нужно было “дозвониться”, и чат начинался только после одобрения вызова. Получались эдакие “текстовые звонки”, коротко это можно понаблюдать в заключении нашего промо-ролика, если приглядеться.</p><p>Мессенджер должен был изначально работать на протоколе WebRTC. Это открытый развивающийся проект, поддерживаемый Google, Mozilla и Opera. Он позволяет передавать данные и медиапотоки, устанавливая Peer-to-Peer соединение между двумя и более клиентами. Это браузерная технология, но мы решили применить ее для мобильного приложения. Это позволяло нам почти не задействовать серверные мощности и сделать переписку по-настоящему приватной, так как в этом случае информация передавалась бы напрямую с устройства на устройство. На самом деле с технологической точки зрения это был бы по-настоящему инновационный момент для мессенджеров – безопасность была бы теперь не просто пустым словом. Первые сборки Blank даже и работали на этом протоколе. Схематично, принцип работы WebRTC (и его составляющих – протоколов STUN и TURN) для Blank описан в этих двух картинках ниже. Но заострять внимание на этом сильно не будем:</p><figure><img src="https://media.tproger.ru/user-uploads/33794/2024-02-19/bd03406f-94fc-4a5a-a167-1a082def24c0.png" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/33794/2024-02-19/bf72a40e-2bbd-45fd-92c9-ffb4ac58cb6b.png" alt="" /></figure><p>Впоследствии мы столкнулись с рядом сложностей. Фактически, у наших первых разработчиков это был первый опыт плотной работы с WebRTC, после инвестигейта ими было заложено слишком мало времени как на реализацию работы с WebRTC, так и на риски. В результате оказалось, что WebRTC более низкоуровневый, чем ожидалось, “из коробки” не обрабатывает типичные для мобильных приложений кейсы (смена режима доступа к интернету, плохая связь и т.п.), которые пришлось делать самим. Мы долго верили в наших подрядчиков, но в какой-то момент решились разорвать с ними отношения, когда поняли, что доведение до ума прототипа на WebRTC не укладывается ни в адекватные сроки, ни в суммы. Какое-то время мы пытались найти специалистов по работе именно с этим протоколом, но столкнулись с тем, что в России (да и в мире тоже) не так много свободных разработчиков, специализирующихся на WebRTC, которые были бы готовы на адекватных условиях взяться за проект.</p><p>В итоге в конце прошлого года, после нескольких месяцев поисков, мы нашли новую команду, которая после первых критичных фиксов предложила нам перейти на новый флоу беседы с переводом Blank на Realtime NoSQL БД – Firebase. Первую рабочую демку запилили буквально за три часа. Тогда уже у нас появились статусы пользователей (казалось бы, что нового в этом для мессенджеров? ? и отложенная переписка, которую раньше чисто технически сложновато было добавить. Очень много усилий пришлось приложить к тому, чтобы «отучить» клиент от старого протокола, ибо он сильно был на него завязан, но мы справились.</p><p>17 мая 2016 года мы <a href="https://itunes.apple.com/ru/app/blank-realtime-messenger/id1070527509?l=ru&amp;ls=1&amp;mt=8">запустили</a> наш проект в App Store. Запустились достаточно колхозно, хотя и продумывали этот процесс. Отчасти, много надежд было возложено на комьюнити Product Hunt, мы заранее запарились и получили инвайт, планируя одновременно с релизом в AppStore «зафичериться» и там. Но, волей случая, нажав кнопку Submit, мы обнаружили, что один из наших бета-тестеров решил уже рассказать о нас там («захантить») самостоятельно, не предупредив нас, и в итоге никакого эффекта с этой площадки (из-за небрежно заполненной заявки и отсутствия внимания с нашей стороны) мы не получили.</p><p>А еще (это может показаться смешным), мы так долго ковырялись с разработкой, что за это время в App Store и Play Market успел появиться еще один Blank Messenger — очень на наш взгляд нелепый. У нас раньше зарегистрирован домен, о нас уже были упоминания в поисковых системах (включая наш проморолик на Youtube) до момента их релизов, но то ли они эти факты проигнорировали, то ли не заметили (в чем сомневаемся) и в итоге зарелизились первыми. Еще во время бета-тестирования нам приходили письма от создателей другого Blank Messenger освободить «их» торговую марку, так как это мешает делать им бизнес. Это, конечно, подпортило нам настроение, но все материалы уже были готовы, и было принято решение публиковаться все равно как Blank Messenger (мы добавили только туда слово Realtime). В итоге сейчас на нас подали жалобу в App Store с просьбой удалить наш мессенджер как приложение-нарушитель. У них нет зарегистрированной торговой марки, что лишает их обращение полноценной юридической силы. Но в числе их преимуществ — более раннее использование торговой марки Blank в коммерции. Посмотрим, что решит Apple. К слову, за неделю мы уже обогнали их по популярности.</p><p>Сейчас мы работаем над расширением пользовательской базы, строим маркетинговый план по продвижению нашего проекта в социальных медиа. Очень хотим создать клиент для Android (тем более, что многие его просят), но это деньги. Пока что мы просто хотим, чтобы Blank пользовался успехом в качестве мессенджера нового поколения. В данный момент у нас 4500 зарегистрированных пользователей. По меркам мессенджеров это очень мало, но на самом деле мы и этому уже рады.</p>]]></content:encoded>
    </item>
    <item>
      <title>Организуем рабочий процесс для максимальной эффективности</title>
      <link>https://tproger.ru/projects/working-process-advice</link>
      <comments>https://tproger.ru/projects/working-process-advice?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Иван Бирюков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/working-process-advice</guid>
      <description><![CDATA[<p>Читатель Стенли Винтергрин делит работу над приложениями на пять частей и начинает с самой главной — организации рабочего пространства.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/working-process-advice">Организуем рабочий процесс для максимальной эффективности</a>»</p>]]></description>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 09 Apr 2016 21:25:54 GMT</pubDate>
      <content:encoded><![CDATA[<p>Наш читатель, <a href="https://vk.com/id175256887">Стенли Винтергрин</a>, поделился с вами советами по организации и оптимизации рабочего процесса при создании приложений.</p><p>Я много разрабатываю для разных платформ на разных языках программирования,  разных машинах и с использованием разного ПО. Для себя я нашел несколько приемов, которые позволяют мне быть намного более продуктивным.  Некоторые приемы покажутся довольно очевидными, а какие-то, надеюсь, будут не так прозрачны.</p><p>Так или иначе, в итоге я пришёл к одной общей схеме, которую успешно применяю сейчас. Будем исходить из того, что мы занимаемся разработкой приложений. Итак, разделите предстоящую работу на 5 частей.</p><figure><img src="https://media.tproger.ru/uploads/2016/04/1-1.png" alt="" /></figure><h3>Рабочее пространство (working place)</h3><p>Самая главная часть. Это именно то, что необходимо для создания приложения. Отличие от остальных частей заключается в том, что сюда необходимо отнести исключительный минимум именно тех средств, без которых написание приложения будет невозможно. К этим средствам можно отнести среду программирования или комплекс из компилятора и текстового редактора.</p><p>Примеры:</p><ul><li>Для разработки приложений под Android я использую AndroidStudio — он включает в себя достаточный функционал и очень удобен (но, к сожалению, только на мощных машинах).</li><li>Для написания простых приложений на C++ (фриланс для студентов) я посчитал достаточным использования Sublime Text и gcc. Очень нетребовательный функционал. Таким образом, я создал систему, с помощью которой я могу легко писать приложение на моём домашнем компьютере на Windows и без проблем продолжать работу на нетбуке слабой мощности на Debian.</li><li>Также был опыт в разработке приложения на Unity3D. В данном случае я, конечно, использовал Unity3D, но он на самом деле выполняет лишь часть задач. Например, для редактирования скриптов на C# нужно использовать специальную утилиту. Мне не понравилось предлагаемое решение MonoDevelop, я посчитал его слишком требовательным (с учётом работы на относительно слабой машине) для того, чтобы писать небольшие скрипты. Поэтому для этого проекта я использовал комплекс из Unity3D и Notepad++.</li></ul><p>Итак, эта часть формируется в зависимости от задачи и личных предпочтений. Я хочу донести, что главное — использовать то, что нужно и важно, и избегать лишних действий, а также инструментов, которые только тормозят разработку.</p><h3>Каталогизация (folder)</h3><p>Теперь не такие важные, но очень полезные приёмы. Итак, под каждый проект нужно создать специальное место для хранения сопутствующих файлов. Внимание, необходимо разделить понятия «файлы проекта» и «сопутствующие файлы». Т.е. это не исходный код, а хранилище ресурсов — всё, что можно уложить в файл. Это должны быть медиафайлы (во многих проектах существует специальные папки под используемые в приложении ресурсы, я говорю о медиафайлах в более широком смысле), сборки проекта в разных версиях, необходимые файлы настроек проекта, сопроводительные документы, необходимые библиотеки и так далее. Суть этой части заключается в создании порядка. Мне часто попадались программисты, которые хранили данные беспорядочно, на рабочих столах, с непонятными названиями, файлы от разных проектов в одном месте, а так же часто теряли их.</p><p>Пример:</p><figure><img src="https://media.tproger.ru/uploads/2016/04/2.png" alt="" /></figure><p>Я являюсь большим фанатом облачных технологий, поэтому для разработки использую Dropbox. Там у меня создана своя собственная и, что важно, удобная для меня иерархия. Хочу сказать, что важно, чтобы у вас всё было разложено по полочкам.</p><p>Dropbox имеет очень удобный (по моему мнению) клиент на Android, и я могу получить доступ к файлам проекта везде и почти всегда. Разворачиваясь на новом месте для работы, всё, что мне необходимо — это зайти в хранилище с другого компьютера и через браузер получить доступ сразу ко всем файлам проекта. Конечно, этот способ работает именно в моём случае, т.е. я всегда ношу с собой телефон с мобильным интернетом и работаю только в местах с доступом к Интернету.</p><p>Никто не мешает вам, к примеру, создать такой сервис у себя на флешке и всегда носить её с собой. Использовать другие сервисы тоже никто не запрещает. Рекомендую создавать на машинах, с которыми часто работаете, локальное подобие такой иерархии, а также temp-trash-хранилище для проверки и сортировки данных, которые впоследствии должны попасть в ваше основное хранилище.</p><h3>Контроль версий (version control)</h3><p>Если вы ещё не используете систему контроля версий, то бегите изучать эту тему. Чем раньше вы начнёте её применять, тем быстрее станете более эффективными. В разработке, конечно, это незаменимый инструмент. Тут нужно сказать, что главное — использовать эту технологию верно и пользоваться удобными инструментами. Таким образом, ваша разработка не будет стоять на месте. Код будет развиваться, а обо всех изменениях будет заботиться система контроля версий. Если у вас есть доступ в Интернет, то вы так же получаете сохранение кода и истории на сервисе, к которому можете получить доступ из любого места, и защищаете себя от потери кода и его порчи.</p><p>Важно не путать использование системы контроля версий и хранение файлов, сопутствующих проекту. Эта часть отвечает за сохранение именно той части приложения, которая необходима для его сборки. Я часто вижу, как эта система используется не совсем верно. В репозиторий заливается весь проект, созданный в какой-нибудь IDE, что я считаю крайне неправильным — репозиторий только для кода. Там не должны лежать файлы настроек проекта, тем более относящиеся к конкретной операционной системе. То же самое можно сказать, если вы имеете некий склад ресурсов для сборки и запуска проекта. Оцените сами, что это из себя представляет.</p><p>Пример:</p><p>Если данные являются файлами кеша для приложения, которое разрабатывается под две платформы (два репозитория), и этот кеш весит 70 Мб, то было бы логичнее как раз эту часть приложения (кеш) передать в какой-нибудь общий ресурс с общим доступом у разработчиков (сервер, облака и т.д.). Думаю, при таком раскладе кеш будет изменяться по воле заказчика, и пусть эти изменения не отслеживаются системой контроля версий. Таким образом, у вас будет два репозитория по 2–5 Мб для кода под каждую платформу и общий ресурс с кешем в 70 Мб, с которого будут брать файлы все, кому это необходимо.</p><p>Лично я использую git и сервисы: GitHub для личных проектов, Assembla для работы. А в процессе работы я решил для себя, что более удобный вариант — пользоваться консольной версией, а не встроенными в IDE аналогами. В управлении быстрее, работает с любыми git-репозиториями, и на всех машинах одинаково. Найдите лучший вариант для вашей ситуации и личных предпочтений.</p><h3>Заметки (notes)</h3><p>Для упорядочивания мыслей рекомендую использовать записные книжки. Записывайте всю информацию, относящуюся к проекту, которую можно перевести в текст. Создайте систему, с помощью которой всегда будет возможность манипулировать этим. Удобное чтение и запись мыслей по теме конкретной работы очень важны. Однако, легко запутаться в истинном назначении данного кейса. Текстовый документ со списком сценариев unit-тестов с доступом к комментированию и редактированию лучше отнести к файлу, который нужно определить в место с общим доступом для работников (сервер, облака… — folder). А если в голове появилась идея о том, как расположить элементы на экране, тут же записывайте список этих элементов в специально отведённое место в вашей книжке. Тут же вы можете оставить комментарии о каждом элементе. К тому же вам никто не мешает продублировать список unit-тестов из официального документа к себе для удобного чтения. Чем больше мыслей, идей и вспомогательной информации вы будете оставлять у себя в удобном виде с удобным доступом, тем меньше вероятность потери данных. И ещё вы сэкономите себе время на поиск необходимых элементов.</p><p>Пример:</p><p>Мне в разработке помогает сервис OneNote — облачная записная книжка с отличными десктопной, онлайн и Android версиями. Пользуюсь им для описания элементов и этапов разработки приложений: дизайны, модели данных, локализация, мысли вслух. Установленное приложение на моём телефоне позволяет не терять ход мысли, даже если я в пути или не на работе. Рекомендую дополнительно использовать бумажную записную книжку для тех же целей. Да и на бумаге удобнее создавать зарисовки и делать наброски.</p><figure><img src="https://media.tproger.ru/uploads/2016/04/3.png" alt="" /></figure><h3>Task manager</h3><p>Фиксирование задач, над которыми вы работаете, и которые необходимо выполнить, поможет вам в отслеживании прогресса и достижении цели. Также можно получить немало другой полезной информации, исходя из полученных данных. Например, учёт времени позволит оценить сложность задач, и в дальнейшем вы сможете оценить свои силы более точно.</p><p>Я перепробовал много менеджеров для отслеживания выполнения задач. Некоторые включают в себя очень много сервисов и функций, другие упрощены и являются вариацией записной книжки. Лично мне потребовалась именно такая система, в которой сами постановки задач были бы упрощены, но при этом существовала бы удобная древовидная система. Могу порекомендовать сервис Todoist, который к тому же доступен онлайн и имеет отличные клиенты под разные платформы.</p><p>Пример применения Todoist:</p><figure><img src="https://media.tproger.ru/uploads/2016/04/4.png" alt="" /></figure><p>Самое важное — определить, что вам нужно от этой системы. Я хотел учитывать каждую деталь разработки без абстракций, но группируя задачи. Это помогло мне обозначить для себя, какие моменты в разработке более важные, какие более сложные, а какие будут общими у многих, с решения каких задач стоит начинать проект. Для всех остальных обозначений я использую именно записную книжку, где подробно описываю всё необходимое.</p><h3>Заключение</h3><p>Эти пять моментов я считаю самыми главными (хотя я сам использую намного больше) и хочу, чтобы мой личный опыт помог вам в применении полезных сервисов для более качественной и быстрой разработки отличных приложений. Итак, группируйте все ваши проекты и всё с ними связанное сразу в понятном и удобном вам виде. Перепробуйте разные способы и выберите свой собственный. Добавьте сюда всё необходимое для вашего удобства. Найдите таймер по типу Toggl. Если вы фанат Pomodoro, приглядитесь к PomoDoneApp, а если вам больше по душе Kanban, то попробуйте Trello. Обязательно общайтесь с другими людьми (или даже сами с собой), создавайте беседы и диалоги: ведите горячие споры в Telegram или начинайте мозговые штурмы в gitter.im. Пользуйтесь сервисами по созданию блок-схем для построения алгоритмов, draw.io —очень хороший пример. Если вы пользуетесь онлайн-сервисами, то группируйте ссылки к сервисам под каждый проект для быстрого доступа. Удачи!</p>]]></content:encoded>
    </item>
    <item>
      <title>Autofox — рассказ о приложении для автолюбителей</title>
      <link>https://tproger.ru/projects/autofox-autoservice-app</link>
      <comments>https://tproger.ru/projects/autofox-autoservice-app?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Иван Бирюков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/autofox-autoservice-app</guid>
      <description><![CDATA[<p>История разработки сервиса для владельцев машин: идея выросла из работы петербургских точек продажи запчастей и обслуживания транспортных средств.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/autofox-autoservice-app">Autofox — рассказ о приложении для автолюбителей</a>»</p>]]></description>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Мобильная разработка]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Mar 2016 21:20:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>Наш читатель поделился с нами историей о разработке своего приложения под Android, созданного специально для автолюбителей. Передаём ему слово.</p><p>Привет, друзья! В этой статье я хотел бы не просто рассказать про разработку нашего продукта, а полностью раскрыть весь процесс создания продукта, на который я и другие люди, связанные с этим проектом, возлагаем большие надежды.</p><h3>С чего все началось?</h3><p>Мои товарищи занимаются обслуживанием транспортных средств (далее ТС) в культурной столице России Санкт-Петербурге. Они являются владельцами нескольких точек продажи запчастей. В СПб, как и во многих других городах, это — очень распространенный вид деятельности. Им пришла идея создать единый ресурс, в котором на карте будут отображены большинство точек обслуживания различных ТС, начиная с легковых автомобилей и заканчивая велотехникой. Было решено создать мобильное приложение, где было бы ранжирование по услугам и возможность выбора категории, которая наиболее точно удовлетворяла бы запросу пользователя.</p><p>Сделав анализ, я в принципе не нашел подобных аналогов и с энтузиазмом поддержал идею. Так как я являюсь разработчиком мобильных приложений для платформы Android, надо было с чего-то начинать и куда-то двигаться, тем более я не был голословен и показал официальные данные популярности операционной системы.</p><h3>Функциональность</h3><p>Обсудив все технические моменты с товарищами, было понятно, какой продукт они хотят получить в результате. Было написано ТЗ, по которому мы начали двигаться к воплощению своей идеи и запуску приложения.</p><p>Основным моментом является деление ТС и услуг по категориям:</p><ul><li>легковые,</li><li>грузовые,</li><li>велосипеды,</li><li>мототехника,</li><li>страхование.</li></ul><p>Каждый вид ТС/услуги в свою очередь должен содержать подкатегорию обслуживания, например:</p><ul><li>легковые:автосервис,автозапчасти,автомойки,шиномонтаж,</li></ul><p>а подкатегория должна также иметь вложенные категории:</p><ul><li>автосервис:кузов,двигатель/трансмиссия,ходовая,электрика,техобслуживание.</li></ul><p>В результате должна открываться карта города, на которой отмечены подходящие точки обслуживания, с возможностью определить свое местоположение и/или выбрать удобную точку и узнать о ней подробности, сделав запрос в виде заявки или телефонного звонка.</p><h3>Дизайн</h3><p>Конечно, здесь все просто в плане выбора. Если мы делаем современный сервис, то мы должны реализовать это все в Material Design. В этом вопросе сомнений не оказалось, и я полностью опирался на Material Design Guide.<br />Дизайн нужно было сделать самым удобным и дружелюбным для пользователя, поэтому выбор пал на светло-синюю цветовую палитру.</p><p>Все иконки приложения были также реализованы в данной цветовой гамме, за исключением категории 3-го уровня. Здесь я, так сказать, позаимствовал идею у Gmail и сделал ее похожей на Gmail Style List.</p><h3>Разработка</h3><p>Сама разработка проекта заняла примерно 6 месяцев c момента написания ТЗ. На первый взгляд, это большой срок, но оцените, что было сделано за это время:</p><ul><li>был разработан интерфейс проекта (в который вошла нарезка всего графического материла для разных разрешений экранов);</li><li>была создана серверная часть проекта;</li><li>был создан <a href="https://web.archive.org/web/20161002103428/http://autofox.su/">сайт</a>;</li><li>была собрана информация из открытых источников о точках обслуживания ТС (описание, контактные данные, точное местоположение, акционные предложения, какие услуги выполняет данная точка и др.).</li></ul><p>Да, серверная часть реализована с помощью Parse. Не ругайте сильно:-) Я объясню. Все делалось параллельно и данный сервис был изначально выбран из-за своего удобства. Когда серверная часть уже была подключена к проекту и собрана, и велась работа по запуску приложения, я узнал о плохих новостях от Parse.</p><h3>Маркетинговые рычаги</h3><p>Так как идея нашего проекта подразумевала и подразумевает в себе монетизацию, а именно получение прибыли от точек, которые захотят разместить свою точку внутри нашего приложения, были разработаны следующие рычаги воздействия:</p><ol><li>Выделение точки обслуживания на карте другим цветом среди других одноцветных точек.</li><li>Размещение точки обслуживания ТС сразу в нескольких категорий.</li><li>Более подробное описание точки в диалоговом окне приложения.</li><li>Отправка push-уведомлений от имени точки.</li></ol><p>И один рычаг, если клиент захочет приостановить сотрудничество, а потом возобновить:</p><ol><li>Просто скрыть точку на карте через админ-панель, поставив значение «false».</li></ol><h3>Продвижение и аналитика</h3><p>В проект я также подключил Google Analytics для мониторинга информации о том, какую категорию наиболее часто использует пользователь и на что следует обратить внимание при последующих обновлениях проекта.</p><p>Также для продвижения я использовал в проекте такие инструменты, как App Invite и App Indexing. По словам Google, App Invite — весьма крутая вещь, которой пользуются юзеры, если приложение удовлетворяет их потребностям. Они делятся с друзьями приложением, а, как мы знаем, друзей у всех много и это неплохой внутренний маркетинг.<br />Пользователь выбирает человека из своих контактов и отправляет ему письмом или СМС приглашение на установку приложения. Честно, не знаю, какой от этого будет результат, но буду наблюдать.</p><p>App Indexing — тоже весьма интересная фича от Google, которую я внедрил. Приложение взаимодействует с сайтом. Если мы в поисковых системах продвигаем наш сайт, то продвигаем и свое приложение — это своего рода ASO. Пользователь, который с мобильного устройства ищет нечто подобное нашему сервису, при поисковом запросе в браузере попадает на наше приложение, которое Google Chrome выбрасывает вверх и затем переходит на установку. Я расписал, как должно быть в идеале, а как всё будет происходить на практике — посмотрим.</p><h3>Заключение и планы</h3><p>10 февраля мы запустили наш проект в Google Play. Сейчас мы работаем над расширением базы данных, строим маркетинговый план по продвижению нашего проекта в социальных сетях и других местах. Хотим наладить контакты с точками обслуживания ТС и предложить поместить их в наш проект. В ближайшем времени хотим также реализовать свой продукт для iOS устройств. Даже на этапе запуска проекта мы уже знаем, чего нам не хватает, и планируем реализовать это в ближайших обновлениях — выбор пользователем марки автомобиля, сортировка точек запчастей для ТС («новые» и «б/у») и другие мелкие исправления. А в более глобальных планах — распространение нашего приложения на другие города, а, может, и страны, ведь сейчас наш проект может быть актуален не только в Санкт-Петербурге и области.</p><p>P.S. Чуть не забыл — свое творение мы назвали «Автофокс».</p><p>Моя личная почта для связи: <a>smzakharov@gmail.com</a></p><p>Напоминаем, что вы можете делиться рассказами о своих проектах на tproger. Для этого присылайте на <a>admin@tproger.ru</a> черновики материала, и мы ответим в течение нескольких дней.</p>]]></content:encoded>
    </item>
    <item>
      <title>Fingers: Alien Invasion — выводим формулу успеха мобильной казуалки</title>
      <link>https://tproger.ru/projects/fingers-alien-invasion</link>
      <comments>https://tproger.ru/projects/fingers-alien-invasion?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/fingers-alien-invasion</guid>
      <description><![CDATA[<p>История читателя о создании казуальной игры на Unity и о поиске общих факторов успеха Agario, 2048, flappy bird и doodle jump.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/fingers-alien-invasion">Fingers: Alien Invasion — выводим формулу успеха мобильной казуалки</a>»</p>]]></description>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 25 Jan 2016 20:26:23 GMT</pubDate>
      <content:encoded><![CDATA[<p>Читатель прислал рассказ о создании казуальной игры на Unity под мобильные платформы. Публикуем его историю и напоминаем, что вы можете присылать свои рассказы на <a>admin@tproger.ru</a> с темой «Рассказы о своих проектах».</p><p>Меня всегда мучил вопрос: можно ли вывести формулу успеха мобильной игры? Каждый раз с появлением таких вещей как Agario, 2048, flappy bird, doodle jump, я в очередной раз приходил в недоумение и спрашивал себя вновь и вновь. Пока однажды не решился попробовать.</p><p>Первичный анализ включил в себя весь вышеупомянутый список. Нужно было найти что-то общее, попытаться прийти к нескольким факторам, которые соответствуют всем или большей части этих игр.</p><ol><li>Бесконечный геймплей. Если навык игрока позволяет, то продолжать игру можно бесконечно.</li><li>Один шанс. Если наш навык недостаточно хорош, у нас нет права на ошибку, проиграл – начинай все с самого начала.</li><li>Хардкор. Завышенная сложность геймплея.</li><li>Необычная механика, которая свойственна только этой игре или небольшому количеству игр.</li><li>Отсутствие уровневости, уровни = зло.</li></ol><p>Пожалуй, это то что нужно, осталось только придумать саму механику. Парочка бессонных ночей и… вуаля! На руках мы имеем рабочий прототип. Сделанный в Unity 3D (наиболее удобного инструмента для прототипирования я попросту не видел, другой вопрос, что после прототипа я продолжил делать казуальную игру на нем, в результате получив билд в 60МБ на выходе, но это совсем другая история).</p><p>Линия доходит до середины экрана, после чего исчезает. Мысленно мы должны продолжить ее движение, а скорость начала перемещения неизменна. И должны остановить линию тогда, когда думаем, что она достигла верхней области. В случае неудачи мы проигрываем, показывается текущий счет (1 очко за каждое попадание) и начинаем все сначала.</p><p>Вроде неплохо, и почти все условия соблюдены, но не хватает графического оформления и сеттинга. В тот момент я принялся к поиску своей темы.</p><p>Сев на пару с художником родился прототип с оберткой в сеттинг.</p><p>Нарастающая линия была заменена на снаряды пушки, область исчезания — облаками, а цель — обозначена инопланетянином. В соответствии с сеттингом название напрашивалось само: Fingers: Alien Invasion.</p><p>Вроде бы супер. И, казалось бы, на этом можно остановиться. Я показал игру парочке ближайших для меня человек, и случилось ужасное. Они начали давать советы, а я начал их слушать. В результате концепт был переработан до неузнаваемости и от первичной простоты почти ничего не осталось. Более того, я забыл о своих анализах и напрочь перечеркнул более половины правил, появились и уровни, и некое подобие жизни. В таком состоянии игра пробыла еще пару месяцев, в постоянных придумываниях и доработках.</p><p>И вот наступил момент, когда ко мне, наконец, пришло осознание сделанных ошибок. Но частично, это сыграло мне на руку. Имея рабочий прототип самой первой версии, теперь у меня на руках 2 абсолютно разные игры. Я попросил художника нарисовать второй вариант с незатейливым сеттингом. Одна — тот монстр который получился, и вторая именно то, что мы хотели.</p><p>Тянуть далее не имело никакого смысла. И я твердо решил, если мы не выпустимся сейчас, то этого может не произойти никогда. А вторую версию игры выложить аккурат после первой через неделю. Таким образом эксперимент не провален, а получил новую ветвь развития, и мы сможем явно сравнить показатели перегруженной игры с показателями первичного концепта.</p><figure><img src="https://media.tproger.ru/user-uploads/33794/2024-02-19/5b466dca-4dbe-4c4f-96fa-04f32ce53dc2.png" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/33794/2024-02-19/3c5e7d40-525d-45c6-a9a4-2b0fa02ffc7e.png" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/33794/2024-02-19/7b317471-9aee-4635-bc3d-d9dbf453698c.png" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/33794/2024-02-19/19e6ac25-8ec6-49d8-ae8c-d18f60285654.png" alt="" /></figure><p>Безусловно, в текущей релизной версии есть множество недочетов, она требует оптимизации и доработок. Но теперь мотивация заниматься всем этим возрастает, как никогда. Когда пользователь ждет, комментирует, указывает на ошибки и просит что-либо доработать. Итак встречайте Fingers: Alien Invasion на просторах Google Play.</p><p>На данный момент говорить об успехе или провале проекта рано. Но уже сейчас можно понять, что начальные ожидания не оправдываются (надеюсь только пока).</p><p>Уповая на большое количество трафика, было принято решение не использовать donations в проекте и мы выбрали appodeal в качестве рекламного агрегатора (что, кстати, безусловно, удобно, он объединяет все популярные сети в одну). Вот такую статистику мы получили за 2 первых дня, не спав трое суток, размещая информацию об игре везде, где только можно:</p><p>У нас 309 позиция в топе российских новинок на данный момент.</p><p>Суммарное количество инсталляций неизвестно. По ориентировочным подсчетам около 300—400 установок. Не густо, не так ли? Но впереди еще много интересного. Мы попали в программу развития отечественных разработчиков Pdalife, про нас обещают снять сюжет на региональном телевидении, и уже есть предварительная договоренность с крупными Android-сообществами о постинге на следующей неделе.</p><p>Upd Параллельно все-таки была доделана вторая версия и выложена под незатейливым названием Simplest (Простейшая). Теперь осталось немного подождать, собрать всю статистику и поделиться со всеми результатами эксперимента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Опыт разработки инди-игры в жанре "кликер"</title>
      <link>https://tproger.ru/projects/killz</link>
      <comments>https://tproger.ru/projects/killz?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/killz</guid>
      <description><![CDATA[<p>Инди-разработчик Антон Чумаченко рассказывает о создании мобильного кликера KillZ на SpriteKit, поставленных целях и монетизации через рекламу.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/killz">Опыт разработки инди-игры в жанре "кликер"</a>»</p>]]></description>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 08 Jan 2016 15:41:23 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сегодня в рубрике рассказов о своих проектах история инди-разработчика Антона Чумаченко. О том, как создавалась игра <a href="https://itunes.apple.com/us/app/killz/id979226583?l=ru&amp;ls=1&amp;mt=8">KillZ</a>, какие были поставлены и достигнуты цели, и какие из этого можно извлечь выводы. Получился довольно любопытный материал, особенно для новичков. Передаём слово Антону.</p><p>KillZ — игра жанра “кликер”, основной отличительной чертой которой является наличие большого числа разнообразных улучшений.</p><p>Цели, которые я преследовал при создании этой игры –– это получение опыта написания мобильных игр и понимание на практике механизмов монетизации при помощи рекламы. В качестве движка я использовал SpriteKit, которую в первую очередь выбрал из-за удобного сочетания с нативными инструментами разработки в среде Xcode.</p><p>Исследования я решил начать со стандартного, но уже отживающего свой век маленького закрепленного баннера. Доход с такого баннера за 1000 показов составляет 20—50 центов (для России). То есть заработок разработчика прямо пропорционален времени, которое пользователь проводит в игре c момента ее установки и до момента последнего запуска. Именно над улучшением этого показателя я и решил работать в первую очередь. Материалов на эту тему в Интернете много.</p><p>Несложно прикинуть, что для получения 50 центов прибыли с одного пользователя нужно показать 1000—2500 баннеров. При 30-секундном обновлении –– это 8—20 часов игрового времени. А если в игру включить показ полноэкранного баннера с разумной периодичностью, то 50 центов можно заработать за 4—10 часов игрового времени.</p><p>Небольшой лайфках, как можно примерно оценить, сколько времени люди тратят на какую-либо игру. Запускаем игру, играем в нее минут 30, потом смотрим сколько людей оказались впереди нас в общей таблице лидеров, а сколько позади. Если мы оказываемся в первой половине, значит в среднем в игре люди проводят скорее всего менее 30 минут, если же во второй, то более 30 минут. Метод, конечно, неточный и работает не всегда, но позволяет сделать некоторые выводы. Например, я видел игру, поиграв в которую несколько минут я оказался в первых 5-ти тысячах игроков, при общем количестве в 700 тысяч. Сразу стало понятно, что усилия на маркетинг были потрачены впустую (отзывы в AppStore подтвердили вывод). Видел и обратный пример, когда из двух миллионов игроков, зарегистрированных в GameCenter после часа игры я оказался на 1 500 000 месте, то есть всего 25% игроков играли меньше часа, а остальные больше. На мой взгляд — это потрясающий результат!</p><p>Прошло долгих десять дней ожидания, и наконец моя игра KillZ <a href="https://itunes.apple.com/us/app/killz/id979226583?l=ru&amp;ls=1&amp;mt=8">появилась</a> среди прочих в AppStore (на текущий момент доступна уже вторая версия, в которой исправлено часть того, про что говорится в статье  — прим. ред.). Мой знакомый занимается видеообзорами приложений на канале Youtube, к нему я обратился за помощью в быстром наборе аудитории из нескольких сотен человек, чтобы иметь более-менее репрезентативную статистику. Для аналитики я использовал бесплатный инструмент <a href="http://www.flurry.com/">Flurry</a>, который производит логирование после прохождения каждого уровня. Это помогает понять, на каких уровнях люди чаще выбывают из игры, чтобы потом «подкрутить гайки». Кстати, заметил, что на уровнях, которые следуют после получения «зарплаты» и прокачки оружия отток аудитории составлял всего 3—4% с каждым уровнем, а на других — 8—14%. Наблюдение за друзьями, которые проходили эту игру и их комментарии вроде «О, зарплата появилась, класс!» или «Теперь минипушка будет стрелять сама, а я могу сидеть и ничего не делать» подтверждали получившиеся показатели. Вот некоторые факты из статистики:</p><ol><li>примерно 50% людей провели более одного часа в приложении;</li><li>среднее время игры составило примерно 4—5 часов;</li><li>всю игру прошли 6% людей (предполагал, что будет меньше).</li></ol><p>Ниже представлена таблица, показывающая количество пользователей, прошедших определенный уровень:</p><h3>Ошибки</h3><p>В целом показатели меня порадовали, учитывая, что это была первая версия игры, но миллионером я не стал, потому что:</p><ol><li>суммарно было около 1500 скачиваний;</li><li>были запрошены примерно миллион маленьких рекламных баннеров, а выданы всего около 60 тысяч (FillRate 6%);</li><li>полноэкранный баннер вообще не работал так, как планировалось;</li><li>отсутствуют внутриигровые покупки (впрочем, их я специально оставил на потом).</li></ol><h3>Как исправить?</h3><ol><li>связаться с несколькими сайтами, которые делают обзоры мобильных игр и предложить дать оценку игре; некоторые могут бесплатно согласиться разместить обзор;</li><li>поменять поставщика рекламы (до этого я использовал рекламные инструменты от Flurry, в итоге поменял на медиатор Adtoapp);</li><li>«допилить»;</li><li>рановато еще, пока сам не считаю игру достаточно хорошей, чтобы можно продавать там что-то (кроме стандартного отключения рекламы, которое я встроил только для того, чтобы проверить, как это работает).</li></ol><h3>Итоги</h3><p>В итоге я «заработал» чуть более $30 с первой версии. Работа над ошибками была произведена, но что делать дальше, было понятно. Нехватка времени вынудила продолжить работу над игрой спустя полгода.</p><p>Кроме исправления явных ошибок, я решил поддать дров в топку и добавить интереса к игре: раньше после 12—13 уровня игра становилась немного однообразной и отток аудитории возрастал. Во второй версии, кроме небольших доработок баланса, я добавил несколько кардинальных изменений:</p><ul><li>система улучшения оружия на каждом уровне;</li><li>с определенного уровня открывается лаборатория, где можно варить и смешивать зелья, чтобы дать кратковременный бонус для прохождения сложных уровней — это позволяет игроку рассчитывать стратегию;</li><li>новые противники, которые обладают разными свойствами и за прохождение дают не основную игровую валюту, а очки алхимии, которые нужны для варки более сильных зелий;</li><li>серебренную и золотую пушки, которые становятся доступны при достижении 30 и 40 уровня;</li><li>таблица рекордов, чтобы можно было смотреть, кто на каком уровне остановился (очень не хватало этого в прошлой версии, согласно отзывам).</li></ul><p>На мой взгляд игра стала интереснее, но без статистики выводы делать рано. Также была проведена работа с показом рекламы. Добавлена возможность добровольного просмотра видео-ролика с бонусными вознаграждениями.</p><h3>Что можно добавить</h3><ol><li>Если ожидания оправдаются и текущая версия выйдет на доход более 25 центов с одного скачивания, то начну активную работу над маркетингом и новой целью станут 20 тысяч установок. Иначе буду разбираться, где я просчитался.</li><li>Реализовать более качественную систему сбора статистики, чтобы еще лучше понимать, как менять баланс в следующий версиях, а также иметь возможность делать A/B тесты и оценивать их результаты.</li><li>Найти художника и поработать над дизайном игры.</li><li>Артефакты и элемент случайности в их выпадении.</li><li>Ввести дополнительные механики по удержанию старых и привлечению новых пользователей:начальный видеоролик и более качественная обучалка для того, чтобы снизить отток на первых уровнях;ежедневные награды;доска с достижениями и награды за них (некоторые просто любят собрать все звездочки);добавить режим игры на время (гораздо более сложный — для игроков с опытом);реферальные акции (необходимо сделать эту функцию удобной и желаемой для игрока);внутриигровые покупки (здесь нужно быть аккуратным, чтобы не напугать «донатом», размер вознаграждения и его уникальность должны быть оптимальными) — но этот пункт, если качество игры будет устраивать лично меня.</li></ol><p>Напоминаем, что если у вас есть свой проект, о котором вы хотели бы рассказать аудитории tproger, то стоит написать на <a>admin@tproger.ru</a>, а к письму прикрепить черновик материала или хотя бы наброски. Мы рассмотрим ваше предложение и ответим в течение нескольких дней.</p>]]></content:encoded>
    </item>
    <item>
      <title>Save the Penguin — рассказ о первом опыте разработки под Android</title>
      <link>https://tproger.ru/projects/save-the-penguin</link>
      <comments>https://tproger.ru/projects/save-the-penguin?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Vladimir Gabrinevski]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/save-the-penguin</guid>
      <description><![CDATA[<p>Программирование велось в Unity в свободное время и заняла около месяца. Идея для игры пришла сама собой: таймкиллер в портретной ориентации с возможностью игры одним пальцем.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/save-the-penguin">Save the Penguin — рассказ о первом опыте разработки под Android</a>»</p>]]></description>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 16 Nov 2015 19:53:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>Наверное, многие хотели бы разработать собственную игру: кто-то хотел заработать денег, кто-то получить бесценный опыт. Мы относимся ко второй категории, поэтому игра не насыщена рекламой, в ней отсутствуют встроенные покупки.</p><p>Идея для игры пришла сама собой, было решено сделать таймкиллер в портретной ориентации с возможностью игры одним пальцем. Я считаю, что для первой игры не стоит выбирать сложный проект, велика вероятность потерять мотивацию, отвлечься и в итоге забросить это дело. Главным героем игры стал пингвин, просто потому что пингвины крутые.</p><p>Разработка велась на Unity в свободное время и заняла около месяца. Над выбором движка долго не думали, ибо мы знаем C# и давно хотели познакомиться с Unity поближе. В процессе разработки возникали некоторые вопросы, о решении которых я расскажу ниже, надеюсь, кому-то из начинающих разработчиков они будут полезны.</p><h3>Первый вопрос. Адаптация под разные разрешения</h3><p>Мы пошли по самому простому пути: использовали текстуры большего размера, чем требовалось, и привязывались не к конкретному разрешению, а к соотношению сторон. В нашем случае все получилось достаточно неплохо из-за характера текстур, мы могли пожертвовать той или иной частью изображения.</p><h3>Второй вопрос. Оптимизация</h3><p>Первая версия игры была написана достаточно быстро, и мы собрали из друзей команду тестировщиков. Оказалось, что на старых устройствах игра вылетала из-за большого потребления оперативной памяти. Для нас это было неожиданным поворотом, но после недолгих размышлений решение получилось следующим:</p><ul><li>Выбор размера ассета в зависимости от разрешения экрана.</li></ul><ul><li>В игре предусмотрена покупка вещей для Пингвина, т.е. смена скина, в первой версии использовался алгоритм, при котором все скины хранились в оперативной памяти вне зависимости от их использования в данный момент. Логика смены скинов была полностью переделана на более правильную, по нашему мнению.</li></ul><p>Также при разработке мы часто использовали метод GetComponent в Update, что крайне не рекомендуется делать, т.к. GetComponent является ресурсозатратной операцией, в большинстве случаев её целесообразно вынести в метод Start, что мы и сделали, тем самым немного увеличив производительность.</p><h3>Третий вопрос. Сохранение данных</h3><p>В Unity существует несколько способов сохранения данных. И мы в очередной раз пошли по самому простому пути — хранение данных с помощью встроенного класса PlayerPrefs. В данном случае хранимые данные не должны превышать 1 МБ, в принципе, вполне подходит под наши задачи, но нам нужно хранить информацию о скинах (доступен тот или иной скин пользователю). По большому счету, это булевая переменная, но хранить несколько десятков таких переменных достаточно затратно. Решение очевидно — использование битовых масок.</p><p>Вывод: eсли вы сомневаетесь, разрабатывать своё приложение или нет — определённо да! Это бесценный опыт, который вам точно не окажется лишним. Главное — помнить об одном: «Успех складывается из мелочей»; если вы взялись за что-то, сделайте это качественно, в наше время плохо сделанный продукт заведомо обречён на провал.</p><p>Ссылка на игру: https://www.apkmonk.com/app/com.pacetap.savethepenguin/</p><p>P.S. Будем очень признательны за вашу критику и фидбэк.</p>]]></content:encoded>
    </item>
    <item>
      <title>Дайджест заявок IT-волонтёра</title>
      <link>https://tproger.ru/projects/it-volunteer-tasks</link>
      <comments>https://tproger.ru/projects/it-volunteer-tasks?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Пётр Соковых]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/it-volunteer-tasks</guid>
      <description><![CDATA[<p>Некоммерческие организации без штатного программиста оставляют задачи на платформе IT-волонтёр, а специалисты откликаются и помогают их решать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/it-volunteer-tasks">Дайджест заявок IT-волонтёра</a>»</p>]]></description>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 11 Nov 2015 14:28:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>Проект IT-волонтёр родился из идеи, что есть некоммерческие организации, которые сами не справляются решением текущих задач и им нужна помощь it-специалистов.</p><p>Сами некоммерческие организации и проекты активно решают социальные проблемы: помогают бездомным, ухаживают за стариками, ищут пропавших или спасают животных. Часто у них нет штатного программиста или сисадмина, который бы помогал им справляться с трудностями при работе в Интернете. Мы предложили им оставлять свои задачи на платформе.</p><p>Вы можете просматривать заявки, откликаться и помогать некоммерческим организациям – для портфолио или резюме, чтоб немного подзаработать или приобрести опыт и просто для души.</p><p>Все актуальные заявки вы можете посмотреть на сайте проекта <a href="http://itv.te-st.ru/">IT-волонтёр</a>, вот некоторые из них:</p><h3>Доработать и настроить сайт благотворительного фонда</h3><ul><li>Сфера проекта: Вы помогаете лечению детей</li><li>Описание: Нужно доработать сайт благотворительного фонда по поиску больных детей и сбору пожертвований для их лечения, подвести под стандарты, помочь разобраться с настройками, подогнать под лояльность поисковых систем и соцсетей.</li><li>Заявитель: Благотворительный фонд «Все поможем детям» Юрия Котанкина (Татарстан). Сайт фонда — Fond-Kotankina-Detyam.ru</li><li>Полное описание заявки и контакт сотрудника фонда по <a href="https://itv.te-st.ru/tasks/nuzhno-dorabotat-sajt-blagotvoritelnogo-fonda/">ссылке</a></li></ul><h3>Разработать мобильное приложение для мигрантов и беженцев</h3><ul><li>Сфера проекта: Вы решаете проблемы мигрантов в России</li><li>Описание: Некоммерческая организация ищет в свою команду разработчика-волонтера в сфере мобильных приложений, которому интересно реализовать общественный и социальный проект по защите прав мигрантов, беженцев, лиц без гражданства и иностранных граждан, проживающих на территории РФ, а это более 17 миллионов человек по данным ФМС России.</li><li>Основная задача: поэтапная разработка мобильного приложения на платформе Android.<br />Дизайн можно использовать унифицированный или уникальный по желанию разработчика.</li><li>Заявитель: АНО «Юридический центр «БАСТИОН» www.pravo-bastion.ru</li><li>Полное описание заявки и контакт сотрудника фонда по <a href="https://itv.te-st.ru/tasks/razrabotka-mobilnogo-prilozheniya-dlya-migrantov-i-bezhentsev-na-android/">ссылке</a></li></ul><h3>Создать сайт благотворительному фонду</h3><ul><li>Сфера проекта: Вы помогаете людям с редким заболеванием</li><li>Описание: Нужен полноценный ресурс о редком орфанном заболевании «Наследственный ангионевротический отек», где помимо общей информации о заболевании хочется, чтобы была возможность регистрации для пациентов, где в личном кабинете они могли бы вести статистику своих отёков.</li><li>Заявитель: «Межрегиональная Общественная Благотворительная Организация «Общество пациентов с Наследственным Ангионевротическим Отеком и другими орфанными заболеваниями» занимается юридическими консультациями, поддержкой и помощью в получении дорогостоящих лекарственных средств от государства для купирования отеков.</li><li>Полное описание заявки и контакт сотрудника фонда по <a href="https://itv.te-st.ru/tasks/sajt-blagotvoritelnogo-fonda-v-podderzhku-lyudej-stradayushhih-redkim-zabolevaniem-quot-nao-quot/">ссылке</a></li></ul><h3>Переработать на сайте форму пожертвований</h3><ul><li>Сфера проекта: Вы участвуете в работе «Российского Красного креста»</li><li>Описание: Нужно подкорректировать форму пожертвований в плагине Лейка (CMS WordPress).<br />Нужны следующие изменения: заменить поле выбора суммы, добавить несколько обязательных полей, изменить внешний вид формы.</li><li>Заявитель: Кемеровское региональное отделение ООО «Российский Красный Крест».</li><li>Полное описание заявки и контакт сотрудника фонда по <a href="https://itv.te-st.ru/tasks/pererabotat-formu-pozhertvovanij-i-kartochku-kampanii-plagina-lejka/">ссылке</a></li></ul><h3>Перенести сайт благотворительной организации на новый движок</h3><ul><li>Сфера проекта: Вы помогаете нужнающимся детям Калужской областиОписание: После лечения вирусов на сайт не добавляются материалы (фото, видео), текст добавляется без редактирования и с ошибками. Программисты, с которыми ранее общались, советуют переписать заново и перенести на новый движок (нынешний — joomla — устарел).</li></ul><p>Заявитель: Межрегиональная благотворительная общественная организация в помощь детям в трудной жизненной ситуации «Новый день» 5 лет помогает нуждающимся детям, одиноким и многодетным матерям в Калужской области.<br />Полное описание заявки и контакт сотрудника фонда по <a href="https://itv.te-st.ru/tasks/perenesti-sajt-blagotvoritelnoj-organizatsii-na-novyj-dvizhok-s-korrektirovkoj/">ссылке</a></p><p><a href="http://itv.te-st.ru/">IT-волонтёр</a> – это некоммерческий проект <a href="http://te-st.ru/">Теплицы социальных технологий</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Дилемма — отвечай на интересные вопросы и вырабатывай свою точку зрения</title>
      <link>https://tproger.ru/projects/sandbox-dilemma</link>
      <comments>https://tproger.ru/projects/sandbox-dilemma?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/sandbox-dilemma</guid>
      <description><![CDATA[<p>Люди боятся говорить правду, затрудняются принимать решения и часто не имеют собственного мнения по актуальным темам. Проект предлагает это исправить.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/sandbox-dilemma">Дилемма — отвечай на интересные вопросы и вырабатывай свою точку зрения</a>»</p>]]></description>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 14 Sep 2015 17:16:37 GMT</pubDate>
      <content:encoded><![CDATA[<p>В современном обществе существуют такие актуальные проблемы, как: боязнь искренности — люди боятся говорить правду и быть за это осмеянными или осужденными; люди затрудняются в принятии решений, либо этого делать совершенно не умеют; у людей часто отсутствует своя точка зрения на многие актуальные темы. И это плохо. На самом деле это очень плохо. Ведь абсолютно каждый человек на этой планете в любой момент времени должен четко знать, что он делает и почему. «Дилемма» была создана для того, чтобы помогать решению этих проблем. Учитывая все вышеперечисленное, проект еще является и развлекательным, ибо структура многих вопросов была построена именно с целью вызвать улыбку у пользователя.</p><p>Вот вы, дорогой читатель этой публикации, позвольте мне задать вам вопрос. Представьте себе мир без насилия и войн, где все люди живут в дружбе и согласии; но в этом мире нет интернета и других аналогов сети. Согласились бы вы жить в таком мире? Да или нет? Отвечая на подобные вопросы, пользователи развивают свою точку зрения и получают пищу для размышлений на темы, о которых раньше могли и не задумываться.</p><p>Хорошо, а если так: «Просто представьте, что вы — самый привлекательный человек на земле, но при каждом первом поцелуе всегда непроизвольно пукаете. Согласитесь?». Я сам люблю задавать друзьям подобные «странные» вопросы, а затем смотреть на их реакцию. Если подумать, это довольно весело, ведь абсолютно каждый человек встречает всевозможные дилеммы в своей повседневной жизни. Разница лишь в том, что у одних они совершенно обыкновенные, а у других — решают судьбу и будущее. Все это я и пытался объединить в одном приложении.</p><p>На самом деле при достижении большой аудитории проект может представлять очень высокую ценность, ибо позволяет собирать статистику о настрое людей в определенных географических зонах. При всем при этом ответы каждого пользователя всегда будут анонимными, а приложение не требует ни регистрации, ни авторизации. Таким образом можно использовать «Дилемму» для анализа всевозможных статистических и социальных экспериментов.</p><p>Техническая реализация оказалась довольно простой. Изначально все было написано на Objective C в XCode. В качестве backend’a был использован Parse. С момента запуска этот сервис продолжает радовать своих пользователей всевозможными «крутыми и удобными штучками». Рекомендую всем небольшим проектам, кто не хочет заморачиваться на настройке своего сервера, ибо даже бесплатный тариф позволяет обрабатывать внушительные вычислительные объемы.</p><p>На данный момент «Дилемма» имеет несколько тысяч загрузок и постепенно набирает обороты. Планируется выпуск Android-версии, для охвата более широкой аудитории. А если актуален вопрос: «почему iOS была выбрана как стартовая платформа?», ответ будет простым. Я принимал участие в летней стартап школе (http://thesummerstartupschool.com), где участники должны были построить готовый iOS продукт за 8 недель.</p><p>Ознакомиться с «Дилеммой» можно прямо сейчас, скачав по ссылке:</p><p>А с автором всегда можно связаться по электронной почте:</p><p><a>anuar.serikov@gmail.com</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Песочница проектов. ВКМетр — расширенная статистика сообществ ВКонтакте</title>
      <link>https://tproger.ru/projects/sandbox-vkmeter-smm</link>
      <comments>https://tproger.ru/projects/sandbox-vkmeter-smm?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/sandbox-vkmeter-smm</guid>
      <description><![CDATA[<p>Сервис VKMeter.ru даёт реал-тайм статистику по пабликам и помогает SMM-специалистам и администраторам сообществ увеличивать охват публикаций.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/sandbox-vkmeter-smm">Песочница проектов. ВКМетр — расширенная статистика сообществ ВКонтакте</a>»</p>]]></description>
      <category><![CDATA[ВКонтакте]]></category>
      <category><![CDATA[Статистика]]></category>
      <category><![CDATA[Песочница]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 12 Aug 2015 09:31:57 GMT</pubDate>
      <content:encoded><![CDATA[<h3>Что такое ВКМетр?</h3><p>VKMeter.ru — сервис, предоставляющий расширенную реал-тайм статистику по вашим пабликам. Он дает дополнительные возможности для её анализа и улучшения, уже есть кейс по реальному увеличению охвата сообщества благодаря публикации постов во время, подобранное с помощью ВКМетра.</p><h3>Для кого предназначен ваш сервис и какие проблемы он решает?</h3><p>Расширенная статистика будет полезна SMMщикам и администраторам сообществ, желающим преуспеть в развитии. В первую очередь проект решает проблемы бедности стандартной статистики ВКонтакте: к сожалению, в ней можно увидеть только несколько показателей по дням. У нас же намного больше функций, и детализация не по дням, а по минутам!</p><h3>Что же он умеет и чем полезен?</h3><p>Кроме поминутных графиков основных показателей на протяжении недели и месяца, у нас есть график количества подписчиков онлайн на протяжении дня, помогающий выбрать лучшее время для публикации постов, график прироста, позволяющий оценить качество того или иного поста. Например, если после поста многие отписались, то пост плохой, если, наоборот, много подписок, то пост хороший. Таким образом можно отсеивать посты, которые плохо влияют на сообщество, и улучшать его показатели.</p><p>И это ещё не всё: ВКМетр имеет много фич, но скоро будет ещё больше. Например, на днях мы планируем добавить функцию сравнения произвольных дней. Для самых любознательных там даже спрятано несколько пасхалок, слабо найти их все? ?</p><h3>Долго кодили? Какие технологии использовали? Какой хостинг выбрали? Как собираетесь раскручивать?</h3><p>Разработка первой версии заняла около 2х недель, большая часть которых, как и полагается, ушла на игру в Risen и распитие пива. По большей части у нас всё стандартно: PHP на бекенде, немного JS и Bootstrap на фронтенде. В качестве библиотеки для рендеринга графиков было решено выбрать flot.js — она, конечно, старая, но имеет большое комьюнити, много плагинов, функций и поддержку ишака старых браузеров.</p><p>В качестве хостинга решено было выбрать Rixis Cloud Hosting из-за его дешевизны (от 15 рублей в месяц), производительности и, самое главное, отзывчивой технической поддержки, которая всегда идет навстречу.</p><p>Из-за активной фазы разработки до серьезной раскрутки руки пока не дошли, но паблик <a href="https://vk.com/smmpub">SMMщики </a> c удовольствием бесплатно разместил о нас несколько публикаций, что дало нам первых пользователей.</p><h3>Я не администратор сообщества, мне не нужны все эти ваши модные штуки и паблики ВКонтакте, мне не интересен ваш сервис. Что мне делать?</h3>]]></content:encoded>
    </item>
    <item>
      <title>Песочница проектов. Nyctophilia — 2D психологический триллер</title>
      <link>https://tproger.ru/projects/sandbox-nyctophilia</link>
      <comments>https://tproger.ru/projects/sandbox-nyctophilia?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/sandbox-nyctophilia</guid>
      <description><![CDATA[<p>Инди-квест с сильным упором на сюжет: автор рассказывает о замысле игры, влиянии Lone Survivor и о том, как менялись детали проекта.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/sandbox-nyctophilia">Песочница проектов. Nyctophilia — 2D психологический триллер</a>»</p>]]></description>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 03 Aug 2015 22:11:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>Идея создать подобную игру появилась у меня достаточно давно. Это должен был быть квест с сильным упором на сюжет, нарисованный в стиле пиксель-арта. Общие детали менялись бесчисленное количество раз, и в итоге получилась эта игра. Источником вдохновения послужила другая инди-игра под названием Lone Survivor.</p><p><b>Трейлер:</b></p><p>Точное решение относительно того, какой должна быть игра, пришло незадолго до начала непосредственной разработки. Языком программирования стал Java. Это было логично, ведь до этого я разработал две игры на Android с помощью этого языка. Чтобы упростить процесс, был использован фреймворк libgdx. Он позволил избежать ненужной возни с низкоуровневыми вещами.</p><p>Проект делался в свободное от учебы время. Поначалу разработка шла быстро, был реализован фундамент для создания уровней. Игровая механика, система скриптов, редактор уровней. На это ушло чуть меньше полугода. Когда пришло время создавать непосредственно уровни, оказалось, что система далеко не так хороша, как показалось поначалу. Это принесло полезный опыт и понимание, как сделать лучше в следующий раз. Разработка сюжетной кампании также потребовала около полугода.</p><p>Геймплей состоит из двух частей. Это день и ночь. Днем игрок решает задачи в доме, следит за своим состоянием, изучает окружающие предметы. Ночью и во сне происходят странные вещи, появляется особая механика решения задач, основанная на переключении между персонажами.</p><p><b>Геймплей</b>:</p><p>Особое внимание было уделено саундтреку. Он состоит из треков, написанных несколькими музыкантами, причем некоторые из них были созданы специально для игры, а другие были любезно предоставлены по моей просьбе.</p><p><b>Саундтрек:</b></p><p>Технически уровень состоит из сцен. Все сцены хранятся в структуре данных типа HashMap. Это означает, что с каждой сценой в паре идет ключ, по которому можно получить доступ к ней. В свою очередь, внутри каждой сцены есть такой же список объектов и источников света. Таким образом, с каждым элементом уровня можно взаимодействовать, зная его имя. Это помогает в работе с редактором уровней.</p><p>Для каждого уровня есть свой атлас текстур, в котором хранится вся графика, нужная именно на этом уровне. Это имеет свои достоинства и недостатки. С одной стороны, все хранится в одном месте, это удобно. С другой стороны, многие элементы приходится дублировать, если они появляются в игре несколько раз.</p><p>В то время как основа для игры написана на Java, скрипты для уровней писались с помощью JavaScript. Редактор уровней встроен в игру, поэтому их можно легко редактировать и тестировать, не переключаясь между разными приложениями. Чтобы загрузить уровень, достаточно передать его название игре. Все ресурсы, скрипты и прочее будут загружены автоматически. Каждый объект на уровне может иметь собственный скрипт, срабатывающий при определенном событии. Скрипты запускаются в отдельном потоке, чтобы во время каких-нибудь сюжетных сцен сама игра не останавливалась. Это позволяет достаточно подробно прорабатывать взаимодействие с окружающим миром, но занимает время.</p><p>Также в игре присутствует простая система освещения. Она используется в темных локациях для создания атмосферы. В сочетании с эффектом «старого монитора» может получиться интересная картинка.</p><p>Сейчас проект полностью рабочий, его можно спокойно пройти до конца, не встретив критических проблем. Но работа над ним продолжается. Вносятся изменения, основанные на фидбеке игравших людей, создаются дополнительные звуки, идет работа над переводом на английский язык.</p><p>В планах исправить все оставшиеся небольшие доработки и выпустить игру в Steam. Она будет полностью бесплатной. Я уже прошел сервис Steam Greenlight и готовлюсь к релизу. Опыт показал, что основная часть трафика генерируется самим Steam в первые 2–3 дня. Дальше посещаемость автоматически падает до примерно 50 человек в день, поэтому судьба проекта решается в первые дни, если не привлекать стороннюю поддержку.</p><p><a href="http://steamcommunity.com/sharedfiles/filedetails/?id=476846326">Проект в Steam Greenlight</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Песочница проектов. Endless TD — Savior of the Humanity</title>
      <link>https://tproger.ru/projects/sandbox-endless-td-savior-of-the-humanity</link>
      <comments>https://tproger.ru/projects/sandbox-endless-td-savior-of-the-humanity?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/sandbox-endless-td-savior-of-the-humanity</guid>
      <description><![CDATA[<p>Юрий из инди-команды Heart beat Games рассказывает о первой игре команды, её отличиях от привычного жанра и ошибках, допущенных при разработке.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/sandbox-endless-td-savior-of-the-humanity">Песочница проектов. Endless TD — Savior of the Humanity</a>»</p>]]></description>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 27 Jul 2015 15:05:52 GMT</pubDate>
      <content:encoded><![CDATA[<p>Добрый день.</p><p>Меня зовут Юрий, я из инди-команды Heart beat Games. Недавно мы выпустили нашу первую игру в жанре tower defense — «Endless TD — Savior of the Humanity». Игра получилась интересной и нестандартной для жанра, поэтому хочу рассказать о ней больше. Также немного расскажу о нашей команде и ошибках, которые мы допустили.</p><p>После того, как собралась наша команда, что произошло очень быстро и спонтанно, мы начали думать, какую игру мы хотим сделать. Когда мы не нашли в Play Market’e игру, которая удовлетворяла бы наши потребности, а также, потому что в команде было очень много любителей жанра tower defense, приняли решение создавать игру в жанре strategy/tower defense. Поставили перед собой цели — сделать механику, которая будет нестандартной и интересной, сделать игру, которая будет нравиться нам самим.</p><p>Перед тем, как рассказать об игре, хочу остановиться на ошибках, которые мы допустили в ходе разработки и работы команды в целом. Первой и главной ошибкой было пренебрежение планированием, за что в итоге пришлось расплачиваться дополнительным временем разработки. Совет для начинающих разработчиков — планируйте заранее все: от маркетингового плана до архитектуры проекта. Это сэкономит вам много времени и денег. Вторая ошибка, которую мы допустили — спешка. Нам очень хотелось выпустить «Endless TD». Как только код и оптимизация были закончены, мы сразу опубликовали игру, но это привело нас к третьей ошибке — ASO и маркетинг. Уже после релиза мы начали заниматься ASO и разрабатывать более четкий маркетинговый план. Четвертое и последнее, что мы не учли — выработка идей и время на это. Выработка идей — очень важный аспект создания хорошей и интересной игры. Изначально мы потратили слишком мало времени на это и, возможно, учли не все фишки, которые были бы интересны пользователям. Поэтому сейчас мы каждую неделю проводим мозговой штурм, на котором придумываем новые механики или игры. Если ваша команда состоит из 3-х и более человек, очень советую попробовать такой подход. Это не только интересно и заставляет мозг работать, но и полезно, т.к. зачастую получаются довольно нестандартные и интересные решения. Сейчас мы научились на своих ошибках — планируем все заранее, тратим больше времени на выработку идей и прототипирование. Надеюсь, молодые и начинающие разработчики учтут эти советы, и они им помогут. Это основные и самые острые проблемы, с которыми мы столкнулись в ходе разработки.</p><p>А теперь о самой игре. Особенности «Endless TD»:</p><ul><li>hardcore-стратегия в жанре tower defense;</li><li>нарастающая сложность;</li><li>свободная застройка на карте;</li><li>бесконечный игровой процесс;</li><li>огромное количество оборонительных стратегий;</li><li>орды монстров из другого измерения.</li></ul><p>Также мы не забыли о главном в TD:</p><ul><li>большое количество оборонительных башен;</li><li>простая и понятная механика усовершенствования башен;</li><li>специфические башни и способы их улучшения;</li><li>усилители, которые позволят быстро расправиться с противником;</li><li>навыки, увеличивающие оборонительную мощь игрока.</li></ul><p>Еще одна особенность «Endless TD» — использование 3D-контента, что для мобильных устройств редкость. И вот почему. Проблема, с которой мы столкнулись в конце разработки — оптимизация 3D-контента. Изначально мы очень подробно детализировали все объекты, но проект был рассчитан на большинство устройств, и на них, увы, он тормозил. Поэтому пришлось пожертвовать детализацией в пользу производительности.</p><p>В «Endless TD» мы используем 2 вида монетизации — реклама и внутриигровые покупки. С первым все предельно просто. Игрок поощряется за просмотр рекламы. Внутриигровые продажи более обширны. Например, вы можете купить новые башни, сбросить откат усилителя или починить базу. Но при создании мы твердо решили, что покупки практически не будут влиять на баланс.</p><p>Недавно мы выпустили 6-е обновление, в котором добавили еще больше функций и фишек для игрока. В дальнейшем планируем расширить функционал игры и даже выпустить вторую часть.</p><p>Для «Endless TD» мы сделали небольшой промо-мультфильм. Он о нашем любимом монстре из игры — Толстяке. Обязательно его посмотрите: <a href="https://www.youtube.com/watch?v=S04BI6MBjnE">https://www.youtube.com/watch?v=S04BI6MBjnE</a></p><p>Будем благодарны сообществу за отзывы и оценки игры.</p><p>Приглашаем всех желающих стать бета-тестировщиками. Вы сможете поиграть в наши новые проекты раньше всех и помочь нам в разработке. Для этого вступите в нашу группу в google+: <a href="https://plus.google.com/communities/104775240047712543200">https://plus.google.com/communities/104775240047712543200</a></p><p>А тем, кому понравился рассказ, предлагаю вступить в наши соц. группы:</p><ul><li><a href="http://vk.com/heartbeatgamesofficial">http://vk.com/heartbeatgamesofficial</a>;</li><li><a href="https://www.facebook.com/HeartBeatGamesOfficial">https://www.facebook.com/HeartBeatGamesOfficial</a>;</li><li><a href="https://twitter.com/HBGamesOfficial">https://twitter.com/HBGamesOfficial</a>;</li><li><a href="https://plus.google.com/+HeartBeatGamesOfficial/">https://plus.google.com/+HeartBeatGamesOfficial/</a>;</li><li><a href="https://play.google.com/store/apps/dev?id=6768660119375902455">https://play.google.com/store/apps/dev?id=6768660119375902455</a>.</li></ul><p>В наших группах вы сможете задавать вопросы непосредственно разработчикам игры и общаться в кругу единомышленников.</p><p>С уважением, команда Heart beat Games.</p>]]></content:encoded>
    </item>
    <item>
      <title>Песочница проектов. inkHunter</title>
      <link>https://tproger.ru/projects/sandbox-inkhunter</link>
      <comments>https://tproger.ru/projects/sandbox-inkhunter?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/sandbox-inkhunter</guid>
      <description><![CDATA[<p>Мобильное приложение показывает, как выбранное тату будет смотреться на теле: нужно нарисовать три линии на коже и навести камеру смартфона.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/sandbox-inkhunter">Песочница проектов. inkHunter</a>»</p>]]></description>
      <category><![CDATA[Дополненная реальность]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 22 Jul 2015 10:52:46 GMT</pubDate>
      <content:encoded><![CDATA[<p>inkHunter — мобильное приложение для  тех,  кто хочет сделать  тату. С его помощью можно выбрать татуировку и проверить, как она будет смотреться на твоем теле, при помощи дополненной  реальности.  Просто  выбери  понравившееся  тату,  нарисуй  3 линии на коже и наведи на них камеру смартфона.</p><p><a href="https://itunes.apple.com/ua/app/inkhunter-try-tattoo/id991558368?mt=8">Скачать приложение можно по ссылке</a></p><p>Эта необычная идея пришла нам в голову во время 48Hackathon, который проходил в ХНУ  имени  Каразина  в  Харькове.  Тогда  мы  собрали  команду  в  последний  день регистрации  и  назвались  LIFO  (забавно,  учитывая,  что  наша  команда  победила).</p><p>Темой хакатона была дополненная реальность. 3 часа мы не могли определиться, что же  нам  делать:  разрабатывать  новую  игру-шутер  или  помочь  выбрать  стол  в  тон  к шторам,  как  делает  IKEA.  Потом  начали  думать  о  примерке  вещей:  очков,  одежды, украшений. Но почему бы не примерять на своем теле татуировки?</p><p>Легко сказать, но как сделать? О распознавании образов и ios-девелопменте мы тогда знали очень мало. Но на это и нужен хакатон — делать крутые вещи, зная только то, как они должны выглядеть. Т.к. на конкурсе нужно было представить только прототип,   мы  пошли  по  пути  наименьшего  сопротивления  и  для  распознавания  метки использовали  Metaio  SDK.  С  приложением  для  iOS  тоже  не  возникло  больших сложностей,  и  через  2  дня  у  нас  был готов  симпатичный  прототип,  с  которым мы  и выиграли хакатон.</p><p>Вдохновленные успехом, мы начали заниматься развитием проекта, но после месяца разработки  мы  не  получили  желаемого  результата.  Потом  наступили  университет, работа, и проект завис в воздухе почти на полгода. Зимой стартовала бизнес-школа Karazin  Startups,  в  которой  мы  приняли  участие  с  inkHunter,  и  работа  над  проектом возобновилась.</p><p>Мы  решили,  что использовать готовое SDK —  не  вариант. Поэтому мы  разработали свою  собственную метку,  которую можно нарисовать где  угодно обычной ручкой или карандашом для глаз.</p><p>Кроме  этого, написали  2  библиотеки:  по  распознаванию  метки  на  основе  OpenCV  и реалистичному  нанесению  тату  на  поверхность.  Сложность  нанесения  татуировки  в том, что кожа имеет неоднородный цвет + блики в разных участках только усложняют дело.</p><p>В мае мы <a href="https://itunes.apple.com/ua/app/inkhunter-try-tattoo/id991558368?mt=8">выпустили приложение</a> на App Store. Поначалу скачивания шли медленно, т.к.  денег  на  раскрутку  у  нас  не  было.  А  публиковать  информацию  о  приложении бесплатно  соглашались  немногие.  Поэтому  мы  решили  продвигать  проект собственными  силами.  Питчили  об  inkHunter  на  различных  ивентах:  Kharkiv  StartUp 2015,  Kharkiv  Tattoo  Fest  2015,  Mystery  Play,  занимались  раскруткой  в  соц.  сетях  и SEO.  Весной  мы  выиграли  второе  место  на  iHub  Ring,  и  дела  пошли  вверх,  о  нас начали писать сами.</p><p>После этого месяц назад нас пригласили в Сан-Франциско на  Thiel Foundation Summit  —  саммит  молодых  программистов,  ученых  и  предпринимателей,  устраиваемый Питером Тилем, где мы выиграли 1000$ за лучший demo pitch.</p><p>Наши  ближайшие  планы  —  выпуск  новой  версии  с  цветными  татуировками,  новой галереей  эскизов  и  крутым  дизайном.  Кстати,  об  этом.  Мы  ищем  человека,  который сможет  разработать  дизайн  для  нашего  приложения.  Так  что  всем,  кто заинтересовался — стучитесь к нам на  <a href="https://www.facebook.com/inkHunter">facebook</a> и почту <a>inkHunterApp@gmail.com</a>. И  напоследок:  спасибо  Типичному  Программисту  за  возможность  рассказать  про inkHunter.  Будем  рады  любым  комментариям  и  предложениям,  которые  вы  можете оставить на наших страницах:</p><p><a href="http://inkhunter.tattoo/">Сайт</a>, <a href="https://vk.com/inkhunter">Вконтакте</a>.</p><p>Олександра Рогачева, CEO inkHunter</p>]]></content:encoded>
    </item>
    <item>
      <title>2+2 — Решай задачи и развивай устный счет.</title>
      <link>https://tproger.ru/projects/2-plus-2</link>
      <comments>https://tproger.ru/projects/2-plus-2?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/2-plus-2</guid>
      <description><![CDATA[<p>Автор вдохновился дизайном DOTS и наблюдениями за игроками в 2048 в метро, чтобы сделать красивую игру без прямых аналогов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/2-plus-2">2+2 — Решай задачи и развивай устный счет.</a>»</p>]]></description>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 11 Jul 2015 18:15:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>Я всегда мечтал сделать интересный продукт, сервис, программу, которые бы помогали людям или как-то занимали их время. Я наблюдал в метро, как люди играют в 2048 и получают удовольствие от этого процесса. И в голову мне пришла мысль сделать игру, аналогов которой нет, при этом она должна быть интересная и красивая.</p><p>Скрывать не буду: на создание этой игры меня вдохновила DOTS. Впервые увидев ее дизайн, я был в полном восторге. Разработка игры началась в сентябре прошлого года. Я особо не торопился при создании, поэтому процесс затянулся, выпуск часто откладывался, но в конце концов я ее выпустил. Я работаю программистом Unity, поэтому выбор технологии был очевиден. В то время, когда я начал разработку проекта, мои знания Unity были невелики, и, постепенно разрабатывая продукт, я улучшал свои навыки использования платформы.</p><p>Вскоре у меня был готов первый прототип, который я показал своим друзьям и знакомым — в целом игра всем понравилась, и главным ее козырем в тот момент был дизайн. На плоский минималистичный дизайн меня вдохновил появившийся Material Design от Google. Интерфейсы собирались с трудом, вымерялся каждый пиксель, шла верстка, пока не получился такой стиль.</p><p>Я часто консультировался по вопросам дизайна с одной из своих коллег, Мисик Кариной, ее видение общей концепции помогло игре обрести свой вид. Интерфейс очень часто менялся и становился только лучше и лучше.</p><p>В игре изначально был один режим, который сейчас называется «Головоломка». В нем нужно было решать примеры, которые постепенно меняли свою сложность, по мере продвижения вперед менялся и статус игрока. После нескольких консультаций с опытным специалистом было принято решение добавить в игру еще 3 развлекательных режима:</p><ul><li>Режим «IQ Тест» считает количество задач, решенных игроком за одну минуту, и потом выносит вердикт его интеллектуальных способностях.</li><li>Режим «Блиц», в отличие от Головоломки, оставляет игроку только 2 варианта ответа на задачу: «Да» или «Нет».</li><li>Режим «Алкотестер» работает примерно по тому же принципу, что и режим «IQ Тест».</li></ul><p>Игра проходила первичное тестирование, в ходе которого выяснилось, что некоторые игроки испытывают трудности в решении задач. Ввиду этого было решено добавить в игру несколько помощников, которые бы позволяли решать примеры быстрее:</p><ul><li>Пропуск примера позволяет заменить текущий пример на новый.</li><li>Подсказка показывает правильный ответ на задачу.</li><li>Замедление времени снижает скорость времени в 2 раза.</li></ul><p>В будущем планируется расширение количества режимов, улучшение дизайнерской составляющей проекта.</p><p>На данный момент в игре 4 режима, и по первичным отзывам мы решили добавить еще как минимум два.</p><p>Первый режим является продолжением режима «Головоломка». Он будет намного сложнее, в нем меньше времени на то, чтобы дать правильный ответ, а также ответ не будет подсвечиваться.</p><p>Второй режим под названием «Бесконечность» будет сочетать в себе элементы всех режимов. В нем игрок сможет скоротать время в поездке или в ином месте. Основная идея данного режима — игрок просто решает примеры, без времени, без жизней. Это весело и позволяет игрокам тренировать устный счет каждый день на задачах разной сложности.</p><p>В игре планируется улучшить систему аналитики, а также сделать более заметным функционал модуля «Рассказать друзьям».</p><p>На данный момент нам нужно как можно больше отзывов, чтобы сделать игру лучше. Ведь мы создаём её абсолютно для всех вокруг, а не только для самих себя.</p><p>Наша официальная группа Вконтакте: <a href="http://vk.com/sharkgamestudio">http://vk.com/sharkgamestudio</a></p><p>P.S. Если также хотите участвовать в «Песочнице проектов» и писать свои статьи о проектах: <a href="https://tproger.ru/about/sandbox/">https://tproger.ru/about/sandbox/</a></p><p>Роман Бабушкин, создатель игры «2+2»</p>]]></content:encoded>
    </item>
    <item>
      <title>Песочница проектов. Colors United</title>
      <link>https://tproger.ru/projects/sandbox-colors-united</link>
      <comments>https://tproger.ru/projects/sandbox-colors-united?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/sandbox-colors-united</guid>
      <description><![CDATA[<p>Colors United выросла из простой игры с квадратным полем и тремя режимами сложности. Автор описывает, как дорабатывал механику и развивал проект.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/sandbox-colors-united">Песочница проектов. Colors United</a>»</p>]]></description>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 11 Jun 2015 23:33:23 GMT</pubDate>
      <content:encoded><![CDATA[<p>История Colors United началась как раз с группы «Типичный программист». Я увидел очень простую игру в альбоме с проектами пользователей. Она предоставляла возможность играть на квадратном поле в 3-х режимах сложности. Мне очень понравилась механика, но реализация была настолько простой, что я просто не мог позволить себе не довести ее до ума.</p><p>Начинали мы этот проект вдвоем — я и моя девушка. Я занимался разработкой игры, она — составлением уровней.</p><p>Изначально не было цели произвести какую-то техническую революцию и написать игру, ставящую рекорды по производительности. Единственное, что имело на тот момент значение — это время. Времени было совсем немного. Нужно было реализовать как можно больше за время зимней сессии, работая только в вечернее время после основной работы.</p><p>Я неплохо знаю Unity. Организация FuryLion Studios, в которой я работаю, занимается разработкой игр как раз на этом движке. Я только закончил реализацию нашего достаточно большого проекта и решил, что нужно сделать на Unity еще одну игру, пока не растерял навыков.</p><p>В течение полутора месяцев я запустил первую версию. Игра вышла под названием Color Dash. Рекламного бюджета не было никакого. В 3 человека мы рассылали просьбы опубликовать новость о нашей игре во всевозможные сайты и группы. Очень немногие откликались. Каждая новость была маленьким праздником для нас. Помню, сколько было радости, когда Google Analytics показывал 25 человек онлайн. Я очень благодарен тем группам, которые бесплатно публиковали новости о Color Dash. В будущем обязательно закажу у них платную рекламу в знак благодарности.</p><p>За 2 недели мы набрали около 2 тысяч установок. Очень грустная статистика, но вскоре произошло кое-что очень важное. С нами связались китайские издатели и предложили поработать вместе.</p><p>За последний месяц команда из 3-х человек разрослась до 7-ми. Теперь в команде появились несколько продюсеров и звуковик. Игру переименовали и выложили на новом аккаунте. Попадание игры в Best New Games от Apple дало ощутимый толчок для всей нашей команды.</p><p>Сейчас игра очень активно доделывается. Исправляются критические баги и реализовываются новые элементы. На данный момент в Appstore выложен, мягко говоря, не очень качественный билд. Ошибки внедрения сервисов приводят к тому, что игра крашится без интернета. Я совершил очень глупую ошибку, зациклив загрузку рекламного баннера без интернета. Я этого не заметил, этого и не заметили в Apple, но 80% отзывов в Appstore как раз на тему крашей. Людям игра нравится, но невозможность поиграть без интернета, конечно же, их бесит.</p><p>С Android-версией все веселее. Google Play позволяет очень быстро выложить обновление, да и сама ОС гораздо проще справляется с ошибками. Не в обиду Android-пользователям, но на данный момент приходится тестировать билд именно на них. Ошибки iOS обходятся слишком дорого из-за долгого времени ожидания и гораздо большего количества пользователей.</p><p>Уже начинаю задумываться над лицензией Unity, но цена в 4500$ пугает. Слишком много они просят за возможность убрать логотип. И это с учетом того, что уже пришлось выложить около 80$ за плагины для работы со встроенными сервисами iOS и Android.</p><p>В заключение хочу сказать спасибо за возможность показать сообществу свою игру и очень надеюсь, что Colors United вам понравится.</p><p>Google Play: <a href="http://bit.ly/1GCh1VB">http://bit.ly/1GCh1VB</a></p><p>Appstore: <a href="http://apple.co/1KGj2Ek">http://apple.co/1KGj2Ek</a></p><p>P.S. Хотите публиковать статьи о своих проектах? Участвуйте в <a href="https://tproger.ru/about/sandbox/">«Песочнице проектов»</a>.</p><p>Александр Валькович, создатель приложения «Colors United».</p>]]></content:encoded>
    </item>
    <item>
      <title>Песочница проектов. BALDIX</title>
      <link>https://tproger.ru/projects/sandbox-baldix</link>
      <comments>https://tproger.ru/projects/sandbox-baldix?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/sandbox-baldix</guid>
      <description><![CDATA[<p>BALDIX скрестила головоломки Тетрис и Балда и вышла на iOS и Android. Автор первой своей мобильной игры рассказывает о проблемах, технологиях и находках.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/sandbox-baldix">Песочница проектов. BALDIX</a>»</p>]]></description>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 08 Jun 2015 18:40:44 GMT</pubDate>
      <content:encoded><![CDATA[<p>BALDIX — это моя первая мобильная игра. В этой статье я расскажу, как я разрабатывал эту игру, с какими проблемами столкнулся, что новое для себя открыл, какими технологиями пользовался.</p><p>Идея сама по себе очень простая. Я скрестил популярные головоломки Тетрис и Балда в надежде, что из этого получится что-то интересное. Думаю, видео сможет рассказать вам про игру лучше, чем я:</p><p>iOS App Store: <a href="http://apple.co/1eMDUge">http://apple.co/1eMDUge</a></p><p>Android Google Play: <a href="http://bit.ly/1He9TMT">http://bit.ly/1He9TMT</a></p><h3>Как все начиналось</h3><p>А теперь, когда вы познакомились с игрой, я расскажу, как она появилась. Bcе началось с того, что в начале апреля 2015 загнулся мой очередной стартап, и я начал искать работу. После нескольких попыток найти подходящий вариант мне удалось пройти телефонное интервью на позицию программиста в одну зарубежную компанию. Меня пригласили на очное собеседование, и стало понятно, что мне предстоит провести 3 недели дома, в Москве, в ожидании, пока мне не оформят визу. Хотелось успеть сделать за это время что-то полезное. Я подумывал найти себе интересное обучение или попробовать влиться в какой-нибудь Open Source проект, да в конце концов, просто устроить себе диванный отдых, но по воле случая я начал писать мобильную игру.</p><p>Мысль о том, что до боли простые (в плане реализации) казуалки вроде 2048 или Flappy Bird принесли своим создателям огромные деньги, периодически провоцировала в моей голове удары гонга. Я часто видел, как люди залипают в мобильниках над очередной головоломкой, но повода задуматься о том, что я тоже хочу такое сделать, жизнь не подбрасывала. Не подбрасывала до тех пор, пока за очередным приятельским ужином мой друг Илья не начал отвлекаться от разговора со мной на какую-то тыкалку в своем телефоне. Оказалось, он начал осваивать разработку под Android и написал свой первый прототип игры на Unity. Слово за слово, я увлекся его проектом, и вот уже мы сидим, обсуждаем, что бы там можно было еще улучшить в его игре. Знаете, иногда бывает так, что если мысленный поток начал двигаться в каком-то направлении, его уже не остановить?  Пока я ехал домой после ужина из кафе, мой мозг скрупулезно перебирал в голове все известные ему головоломки, расчленял их мысленно на кусочки и пытался выудить из них ингредиенты успеха. В итоге сработал старый добрый инженерный подход: все новое — это рекомбинация чего-то старого. Так и я решил превратить Тетрис в словесную игру. К вечеру следующего дня у меня было написано консольное приложение на Java, которое выплевывало рандомные буквы, а я пытался играть в тогда еще не существующий Baldix на бумажке.</p><p>К утру следующего дня я выработал основную идею:</p><ol><li>На поле размером 5х5 будут волнами падать буквы.</li><li>Собрал из букв слово — и буквы исчезают, провоцируя новую волну.</li><li>Проигрываешь, когда заполнится экран.</li></ol><p>Впереди у меня за вычетом майских праздников и выходных, которые я стараюсь проводить с женой, было 2 недели чистого времени. И я решил, что за эти 2 недели я запущу игру.</p><h3>Осваиваем технологию</h3><p>Я сразу решил сделать игру кроссплатформенной. Проект явно был рассчитан скорее на приобретение опыта, нежели прибыли. Хотелось опробовать как можно больше новых для меня вещей. Сначала я попробовал Unity: установил среду разработки, начал вникать, проходить какие-то туториалы. Через пару часов пришло осознание, что я стреляю из пушки по воробьям. Куча возможностей по работе с графикой: 3D, камеры, эффекты. У меня на все это не было времени. Мне нужны были падающие квадратики с буквами. Все.</p><p>Я начал искать другое решение и наткнулся на libGDX. Тоже куча возможностей: физический движок, ненужная мне библиотека GUI компонентов. И тем не менее, это Java, которую я хорошо знаю, и это Open Source, и квадратики легко рисуются… Я погрузился в изучение libGDX и решил дальше не искать. Так и мучаюсь с ним до сих пор ?</p><p>Из движка я, по сути, мало чем воспользовался и написал довольно велосипедный код. Взял только общий каркас по обработке событий, перемещений, сайзинга, плюс отрисовку шрифтов и графических примитивов. Все остальное сам ручками сделал.</p><p>Если соберетесь осваивать libGDX, советую принять во внимание один важный момент. Для работы на iOS этот движок использует виртуальную Java машину RoboVM. Она пакуется в ваше приложение вместе со всем остальным кодом, и размер вашего .ipa файла растет, как на дрожжах. В Baldix-е папка со всей графикой и звуками занимает 1.2MB, а установочный файл игры получается 52MB.</p><p>Дело тут не только в самой виртуальной машине. Мало того, что она сама занимает кучу места, так это еще не все. Вы ведь хотите встраивать в игру сторонние SDK: интеграцию с фейсбуком, вконтакте, рекламу. Над нативными библиотеками для RoboVM пишутся специальные обертки. Называются они RoboVM bindings. Для фейсбука, например, такая обертка весит 38MB, для AdMob — 19MB. И так ваше приложение разрастается до фантастических размеров. Стоит об этом подумать заранее, учитывая, что Apple разрешает закачивать приложения больше 100Mb только по WiFi.</p><h3>Оттачиваем геймплей</h3><p>На освоение libGDX вкупе с приобретением лицензий разработчика в Google Play и App Store ушло 2 дня. Еще 3 дня я потратил на разработку первого прототипа. И вот к концу первой недели работы у меня на руках была первая сборка, которую можно было тестить.</p><p>Моя игра была максимально простой визуально. Мне хотелось, чтобы это касалось не только графики, но и геймплея. Я помню, как проводил аналогии между бритвой Оккама и игрой.</p><p>В первой версии игры после набора слова из букв нужно было нажать на кнопку «готово», чтобы они исчезли. Я решил выбросить лишнее нажатие и удалять буквы по таймеру. Я долго подбирал время, за которое буквы должны исчезнуть, и впоследствии собрал кучу гневных отзывов от игроков по этому поводу. В итоге, не без помощи обратной связи и множества экспериментов, оптимальное время было найдено — 2.4 секунды.</p><p>Мне хотелось добавить в игру элемент, который бы заставлял концентрироваться игрока на приложении. Чувство концентрации повышает для человека важность того, чем он занимается в данный момент. Я пронаблюдал этот феномен на примере игры Flappy Bird и попытался сделать аналогичный шаг, добавив в приложение таймер. На данный момент мне сложно сказать, было ли это хорошей идеей. Многие игроки просят добавить в игру режим игры без таймера, и, возможно, он появится в одном из ближайших обновлений.</p><p>Тут подправил, там подкрутил, подобрал цвета, вставил звуки, запрогал игровое меню и оглянуться не успел, как пролетела вторая неделя. Пора было выкладывать приложение в игровые маркеты. Я понятия не имел, как это делать, но я справился. О том, что случилось после запуска, как я пытался раскручивать приложение и что из этого вышло, я напишу в следующей статье. Если вам интересны другие подробности внутренней кухни создания Baldix, заходите на огонек в группы в социальных сетях:</p><p>Пишите отзывы. Всем буду рад.</p><p>Сергей Кюне, создатель игры «BALDIX»</p>]]></content:encoded>
    </item>
    <item>
      <title>Как создавалось приложение MafiaDroid</title>
      <link>https://tproger.ru/projects/mafia-android</link>
      <comments>https://tproger.ru/projects/mafia-android?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/mafia-android</guid>
      <description><![CDATA[<p>Автор MafiaDroid рассказывает об этапах разработки под Android и о том, как изучение игры Мафия с точки зрения математики превратилось в приложение.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/mafia-android">Как создавалось приложение MafiaDroid</a>»</p>]]></description>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 27 May 2015 23:14:07 GMT</pubDate>
      <content:encoded><![CDATA[<p>Рассказывает создатель приложения MafiaDroid для Android</p><p>Хочу поделиться с вами своей игрой, а так же описанием некоторых интересных этапов разработки под Android.</p><p>Игра является результатом изучения теории игр <a href="https://clck.ru/9Qwfr">Мафия</a> с точки зрения математики. И очень нежелательного, но пока обязательного атрибута — один человек должен быть ведущим.</p><p>Весь процесс разработки можно разделить на две большие части:</p><ul><li>Ядро с реализацией минимально необходимой логики;</li><li>Реализация на Android.</li></ul><p>(Разработка ядра очень простая, но, по-моему, в ней есть много интересных моментов, и для описания нужен отдельный рассказ, поэтому сейчас только Android.)</p><h3>Предисловие — «а с чего всё началось…»</h3><p>Идея перешла в проектирование после нескольких игр в мафию с ведущим. Если игроков мало, то это смотрится как нежелательная деталь. Ведущий тоже хочет поиграть, а другие игроки недовольны тем, что их меньше. Реализация ведущего на машине ударила в голову когда всё сложилось в реальное решение с учётом всех правил (учитывались правила по которым играли именно мы, а про то что правил игры очень много, и они могут сильно отличаться, и как моё решение реагирует на этот факт, я напишу ниже).</p><p>Чтобы стало понятно о чём конкретно идёт речь, расскажу правила, по которым играли именно мы:</p><p>Вся игра разбита на два процесса.</p><ul><li>«Ночь» — игроки в закрытую выполняют свои функции:идёт подсчёт «выживших»;умершие выбывают из игры;если условия победы не выполнены — наступает день.</li><li>«День» — игроки обсуждают в открытую, кого они хотят «казнить»:идёт подсчёт «выживших»;умершие выбывают из игры;если условия победы не выполнены, наступает ночь.</li></ul><p>И так, пока не объявится победитель (или ничья).</p><p>Теперь про само приложение.</p><p>Есть готовая библиотека (библиотека классов Java. То самое ядро в виде .jar, которое я собрал в NetBeans) с реализованными и работающими элементами: игроки, роли, действия.</p><p>Осталось реализовать логику на аппарате и дизайн. Обычно, при реализации какого-либо проекта, я решаю комплекс задач. Желательно изучать новое. А здесь попробовать новые фичи дизайна (перелистывания экранов, если конкретно, работа с ViewFlipper и SeekBar), логирование, прикручивание GoogleAnalitics, прикручивание AdMob с рекламой.</p><p>Разработка длилась около 6-ти месяцев (включая ядро). Всё из-за занятости на основной работе. Но получалось умело использовать комбинацию Acer Aspire One + Debian + NetBeans + Git. (Работал тогда выездным, и ядро писалось «на коленке» в NetBeans.) Проект именно для смартфона писался в Android Studio дома.</p><p>Фичи, которые я использовал и про которые узнал:</p><ul><li>Т.к. версия всё ещё тестируется, для особо любопытных был прикручен отладочный лог с подробным выводом действий всех игроков и результатов игры. По пути /mnt/sdcard/Mafia создаётся файл (название выбирается в зависимости от даты).</li><li>GoogleAnalytics и AdMob имеют инструменты, позволяющие отслеживать действия, совершённые пользователями на их телефонах, и выдавать эту информацию разработчику (AdMob ещё платит за рекламу, но я пока не разбирался по поводу вывода денег). У меня получилось подключить и настроить эти службы. Есть несколько подводных камней, которые не описываются в стандартных туториалах. Хочу поделиться опытом:Для отслеживания действий с рекламой необходим «код отслеживания», так вот, он необходим не один, а для каждого рекламного элемента (баннер, видео и т.д.). И необходимо сначала каждый элемент, который вы хотите использовать в приложении, зарегистрировать на сайте AdMob. Потом на него сгенерируется уникальный ключ (в мане от гугла написано просто «ключ» и понимай как хочешь). И вот ещё ссылка на stackoverflow, где я получил ответ (наткнулся на это обсуждение на 5-7 странице поиска, в этом обсуждении человек задаёт вопрос по поводу этих непоняток, а потом сам отвечает и описывает как он допёр до этих сверхочевидных преобразований).Как оказалось, любопытство и кривые руки берут своё. Моя реализация по идее должна была позволять одному игроку ночью делать все его грязные делишки, а после передавать телефон другому игроку, и тот должен был как-либо разблокировать доступ к личной информации. Была поставлена кнопка «Проснуться» (как блок). На деле она случайно нажималась ещё до передачи нужному человеку. Поэтому теперь блок представляет из себя сложный SeekBar, который необходимо передвинуть, строго схватившись за рычажок и протянув ровно до конца. Если процесс прервётся, то придётся начинать сначала. А если сделать всё правильно, то вы увидите, как на фоне просыпается рожица.Также слайдер пришлось добавить для персонажей без действий, чтобы такого человека было сложнее вычислить. Как оказалось, после этого игроки, которые поняли как и что делать, просто выбирают жертву и стреляют. Теперь это занимает 3 секунды. А когда телефон попадает мирному жителю, после 10 секунд можно услышать матные комментарии в сторону неудобного слайдера. Так что эта система скорее нуждается в доработке, чем идеальна.Ролей для игры нужно указывать конкретное количество (роли == игроки). Поэтому была идея реализовать для каждой NumberPicker. Он является стандартным элементом в Android и включает в себя систему хранения и изменения значений (самый простой его вид — это целые числа в заданном диапазоне — то, что доктор прописал). Роли выводились в списке а для каждой нужно было вставлять в элемент списка NumberPicker. Самое интересное, что его старая версия содержит текст и две кнопки, а вот новая содержит систему с пролистыванием и красивым выводом. Оказывается, новый конфликтует своим вертикальным скролом с родительским вертикальным скролом. Его можно настроить, но это делается очень неудобно, и в итоге получается неприятный инструмент, который не будет выполнять своих функций, но будет отторгать нажатия пальцев хозяина. Совет — проверяйте функционал приложения на разных версиях андроида.ViewFlipper оказался очень даже приятным для ознакомления. Огромной пользы я от него не получил, но научился им пользоваться и создал два экрана в меню предподготовки Игроки/Роли, между которыми можно перемещаться, пролистывая пальцем по экрану. Реализация мне показалась интересной. Я немного поколдовал и сделал из этого выезжающие из края экрана уведомления (в данном приложении они будут выезжать внизу и будут с красным текстом).Самым сложным для меня, пожалуй, стал процесс блокирования персонажей. Свобода создаёт возможность такого конфликта: две роли заблокируют друг друга (получается если блокировка сработает, то она не сработает 0_о и наоборот — замкнутый круг). В реальной мафии нет правил по поводу того, что одна роль важнее другой. Поэтому подобные случаи нужно обговаривать заранее и у меня не получилось однозначно обыграть данную ситуацию так, чтобы не изменять и правила мафии и мою систему.Для создания иконок в приложении (иконки кнопок +/-, иконки ДЕНЬ/НОЧЬ и тд) я использовал сервис Android Asset Studio — очень удобный инструмент для создания иконок для сразу 5 размеров экранов. Так же есть дополнительные инструменты по типу nine-patch. Все результаты можно скачать в виде архива с папкой res, в которой уже правильно размещены все изображения которые вам необходимы (чтобы добавить изображения можно просто перекинуть в папку с проектом папку res). Всем советую не тратить время на велосипеды, а пользоваться готовыми онлайн сервисами по типу этого, если такое возможно.</li></ul><p>Данная версия бесплатная и имеет в себе специально урезанный функционал. Можно выбрать не более 15ти игроков. На выбор только 4 роли (Мафия, Доктор, Комиссар, Мирный житель) и есть ограничения по количеству игроков и ролей. Также есть строгие правила о количестве мафии относительно городских. Все эти параметры нельзя менять, но планируется подарить эти и ещё несколько дополнительных возможностей в платной версии приложения. Мой функционал позволяет реализовать главную идею — кастомизацию ролей и правил игры внутри приложения. Чтобы стало понятно, например, можно будет создавать такие сложные роли, как «внебрачный ребёнок босса». Он является городским жителем, но при этом на проверку он определяется как мафия, и ещё мафия не может его убить.</p><p>Ядро лежит <a href="https://github.com/kepocnhh/Presenter">на гитхабе</a> (проект NetBeans). Само приложение <a href="http://www.apkmonk.com/app/stan.presenter.mafia/">на GooglePlay</a>.</p><p>Приложение уже тестировалось на моих друзьях и логических ошибок выявлено не было. Буду благодарен за помощь в поиске багов ?</p><p>Хочется поговорить о развитии данного приложения. Может, получится найти тестировщиков платной версии (которых, как оказалось, очень даже не хватает) или программистов, которые присоединятся к разработке.</p><p>Спасибо!</p>]]></content:encoded>
    </item>
    <item>
      <title>Бесконечная лента</title>
      <link>https://tproger.ru/projects/endless-ribbon-of-saint-george</link>
      <comments>https://tproger.ru/projects/endless-ribbon-of-saint-george?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/endless-ribbon-of-saint-george</guid>
      <description><![CDATA[<p>Лента интернет-проекта состоит из «пикселей» — фотографий участников, растёт без ограничений по длине, а регистрация идёт через соцсети по OAuth.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/endless-ribbon-of-saint-george">Бесконечная лента</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 06 May 2015 10:43:58 GMT</pubDate>
      <content:encoded><![CDATA[<p>Создатели проекта бесконечной ленты поделились с нами некоторыми фактами из разработки.  Передаём им слово.</p><h3>Основная информация о разработке</h3><p>Основным элементом интернет-проекта является лента, состоящая из «пикселей», которыми являются фотографии участников. Когда на портале регистрируется новый пользователь и загружает свою фотографию, один «пиксель» окрашивается цветом ленты.  Главная особенность и сложность реализации этой идеи в том, что лента масштабируется в зависимости от количества участвующих в проекте пользователей и не имеет ограничений по длине.</p><h3>Техническая реализация</h3><p>Регистрация пользователей через социальные сети реализована с помощью протокола Oauth. Публикация ссылок на «пиксель» пользователя и на страницу проекта реализована через API социальных сетей с использованием технологии Open Graph.</p><p>Для ускорения загрузки главной страницы проекта используется кеширование на уровне прокси-сервера Nginx.</p><p>Получение всей информации для построения ленты (загрузка и обновление ленты, поиск по координатам, статистика) происходит по протоколу WebSocket с двухуровневым gzip-сжатием данных (первый является расширением WebSocket, а второй был реализован самостоятельно на уровне приложения). «Пиксели» пользователей передаются по WebSocket в формате base64.</p><p>Для обработки запросов используется событийная модель работы сервера приложений. Для обеспечения оптимальной производительности и поддержки работы с WebSocket настроен сервер Puma в режиме кластеризации.</p><p>Поддержка событийной модели на уровне приложения (server-side) осуществляется на основе push-нотификаций.</p><p>В качестве основного языка программирования используется Ruby.</p><h3>Особенности разработки</h3><p>Основная проблема, с которой пришлось столкнуться разработчикам – это постоянная асинхронная передача большого объема данных для построения ленты (“пиксели” пользователей) на client-side и их обновление в онлайн режиме большому числу пользователей без задержек. В качестве решения этой проблемы была разработана архитектура работы системы на основе событийной модели (в качестве транспорта для client-side используется протокол WebSocket, а передача информации о событиях на server-side осуществляется с помощью push-нотификаций).</p><h3>Разработчик компания AT Consulting</h3><p>AT Consulting — это один из сильнейших игроков на рынке информационных технологий и консалтинговых услуг для телекоммуникационного, финансового, государственного и других секторов. Ключевые направления деятельности компании: внедрение и сопровождение сложных информационных систем, управленческий и операционный бизнес-консалтинг, управление проектами и ИТ-аутсорсинг.</p>]]></content:encoded>
    </item>
    <item>
      <title>Идея и создание веб-приложения Br.Asst. — Browser assistant</title>
      <link>https://tproger.ru/projects/br-asst</link>
      <comments>https://tproger.ru/projects/br-asst?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/br-asst</guid>
      <description><![CDATA[<p>Веб-агентство CHEERS! Unlimited создаёт простые и эффективные приложения и учитывает совместимость веб-систем с популярными браузерами и их версиями.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/br-asst">Идея и создание веб-приложения Br.Asst. — Browser assistant</a>»</p>]]></description>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 07 Mar 2015 16:58:41 GMT</pubDate>
      <content:encoded><![CDATA[<blockquote>«Один из важнейших уроков, преподанных компьютерной индустрии, заключается в том, что для пользователя ценность компьютера определяется преимущественно качеством и многообразием существующих программ. Мы все, занятые в этой индустрии, усвоили этот урок; кто-то учился на чужих ошибках, а кто-то — на своих»Билл Гейтс, «Дорога в будущее»</blockquote><p>С самого основания веб-агентства CHEERS! Unlimited мы ориентировались в первую очередь на создание веб-приложений, не собираясь ограничиваться одной лишь разработкой персональных и корпоративных веб-сайтов. Каждое подобное веб-приложение – это инструмент для решения определенных задач; они создаются специально для повседневного использования; дело разработчиков – сделать их простыми и понятными в обращении, но главное – максимально эффективными среди существующих аналогов (либо даже не имеющими таковых).</p><blockquote>«Ведь в конечном итоге значение имеет только коэффициент полезного действия для определенного индивида»</blockquote><p>При этом аудитория, которая использует данные инструменты, потенциально может насчитывать как тысячи пользователей, так и быть полезной лишь тесному кругу заинтересованных лиц.</p><p>В самом деле, для профессионального разработчика одинаково важно ощущать свой вклад, как в строгое узкоспециализированное приложение, так и в гораздо более многогранный массовый продукт.</p><p>Проблема безответственного обращения пользователя со своим программным обеспечением, далеко не нова. Тем более проблема веб-содержимого (истоки её лежат еще в ранних годах существования Интернета) не меняется из года в год: корректное отображение и работоспособность веб-ориентированных систем наиболее распространёнными браузерами и основными их версиями.</p><p>Многие веб-разработчики сталкивались с неприятностями, когда приходится изменять внешний вид либо функционал своих приложений из-за требования к совместимости со старыми версиями браузеров. Во времена ускоренного развития доступного им инструментария для визуальной манифестации клиентских интересов очень часто возникают ситуации, когда сделать «вот так» – лучше всего; просто замечательно! Но нельзя. Потому что «вот так» не будет работать в древнем Internet Explorer 8, а у серьёзных людей и требования прописаны, и массовый пользователь у них не знает, что такое есть этот самый браузер.</p><blockquote>«В связи с этим разработчики должны устанавливать для себя определенную планку, ниже которой они опускаться не хотят, или не видят смысла, или просто нельзя – в виде минимально необходимой версии браузера клиента, где их продукт будет гарантированно выглядеть и работать корректно»</blockquote><p>И даже несмотря на добросовестное тестирование на разных операционных системах и в разных версиях популярных браузеров все равно находятся пользователи, которые предпочитают, к примеру, надежную, безотказную и все же безнадежно устаревшую Opera 12.</p><p>Бессмысленно и непрофессионально в ответ на возмущение новоиспеченного владельца сайта советовать его клиентам использовать браузер последней версии. Гораздо более здравый вариант – заставить саму систему говорить пользователю, что она, возможно, будет выглядеть и работать плохо, если пользоваться ею через браузер трехлетней давности.</p><blockquote>«В связи с особенностями менталитета так уж сложилось, что компьютеру люди порой доверяют больше, чем себе подобным, и советы от лица машины воспринимаются на порядок серьёзнее»</blockquote><p>Оставим разъяснения, что на самом деле компьютер есть глупейшая вещь, не обремененная интеллектом, и попробуем предложить решение на основе данной концепции.</p><p>Системы, подобные Br.Asst., конечно же, существуют, но, по нашему мнению, их реализация является недостаточно оптимальной. Некоторые оценивали браузер по несколько ненадежным критериям, другие представляли собой просто сайты без соответствующей возможности подключить их к нашим проектам, одни даже хотели денег за подобную возможность… А как же принципы свободного программного обеспечения и волшебный мир, где все разработчики – братья, а? Да и в целом, использовать стороннее решение в данном случае было бы так же странно, как как сотруднику компании A, производящей смартфоны, пользоваться смартфоном компании S. Тем более если мы действительно можем создать веб-приложение, сочетающее в себе лучшие стороны подобных решений!</p><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst2-1024x730.jpg" alt="" /></figure><ol><li>Для начала необходимо создать своего рода «стыковочную станцию» между сайтами, которые отслеживают версию браузера пользователя, и официальными страницами разработчиков браузеров, где можно получить новейшие версии.</li><li>Определить браузер пользователя через сайт, который использует Br.Asst.</li><li>Понять, соответствует ли версия браузера пользователя наиболее новой версии.</li><li>Предупредить пользователя в случае, если версия браузера устарела, желательно перед или в самом начале работы с веб-сайтом; указать на возможность обновления.</li></ol><p>Основные вопросы по визуальной и функциональной части системы решались непосредственно при этапе создания «стыковочной станции» – базового сайта, куда пользователь перенаправляется с веб-сайтов, использующих Br.Asst., и совершает необходимые действия для обновления браузера.</p><p>Концепции внешнего вида наших веб-ориентированных систем во многом зависят от атмосферы, в которой они создаются; атмосферы, навеянной произведениями искусства и окружающим миром, влияющие на разработчиков в процессе визуализации. Основой представления Br.Asst. и первого поколения наших веб-приложений собственного производства послужили статьи о концепциях теоретической физики из серии «для чайников», а также глубокий амбиент «Particle Ghost» и «Slow Light» из саундтрека к одной очень известной компьютерной игре.</p><p>Из указанного выше настроения сформировалось видение хаотично двигающихся в пространстве частиц, создающих и разрывающих между собой связи, дополненные взаимным притяжением, которое слегка разгоняет их друг относительно друга.</p><blockquote>«На некотором абстрактном уровне их можно воспринимать как узлы соединений сети, пользователей, обменивающихся информацией в Интернете, создающих плавный повседневный процесс движения сетевого траффика»</blockquote><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst3-1024x819.png" alt="" /></figure><p>Целостный интерфейс пользователя было задумано представить в виде боковой панели, которая совмещает уместный минимализм и в то же время позволяет совершить все общие операции с системой.</p><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst4.png" alt="" /></figure><p>Логотип Br.Asst сам по себе является отсылкой к ячейкам таблицы периодической системы элементов Менделеева и может быть легко модифицирован для последующих веб-приложений.</p><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst5.jpg" alt="" /></figure><p>Цифра в левом верхнем углу – порядковый номер приложения в линейке подобных инструментов.</p><p>При разработке приложения необходимо было решить ряд несложных вопросов, а именно:</p><p>Q: Как определить, каким браузером пользуется посетитель сайта?</p><p>A: Практически каждый браузер сам по себе содержит строку самоидентификации и при соединении передает её серверу, который обслуживает сайт. Выглядит она примерно так:</p><p>Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0</p><p>Из-за большого количества браузеров и систем лучше не заниматься распознаванием своими силами, а использовать готовые и поддерживаемые (а главное – открытые) скрипты. Мы сделали выбор в пользу замечательного Device Detector от команды Piwik, который умеет распознавать  десятки существующих браузеров. Помимо информации о браузере клиента, Device Detector также сообщает такие полезные сведения, как устройство, с которого был осуществлен доступ и операционную систему пользователя.</p><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst6.png" alt="" /></figure><p>Q: Как узнать последнюю версию каждого из наиболее популярных на сегодняшний день браузеров?</p><p>A: Вопрос на самом деле нетривиальный. Смотреть версии на сайтах разработчиков браузеров и вручную зашивать их в систему – плохой вариант, так как вступает в силу человеческий фактор и сопутствующие проблемы постоянного отслеживания версии и обновления в ручном режиме. Процесс необходимо было максимально автоматизировать. Это означает написание скрипта, который будет самостоятельно забирать необходимые данные из сети. Откуда? Очевидный ответ – на сайтах разработчиков браузеров – на самом деле не очень хорош; сайты разные, а программе придется точно сообщить определенное место на странице, откуда нужно извлечь эту самую версию. Какой же сайт обладает одинаковой структурой страниц, постоянно обновляется, и содержит наиболее свежие данные? Конечно же, Wikipedia! Ознакомившись с публичной лицензией по использованию информации с её страниц, с помощью HTTP-клиента Guzzle мы бодро подтягиваем данные оттуда.</p><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst7-1024x819.png" alt="" /></figure><p>Q: Как подключить определитель к целевым сайтам – собственно, ради чего все и затевалось?</p><p>A: Для этого нужен API – «Автоматизированный Программный Интерфейс» – по сути комплекс мероприятий, который позволяет связать систему Br.Asst с внешними сайтами и использовать её функционал удаленно. И если уже делать API, то почему бы не дать возможность пользоваться системой всем желающим? Соответственно под это дело нами был создан простой интерфейс взаимодействия, с подключением которого справится даже начинающий разработчик или веб-мастер. Любой веб-сайт, к которому подключен Br.Asst., будет определять браузер пользователя и его версию, а в случае, если версия устарела – предлагать обновление. Чтобы не вызывать судороги у замученных всплывающей рекламой пользователей, мы постарались сделать внешний вид определителя максимально ненавязчивым, а также  дали возможность скрыть и больше не показывать блок Br.Asst., если так будет угодно.</p><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst8-1000x1024.png" alt="" /></figure><p>Осталось самое важное – высказать предположения, как созданный нами веб-сервис и API могут повлиять на пользователей наших сайтов? Что ж, теперь каждый просматривающий наши веб-сайты через устаревшие браузеры, будет предупрежден и узнает о возможности обновления. Также Br.Asst. смогут использовать разработчики и веб-мастера для собственных проектов.</p><figure><img src="https://media.tproger.ru/uploads/2015/03/brasst9-1024x819.png" alt="" /></figure><blockquote>«На самом деле ожидаемый прогноз активности пользователей Br.Asst. весьма умеренный»</blockquote><p>Главная же цель проекта несколько иная – это шанс через ненавязчивую агитацию изменить картину восприятия веб-сайтов как систем, которым небезразлично программное обеспечение пользователя. Сам же пользователь может оценить влияние  браузера на собственный спектр впечатлений от серфинга в сети. Это лишь один из множества шагов по улучшению качества продукта нами, веб-разработчиками, посредством возможности повышать планку и более свободно внедрять наиболее технологичные решения.</p><blockquote>«Очень важно развить в пользователях понимание, что некоторая часть разумной ответственности при использовании веб-ориентированных систем остается за ними»</blockquote><p>Команда веб-агентства CHEERS! Unlimited специально для «Типичного программиста».</p>]]></content:encoded>
    </item>
    <item>
      <title>Никаких симуляторов. Рассказ о платформе для удалённого обучения программированию в реальном окружении</title>
      <link>https://tproger.ru/projects/hexlet</link>
      <comments>https://tproger.ru/projects/hexlet?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/hexlet</guid>
      <description><![CDATA[<p>На платформе Хекслет каждый урок идёт на полноценной машине с сетью, поэтому учиться можно не только коду, но и базам данных и серверам.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/hexlet">Никаких симуляторов. Рассказ о платформе для удалённого обучения программированию в реальном окружении</a>»</p>]]></description>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Обучающие курсы]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 13 Feb 2015 12:49:17 GMT</pubDate>
      <content:encoded><![CDATA[<p>Хекслет — это платформа для создания практических уроков по программированию в настоящей среде разработки. Главное отличие от других проектов в том, что на Хекслете нет симуляторов: в каждом уроке пользователь работает с полноценной машиной, подключенной к сети. Это позволяет обучать и обучаться не только программированию, но и работе с базами данных, серверами, сетью, фреймворками и так далее. Грубо говоря, если это запускается на Unix-машине – этому можно обучать на Хекслете.</p><p>В этой заметке я расскажу про архитектуру платформы и инструменты, которые мы используем.</p><p>Почти весь бэкэнд написан на Rails, все крутится на Amazon AWS. Мы не привязаны к инфраструктуре Амазона, но из специфичных вещей используем RDS (Relational Database Service). Там крутится PostgreSQL (основная база) и Redis (для очередей). Благодаря RDS нам можно не волноваться о бэкапах, репликации, обновлении – все работает автоматически. У Амазона куча крутых штук, к которым легко привыкнуть и привязаться, но наша схема позволяет при желании довольно легко уйти на любую другую инфраструктуру. Это возможно благодаря Докеру.</p><figure><img src="https://media.tproger.ru/uploads/2015/02/hexlet_screen_1.png" alt="" /></figure><p>На самом деле, Докер это вообще краеугольный камень всей платформы.</p><p>Итак, каждый сервис у нас завернут в свой контейнер. 1 контейнер = 1 сервис. Сайт, Redis, Grafana (для построения графиков, об этом чуть ниже). Большинство образов для контейнеров – готовые из tutum.co.</p><p>Репозиторий для своего приложения мы храним в Docker Registry. Там удобная система – образ собирается автоматически при коммите в Dockerfile. Сам код хранится в Github, получается, процесс такой: новый коммит в Dockerfile в гитхабе -&gt; запуск нового билда в docker registry. Билд занимает значительное время, 20-60 минут в зависимости от условий, поэтому вариант “по-быстрому пофиксим продакшен” невозможен. Но оказалось это не проблема, даже дисциплинирует.</p><p>Изначально для деплоя мы использования Capistrano, но в итоге отказались от нее в пользу Ansible. По сути, Ansible просто доставляет конфиги на удаленный сервер и запускает upstart, а тот в свою очередь уже обновляет образы. В такой схеме нам не нужно ничего особого устанавливать на сервера (нужен только ssh-доступ), и легко откатываться назад. Для версионирования используются теги (v24, v25 и так далее), а деплой на стейджинг всегда использует самую последнюю версию (latest) кода. Когда что-то идет не так при деплое на продакшен, мы просто убиваем один контейнер и поднимаем другой.</p><figure><img src="https://media.tproger.ru/uploads/2015/02/hexlet_screen_2.png" alt="" /></figure><p>Что круто, при локальной разработке мы используем почти 1-в-1 те же Ansible-плейбуки что для продакшена. Так что инфраструктуру мы обкатываем локально, что позволяет минимизровать ошибки класса “а на локалке работало”.</p><p>Мы также используем амазоновский балансировщик, и при повышенной нагрузке за 10-20 минут можем поднять дополнительные машины. Конечные веб-серверы не хранят никакого состояния (что и позволяет быстро масштабироваться), на них не сохраняется никаких данных.</p><p>Суть проекта – позволять людям учиться в реальном окружении, для этого каждому юзеру мы поднимаем контейнер, в котором он выполняет практическое упражнение. Эти контейнеры поднимаются на специальном “eval”-сервере. На нем есть только Докер и обращаться к нему можно только из Sidekiq, асинхронно. В идеале хочется придти к схеме, где на каждого юзера поднимается полноценная виртуалка.</p><p>Отдельной истории заслуживает браузерная среда разработки, с помощью которой пользователи работают внутри своего контейнера, правят файлы и запускают программы. Существует много облачных IDE, и мы, как любой уважающий себя стартап, хотели по максимуму использовать готовые решения. Нашли классный IDE с кучей функций (даже с интеграцией с Git), но потом оценили стоимость поддержания чужого кода (полного изобретенных велосипедов, между прочим) и решились писать свой простой IDE. Здесь нас спасла еще одна довольно новая технология – ReactJS и концепция Flux. Наш Hexlet IDE – в опен-сорсе.</p><p>Разные события вроде регистраций, начала и завершения уроков, оплаты, а также информация о состоянии сервера сыпятся в специальную базу InfluxDB, а на основе этих данных строятся графики с помощью Grafana. Каждый день мы смотрим на такое:</p><figure><img src="https://media.tproger.ru/uploads/2015/02/hexlet_screen_5.png" alt="" /></figure><figure><img src="https://media.tproger.ru/uploads/2015/02/hexlet_screen_4.png" alt="" /></figure><figure><img src="https://media.tproger.ru/uploads/2015/02/hexlet_screen_3.png" alt="" /></figure><p>Наша команда сама создает уроки, а также приглашает авторов из числа профессиональных разработчиков. Любой человек или компания могут стать авторами уроков, как публичных, так и для внутреннего использования, например, для обучения внутри своего отдела разработки или для проведения воркшопов.</p><p>Спасибо за внимание!</p><p>Рахим Давлеткалиев, CEO Hexlet.io специально для «Типичного программиста»</p>]]></content:encoded>
    </item>
    <item>
      <title>Сайт "для себя": как получить 25 000 уникальных посетителей за 4 дня</title>
      <link>https://tproger.ru/projects/how-to-reach-25k-visitors-in-4-days</link>
      <comments>https://tproger.ru/projects/how-to-reach-25k-visitors-in-4-days?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Типичный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/how-to-reach-25k-visitors-in-4-days</guid>
      <description><![CDATA[<p>Команда делится неожиданным кейсом своего проекта и размышлениями о том, что российский рынок не созрел для действительно интересных ИТ-решений.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/how-to-reach-25k-visitors-in-4-days">Сайт "для себя": как получить 25 000 уникальных посетителей за 4 дня</a>»</p>]]></description>
      <category><![CDATA[Стартапы]]></category>
      <category><![CDATA[Для мотивации]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Dec 2014 08:29:33 GMT</pubDate>
      <content:encoded><![CDATA[<p>Здравствуйте. Хотим поделиться интересным кейсом, который совершенно неожиданно у нас вышел.</p><p>Небольшая предыстория: мы уже год думаем о том, куда бы податься с нашими проектами, потому как видим, что российский рынок просто не созрел для каких-то действительно интересных ИТ-решений. И, по иронии судьбы, на глаза постоянно попадались новости, как очередной стартап, имеющий те или иные черты, схожие с нашими проектами, то получил финансирование, то был куплен, то назван лучшим приложением года…</p><p>В общем, потихоньку мы знакомились со статьями о том, как айтишникам живется в разных странах. Потом нам попался отличный гуглдок, который когда-то в 2009 году начали заполнять пользователи Хабра — в документе люди, покинувшие нашу любимую Родину, делились различными аспектами жизни и работы на новом месте. “Отличная вещь!” — подумали мы, только вот изучать огромную таблицу было не особо удобно. Ну мы и решили сделать простой сайт <a href="http://techvillage.ru">techvillage.ru</a> и перенести туда эти отзывы, только сделать их на карте. Пара дней работы вебера и дизайнера — и, вуаля!, у нас готов сайт. Пользоваться им было удобно, ну мы решили им поделиться. Так как мы продвигаем другой свой проект, у нас на Хабре есть блог, где мы и написали небольшую статью (скорее пост) о том, что сделали такую вещь, мол, пользуйтесь.</p><p>И вот наши результаты спустя 4 дня после публикации:</p><ul><li>25 тысяч уникальных посетителей сайта</li><li>Более 21 000 просмотров <a href="http://web.archive.org/web/20150424233353/http://habrahabr.ru/company/favoraim/blog/245915/">статьи</a> на Хабре и размещение на главной в день публикации</li><li>Увеличение первоначальной базы отзывов более чем в 2 раза</li><li>С нами связались представители другого сайта (там мы получили чуть меньше 2 000 просмотров)</li><li>30 новых отзывов каждый день</li><li>600 писем на почту по поводу проекта</li><li>4 предложения о размещении рекламы (хотя мы писали, что проект некоммерческий)</li></ul><p>Фух, на такой ажиотаж мы явно не рассчитывали. Поэтому решили проанализировать ситуацию, вынести из нее самое полезное и учитывать это в будущем.</p><ol><li>Конечно, самый важный фактор в успехе этого небольшого проекта — это его высокая релевантность. Во-первых, среди айтишников и так сформирована культура “буду работать, где захочу”, а во-вторых, учитывая экономическую и политическую ситуацию последних дней, у нас получился прямо материал на злобу дня, что спровоцировало множество обсуждений и шуток под статьями.</li><li>Следующим фактором успеха, по нашему мнению, можно посчитать то, что написана статья была максимально честно и в доверительном стиле. Например, было упомянуто, что мы для начальных данных использовали чужие материалы. Естественно, никаких рекламных слоганов и призывов. В результате наш проект был принят довольно тепло. Правда, это касается только первой статьи, на втором сайте отреагировали гораздо более агрессивно. Люди жаловались на малейшие недостатки сайта, хотя никто не говорил, что это полноценный готовый продукт. Немного обидно, но, видимо, все зависит от менталитета пользователей определенных ресурсов:)</li><li>Кажется, нам повезло и со временем публикации — утро вторника. Мы не планировали опубликовать в какое-то особое время, но раздумывая сейчас об успехе статьи, кажется, что время было подобрано идеально.</li></ol><p>Это основные выводы, которые были сделаны. Конечно, тут есть и другие факторы, типа “это же Хабр” и т.п., но мы думаем, вы и так понимаете, что мы тоже не наобум это публиковали и подобрали соответствующий ресурс.</p><p>В очередной раз убедились, если чего-то не хватает — делай это сам, находи единомышленников, и тогда 100% будет успех. Сейчас мы уже думаем, а не попробовать ли нам сделать проект международным:) Вот такой неожиданный кейс у нас получился. Если у вас есть подобный опыт, давайте делиться им в комментариях.</p><p>Команда Favoraim специально для <a href="https://tproger.ru/">Типичного программиста</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Методы оптимизации при разработке в Unity 3D</title>
      <link>https://tproger.ru/projects/optimization-methods-unity</link>
      <comments>https://tproger.ru/projects/optimization-methods-unity?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Саша Ушатинская]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/projects/optimization-methods-unity</guid>
      <description><![CDATA[<p>Производительность решает всё для мобильных игр, и подходы к оптимизации проверены на игре «Spearfishing 3D — подводная охота» для iOS.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/projects/optimization-methods-unity">Методы оптимизации при разработке в Unity 3D</a>»</p>]]></description>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[Для продолжающих]]></category>
      <category><![CDATA[Для продвинутых]]></category>
      <category><![CDATA[Рассказы о своих проектах]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 08 Mar 2013 12:24:40 GMT</pubDate>
      <content:encoded><![CDATA[<p>Производительность имеет решающее значение для мобильных игр. Особенно если игра сочетает в себе физику, AI (искусственный интеллект) и полностью анимированных персонажей 3D-мира. Некоторое время назад мы сделали игру под названием «Spearfishing 3D — подводная охота» для iOS. За первые полгода после релиза игра была скачана около двух миллионов раз и попала в топ-10 в категории «Игры» в разных странах мира. Одна из основных проблем, которую нам понадобилось решить, — обеспечение работы игры с 60 fps. Это стало проще с выпуском iPad и iPhone 4, но мы по-прежнему должны поддерживать как минимум 30 fps для iPhone 3G/3GS. В этой статье я опишу подходы, которые мы использовали для оптимизации игр на основе Unity.</p><h2>Использование Performance Profiler</h2><p>Первое место, куда нужно смотреть, когда хочется улучшить производительность — это Unity Profiler. Эта функциональность доступна в Unity Pro и позволяет анализировать проблемные места. Профайлер — бесценный инструмент. С его помощью можно определить, где возникают проблемы с частотой кадров. Для его использования запустите игру на мобильном устройстве и профайлер на PC. Когда вы запускаете игру, профайлер начинает загружать данные о производительности.</p><p>Чтобы использовать профайлер на мобильных устройствах, сделайте билд в Developer mode. Из документации Unity:</p><blockquote>Чтобы иметь возможность подключиться к плееру, плеер должен быть запущен с помощью опции Development Build, которая находится в диалоговом окне Build Settings.</blockquote><p>Здесь также можно отметить флажок для автоматического соединения редактора и плеера. Профайлер показывает график использования CPU во время игры. Просто подключите мобильное устройство к машине для разработки и проходите игру. Профайлер покажет все проблемы в режиме реального времени. Он разбивает активности на Rendering, Scripts, Physics, GarbageCollector, VSync и другие. В мобильных играх часто бывают проблемы с рендерингом. Иногда скачки производительности возникают в скриптах при загрузке сцены, но в этом нет ничего необычного. Некоторые скачки связаны с физикой.</p><h2>Физика и искусственный интеллект</h2><p>Я опишу несколько основных идей оптимизации кода физики и перейду к графике.</p><ul><li>Старайтесь, чтобы как можно меньше объектов двигалось одновременно. «Спящие» объекты намного дешевле.</li><li>То же самое касается искусственного интеллекта. Если объект находится далеко от главного героя или его не видно, не запускайте скрипты искусственного интеллекта.</li><li>Рейкасты очень дорогие. Не делайте рейкаст на каждый фрейм — попробуйте кэшировать результаты и пропустить некоторые фреймы.</li><li>Старайтесь избегать сложных меш коллайдеров.</li><li>Проверьте функции Update(). Они запускают каждый кадр и, следовательно, дорогие. Вместо этого используйте Coroutines.</li></ul><h2>Static batching</h2><p>Это фича Unity, которая экономит много циклов CPU. Каждый раз, когда объект рендерится, происходит Draw Call — команда для CPU или GPU о том, что объект должен отрендериться. Unity запускает несколько вызовов отрисовки и накладывает их друг на друга, это и формирует сцену. Однако каждый Draw Call требует ресурсов CPU, поэтому мы хотим минимизировать их количество.</p><p>Тут и стоит использовать Batching. Он нужен для того, чтобы не делать лишние Draw Calls. Batching бывает двух видов: статический и динамический. Статический дает лучшую производительность, поэтому мы всегда стараемся использовать его.</p><p>Чтобы эффективно применять Static Batching, используйте как можно меньше различных материалов. Для этого скомбинируйте все материалы в одну большую текстуру. Последний шаг — добавить Lightmap к сцене. Поскольку мы практически не используем память для текстуры объектов, можно сделать довольно подробную Lightmap, и проблем с памятью не возникнет.</p><p>Для использования Static Batching поставьте флажок Static в свойствах объекта. Его можно использовать только для объектов, которые не перемещаются, не вращаются и не масштабируются в сцене.</p><h2>Dynamic Batching</h2><p>Для не статических объектов можно использовать Dynamic Batching. Объекты с Dynamic Batching требуют определенные ресурсы на каждую вершину, поэтому он применяется только к мешам, содержащим менее 900 вершин. Наш шейдер использует Vertex Position, UV и Colors. Таким образом, у нас может быть до 300 вершин на объект.</p><p>Некоторые полезные советы из руководства Unity:</p><ul><li>Динамический батчинг связан с дополнительной нагрузкой для каждой вершины, так что он применим только к мешам, в сумме содержащим менее 900 вершин.</li><li>Если ваш шейдер использует Vertex Position, Normal и единственный UV, то вы можете батчить до 300 вершин; тогда как если шейдер использует Vertex Position, Normal, UV0, UV1 и Tangent, то только 180 вершин.</li><li>Не масштабируйте. Объекты с масштабом (1,1,1) и (2,2,2) не будут батчиться.</li><li>Равномерно масштабированные объекты не будут батчиться с неравномерно масштабированными.</li><li>Использование различных материалов приведет к сбою батчинга.</li><li>Объекты с Lightmap имеют дополнительный (скрытый) параметр материала: смещение/масштаб в Lightmap, поэтому объекты с Lightmap не будут батчиться.</li></ul><p>Заметьте: если у объекта есть анимация, но при этом есть часть, которая никогда не двигается, можно отметить эту часть как статическую, и она не будет мешать анимации.</p>]]></content:encoded>
    </item>
  </channel>
</rss>