Не очень давно мне на Quorа попался вопрос об отличиях корявом приблизительном переводе.
Вы в джунглях. У вас есть карманный нож.
Кто-то просит вас убить горного льва. Кто угодно, кроме программиста, спросит: «Какого черта горный лев делает в джунглях?» Но спрашивать — это не то, что вас учили делать в качестве программиста. Вы здесь, чтобы решать проблемы, а не задавать вопросы.Вы хорошо обучились за годы тренировок. Вы воспользуетесь ножом, чтобы заострить палку. Вы срежете лиану, чтобы привязать острые камни к концу палки. Может быть, вы закончили один из лучших университетов и знаете, как извлечь из растений и насекомых вокруг вас необходимые ингредиенты, чтобы изготовить яд и нанести его на острие своего оружия.
И будучи убеждённым, что у вас есть эффективный и действенный способ убить льва, вы выдвигаетесь, чтобы выполнить свою задачу. Может быть, ваша палка оказалась слишком коротка или ваш яд не сработал. Всё в порядке — вы возвращаетесь, чтобы усовершенствовать оружие и попробовать в другой раз.
Потом
кто-то находит способ изготовления низкокачественной взрывчатки из добытых в джунглях химических веществ. Теперь метод убийства льва с помощью копья далеко не лучший путь решения вашей задачи. Тем не менее, этопо-прежнему простой способ ипо-прежнему будет преподаваться в школах. Каждого убийцу львов научат, как создавать свое оружие с нуля.Это
«real-life» программирование.В соревновательном программировании, вы начинаете с теми же ресурсами (складной нож), только у вас есть 2 минуты, чтобы убить льва.
Будучи новичком, вы уставитесь на льва и ничего не сможете сделать.
Вскоре вы узнаёте, что если убить белку, то судья может подумать, что это был лев, и вы окажетесь молодцом.
Более опытный программист просто продолжит колоть льва и надеяться, что тот умрёт вовремя. Затем вы узнаёте, что на теле льва есть определённые места, устойчивые к повреждениям. Вы научитесь не тратить свое время на эти места. Но если таких точек не видно, то вы становитесь действительно хорошим убийцей белок.
И вообще, чтобы быть отличным соревновательным программистом, вы должны быть в состоянии делать две вещи.
Во-первых , вы должны научиться находить уязвимое место у льва и убивать его одним быстрым ударом.
Во-вторых , вы должны научиться работать ножом так хорошо, чтобы вырезать острую палку за 1 минуту и провести следующую минуту, закалывая льва до смерти.Но у вас
никогда-никогда не будет достаточно времени на изготовление взрывчатки, чтобы избавиться ото льва.Anthony Moh, Over-generalizer
Свое мнение по теме можно высказать в комментариях, там же принимаются замечания по переводу. От себя могу сказать, что я вполне согласен с приведённым мнением, иначе вряд ли бы оно попало ко мне в блог.
В общем, я загорелся идеей переделать свой блог на статическую генерацию. И в связи с этим посмотрел несколько кандидатур: Jekyll, DocPad, Hugo и Hakyll. У каждой из систем свои достоинства и недостатки. Вообще, статические генераторы сайтов — это благодатная тема для обсуждения: вариантов множество и каждый день появляются новые. Если у вас есть опыт работы с
Jekyll — практически стандарт
Hugo — молодой движок на Go. Работает очень быстро. По заявлению разработчиков, время генерации одной страницы не должно превышать
DocPad — очень гибкий вариант, написанный на JavaScript. Для DocPad существует множество плагинов под самые различные нужды. Но в этом генераторе мне не понравилось соглашение по именованию файлов. Например, в 2013-09-10-something.html.md
расширение означает, что файл нужно будет преобразовать из markdown в html, как будто нельзя это указать в конфигурации.
И, наконец, Hakyll. Это скорее не отдельное приложение, а библиотека для создания статических генераторов. Его конфигурация представляет собой программу на языке Haskell, а потому бинарник должен пересобираться после каждого изменения. Зато такой способ даёт подлинную гибкость. Даже если
Надеюсь, пройдет совсем немного времени и мы увидим обновлённый блог, работающий ещё быстрее. Наблюдать за процессом можно на GitHub.
Иногда, когда пишешь приложение на 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). Теперь в консоли вы увидите все события, которые генерирует этот класс.
Если что-то непонятно, можно спросить в комментариях.
Идея, на самом деле, витала в воздухе. Уже не раз для хранения данных с неопределенной структурой приходилось использовать единственное поле, в которое эти данные помещались в сериализованном виде. Оставалось сделать один шаг: убрать все остальные поля. Нет ничего проще. Засунули все кроме первичного ключа в то же самое поле — и готово. В таком варианте остается вопрос с поиском, ведь потребность в индексах пока никто не отменял. Для этой цели можно использовать вспомогательные таблицы 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, знают про директиву ngController. В нее передается функция, описывающая поведение блока с директивой. И тут начинается магия! Если наша функция выглядит так:
SomeController = function ($scope) {...};
то она будет вызвана с одним параметром — scope, связанным с контроллером. А если, она выглядит, например, так:
SomeController = function ($http, $location, $scope) {...};
то передаваемых параметров станет внезапно три: два системных сервиса ($http и $location) и тот же самый scope.
Так как же фреймворк определяет, какие параметры нужны для вызова контроллера? Эта магия называется Function.toString()
. Метод toString()
у функции возвращает ее текст, а дальше дело техники: /^function\s*[^\(]*\(\s*([^\)]*)\)/m
. Получили имена параметров, разобрали, подставили. Вот такой нетривиальный подход.
Детали можно посмотреть в исходниках.