Отличия соревновательного и «real-life» программирования

Не очень давно мне на Quorа попался вопрос об отличиях «real-life» и соревновательного программирования. Самый популярный ответ мне так понравился, что не могу не привести его тут, конечно, в моем корявом приблизительном переводе.

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

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

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

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

Это «real-life» программирование.

В соревновательном программировании, вы начинаете с теми же ресурсами (складной нож), только у вас есть 2 минуты, чтобы убить льва.

Будучи новичком, вы уставитесь на льва и ничего не сможете сделать.

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

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

И вообще, чтобы быть отличным соревновательным программистом, вы должны быть в состоянии делать две вещи.

Во-первых, вы должны научиться находить уязвимое место у льва и убивать его одним быстрым ударом.

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

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

Anthony Moh, Over-generalizer

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

Hakyll

В общем, я загорелся идеей переделать свой блог на статическую генерацию. И в связи с этим посмотрел несколько кандидатур: Jekyll, DocPad, Hugo и Hakyll. У каждой из систем свои достоинства и недостатки. Вообще, статические генераторы сайтов — это благодатная тема для обсуждения: вариантов множество и каждый день появляются новые. Если у вас есть опыт работы с какими-то другими вариантами, то милости прошу в комментарии.

Jekyll — практически стандарт де-факто, написанный на Ruby. На этом движке работает GitHub Pages. Но в нем не хватает некоторых очень важных функции, вроде раздельной пагинации для различных типов записей.

Hugo — молодой движок на Go. Работает очень быстро. По заявлению разработчиков, время генерации одной страницы не должно превышать 3-х миллисекунд. Пагинация отсутствует вообще, но Roadmap проекта утверждает, что она скоро должна появиться. Думаю у проекта большое будущее. А пока…

DocPad — очень гибкий вариант, написанный на JavaScript. Для DocPad существует множество плагинов под самые различные нужды. Но в этом генераторе мне не понравилось соглашение по именованию файлов. Например, в 2013-09-10-something.html.md расширение означает, что файл нужно будет преобразовать из markdown в html, как будто нельзя это указать в конфигурации.

И, наконец, Hakyll. Это скорее не отдельное приложение, а библиотека для создания статических генераторов. Его конфигурация представляет собой программу на языке Haskell, а потому бинарник должен пересобираться после каждого изменения. Зато такой способ даёт подлинную гибкость. Даже если какой-то возможности и не хватает, ничего не мешает её дописать. Да-да, Haskell не может похвастаться огромной популярностью и учить ради какого-то генератора новый непростой язык вряд ли кому захочется. Но так уж получилось, что у меня есть базовые знания, поэтому я решил попробовать и пока не разочаровался.

Надеюсь, пройдет совсем немного времени и мы увидим обновлённый блог, работающий ещё быстрее. Наблюдать за процессом можно на GitHub.

Отладка событий в ExtJS/Sencha Touch

Иногда, когда пишешь приложение на Sencha Touch или Ext JS, очень нужно отследить порядок событий в различных компонентах и передаваемые в обработчики параметры. Зачастую это помогает лучше понять, что происходит и в самом фреймворке. Мне это тоже иногда необходимо, поэтому я написал небольшой миксин, который можно встраивать в свои компоненты.

Вариант для Sencha Touch:

Ext.define('Ext.debug.ShowEvents', {
    requires: ['Ext.mixin.Observable'],

    onClassMixedIn: function (cls) {
        cls.prototype.fireEvent = function () {
            console.log.apply(console, arguments);
            Ext.mixin.Observable.prototype.fireEvent.apply(this, arguments);
        };
    }
});

Вариант для Ext JS:

Ext.define('Ext.debug.ShowEvents', {
    requires: ['Ext.util.Observable'],

    onClassMixedIn: function (cls) {
        cls.prototype.fireEvent = function () {
            console.log.apply(console, arguments);
            Ext.util.Observable.prototype.fireEvent.apply(this, arguments);
        };
    }
});

Не забудьте указать фреймворку, где этот файл лежит. Использовать его нужно приблизительно так:

Ext.define('App.view.MyComponent', {
    extend: 'Ext.Component', 
    mixins: ['Ext.debug.ShowEvents'],

    ...
});

Вместо Ext.Component подойдет любой класс с Ext.mixin.Observable (Ext.util.Observable для Ext JS). Теперь в консоли вы увидите все события, которые генерирует этот класс.

Если что-то непонятно, можно спросить в комментариях.

MySQL в качестве NoSQL базы данных

Идея, на самом деле, витала в воздухе. Уже не раз для хранения данных с неопределенной структурой приходилось использовать единственное поле, в которое эти данные помещались в сериализованном виде. Оставалось сделать один шаг: убрать все остальные поля. Нет ничего проще. Засунули все кроме первичного ключа в то же самое поле — и готово. В таком варианте остается вопрос с поиском, ведь потребность в индексах пока никто не отменял. Для этой цели можно использовать вспомогательные таблицы c примерно такой структурой:

CREATE TABLE index_user_id (
    user_id BINARY(16) NOT NULL,
    entity_id BINARY(16) NOT NULL UNIQUE,
    PRIMARY KEY (user_id, entity_id)
) ENGINE=InnoDB;

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

Больше подробностей о подобном подходе можно прочитать в блоге у CEO FriendFeed. Мне кажется, тема заслуживает внимания.

AngularJS и параметры контроллеров

Те люди, которые работают с AngularJS, знают про директиву ngController. В нее передается функция, описывающая поведение блока с директивой. И тут начинается магия! Если наша функция выглядит так:

SomeController = function ($scope) {...};

то она будет вызвана с одним параметром — scope, связанным с контроллером. А если, она выглядит, например, так:

SomeController = function ($http, $location, $scope) {...};

то передаваемых параметров станет внезапно три: два системных сервиса ($http и $location) и тот же самый scope.

Так как же фреймворк определяет, какие параметры нужны для вызова контроллера? Эта магия называется Function.toString(). Метод toString() у функции возвращает ее текст, а дальше дело техники: /^function\s*[^\(]*\(\s*([^\)]*)\)/m. Получили имена параметров, разобрали, подставили. Вот такой нетривиальный подход.

Детали можно посмотреть в исходниках.

← СтаршеМоложе →