суббота, 19 января 2019 г.

Почему я не продлеваю Amazon Prime

Я никогда не видел для себя большой пользы от Amazon Prime, на который подписано 100 млн домохозяйств. Но год назад я на фоне получения американского гражданства и создания сайта о грин-картах читал много юридической ерунды и даже подумывал о поступлении в law school в отдаленном будущем. На ютубе горячо рекомендовали сериал Suits на эту тему, а он был доступен на Amazon Prime Video. И это явилось последней каплей, чтобы попробовать подписаться на этот сервис ($109 за год с налогами; сейчас стало дороже).


Из заголовка видно, что особой ценности я в нем так для себя и не нашел. На самом amazon.com мы сделали 6 заказов на $475, пусть будет $500 с Whole Foods (который как магазин проигрывает связке Safeway–QFC–TJ’s по всем позициям; а Amazon Go – это аттракцион, куда можно зайти раз в жизни, но не более). Это мы еще старались заказывать побольше, раз Prime действует. Но дело в том, что у нас все есть, а обрастать хламом, пока у нас не будет своего дома для его хранения, я очень не люблю.

Не помогло и заведение кредитки от Chase, которая дает 5% cash back на покупки в Amazon для prime members. Без членства она дает 3%, то есть надо купить на $110 / (5% - 3%) = $5,500, чтобы окупить этим кэшбэком prime. Ну, хорошо, они дали $70 sign-up bonus, но у остальных кредиток подобные бонусы сейчас выше.

Сериал о юристах у меня не пошел дальше первого сезона, который я, так и быть, вымучил. Кино очень отличалось от того, что я читал в Federal Rules of Civil Procedure и все больше стало скатываться в разбор проблем в личной жизни жуликоватых людей. Реальным судам, подготовке документов там уделено очень мало времени. В общем, из них такие же юристы, какие ученые из чудиков в The Big Bang Theory. Все эти сериалы снимают для кого-то другого, но не для меня.

(При этом во время поездки в Нью-Йорк я бесплатно скачал на сайте сиэтлской библиотеки книгу “The Rainmaker” by John Grisham – тоже популярное чтение, тоже про юристов, но как раз на том юридическом уровне, какой я хотел найти в сериале).

Сериалы я вообще редко могу смотреть дальше первого сезона. Мне надоедает. Пробовал смотреть на Amazon Prime другие доступные там фильмы, как документальные (о Древнем Египте или о живности в Тихом океане), так и художественные. Некоторые мне весьма понравились (давно хотел посмотреть экранизацию Fiddler on the Roof 1971 года), но выбор там очень ограниченный. Если бы там были все фильмы за $120 в год, то я за такое готов платить. А так взял список из 20, которые я бы хотел посмотреть, и там нашелся только один. Мой брат вообще ничего там не посмотрел. Правильно, фильмы только от работы отвлекают, а для развлечения можно смотреть PUBG на Twitch (который принадлежит Amazon).

К тому же недавно другой принадлежащий Amazon сайт Imdb (собрание информации о фильмах) запустил сервис Freedive, где можно смотреть фильмы бесплатно, безо всякой подписки, но с рекламой. Я и в наших приложениях сторонник такой модели монетизации, и оказалось, что там выбор фильмов даже больше отвечает моим вкусам, чем на Amazon Prime. А блоки рекламы по 45 секунд каждые 10 минут я перетерплю. Все равно я фильмы сейчас смотрю, одним глазом что-то еще читая в соседнем окне. Во время рекламы читаю двумя глазами.

Что еще хорошего в Prime? Доставка за два дня? Так мы обычно все планируем заранее, никуда не торопимся и можем ждать посылку хоть неделю, хоть две. Бесплатные электронные и аудиокниги? Так тоже не все книги на свете. Чем это выгоднее сиэтлской библиотеки, где я могу те же книги скачать, чтобы читать на своем iPad (Amazon, понятное дело, пытается навязать свой Kindle)?

В общем, мое членство в Amazon Prime заканчивается через две недели, и я пока не намерен его продлевать. Этот пост я написал во многом, чтобы фанаты этого сервиса попробовали меня переубедить. Вдруг я чего-то не понимаю?

суббота, 5 января 2019 г.

Как я разбирал Chronometer и нашел “пасхальное яйцо”

Кто чем занимался 31 декабря, а я разбирал класс Chronometer из стандартной библиотеки Андроида. Как раз в 11:30 pm закончил. И вот хочу поделиться, что нового я узнал, плюс порассуждать о своем прогрессе в обучении программированию в целом.

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

Моему брату надоели баги в кросс-платформенном движке cocos2d-x, на котором написаны наши приложения, поэтому он переписывает код на нативную для Андроида Java. Я установил Android Studio и принялся тоже учить Java и Android по разнообразным туториалам и официальной документации, чередуя теорию с практикой, то есть с написанием собственных небольших проектов.

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


Цифры “9.9” в верхнем правом углу и есть обратный отсчет времени: у вас осталось меньше десяти секунд, чтобы перемножить 27 на 22.

Для другого своего проектика “Отгадай цифры” я попробовал другое решение, которое подсмотрел в одном из чужих проектов на github, – готовый андроидный виджит Chronometer (в toolbar справа):


Брат посмотрел на мои поделки и сказал: “А вот теперь разберись, как этот хронометр работает?”. “Как же я могу это сделать?” – спросил я. Я уже знал, что в Android Studio можно щелкнуть на любой класс, зажав Cmd, и он откроет определение этого класса, но для стандартных андроидных классов он открывал мне только заголовки методов, без их внутренностей.

Брат покачал головой, насколько можно быть тупым, чтобы полгода учить Android, и даже не установить его исходный код, который, как оказалось, полностью открыт, и может быть легко дозагружен из интернета. После чего на меня напало воодушевление: я же могу сейчас почитать код, который настоящие гуглеры пишут, а не какие-то чудики с гитхаба. И 31 декабря я сел разбирать Chronometer.

В моем ученическом представлении разобрать класс – это прочитать его код, понять все слова и что какой метод делает. Код у Chronometer – всего 400 строчек с пробелами и комментариями.

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

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


public class Chronometer extends TextView {


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


    private final Runnable mTickRunnable = new Runnable() {
        @Override
        public void run() {
            if (mRunning) {
                updateText(SystemClock.elapsedRealtime());
                dispatchChronometerTick();
                postDelayed(mTickRunnable, 1000);
            }
        }
    };


А вот время они берут разное. У меня было System.currentTimeMilles() – число миллисекунд между текущим временем и 1 января 1970 года по Гринвичу. А в Chronometer оказалась другая функция SystemClock.elapsedRealTime(), которая возвращает число миллисекунд с последней загрузки устройства, что намного логичнее, так как я не хочу, чтобы автоматическая смена часового пояса или перевод часов самим пользователем сбил мой хронометр на пару часов.

Я стал читать про разные системы времени, встретил незнакомый мне модификатор native у elapsedRealTime(), но брат, с которым я делился своими разысканиями, сказал мне не лезть в такие дебри. Native – обращение к коду, написанному не на Java. Android как операционная система является разновидностью Linux, поэтому такие фундаментальные вещи, как системное время достается через код на C.

То же самое он сказал мне о словечке synchronized, которое используется как модификатор метода updateText(long now) в Chronometer. Что это нечто, связанное с многопоточностью и что мне о таком рано знать. И вообще непонятно, что оно в хронометре делает, потому что вывод текста на экран – это основной поток. Брат решил, что это баг.

А вот следующая функция isTheFinalCountDown() багом не была:


/**
     * @return whether this is the final countdown
     */
    public boolean isTheFinalCountDown() {
        try {
            getContext().startActivity(
                    new Intent(Intent.ACTION_VIEW, Uri.parse("https://youtu.be/9jK-NcRmVcw"))
                            .addCategory(Intent.CATEGORY_BROWSABLE)
                            .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
                                    | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT));
            return true;
        } catch (Exception e) {
            return false;
        }
    }


Из официальной документации класса Chronometer невозможно догадаться, что она делает. Проверят финальный ли это отсчет – что это значит?

Ответ есть в исходном коде. Моих познаний в Android уже было достаточно, чтобы понять, что при вызове этот метод попытается открыть в браузере YouTube, а там песню группы Europe “The Final Countdown” 1986 года. Популярную, судя по 500m+ просмотрам.

Зачем? Этим вопросом задавался не только я. Поэтому нашел обсуждение этого метода на Reddit, где все решили, что это так называемое “пасхальное яйцо” от разработчиков Google, добавленное, кстати, весьма недавно, в API 26 Android Oreo, вышедшей в 2017 году. Именно, чтобы заставить недоумевать, а потом улыбнуться тех, кто будет читать исходный код класса Chronometer.

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

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

Но если продолжать сравнения, я со своими недоприложениями, которые нельзя в таком виде публиковать, и знанием, что каждое слово значит в Java, сейчас нахожусь на той же стадии обучения, где находится химик, который знает кучу химических реакций, умеет ставить их в лабе, но не умеет делать хроматографию и разбирать ЯМР. Он может побеждать на олимпиадах, сдавать экзамены и пройти практикум по органике на третьем курсе СПбГУ, но в реальном синтезе он не уйдет дальше первой стадии. Ни продукта выделить не сможет, ни понять, какая его структура и насколько он чистый.

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

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

Помучившись, я переворачивание сделал, но я сам знаю, что у меня есть баг: эпп вылетает, если перевернуть во время “экрана победы”. И мне под силу этот баг исправить, но так не хочется. Я же не собираюсь этот проект публиковать.


Зато сегодня с утра за полчаса добавил в toolbar сердечки-жизни, которые гаснут с заполнением каждого ряда. Вот такое я уже умею. Научусь и с багами воевать. Когда-нибудь. Главное не грузить себя до потери всякой мотивации учиться.