Firefox Containers & Firefox Focus

В очередной раз я расскажу про Firefox, а точнее порекламирую одну крутую фичу и новое приложение.

Firefox Containers

Эта фича доступна в Firefox Nightly и в программе экспериментов Firefox Test Pilot. Идея очень простая – двумя кликами вы создаете в браузере новый контейнер, который имеет свой набор cookies, local/session storage и т.д. Можно сказать это отдельные профили, только каждый профиль это не отдельное окно/набор окон, а отдельный таб/набор табов. Зачем это нужно? Можно быть залогиненым на одном сайте с разных аккаунтов (например: рабочий/личный контейнеры). Можно повысить безопасность интернет-банкинга, используя отдельный контейнер для платежей. Можно легко избежать трекинга во время поиска, т.е. искать в отдельном контейнере. В целом я использую контейнеры для всего этого и нахожу это киллер фичей ради которой можно перейти на Firefox.

Firefox Focus

Новое приложение от Mozilla для Android/iOS. Внезапно, но оно использует ровно мой паттерн использования Firefox на телефоне: открыть вкладки, почитать, закрыть файрфокс. Причем у меня при закрытии происходит очистка истории/кук и т.д. Но теперь эта функциональность – first-class citizen, т.е. это главная идея всего приложения! Кроме этого “маленькие” фичи типо блокировка трекеров и рекламы из коробки.

How to use Apache AsyncHttpClient with Kotlin Coroutines

If you try to use Apache Async HttpClient with Kotlin coroutines you will found that their API (execute method) returns java.util.concurrent.Future that can’t be simply used with coroutines. But, you also allowed to pass future callback to execute method:

// interface HttpAsyncClient
Future<HttpResponse> execute(
    HttpUriRequest request,
    FutureCallback<HttpResponse> callback
);

Let’s take a look at FutureCallback interface:

public interface FutureCallback<T> {
    void completed(T result);
    void failed(Exception ex);
    void cancelled();
}

Step 1: Init.

There are many in common between CompletableFuture and FutureCallback API, so let’s create CompletableFuture and wrap current method call to return it:

fun HttpAsyncClient.execute(request: HttpUriRequest): CompletableFuture<HttpResponse> {
    val future = CompletableFuture<HttpResponse>()

    this.execute(request, object : FutureCallback<HttpResponse> {
        override fun completed(result: HttpResponse) {
            future.complete(result)
        }

        override fun cancelled() {
            future.cancel(false)
        }

        override fun failed(ex: Exception) {
            future.completeExceptionally(ex)
        }
    })

    return future
}

So what happens here:

We create extension function for HttpAsyncClient, and we can use this function in more natural way:

override suspend fun getCount(url: String): Int {
    // ...
    val response = httpClient./* calling extension */execute(request)./* kotlinx.coroutines extension */await()
    // ...
}

On first method’s line we create a new incomplete instance of CompletableFuture and return it on last line. We use this instance inside FutureCallback. So when some method of callback will be called, our future will change state.

Another important part – suspend doc modifier on function, that mean that function can be suspended.

Step 2: Refactor.

Imagine that we have few methods execute and we want to reuse code. Then again: extension functions and class delegation to the rescue!

class CompletableFutureCallback<T>(
    val completableFuture: CompletableFuture<T>
) : FutureCallback<T>, Future<T> by completableFuture, CompletionStage<T> by completableFuture {
    override fun failed(ex: Exception) {
        completableFuture.completeExceptionally(ex)
    }

    override fun cancelled() {
        completableFuture.cancel(false)
    }

    override fun completed(result: T) {
        completableFuture.complete(result)
    }
}

suspend fun <T> CompletableFutureCallback<T>.await(): T = this.completableFuture.await()

And now we can use this class like this:

fun HttpAsyncClient.execute(request: HttpUriRequest): CompletableFutureCallback<HttpResponse> {
    val future = CompletableFutureCallback(CompletableFuture<HttpResponse>())

    this.execute(request, future)

    return future
}

// Somewhere

client.execute(request)./* our extension */await()

So that’s it, most simple approach to use HttpAsyncClient with coroutines.

Step 3: Performance.

You can see that we create at least one instance of CompletableFuture, so we do one allocation of CompletableFuture for every call. Is it necessary?

What we do: we create instance of CompletableFuture and then suspend on it with help of CompletableFuture.await() extension. You can see that await uses suspendCancellableCoroutine function under the hood. Can we use this function directly? Sure, why not:

suspend fun HttpAsyncClient.execute(request: HttpUriRequest): HttpResponse {
    return suspendCancellableCoroutine { cont: CancellableContinuation<HttpResponse> ->
        val future = this.execute(request, object : FutureCallback<HttpResponse> {
            override fun completed(result: HttpResponse) {
                cont.resume(result)
            }

            override fun cancelled() {
                // Nothing
            }

            override fun failed(ex: Exception) {
                cont.resumeWithException(ex)
            }
        })

        cont.cancelFutureOnCompletion(future);
        Unit
    }
}

Looks good, we use low-level suspendCancellableCoroutine function from standard library, and also we support cancellation of Future!

This is my final approach for today.

Firefox not Dead!

Я использую Firefox с первой версий, это именно тот браузер на который я перешел с IE6. Отлично помню как подбивал друзей скачать Firefox 3, чтобы Firefox набрал 8 миллионов инсталляций за 24 часа. С тех пор прошло много лет, точнее 13 лет. И сейчас я пишу этот пост в Firefox, а конкретнее в Firefox Nightly 55.0. Также у меня открыт второй Firefox стабильной ветки с 178 вкладками! На телефоне я тоже использую Firefox, вместо Chrome. В свое время это было волевое усилие, но теперь я намного больше доволен мобильным Firefox, чем Chrome.

Но Firefox находится в опасности, говорят что Chrome победил.

Что привело к такому положению?

  1. Firefox рекламировала поиск google внутри себя, и долго жила за эти деньги;
  2. Сервисы google агрессивно навязывали chrome;
  3. Сотни программ устанавливали chrome, если не убрать галочку. Типичный adware;
  4. …?

Чем Firefox хуже?

  1. Devtools медленнее, намного медленнее. Честно говоря по работе я часто пользовался хромом чтобы дебажить приложения. В Firefox это было намного сложнее. Правда ситуация меняется и дебаг в Firefox постепенно становится лучше. А ведь когда-то именно Firefox была лидером в этой сфере с её Firebugs! Просрали все полимеры!
  2. Ест больше памяти. Недавно слышал это заблуждение из 2000-x. Нет, Firefox уже давно не течет и ест меньше Chrome.
  3. Встроенный Flash, мультипроцесоность. В своё время дали неплохой плюс с точки зрения безопасности и юзабельности браузера. Сегодня Flash никому не нужен, а мультипроцесность есть и в Firefox.
  4. …?

Чем Firefox лучше?

  1. Плагины. Крутых плагинов больше. Непонятно как все будет после того как выпилят XUL. Но пока так.
  2. Крутые фичи, типа Firefox Container. Эта фича включена в Firefox Nightly. Теперь я без проблем могу иметь изолированные вкладки и сайты в пределах одного окна. Сидеть в трех твиттерах одновременно, делать оплату в банке более безопасно, не давать другим сайтам знать что я залогинен в google или facebook. Это киллер фича для вашей безопасности и приватности!
  3. Приватность. Думаю тут понятно, Firefox сливает меньше данных (а при желании вообще не сливает ничего), Chrome собирает о вас все: историю посещений, закладки и прочее по дефолту. Ну и Chrome (не путать с Chromium) это таки Closed Source, а Firefox – Open.

Что делать?

Если вам важна судьба Firefox то вернитесь на него с Chrome, пересадите мам, пап, бабушек. Попробуйте Firefox для телефона. Поставьте Firefox Container и оцените удобство фичи. Не забывайте тестировать ваш сайт в Firefox!

Олдфаг

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

  1. Первый мой компьютер работал под управлением Windows 98(или 95, не помню), 16mb оперативной памяти и имел процессор Pentium 100. Тогда уже был Dial-up, 8 600 100! Помните, да? 🙂 В общем история такая что Отец принес мне модем, т.к. я очень хотел попасть в интернет (на сайт Cheetos). И все было бы хорошо, но модем подключался по COM порту как и мышь. В итоге мы пытались серфить интернет через древний IE в древней Windows, с клавиатуры :). Руслан, ~ 6 Лет.
  2. Этот компьютер активно использовался для написания дипломов и курсовых, а в его свободное время я вовсю запускал на нем диск 700 Русских Игр! 700 игр, но одном диске! 🙂
  3. Через какое-то время уже были машинки помощнее, и я помню как я ходил к другу(привет Дима Запруцкий!) по этажу посмотреть на игру “Гарри Поттер и философский камень”. Там была 3D графика, на то время это было что-то невероятное!
  4. Я помню как сидел на dial-up в IE6. Все тормозит, куча окон с сайтами и загрузок. Принцип был такой: подключился, нагрузил, отключился чтобы не занимать телефон.
  5. Уже чуть позже, когда у меня был Athlon XP 1500+, я конечно увлекся Warcraft III: Reign of Chaos & The Frozen Throne. Компания, дота, игра по интернету. Форум и сайт Xtream Game Modmaking (xgm.ru), попытки написать свои карты: редактор карт и мой первый язык: JASS! Еще можно было вставать пораньше с утра (5-6 часов) чтобы поиграть с более или менее нормальным пингом 🙂
  6. Список будет пополняться

Small scopes and SRP rocks, isn’t it?

We discussing recent post by “OOP” lover Yegor Bugayenko.

My thoughts that it’s not about FP or OOP, objects or functions, it’s all about SRP. Like we have two initialization blocks in one method, and then we test results of these blocks. We can move this blocks in lambdas/functions/classes, but in general it’s just two functions that produces a and b and then we compare a and b. After working with Kotlin I’ll write this test like:

@Test
void testIntStream() {
    final long seed = System.currentTimeMillis();

    assertEquals(
        run(() -> {
            final Random r1 = new Random(seed);
            final int[] a = new int[SIZE];
            for (int i = 0; i < SIZE; i++) {
                a[i] = r1.nextInt();
            }
            return a;
        }),
        run(() -> {
            final Random r2 = new Random(seed);
            return r2.ints().limit(SIZE).toArray();
        })
    );
}

Just like in Yegor’s solution my test have only one statement: assertEquals.
My approach much more clean, and for every new test I don’t write any boilerplate to the glory of “OOP” God.

Just like Yegor’s solution, my approach have same benefits over original test:

  • Reusability — I can easy extract lambda from test, and reuse between number of test.
  • Brevity — It’s much less code with in place lambdas.
  • Readability
  • Immutability

In post Yegor’s approach seems good, but it doesn’t scale to real applications.

run function for the reference:

public static <R> R run(Producer<R> producer) {
    return producer.produce();
}

Kotlin version

So also I’d like to add Kotlin example for this test, it’s much more readable even than Java version with lambdas (no surprise here)

@Test fun testIntStream() {
        val seed = System.currentTimeMillis()

        assertArrayEquals(
            expected = {
                val r1 = Random(seed)
                IntArray(SIZE).also { array ->
                    for (i in 0..SIZE - 1) {
                        array[i] = r1.nextInt()
                    }
                }
            },
            actual = {
                val r2 = Random(seed)
                r2.ints().limit(SIZE.toLong()).toArray()
            }
        )
    }

I am using JUnit 5 for this test, and was expecting that JUnit 5 has methods that accepts lambdas for assert, but unfortunately – there are no such signature. So I added it:

fun assertArrayEquals(expected: () -> IntArray, actual: () -> IntArray) {
    Assertions.assertArrayEquals(expected.invoke(), actual.invoke())
}

I think will be nice to have support library for JUnit 5 with such methods.

Mockito 2.1

Наконец-то дошли руки посмотреть на Mockito 2.

Из того что мне показалось интересным:

  • CGLIB заменили ByteBuddy
  • Частичная поддержка Java 8
  • MockitoExtension для Junit 5 (3rd party)
  • final class теперь можно мокать (опционально и вообще не делайте так)

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

testCompile("org.mockito:mockito-core:2.7.22")

История про программиста

@shipilev: @qwwdfsad Там давно уже не LCG, а Marsaglia xor-shift, но сути комментария это не меняет
@qwwdfsad: о, он теперь по дефолту включен?
@shipilev: да
@shipilev: Trivia: я его случайно переключил, когда пушил @Contended в восьмёрку, но обнаружилось это только когда восьмёрка уже вышла во все поля
@shipilev: https://bugs.openjdk.java.net/browse/JDK-8006176
@shipilev: Не, ну я проверил, что распределения не удолбищные. Оно даже многие DieHard проходило. Из спектральных тестов невооружённым глазом видно, что лучше: http://cr.openjdk.java.net/~shade/8006176/randomicity/
@shipilev: Потому что это был экспериментальный однострочный фикс, на котором я перф тестировал. Он просто так утёк в коммит другой фичи, гыгы.
@gurinderu: @shipilev и никто не заметил?)
@shipilev: Судя по всему, нет. Потому что мне самому кто-то в твитторе года два спустя сказал, что “да вон парни из Оракла переключили hashcode=5, и всё стало шоколадно”. И тут я посмотрел в историю и понял…
@gurinderu: понял почему Шипилёва выгнали из Оракла
@shipilev: Но-но! Я косячнул один раз и это всё равно улучшило перформанс. Beat that, suckers.

The Brave One

JavaScript creator and Mozilla co-founder Brendan Eich just released version 0.11.6 of Brave browser.

It’s amazing how easy it’s today to make the browser: just take Node.js, Electron and a small team… Boom, you have a modern browser with the latest web technologies.

Brave has good privacy defaults: https everywhere, tracking protection and ad blocking. Also, you can block scripts in few clicks, it’s really funny since Brendan is JavaScript creator. For sure I’ll keep this browser and maybe will use it from time to time.

Hope Firefox will apply this defaults too.