• On Clojure arguments

    Sometimes, a function that we are working on needs to take lots of parameters. Not just one or two but a decade or even more. I used to face with such a problem many times. I’m not sure solutions made by me were always good enough.

    You might be brave enough to say you will never face such an error. It’s probably a weird architecture. A function should accept at least five arguments. You will refactor such a code for sure.

    But look at this:

        def __init__(self, verbose_name=None, name=None, primary_key=False,
                     max_length=None, unique=False, blank=False, null=False,
                     db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
                     serialize=True, unique_for_date=None, unique_for_month=None,
                     unique_for_year=None, choices=None, help_text='', db_column=None,
                     db_tablespace=None, auto_created=False, validators=(),
                     error_messages=None):
    

    It is from Django, the world-wide spreaded framework to build robust web applications. Except self, the constructor takes 22 optional arguments. Saying more, it is just a basic abstract class. Its descendants require their own arguments in addition to default ones.

    Common languages such as Python, Ruby or Java give only one standard way to deal with lots of parameters. In fact, using them you cannot be mistaken since you have no other choice. The question here is how to make you code less ugly than it is now.

    People who are new in Clojure, especially if they came from classical Python/Puby/PHP, face troubles when passing lots of arguments into a function. Since it’s Clojure, there are several ways to do that. This article highlights some on them, their benefits and disadvantages.

    Multi-arity

    Any function in Clojure may have more than one body with its own signature. That’s normal for any functional language, but sounds surprisingly to former Python/Ruby adepts. An interpreter dispatches that bodies by a form of arguments. The first found body is called. When no body is found, an exception is raised.

    For example, the same function could be called with either two or three arguments if we declare it in such way:

    (defn foo
     ([x y]
      (println "two arguments")
      (+ x y))
     ([x y z]
      (println "three arguments!")
      (+ x y z)))
    
    (foo 1 2)
    3 ;; prints `two arguments`
    
    (foo 1 2 3)
    6 ;; prints `three arguments!`
    

    Calling a function with zero, one or ten arguments will raise an exception. Depending on your application’s logic, it could be both good or bad behaviour.

    To fallback to default body that deals with any set of arguments, add one more implementation:

    (defn foo
     ([x y]
       ...
      )
     ([x y z]
      ...
      )
     ([& args]
      (reduce + 0 args)))
    

    Now, you may add any arguments set together:

    (foo 1 2 3 4)
    10
    
    (foo)
    0
    

    The order of bodies is important. If you put [& args] clause on the top, it will cover all the possible function calls. So you will never reach [x y] or [x y z] implementations.

    One interesting feature is you may redirect function call inside a body just calling the same function with another argument set. For example:

    (defn test
      ([x y]
       (test x y nil)) ;; redirects to the second body
      ([x y z]
       (do-some-stuff x y z)))
    

    Clojure dispatches a proper body quite fast. It is a key feature of Clojure’s runtime. There are lots of core functions that declare two, three or even five bodies regarding to performance issues. It’s much faster then having a single body with multiple ifs, case or condclauses.

    A quick copy-paste from Clojure sources:

    (defn juxt
      "..."
      ([f] ...)
      ([f g] ...)
      ([f g h] ...)
      ([f g h & fs] ...))
    

    Multi-arity is great when you already have a function that takes a couple of scalar parameters and then you need to add some extra one ASAP. Usually, the most needed function is called in thousand places so adding an extra parameter everywhere would be a mess.

    In Java or Python world, it is named “refactoring”. You need a robust commercial IDE to scan the project and change each call of a function. In Clojure, you just do:

    ;; old
    (defn test
      [x y]
      (do-old-stuff x y))
    
    ;; new
    (defn test
      ([x y]
       (do-old-stuff x y))
      ([x y z]
       (do-new-stuff z)
       (do-old-stuff x y)))
    

    Now you can keep the old calls without changing your code. And pass the new argument only where you need.

    Maps

    Your function may need lots of additional arguments. For example, boolean flags, extra options for HTTP connection, timeouts, headers, error messages.

    A good way to solve the problem is to join them into a single map. Thus, your function accepts only a couple of required parameters and the rest are put into an optional map. Say, you pass a hostname and a method name and a map with :timeout, :headers keys on so on.

    Inside a function, you either take optional arguments one by one:

    (defn foo [hostname port & [opt]]
      (let [timeout (:timeout opt)
            headers (:headers opt]
        (http-request hostname port timeout headers)
        ...)
    

    or decompose a map on separated variables at once:

    (defn foo [hostname port & [opt]]
      (let [{:keys [timeout
                    headers]} opt]
        (http-request hostname port timeout headers)
        ...))
    

    Decomposition works as well on the signature level. I do not like this method though since it brings some noise in the code:

    (defn foo [hostname port & [{timeout :timeout
                                 headers :headers}]]
      (http-request hostname port timeout headers)
      ...)
    

    A good point there is you may keep a default map somewhere and merge it with the passed ones to fallback to default values:

    
    (def foo-defaults
      {:timeout 5
       :headers {:user-agent "Internet Explorer 6.0"}})
    
    (defn foo [hostname port & [opt]]
      (let [{:keys [timeout
                    headers]} (merge foo-defaults opt)]
        ;; now timeout is always 5 when not passed
        ...
        ))
    

    This way of passing a map is widely-spreaded across Clojure libraries. It even considered as the standard one because of its simplicity and transparency. If you have just started with Clojure and need a function with multiple arguments, use a map.

    Rest arguments as a map

    There is another way to deal with multiple arguments. Do you remember the rest arguments prepended with & in a function signature? Something like that:

    (defn foo [& args]
      ;; args is a list)
    
    (foo 1 2 3 4) ;; args is (1 2 3 4)
    

    Starting with Clojure 1.5 (or 1.6, I don’t remember exactly) you may turn the rest arguments into a map. The syntax is:

    (defn foo [& {:as args}]
      ;; now, args is a map!
      args)
    
    (foo :foo 1 :bar 42)
    {:bar 42, :foo 1}
    

    Pass extra arguments remembering some simple rules:

    1. there must be even number of rest arguments, otherwise you will get an error;
    2. each odd argument (usually a keyword) is a key;
    3. each even argument is a value;
    4. you cannot duplicate key items.

    Turning rest arguments into a map is also used oftenly in Clojure. You may choose that method over a map as well when developing with Clojure.

    Pure map vs rest args

    Each of two method described above has its own benefits and disadvantages. Let’s highlight some of them:

    1. Using a map is good when you don’t know exactly what arguments you will pass into a function. It’s a common situation when the final set of options is unknown for the last moment. It might depend on user input, environment variables or any conditions. Usually, you compose a map step by step, validate it with somehow and pass into a function. With sequences, it’s more difficult to compose a set of arguments.

    2. Passing a map into a function with the & rest signature requires some additional steps. You should flatten you map into a vector or sequence and then apply it to a function:

      (def opt {:foo 42 :bar [1 2 3]}) ;; your options map
      
      (defn foo [& {:as args}] ...) ;; but the function accepts rest arguments
      
      ;; turns opt to a seq of (key1 val1 key2 val2)
      ;; then apply it to the function
      (apply foo (mapcat identity opt))
      

      Note how long is the code. Probably, you’d better to modify the function to accept just map.

    3. With the rest arguments, partial works like a charm. Say, we have a function that returns a set of rows from the database. The first argument is a table name, and the rest are a sequence with each odd argument as a column name and even argument as a value:

      (db-query :users :active true :staff true :name "Ivan")
      ;; performs a query like:
      ;; select *
      ;;   from "users"
      ;; where
      ;;   active
      ;;   and staff
      ;;   and name = "Ivan"
      

      Some of our users could be blocked. We may forget passing :active false clause every time you query for users. To prevent returning blocked ones to the frontend, it’s better to have a special function for that:

      (def active-users (partial db-query :users :active true))
      

      In addition to this constraint, we might be interested in only staff users. Let’s extend our function with another partial application:

      (def staff-active-users (partial active-users :staff true))
      

      Finally, we may select all the non-blocked staff users whose name is Ivan:

      (staff-active-users :name "Ivan")
      ;; [{:id 1 :name "Ivan" :surname "Petrov"}
      ;;  {:id 1 :name "Ivan" :surname "Sidorov"}]
      
    4. Instead, with maps you cannot declare a partial function. You need to invent your own partial-map implementation:

      
      ;; let `foo` is a function that accepts a map
      (defn foo [opt]
        opt)
      
      ;; our own `partial`
      (defn partial-map [f defaults]
        (fn [opt]
          (f (merge defaults opt))))
      
      ;; example:
      (def foo-timeout (partial-map foo {:timeout 5}))
      
      (foo-timeout {:bar 42})
      {:bar 42 :timeout 5}
      

    Conclusion

    The examples above show there are more then one way to deal with multiple arguments in Clojure. These are multi-arity, maps and rest arguments. All of them cover you common requirements as well.

    Remember, you are not limited with the only three those ones. With macroses, you can implement you own arguments system: Common Lisp-wise or any other. The only limit there is your imagination.

  • Нелюбовь

    cover

    Посмотрел Звягинцева.

    Переполняют чувства, но писать рецензии как Носик я не умею, поэтому буду краток.

    Великое кино. Шедевр от вступительных титров до последнего кадра.

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

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

    Бывает, мы говорим: это было как в кино. То есть волшебно, непонятно, не так как мы привыкли. А у Звягинцева – как в жизни. И это пугает, потому что понимаешь, что все происходящее может завтра случиться с тобой.

    Так же столкнешься с бездействием ментов, произволом на всех уровнях, офисным рабством, пасьянсом “косынка” в ожидании обеда. Православным начальстом, греющим руки на строительстве храма.

    И конечно, недостатком внимания к тем, кто рядом и заслуживает этого.

    Каждую сцену можно просматривать бесконечно: включается латентный вуайерист. Словно подглядываешь за чьей-то жизнью, и все фейлы, измены видны, как день.

    Сцена с Киселевым и Украиной следует за сценой с моргом. Обе они дают декартово произведение ужаса и тоски. В тот момент в кинотеатре я почуствовал, будто в сердце что-то воткнули.

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

  • What to read #24

  • Does any program really have an unlimited number of bugs?

    I really enjoy reading Yegor’s blog. He brings quite interesting ideas regarding programming and business. But sometimes, the thoughts he shares there look a bit strange to me. I’m talking about one of the latest posts titled “Any Program Has an Unlimited Number of Bugs”.

    I’m writing this in reply to Yegor’s points mentioned there. Please read them first. To focus on the key notes, let me quote the most sensitive part:

    Let’s take this simple Java method that calculates a sum of two integers as an example:

    int sum(int a, int b) {
      return a + b;
    }
    

    How about these bugs:

    • It doesn’t handle overflows
    • It doesn’t have any user documentation
    • Its design is not object-oriented
    • It doesn’t sum three or more numbers
    • It doesn’t sum double numbers
    • It doesn’t cast long to int automatically
    • It doesn’t skip execution if one argument is zero
    • It doesn’t cache results of previous calculations
    • There is no logging
    • Checkstyle would complain since arguments are not final

    Well, the points highlighted above make me really uncertain about what really Yegor meant. And since he didn’t answer me in the commentary section, I will put my thoughts on that in my own blog.

    Let’s look closer at some of them.

    It doesn’t have any user documentation

    The question is, do you really think we need documentation for sum function? What will you put there? I cannot guess nothing other than It adds two integers. So what the reason for having it in our code?

    In a previous project, I had a teammate who was a fan of docstrings. Every module, a class or a method should have a docstring, he said. The code he wrote looked like a school composition. You could not ship your code without his comments something like “add docs here and there plz”.

    Since our product was developing rapidly, we had to change the code all the time. Surely, we used to forget to update those docstrings because it took extra time. It was even worse because the docstrings didn’t tell the truth anymore. Nobody believed them as a result.

    What we need sum documentation for? How should it look like? Who will read this documentation? A user? I doubt it. A programmer? Even programmers need not a machinery-generated HTML made of docstrings, but human-written manuals with examples and snippets.

    When you open a particular GitHub project, what do you do first? Reading the code? No, you scroll down for README or click on Wiki link. Digging the source code is the last thing you would make if something works not well.

    Let’s recall what does one say on DOOM III source code and ID Software code standards in general:

    Code should be self-documenting. Comments should be avoided whenever possible. Comments duplicate work when both writing and reading code. If you need to comment something to make it understandable it should probably be rewritten.

    Its design is not object-oriented

    We all know Yegor is passionate by OOP. But really, naming a function buggy just because it’s non-OOP designed is not fair.

    What would happen if we had an OOP version of sum function? I can imagine something messy like this:

    Adder adder = new Adder();
    adder.setA(1);
    adder.setB(2);
    Integer result = adder.getResult() // 3
    

    We’ve got lot more problems here. The number of lines grew up from 1 to 4 (compare to add(1, 2)). In addition, now adder object also keeps it’s own state. How may I track whether .setA was called or not? What will happen if I forget to put .setB in my code? Will it get a Null value or an exception raised?

    What will happen if I share adder object across multiple threads so they call setA, setB and getResult simultaneously? Nobody would predict the result.

    Functional programming teaches us to avoid having state and keep the things simple. Having a small function without any state rather than manipulating with objects will pay off for sure.

    It doesn’t sum three or more numbers

    Surely, if you a Java programmer, you’ve got a problem. Because there is nothing you can do without rewriting the code. But if you are aware of FP-style and you have your add function, you simply do:

    (reduce #'add (list 1 2 3) :initial-value 0) ;; common lisp
    (reduce add 0 [1 2 3])                       ;; clojure
    

    or, in Python:

    reduce(add, [1, 2, 3], 0)
    

    This is definitely the right way with reduce also known as fold. You don’t need to write a function that adds million of integers. Instead, you add just two! And reduce will care of how to spread it across a sequence of data.

    That’s normal to focus on simplest cases and primitive operations first. Then you build abstractions with high-order functions based on primitives. It makes the code easier to understand and debug.

    It doesn’t sum double numbers and It doesn’t cast long to int automatically

    I don’t know if it is really a bug. On the one hand, it would be great to have a function that adds everything. Again, within any Lisp dialect or Python I may have it easily. Instead, with static typing you have to write more code.

    But on the other hand, having exact integer types might be some kind of specific requirement made by design. It could be an utility function that adds to years or any numbers that do not exceed a couple of thousands. So it’s difficult to judge without a full context (I’ll say more on that below).

    It doesn’t skip execution if one argument is zero

    I really doubt it will increase the performance. Adding zero to an integer costs really nothing on modern hardware. The compilers are smart enough to deal with such cases. But putting an extra if clause will definitely increase the number of instructions because now your program makes a comparison step.

    This is exactly what did Knuth say about preliminary optimization. You don’t even have any metrics about what runs faster: adding zero of extra if statement. You even don’t now how frequently your function will be called with zero argument. I might be 1 time per 100k calls so your trick is made in vain in that case.

    It does not worth it, after all.

    It doesn’t cache results of previous calculations

    I’m sure any cache system brings as many problems as it solves. First, where would you store that cache? In application’s memory? In Memcache? User’s cookies?

    Then, you program could sum million of numbers per second. Every cache call needs al least O(C) or O(logN) time to lookup a value. You will slow down your program dramatically with such approach when caching small functions.

    There is no logging

    The same claims are here: what exactly are you going to log? Who will read that logs and how often? For what purpose you want to store such kind of logs? Where would you store such amount of logs? Did you estimate the slowdown that you will bring to your system by adding logging? What if some of Ops team would misconfigure logging system and add email handler to that logger? Or sending SMS message?

    Finally, this function is taken completely out of the scope so it’s impossible to judge on its quality. We should never examine a single function but only their composition instead. Every function has its own weaknesses and strengths. Linked together properly they build a system. In such a system, weakness of any specific function is supported by another function that validates data, filters input params, cleans up system symbols and so forth.

    What I want exactly to say is there is nothing criminal in such a function that adds to integers. If it’s surrounded with another function that ensures that both numbers are really integers, there is no need to do all that validations again when adding them. In our projects, we usually separate our application on several levels. On the top level of the application, threre is one that validates the input data. If they are fine, functions on the next level operate on them as well.

    In conclusion, please avoid using word “bug” when you talk about lack of logging or caching. Probably you don’t need that stuff. Keep functions free of having state and producing side effects. When you afraid of the data you use may be incorrect (Nulls, overflows), don’t rush into adding nested ifs. You’d rather update your validation logic first.

  • Об авторском праве

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

    Главная проблема авторского права состоит в том, что до недавнего времени люди мерили собственность и богатство материальными единицами. Долларами, квадратными метрами, тоннами. В классическом предствалении богач – это тот, у кого чего-то много. Это самое “много” легко представить или изобразить. У богатого человека большой дом, огромная фабрика, мощный параход.

    В материальном мире одна и та же вещь не может существовать дважды. Поэтому у каждой вещи только один владелец. Если у человека забрать что-то материальное, это сразу станет заметно. Так ввели понятие кражи, определили институты закона и суда. Человек додумался до этого еще несколько тысяч лет назад. Базовые нормы общества вроде “не укради” опираются на аналоги, разработанные в Древнем Риме.

    Цифровые технологии изменили восприятие собственности. Впервые человек столкнулся с тем, что определенный тип материи может быть скопирован практически бесплатно. Это вкорне противоречит привычной модели материальных благ. Чтобы скопировать устройство, например, зарубежный фотоаппарат, подводную лодку или атомную бомбу, нужны ресурсы, намного превышающие затраты на постройку оригинала.

    Индустрия не была готова к такому феномену и до сих пор пребывает в фазе медленного перехода к чему-то осмысленному. Этим объясняются случаи нарушения прав человека, баснословные штрафы, судебные тяжбы.

    Мысль о бесплатном копировании чего угодно пугает неопределенностью. Мы привыкли, что любой ресурс конечен. Среднестатический человек тратит четверть жизни на обучение, чтобы устроиться на работу и поддерживать материальное состояние. Тысячи людей по всему миру живут только затем, чтобы к вечеру заработать на еду.

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

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

    Регулярно возникают случаи нарушения авторских прав, и я хотел бы поговорить об этом подробней. Некоторые аспекты копирайтинга мне кажутся спорными. Да, они утверждены законом, но только одно это не мотивирует их соблюдать, поскольку закон относителен. Одно и то же может быть нормой в одной стране и преступлением в другой. Скажем, ловля покемонов в храме или съемка порнографии.

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

    Что касается игр, здесь ситуация однозначно меняется к лучшему. Еще 10 лет назад было нормально качать торренты, переписывать игры на болванки, искать кряки и серийные номера. А сегодня есть Стим, который свел пиратство игр на нет. Благодаря Стиму среди моих знакомых не осталось никого, кто бы ставил игры из неофицальных источников.

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

    С момента изобретения кино некоторые эксперты пророчили смерть театрам. Зачем ехать в вечернее время в центр города, наряжаться, соблюдать этикет? С изобретением телевидения даже потребность в кино отпадает, утверждали эксперты. Все можно посмотреть дома. И тем не менее, театры востребованы. У кого есть дети, знают, что брать билеты на спектакли нужно за месяц вперед: раскупают мгновенно.

    Аналогично с концертами и фестивалями. Если предложить фанату вернуть билет на выступление любимой группы с предложением посмотреть на экране, он просто покрутит пальцем у виска.

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

    Поиск фильма по фразе “смотреть онайн бесплатно” перебрасывает человека на сайты, увешанные баннерами и виджетами. Экран застилают предложения что-то увеличить. Подобным сайтам, в общем-то, все равно, что пользователь уходит. Главное – скормить ему максимум рекламного трафика. В следующий раз пользователь все равно прилетит из Гугла на этот же сайт или его зеркало в поисках другого фильма.

    Как бы ни был безграмотен в компьютерном плане пользователь, он догадывается, что такое положение дел неправильно. Это как будто закрылись магазины, и ты ходишь по барыгам.

    Вопрос, почему полулегальные сайты стоят в выдаче поисковика выше официальных? Неужели у поборников авторских прав нет денег на раскрутку?

    Да, некоторые фильмы можно легально просмотреть на Ютубе, купить в магазинах Эппла и Гугла. Но опять же, новинки попадают туда с опозданием. Другой минус состоит в том, что покупая там, пользователь очень стеснен в выборе и правах.

    В онлайн-магазине вы не можете выбрать языковую дорожку. Ваш аккаунт намертво привязан к стране и правовым нормам, которые запрещают купить фильм в оригинальной озвучке, если вы, например, из России. Только дубляж. Никому не интересно, что ты учишь английский или французский. Я помню, лет 15 назал покупатели массово требовали русский язык в пиратских релизах. Сегодня, наоборот, чтобы скачать английскую версию, пользовтель вынужден серфить торренты.

    Я в корне не согласен с тем, что нельзя выбирать локализацию продукта.

    Защитники авторских прав утверждают, что терпят колоссальные убытки от пиратства и торрентов. Называют колоссальные цифры, рассказывают, кто из музыкантов сколько недополучил. Подвох кроется в том, что ни в одном отчете не сказано, как именно считались убыки и как они структурированы в принципе.

    Помните, как считали потери в Микрософте? Брали число школьников, у которых дома пиратская Винда’98 и умножали на стоимость лицензии. Получали дутые суммы, в то время как никаких убытков не было. Напротив, именно пиратские версии заполонили компьютеры пользователей. Со временем пользователи легализировались. Люди взрослеют, у них заводятся деньги, и с какого-то момента человеку становится проще купить коробку и вбить номер с нее, чем лазить по левым сайтам в поисках ключа.

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

    Не учитывается факт, что сегодня, при наличии быстрого интернета и свободного места на дисках, много фильмов, музыки и игр скачивается просто так. Синдром Плюшкина: скачаю, а потом, может быть, послушаю-посмотрю. У каждого из нас есть на компьютере папочка с пиратскими книгами и фильмами, до которых мы никогда не доберемся из-за нехватки времени. Книга качается 10 секунд, а читать ее нужно месяц. Игра установлена, но некогда даже посмотреть вступительный ролик. Поэтому умножать стоимость фильма на число скачиваний просто нелепо.

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

    Идея о том, что нельзя что-то читать, слушать или смотреть при перемещении на несколько сотен киломентров, кажется мне сошедшей со страниц 1984.

    В какой-то момент Айтюнс удалил с моего телефона честно купленный альбом. Не было ни писем, ни смс. Эппл не посчитал нужным сообщать о причинах проишествия. Ссылки на альбом ведут в никуда. Конечно, через 15 минут я скачал торрент.

    Игроки-пользователи Стима и Близзарда отмечают схожее поведение компаний при переезде в другие страны. Как только россиянин входит в Стим из США, аккаунт блокируется. Начинается долгая тяжба по его восстановлению. Формально это объясняется проверками на взлом, но, по неофициальным данным, реальная причина связана с правовыми нормами и лицензионными соглашениями.

    Права на игру, выпущенные в одном регионе, не тождественны правам на ту же игру в другом регионе. В теории, они могу быть равны, но чтобы точно убедиться, нужны человеческие ресурсы, помощь юристов. Чем больше игр купил пользователь, тем сложней ситуация. В случае ошибки засудят на крупные суммы. Поэтому фирмы затягивают восстановление аккаунта и неформально подталкивают пользователя к регистрации нового с повторной покупкой тех же игр, но уже изданных в США.

    Нужно понимать, что любой продукт, даже самый коммерческий, со сременем становится частью культуры, в рамках которой он создается. Любая человеческая мысль, сюжет или персонаж является компиляцией чужих идей и образов. Например, писатель находит вдохновение в прогулках по парку. Обязан ли он платить фирме, занимающейся содержанием парка? Или автор написал интересную книгу. Как быть с тем фактом, что другие люди прочли ее, сформировали мнение, поделились эмоциями, посоветовали друзьям ее купить?

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

    Представьте себе, что внезапно ожили древние римляне и потребовали выплат за использование имен богов в названиях космических кораблей и студий красоты. Кирилл и Мефодий запросли авторские отчисления за кириллицу. А чтобы выплатить гонорар изобретателю колеса за каждый факт его применения, у человечества не хватило бы суммарных денег.

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

    Копирайтеры, возможно, видят мир немного иным, где каждый озадачен проблемой легальности. Перед просмотром фильма или кликом по ссылке пользователь взвешивает: не нарушаю ли я права, а если да, то чьи и на какую сумму. В реальности потребитель бесхитростен и совершенно безграмотен в этом вопросе. Если браузер показывает, значит, смотреть можно – вот его аргументы.

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

    Задача индустрии в том, чтобы сделать качественные сервисы с удобной навигацией и оплатой. Чтобы они всплывали в поисковиках раньше полулегальных сайтов. В идеале, последние вообще должны исчезнуть с первых страниц выдачи Гугла и Яндекса и стать уделом маргиналов.

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

    Правильное решение придет со временем.

  • What to read #23

    The last time I had to skip the rubric. Here are a couple of more links to compensate that:

  • Do's and Don'ts

    Here is a short list of rules I try to follow when working:

    Database

    • Avoid using nullable fields in your DB. Put not null everywhere you can when defining a table. Assign a default blank value if submitting a field is not necessary:

      create table foo (
        ...
        comment text not null default '',
        count integer not null default 0
      );
      
    • Keep your database migrations in raw *.sql files. Wrap each migration into transaction explicitly putting begin; and at the top of file and commit; at the bottom:

      --
      -- A short comment about what this migration does.
      --
      begin;
      
      update foo set bar = 42 where id = 100500;
      
      alter table baz drop column test;
      
      commit;
      
    • Don’t delete anything from your DB. Add deleted boolean flag that is false by default and put AND NOT mytable.deleted in WHERE or JOIN statements:

      select * from foo where not deleted;
      
      select *.f, *.b
      from foo f
      left join bar b on foo.bar_id = b.id and not b.deleted;
      
    • For each table, add created_at that fixates creation time automatically:

      create table foo (
        ...
        created_at timestamp not null default current_timestamp;
      );
      
    • Once you’ve got any geographical data (locations, areas, routes), install PostGIS extension without inventing your own “smart” algorithms. They will let you down one Friday evening.

    • Postgres is great for full-text searching. Try to deal with standard PostgreSQL capabilities before installing Elastic, Sphinx and related stuff.

    • Avoid using ORMs. A small wrapper that parses *.sql files and creates plain functions would be enough.

    • Don’t use triggers to implement business logic. Such behaviour is quite implicit and difficult to maintain. And business rules change all the time.

    Code

    • Don’t align you code with spaces like it’s shown below. Use one space only.

      foo = {
        "short":              1,
        "a-bit-longer":       2,
        "very-very-long-one": 3,
      }
      
    • Write unit tests for both server and UI sides immediately once you’ve started a new project.

    • Classes are not data. Prefer plain data structures like lists and maps over classes. Usually, structures are fast and covers the most of requirements.

    • Try to follow functional approach when develop a program. Avoid keeping state where it can be skipped. Separate IO from code that does pure calculations.

    Frontend

    • Don’t use vanilla Javascript. Use such modern technologies as ClojureScript, TypeScrip or Elm to develop without pain in the ass. Consider JS as necessary evil running under the hood to ship your application.

    • Don’t make SAPs (single page applications). Usually they work poorly, the layout leaks, you cannot open a link in a new window and they break W3C standards.

    • Even with Javascript turned off, your client must see important information on their screen.

    • Don’t make you own widgets to substitute standard ones (inputs, drop-downs, etc).

    • Never interrupt a user with alerts, pop-ups, splashes.

    • Never claim on Ad-Block enabled. It’s so ridiculous. It’s users choice what software to use when browsing the Internet.

    Architecture

    • Don’t make micro-services. Try to keep the whole codebase within. Run different domains of your application in separate threads as components.

    • Queues might help a lot. Don’t invent your own message queue facility. Use Rabbit, ZeroMQ or even Redis.

    • For message processing, use text format but not binary one. You are not Google with their proto-bufs invented to break down network limitations.

    • Writing logs in a file and tailing them via SSH is a mess. Write all the logs into (remote) syslog, either your own one or any third-party one. Syslog brings huge capabilities with logs processing.

    • Never commit to master branch directly (set that option in your Git config). Use the simplest Git pipeline you can imagine:

      master -> feature-branch -> commits -> pull request -> review -> merge
      
    • JSON is bad when configuring software: lots of braces, no comments. Take YAML.

    Programming languages

    • Prefer those languages that could give you a single compiled file as a result of you effort (both binary or bytecode). C-family, Go, Rust, Haskell, Java-family are OK. PHP, Python, Ruby, Perl, JavaScript are less OK.

    • Take a look at functional languages even you don’t have intentions using them in your daily work.

    • You’d better try not modern languages but rather old ones. Smalltalk, Lisp, OCaml would be a great choice.

    Workspace

    • Keep you desktop free from unused items.

    • The more gadgets you need having around the less you are productive. Ideally, you only need your Mac connected to the Internet.

    • Use messagers on mobile only except those you need to communicate with your customer. On my desktop, I have only Slask running with my customer’s room. Leave Telegram, Skype, WhatsApp or whatever else on you phone and check them rarely.

    • Turn off all the notifications on you phone/desktop.

    • Try to keep you developing tools simple. Choose text editor like Vim or Emacs over IDE. Work with Git from a command line.

    • Don’t work in open-space. A room with 3-4 people around is OK.

    • Don’t read the news. Your friends will warn you if something really important happens.

    Communication

    • Don’t argue on Vim vs Emacs, Python vs Ruby and so on. It looks quite unprofessional.

    • If you full of thoughts you want to share with the world, open a blog or write a book. But never argue on them in social networks or messagers.

    • Even you are a remote worker, say Hi and Bye every time you’ve started or finished your work day. Your team should know whether are you at the desk or not.

    • Be always polite.

    • When you don’t know what to say, keep silence.

    • Never afraid saying No.

    • Read about negotiations.

    • Invest time and money in improving your English skills.

    This post is a snapshot of my Do’s And Don’ts repository. You may always find updates there.

  • English

    Disclaimer: this post just shapes my opinion on how to become better in English. I’m not forcing anyone to follow the way I describe here. There are no links, promo-codes, Skype contacts, etc to share. I believe you may google them by yourself. The text given below is rather random advise that I consider to be useful. I admit it could look a bit weird to you or even wrong, but I don’t care.

    You may notice I’ve been blogging in English for the last two month. That is not because I’m so good at it. I’m really far away from reckoning myself as a confident English speaker. The auditory of this blog are native Russian speakers in most. So why switching then?

    Well, I consider writing in English as additional effort to learn it.

    Switching to another language also shifts something in your mind, I bet. It’s not as simple as I wish, though. When write English posts, I often feel I sound unnatural and the sentence looks artificial. Sometimes, I cannot find a proper word to ship the idea with all its details.

    In that post, I’m going to share a set of advise for those who just started learning English. I’d like somebody gave me a hand several years ago. These are just my opinion, though. Following them is up to you.

    First, you agree that English is quite important. All the new materials nowadays appear in English-speaking communities first. Blog posts, articles, documentation, talks… It would take a long time before they come into Russian- or any other Cyrillic-speaking group being translated poorly. Why wait for such long?

    Books? I’m feeling sad saying this, but I’ve stopped buying Russian IT books for now. Usually they are outdated: up to decade of years might pass since the original edition was issued. It’s OK though when you are interested in particular academic knowledge or algorithms, O-complexity and everything that has not been altered for years. For example, there are some quite good books on C and Pascal in Russian.

    But usually our books are made of extremely bad quality. They are issued with lots of typos and missing spaces in the text. Even MS Word auto-correction could indicate most of them. The page layout is terrible: thin margins, weird font, large gaps or tunnels in paragraphs. Paperback’s quality is low. Opening such a book twice breaks it in the middle on two half. Agrrr!

    For the last year, I’ve been reading SICP in Russian edition. It suffers from all the issues I covered above. I’m finishing it on Kindle nowadays.

    Working with foreign customers brings more income. It also makes you more independent and opens world-wide opportunities. Read my previous post on remote working.

    I’m sure I was convincing on telling the reasons you should learn English. Now we may focus on steps required.

    Start with something simple: enable English language whenever you can. In your phone, computer or a tablet. Choose English over your mother tongue in video games or series. It is really a pleasure to listen to the original voices rather than localized ones, even made with high quality.

    Attend to English class at work. I’ve been learning English in a small group of 6 at my previous job and it was a great experience. Small groups are great and the learning process is quite effective. Having few people around means you may count on having enough time to perform over the group.

    No English group in you office? You could always organize it by yourself. I believe you may find colleagues who also want to learn it. All together, come to your head department and discuss an option to hire an English teacher at your office. Don’t expect your boss will agree at once. Be ready to share the price within all the members. It’s for your interests all in all, not for your boss. There is only one man interested in your career. You are.

    There is a wide-spreaded myth that only a native speaker could be a good teacher. That’s totally wrong. I’ve been thinking the same way for a long time. I confess it could prevent you from meeting a really good teacher.

    Remember, even a great pronunciation does not make a person a good tutor. A good one is interested in correcting your mistakes and giving useful advise. Instead, a good native-speaker who does not have any teaching experience is not interested in correcting your English. You may say something with terrible mistakes, but your teacher will just reply “Wow cool!”. Such a way of having lessons does not give a result.

    I used to take some lessons from a USA girl. She was a great native English speaker, no claims to her pronunciation nor accent. But she was talking all the time. I’ve been spending my time listening to her bobbing my head and adding “Oh really?” or “That’s cool”. That learning period went quite ineffective.

    Nowadays, there are lots of cheaters who pretend being a good teacher. Don’t let them fool you. A good teacher asks you about the reason of education first. What skills do you want to improve? Reading, grammar, speaking, listening? Or prepare for exams maybe?

    A good teacher always asks you to share you thoughts on every fact you discuss. It’s not because he or she is so interested in your opinion. It’s to develop your mind. Matt, my current teacher, asks me all the time regarding everything we talk about: what do you think on this? What would you do in such a situation? And even a particular question sounds naive, it could become a challenge to compose a good answer and share your opinion in a clear strict way.

    When learning new words, there is a good trick to remember them. Open a exercise book subdivided on thematic sections: food, cars, computer, home etc. Then put a particular word you want to fixate in your memory in a proper section. “Gear” into “cars”, “towel” into “house”, “ceiling” into “buildings” and so on. To find a proper word, don’t open a translation program immediately. Try to find out for something from you exercise book first. Write icons near the words you remember less. But never scribe a translation on your native language beneath.

    When you are at your English class, do not switch at Russian at all, even you need to rest for a minute or say something that is not related to your class. Even if one is asking “What does the word X mean?”, don’t give a quick Russian meaning. Try to compose a phrase that reflects the subject in English words that you know. It is difficult sometimes, especially with such abstract terms as truthiness, honor and others. But you ought to try.

    Do not drill English Tense Chart. One consider that chart as a formula: mix together “have”, “been” and the third form of a verb to get a proper result. They even pass class tests with such approach. It does not work in real life, though.

    have + been + V(3) = profit!
    

    Instead of drilling the whole table, I recommend you to focus on three main tenses: just past simple, present simple and future simple. That fits your mind because we also have three terms in Russian as well. For the beginning, try to explain your thoughts within these three tenses. Keep your phrases simple. It’s always miserable to hear somebody trying to compose a complicated sentence but stops in a middle of it, breaks the whole line and starts from the beginning… Please avoid doing that.

    You’ll definitely need to use more tenses once you have become better in English. You’ll use them to bring additional details into your narrative; to fixate time boundaries more precisely.

    For example, you spent some time on a task and still continue working on it. On a daily call, you might say: I’ve been working on that task for 2 days. That’s great because it brings the whole context of what’s going on. If you are not ready for using such a tricky tense, you say: I was working on the task for 2 days. This form is less precise but nevertheless acceptable. Finally, you may say: I worked on that task yesterday and still continue today. Past simple plus present simple. A bit redundant but also works.

    What you really should drill is irregular verbs. A funny fact: there seems to be more irregular verbs then regular ones. In English, my school teacher used to joke, for each rule you’ve got more exceptions then ordinary cases.

    A minimal table of irregular verbs takes about three pages of A4 size. The most used verbs in our daily and business life are irregular ones. Say, write, read, go, do, make, pay, eat, grow, raise… you will need all of them talking to your teammates, customers or friends. Just decorate your wall with printed table and drill. No life-hacks here.

    I used to take advise on improving listening skills in my previous post about remote work. Start with listening to VOA Learning English videos on YouTube. They speak grotesquely slowly and clear and subtitles are rolling below. Chose any video you like and do the following action in series:

    1. watch it reading subtitles.
    2. Watch again without reading them (scroll the page a bit down); you should recognize all the words clearly.
    3. Increase the speed of video to 1.25 (Put a gear button, then “Speed”). Ensure you still may recognize all the words.
    4. Again, but at 1.5 speed.
    5. Finally, but at 2.0 speed. Return back to 1.5 or 1.25 if you miss the meaning.

    A note: speed change works only in Google Chrome on desktop. Tablets and phones won’t work unfortunately.

    The whole process takes usually 15 minutes per a single video. Even less then you spend on Twitter or being smoking. Do it every morning before starting your daily job. This exercise is quite productive, I may assure you. Even a week enough to start recognizing words in English songs. A month later you can understand most of spoken English as well.

    Read classical English literature. Indeed, not technical. Classical literature keeps its own secret: the language there is quite complicated and well structured. For example, after reading SICP I switched to 1984 by George Orwell. That is totally different English that I have never seen before! The phrases composed in a such precise way. The text is full of adjectives and nouns that bring particular meaning.

    But the main benefit here you start filling the structure of the language. Reading classical books brings huge advantages. Matt, my English teacher, highly appreciates my choice.

    When you finish your English classes, you might still have troubles speaking to your customers. Don’t think you have wasted your time though. In a middle of your daily calls, try to find a chance to practice your communication skills. Personal English teacher would be a great option. As for me, I have 30 minutes lesson every week with Matt. He grew in London and than moved to China to teach English there. Usually, we discuss various themes such as politics, art, literature, hobbies and so on.

    Finally, don’t think one day you’ll know English as completely so you may stop. You should never stop trying to learn more about English. Remember at school, you’ve been learnt Russian for ten years right? And you still make mistakes for sure. It’s the same with English. Once you started with it, it will become better and better, but you never should stop. It would be a catastrophe.

    Learning English is the same as any learning process in general. Your life has just expanded to keep and grow a new knowledge. Like programming, math or something else. The good things never end.

    But finally, this article has got ended for now.

  • Что почитать №22

    На этот раз все ссылки на русском, так что не буду выпендриваться.

  • Thoughts on Russian-speaking communities

    I decided to not stay in Russian-speaking communities anymore. No matter what they are about: Clojure, Emacs, etc… When I see “…for Russian speakers” at the end of the title my hand moves to the cross-button by itself.

    The main problem of Russian communities is they are all about trolling and rudeness. Every single person reckons himself as a Single Source Of Truth no matter what the facts say.

    Even without opening a chat I can say what it is about. Definitely, to prove you are the most clever guy all around.

    Recently, I’ve been chatting in Russian Clojure community in Telegram channel. That was awful. There were more then 100 people there, but only three of them (including me) work with Clojue for their daily work.

    Nevertheless, the chat was boiling all the time. People argued on functional programming without any knowledge of that. There were trolls whose intentions were just to throw shit on fan.

    I knew a person who was only 3 months with Clojure but argued so violently like he’s been 30 years with Lisps and functional programming. It applies to almost every member of discussion. On the first monitor, they have chat window and on the second there is a Wiki page or Stack-overflow where they convulsively try to find facts to support their opinion.

    I looks so poorly.

    And it’s this the same with other messagers and channels. No matter what is the subject of a community. In Russian-speaking group, it always ends up with a question who is cooler.

    That behaviour shows all the bad traits human have. We try to pretend we know everything, be a leader (no matter in what way), hide our weaknesses and muffle misunderstanding of something.

    What’s the point to read all that rubbish? Why do I need spend my time scrolling a feed full of arrogance?

    I must confess Russian people are rude in general. This is particularly noticeable after you have told to non-Russian native speakers. Russian way of discussing tend to be aggressive and even impolite sometimes.

    So what should you do? As for me, it’s better to join world-wide communities and channels in English. I’m sure you can easily find out Slack or Google Group channel for any language or technology you are interested in.

    Staying in Russian communities only stops your development and limits your horizons.

    If you disagree with me I highly recommend you to read that article written by Ivan Sagalaev, a famous Russian Python developer who moved to USA:

    …у меня есть небольшое завещание заявление в адрес этого самого русскоязычного сообщества.

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

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

Страница 54 из 84