Пишу свои мысли о web-разработке и о жизни. Работаю CTO в «Фениксе» — разработка сайтов для застройщиков.
Связаться со мной можно по почте viktor@koreysha.ru

Later Ctrl + ↑

Книги о самых посещаемых сайтах в рунете

На Новый год мне подарили две книги: Яндекс.Книга и Код Дурова. До того, как я их открыл и прочитал для меня между ними было много общего. Сегодня будет экспериментальный пост-рецензия.

Яндекс.Книга

В каждом, самом незначительном, аспекте книги, от обложки до верстки, от структуры повествования до построения фраз чувствуется, что автор проникся особым духом компании Яндекс. Книга рассказывает о том, что наш поисковик №1 совсем не калька с Гугла, и заставляет поверить, что где-то на постсоветском пространстве остались еще светлые головы.
После прочтения я для себя вынес, что

  1. У прорывных проектов нет простых времен. Каждый этап развития это битва за выживание.
  2. Возможно делать продукты для людей и при этом зарабатывать деньги. До этого меня периодически одолевали сомнения — будет ли в нашей стране жить бизнес, в котором не надо будет каждый день идти против себя и считать своих клиентов биомассой.
  3. Кадры решают все. В дальней перспективе сильная команда с единым «вектором развития» важнее, чем деньги, связи, клиенты и все остальное.

Периодически в книге проскакивают решения, принятые Аркадием Воложем вопреки внешним обстоятельствам. Или такие на которых настоял Илья Сегалович, хотя на момент принятия они совсем не казались очевидными. Но в отличает от «Кода Дурова», читатель четко понимает, что у основателей Яндекса была своя философия и в её рамках все закономерно.

Стоит прочесть всем, кто ведет бизнес в России; всем, кто хоть отдаленно связан с IT; всем, кто управляет хотя бы маленькой командой; всем, у кого есть конкуренты; всем кому интересно, что у нас все еще есть чем удивить запад.
Не стоит читать только если вы не верите в людей, в страну, в идеи и ненавидите все это.

Код Дурова

Прежде, чем высказать свое мнение об этой книге оговорюсь, что я знаком с действиями Павла Дурова только по ней и редким отголоскам СМИ, которые до меня долетали. По этому все, что я буду о нем говорить относится только к персонажу книги, но никак не к реальному человеку.
Книга о том, как самовлюбленный мажор, который верил в свое величие и успех со школьной скамьи, без особых усилий и со скромными познаниями в программировании строит виртуальную империю. При этом у нег нет сильных компаньонов — все они оказываются мелочными, меркантильными и недальновидными. У него нет сильной команды — единственный программист о котором книга отзывается хорошо бежал из компании «вконтакте» при первой же возможности.
Автор называет основателя соцсети не иначе, как «тотем». Реже «архитектор». Все решения, которые «тотем» принимает приходят к нему свыше и никак не согласуются с реальностью. При этом, главный герой умудряется просто так без веских причин и без нужны в инвестициях продать большую долю Мильнеру, что в итоге приводит к тому, что компанию у него планомерно отжимают. Сам же Павел ведет себя, как истеричка, то выкладывая фото с «факом» после деловых переговоров, то намеренно провоцируя государство. После последнего он, кстати, выходит сухим из воды, просто не открыв дверь ОМОНУ.
Прочитав эту книгу тебе кажется, что:

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

Стоит прочесть тем, кто в восторге от «Вконтакте» и считает его скорее божественным провидением, чем земным созданием.
Не стоит читать если вы верите в здравый смысл в бизнесе.

Роутер, как компонент веб-системы. Часть 1.

Я продолжаю разбирать разные компоненты CMS. Предыдущие заметки по теме:

Любая страница сайта доступна по какому-то адресу (URL). Бывает, конечно, что у одной и то же страницы несколько адресов. Или наоборот, при какой-то динамической погрузке контента, в итоге пользователь по одному и тому же адресу увидит разные страницы (Что является грубой ошибкой, но ою этом как-нибудь потом). Но в целом какое-то соответствие адреса и страницы есть всегда.

К радости начинающих и ленивых разработчиков, это соответствие уже работает на стороне web-сервера. Сначала, он с помощью механизма Виртуальных Хостов определяет корневую директорию сайта и сам ищет в ней фаил index, который и становится главной страницей. Потом, каждой папке dir ставит в соответствие адрес mysite.ru/dir/. Для простых сайтов без сложной внутренней архитектуры этого вполне достаточно.

Что же не так?

Но при построении CMS возникает ряд сложностей с такой системой:

  1. Хочется из административной панели управлять URL-ами. А это значит, надо дать возможность оттуда создавать и удалять папки. Это не безопасно давать администратору сайта такие серьезные права на сервере. С ними он может снести весь сайт. А право управления URL фактически приравняется к праву администратора сервера.
  2. Перенос кода из одних папок в другие сильно осложнит разработчикам жизнь. Такая неразбериха противоречит идеям контроля версий кода. Кроме того, усложняет задание относительных путей внутри системы.
  3. Код разбросанный по разным папкам по принципу отношения к разделам, прямо скажем, очень плохое архитектурное решение. Нам важно минимизировать дублирование кода и упростить разработчикам поиск места «где считается вот-такая-вот циферка». И та и другая задача решены в этом случае крайне плохо.
  4. URL должен быть удобен для пользователя и понятен поисковым роботам, а внутренняя система директорий должна быть удобна и понятна разработчикам. Нет никакого смысла усложнять жизнь одним, в угоду других. Этот пункт частично пересекается с предыдущими, но думаю, что его стоит выделить.

Все эти сложности и, возможно, еще какие-то заставили разработчиков искать выход. Я наблюдал в разных системах несколько вариантов таких выходов. Принципиально можно выделить два подхода.

В каждой папке подключаем ядро

Оставляем маршрутизацию на совесть web сервера, но отказываемся от кода внутри каждого раздела. Все, что мы делаем — это запоминаем что это за раздел (например записываем его ID) и дальше подключаем «ядро системы», которое уже обрабатывает запрос, готовит контент и т.д.
В этом случае внутри папки about будет примерно такой код:

$section = ‘22’;
include(‘/includes/core.php’);

А вся остальная система уже разворачивается из core.php.

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

Минусы в том, что пользователь все-же из административной панели управляет созданием и удалением папок. Это может привести к трудноуловимым ошибкам. Например, если администратор сайта создаст раздел lib, а у нас есть такая папка и она содержит важные для нас библиотеки, то либо он её удалит и прекратит работать вообще все, либо не сможет создать раздел и опечалится.

Единая точка входа

Более распространенный в крупных системах вариант — это единая точка входа. Тут основная идея простая. Что бы не запросил пользователь мы должны всегда отправить его в один и тот же фаил, где уже разобрать его запрос и решить какой контент стоит отдать. Обычно при таком подходе вариант по умолчанию все равно остается и помогает подключать скрипты картинки и т.д. Но для основных адресов сайта паки не создаются. Вместо этого мы так настраиваем наш web-сервер, что бы при невозможности найти папку мы всех отправляли в единый фаил. А в нем уже решаем валидный это адрес для нашей системы или надо отдать какую-нибудь ошибку.
Вот пример простого .htaccess для такого подхода:

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*$ /core.php [NC,L]

Тут написано, что если ни фаил ни дириктория не найдены, то отправлять все в core.php.

Главный плюс такого подхода — бОльшая гибкость. Ну а минус — сложности при переносе на дешевые хостинги.
Отдельно хочу отметить, что этот подход очень хорошо сделан в Yii фраемворке. Все файлы, которые нужно находить «встроенной» навигацией находятся в папке public, а все «внутренности» в отдельной папке protected. Такое распредление позволяет достаточно безопасно настроить права доступа.

#После точки входа
В обоих подходах всегда есть общая точка входа. И у же в ней идет формирование того, что мы отдадим пользователю. Как правило эта точка входа построена в два этапа. В первом этапе подключаются и инициализируются срикпты, которые должны работать на сайте всегда, не зависимо от того, куда хотел попасть пользователь. Это, например, подключение к базе данных.
А второй этап, как правило, зависит от того, что запросил пользователь. Конечно, можно прописать в ядре какой-то гигантский оператор switch и при добавлении каждого нового функционала дописывать к нему опции. Но это подход человека, который не слышал об архитектуре приложении. Более же правильный путь — создать набор модулей. И по надобности подключать тот или иной модуль. Именно так устроены большинство CMS и фраемворков.
В таком случае нам понадобится блок в коде, который принимает запрос и решает какой или какие модули нужно подключить. Именно этот блок и называют Роутером или по-русски Маршрутизатором.

Уф. Большое получилось вступление. Пожалуй, остановлюсь тут и продолжу во второй части.

Почему на ноль на самом деле нельзя делить

На днях посмотрел ролик Почему на ноль делить нельзя. Тезисно логика автора такая:

  1. Чем меньше делитель, чем больше результат.
  2. Ноль минимальный из возможных делителей.
  3. Результат — самое большое число.
  4. Самое большое число — бесконечность.
  5. Бесконечность — не число.
  6. На ноль делить нельзя по тому, что в результате мы получим не число, хотя планировали получить число.

Если бы мне задали этот вопрос в 10ом классе, я, наверное, так же бы ответил. Но я бы не стал снимать по этому поводу видеоролик и позиционировать себя, как эксперт. Не стал бы кричать «Лож» и сам при этом врать зрителям в лицо.

При чем тут программирование?

Но самое обидное, что так думает не только автор ролика. Но и, например, создатели джаваскрипта. Попробуйте написать alert(1/0); Мы получим: Infinity . Давайте разберемся, что тут не так.

Для начала разберемся с Infinity. В джаваскрипте есть определение и оно очень похоже на определение бесконечности автором ролика. Это некое число, которое больше, чем любое число. Поскольку компьютеры под каждую переменную вынуждены отводить память у этого числа даже есть конкретное значение. Оно больше, чем любое другое число, то есть Number.MAX_VALUE + 1 или 1.7976931348623157e+308 + 1. Нюанс заключается в том, что компилятор не даст нам прибавить к этому числу единицу (просто оставит число таким же) или вычесть единицу из Infinity (опять же останется «бесконечность»). Из-за это особенности авторы языка притворяются, что это действительно бесконечность, а не «то, что вы подумали».
С какой-то версии, правда, ввели еще одну особенность — Infinity>Infinity это true. Так как по логике авторов Infinity — число, которое больше любого числа. Справа — число. Слева то, что всегда больше числа. Понятно. что результат TRUE.

Что делать?

Какой же ответ должен быть с точки зрения математики на пример 1/0? Конечно NaN! NaN — аббревиатура, полная версия это Not a Number, то есть «Не Число». Значение NaN не равно никакому другому числу, включая само NaN. Очевидно, что именно такое «не число» мы и получаем при попытке делить на ноль, а совсем никакую не бесконечность.

В математике есть такой метод, если решение сразу найти не удается, попробуй близкую задачу, которую решить гораздо проще. А потом учти разницу. Например, если меня попросят разделить 100 на 17, то я не смогу того сделать сразу. Мне надо будет сначала решить похожую задачу — разделить 100 на 20. Получится 5. А дальше «учесть ошибку». Ошибка тут это по 3 с каждого вхождения 17 в 100. 3*5 = 15. Итого 100/17 = 5 целых и 15/17. Надеюсь, я смог пояснить метод.

Тут так же. Попробуем взять 1 и поделить на 1. Получится, очевидно 1. Теперь поделим на 0.5. Будет 2. И таким образом мы покажем, что чем меньше число на которое делим, тем больше результат. Тут легко сказать «ну значит ответ бесконечность» и успокоится. Но надо вспомнить, что к нулю можно «подходить» с разных сторон. Если попробовать идти от отрицательных чисел, то будет: 1/(-1) = -1, 1/(-0.5) = -2 .... И так мы получим минус бесконечность. Это можно проиллюстрировать графиком.

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

Очевидно, что в такой ситуации мы не можем подобрать такое число, которое хоть как-то близко к решению. Ведь чем ближе число к «решению справа», тем дальше от «решения слева» и наоборот. Это самый, что ни на есть нот-э-намбер.

Вместо вывода

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

Новогодний снежок на сайт

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

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

В общем, не хочу больше затягивать, я за пол часика собрал наше «легкое» исполнение. Идею подсмотрел, но убрал все лишнее и сделал под себя. Хочу им поделится с читателями. Почитать будет полезно тем, кто только изучает джаваскрипт. А итог могут использовать на своих проектах все желающие. Так же буду рад критике коллег.

Результат

Процесс

Эта часть для тех, кто только изучает джаваскрипт. Всем остальным, думаю, будет не очень интересно.
Все, что нам понадобится в HTML, это canvas с идентефикатором snow. И я запустил скрипт по событию на BODY onload=“init()”. Это не лучшее решение, но оно за рамками самого «снега», так что оставлю его на совесть того, кто будет код использовать.
Весь наш код состоит из четырех функций.
function init() — тут мы делаем подготовку к запуску и запускаем. В этой функции должны быть все операции, которые нужно произвести до основного кода.
function draw() — отвечает за отрисовку текущего состояния снега.
function update() — отвечает за установку нового состояния. Оно будет отрисовано на следующем шаге.
function mousemove(event) — отвечает за отслеживание положения мыши. Эту функцию я добавил по тому, что захотелось какого-то интерактива. Снег не должен всегда падать только вниз, в жизни его сдувает ветром то туда, то сюда. Я решил, что за ветер будет отвечать курсор. Чем дальше он от центра экрана (горизонтално), тем сильнее ветер в эту сторону. Если интерактив не нужен, то от этой части можно отказаться.

Подробнее

Начну разбор с инициализации. Для начала я накидал что-то подобное:

function init() {
  //Canvas init
  var canvas = document.getElementById(‘snow’);

  //Canvas resize
  var W = window.innerWidth;
  var H = window.innerHeight;
  canvas.width = W;
  canvas.height = H;

  //Get context
  var ctx = canvas.getContext(‘2d’);
  ctx.strokeStyle = ‘white’;

  //Prepare array of particles
  var mp = 100;
  var particles = [];
  for (var i = 0; i < mp; i++) {
    particles.push({
      x: Math.random() * W,
      y: Math.random() * H,
      r: Math.random() * 3 + 1
    })
  }
}

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

В последнем блоке создаем массив, который будет отвечать за снежинки. Particles — массив снежинок. А каждая снежинка это объект, который «помнит» о своих координатах и диаметре. Для каждой снежинки задаем её начальное состояние: она должна быть где-то на нашем канвасе (случайным образом) и должна получить диаметр от 1 до 4 пикселей.

После этого переходим к отрисовке текущего состояния нашего снега.

function draw(W, H, particles, mp, ctx) {
  //Clearing
  ctx.clearRect(0, 0, W, H);

  //Set white whith opacity 0.8
  ctx.fillStyle = “rgba(255, 255, 255, 0.8)”;

  //Drowing
  ctx.beginPath();
  for (var i = 0; i < mp; i++) {
    var p = particles[i];
    ctx.moveTo(p.x, p.y);
    ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
  }
  ctx.fill();
}

Тут то же все просто. Чистим поле и заново рисуем каждую снежинку на её координатах и с её диаметром. Для новичков хочу обратить нимание, что мы сначала «накидываем» все в контакст. И только один раз отрисовываем с помощью ctx.fill();

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

function update(W, H, particles, mp, ctx) {
  for (var i = 0; i < mp; i++) {
    var p = particles[i];
    p.y += 1 + p.r/2;

    if (p.y > H) {
      particles[i] = {
        x: Math.random() * W,
        y: -10,
        r: p.r
      };
    }
  }
}

Скорость падения зависит от радиуса. Можно добавить какой-нибудь дополнительный случайный параметр, который вместо радиуса будет влиять на скорость. Но мне показалось, что и так не плохо. Если снежинка вылетела за поле вниз, то сразу перемещаем её в выше верха и смещаем случайно по оси X. Ничего хитрого.

Когда мы все это подготовили нам осталось запустить отрисовку по таймеру. Для этого добавляем в init:

setInterval(function() {
    draw(W, H, particles, mp, ctx);
  }, 50);

И после отрисовки сразу общитывать новое состояние. Для этого вызываем update в конце draw:

update(W, H, particles, mp, ctx);

Интерактивчик

Все. Простой снег готов. Но мне захотелось добавить интерактива. А то никакого профита, что налету снег обсчитываем. Добавляем функцию, которая отслеживает движения мыши и всгда записывает её положение. Для записи я расширил объект body, который точно есть у нашей веб-страницы. Добавляем в init:

document.body.myData = {
    x: 0,
    y: 0
  };
  document.onmousemove = mousemove;

Теперь по умолчанию мышка у нас в верхнем левом углу, но как только пользователь её сдвинет, мы обновим координаты.
Записывать при сдвиге мыши будем с помощью такой функции:

function mousemove(event) {
var mouse_x = mouse_y = 0;
if (document.attachEvent != null) {
mouse_x = window.event.clientX;
mouse_y = window.event.clientY;
} else if (!document.attachEvent && document.addEventListener) {
mouse_x = event.clientX;
mouse_y = event.clientY;
}
document.body.myData.x = mouse_x;
document.body.myData.y = mouse_y;
}

Отследить то мы отследили. Осталось добавить скорость вдоль горизонтальной оси Ox:

var speed_x = (document.body.myData.x – (W / 2)) / W;

Смотрим в какой половине мышь: в правой или левой. И как далеко она от центра. Чем дальше, тем «сильнее ветер».

И осталось добавить сдвиг по Ox:

p.x += speed_x * 10;

Вместо послесловия

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

Прошел месяц. Итоги.

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

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

Статистика

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

В среднем за этот месяц я выкладывал заметки 9 раз. 9 дней из 30 это ровно 30%. Притом, в эти дни по данным метрики у меня побывало 34% посетителей. Тенденция за 30 процентов времени 34 процента посетителей далеко не очевидно говорит о увеличении интереса к блогу в дни выхода заметок. А потом я вспомнил, что в эти дни сам несколько раз заходил (что бы написать материал и посмотреть, как он выглядит). Вычел себя и получилось 28 процентов визитов за 30 процентов времени. Это показалось мне забавным.
Всего я получил два комментария от одного и того же человека. Это говорит о том, что темы, которые я выбираю мало кого задевают. Постараюсь хоть иногда делать что-то более злободневное.

Немного лирики

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

На вопрос «Зачем?» я смог для себя ответить. Пока я пишу какой-то материал, обязательно сморю что-то по теме. Мысли других людей по какому-либо поводу. Я считаю, что это еще один вектор развития. Пока ты пишешь код, ты не понимаешь растут твои навыки или ты не успеваешь за бегущим вниз эскалатором. Кажется, что ты используешь одни и те же известные приемы и нет никакого способа попробовать что-то принципиально новое — на домашние проекты банально не хватает времени (мелкие делать не хочется, нужен масштаб), а в рабочих проектах велик шанс не уложиться, не успеть и не заработать, а потерять.
Есть у меня и еще один ответ. С тех пор, как небезызвестное дизайн бюро объявило о создании и первом наборе в свою школу стажеров, я мечтал туда попасть. Многие дисциплины мне крайне интересны. Проблема была в том, что я ни разу не дизайнер. Мой первый и единственный опыт дизайна оказался не особо удачным и я пока не готов продолжать попытки.
Но через год примерно появилась робкая надежда. Школа не только для дизайнеров, но и для редакторов. Редактор/писатель/журналист из меня так себе, но я, по крайней мере, вижу в себе силы научится. Начать решил с преодоления боязни письма, чем в данный момент и занимаюсь.
Следующий шаг — научится грамотности. С этим, боюсь, будет куда сложнее.

Earlier Ctrl + ↓