Пишу свои мысли о web-разработке и о жизни. Работаю в веб-студии Феникс — phoenix-cg.ru Связаться со мной можно по почте viktor@koreysha.ru
Ctrl + ↑ Later

Как я открыл для себя миграции

Mar 13, 2016, 12:12

Как правило, перенос сайта с одного сервера на другой состоит из двух этапов: перенос файлов и базы данных. Когда мы говорим о разработке и поддержке серьезного проекта, обычно, мы имеем несколько серверов с разными версиями. Например сервер разработки (DEV), сервер тестирования (TEST) и «боевой» (PROD). А иногда, по копии сайта для каждого разработчика.

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

Решение, как все гениальное, кажется очевидным, когда ты его знаешь. Как избавится от двух этапов переноса? Сделать так, что бы один этап автоматически «подтягивал» второй. Например, хранить все изменения для БД в файловой системе. Благо, SQL нам в этом помогает очень сильно. Такие изменения назвали миграциями.

Я впервые познакомился с механизмом миграций в CMS yupe, на базе фраемворка Yii. По этому все, что напишу далее относится к этой конкретной реализации, хотя идея, в целом, остается неизменной везде.

Итак, если мы хотим внести изменения в базу, то вместо того, что бы лезть туда руками, мы создаем скрипт, который знает что нужно делать для применения изменений и для их отмены. Например, для этого создается класс с двумя методами up(), который создает новую таблицу, и down(), который её удаляет. Все остальное, что ему нужно он наследует от системного класса.

Далее, в системе есть способ (специальный скрипт), который для применения миграции создает объект этого класса и выполняет up, а для отмены down. Разумеется, в базе нам так же нужно хранить информацию о том, какие миграции к ней уже применились, а какие еще нет. Так же важен механизм очередности миграций, который так же зашит где-то в системе. Таким образом мы:

  1. Всегда уверены в актуальности бд. Всегда точно знаем, что к ней уже применилось, а что еще нет.
  2. Храним всю историю в системе контроля версий вместе со всей остальной историей разработки.
  3. Можем в любой момент откатить не только состояние кода, но и базы данных к любому этапу.
  4. Легко сливаем изменения от нескольких разработчиков. Теоретически, могут возникнуть конфликты, но на практике ни разу у меня не возникали.

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

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

Гиковский сайт

Mar 3, 2016, 14:48

В блоге «Записки программиста» нашел ссылку на суперминималистичный сайт Андрея Прокопюка. Решил пофантазировать на тему, как можно сделать сайт еще более гиковским?

Представляю вашему вниманию мою первую попытку. Буду рад отзывам, замечаниям и предложениям.

Как мы вводили git

Jan 15, 2016, 22:10

Git — это одна из популярных систем контроля версий. Код — это, прежде всего, текст. Такой текст, который правят многократно и по чуть-чуть в разных местах. Хранить только последнюю версию кода не дальновидно, по тому, что часто какие-то правки приходится отменять, а в каких-то случаях надо посмотреть «как оно работало раньше». Хранить каждую новую версию кода, то есть копировать всю директорию, допустим раз в день, не удобно по двум причинам: во-первых, занимает много места, а во-вторых, не дает никакого понимания о том, что именно изменилось.
Умные программисты придумали решение этих проблем. Оно заключается в том, что бы хранить какую-то базовую версию, а после сохранять только маску изменений. Например, мы храним 1000 строк кода и после изменений запоминаем, что поменялись 387 строка и 425.
Такое решение дало еще один неожиданный плюс. Оно позволило работать над одним и тем же кодом разным людям одновременно. Первый программист поменял вторую, третью и четвертую строку, а второй — девятую и десятую. Система сама поняла, что может применить к начальному коду и те изменения и эти. И только, если возникнет конфликт, придется разруливать людям.

Америка

Впрочем, если вы так или иначе связаны с разработкой программного обеспечения, скорее всего, Америку я вам не открыл. Во всем мире различные системы контроля версий — неотъемлемый атрибут любого программиста. Читая профессиональные форумы, блоги известных web-разработчиков и доклады с различных конференций сложно себе представить, что кто-то может жить без git-а или svn-а. Однако, в наших реалиях куча небольших веб студий и одиночек-фрилансеров работают «по-старинке». Так получилось, что и я на первых своих местах работы с системами контроля версий познакомился только заочно. До сих пор стыдно признаться, что несколько лет я писал код без таких систем.
Впрочем, я был такой не один. И так получилось, что у нас собралась команда из четырех человек, где никто полноценно с контролем версий не работал. У меня был до этого опыт, где все настроили до меня и оставалось только коммитить, то есть записывать изменения которые я внес. Еще у двоих членов команды был подобный опыт. Однако никто из нас не представлял, как полностью должна работать система от компьютера программиста до «боевого сервера».

Как ни странно, гугление не могло ответить на те вопросы, которые возникали у меня в первую очередь. Например гугл на вопрос «Как смержить ветки git» дает около 700 результатов и вся первая страница по делу. А на запрос «git локально или на сервере» дает 275 тыс ответов и я не смог найти что-то в тему.

Наши правила

Многое мне было непонятно. Но в итоге чтения кучи статей и советов я принял ряд решений.

  1. Мы отказались от гита локально на каждом компьютере разработчика. Вместо этого, мы используем IDE и копию проекта на нашем сервере. У каждого разработчика есть своя локальная копия и своя удаленная копия. Уже на сервере стоит гит и туда надо зайти что бы провести с ним какие-то операции. Такое решение я принял по целому ряду причин. Основная причина в том, что мы взяли курс на проекты выше среднего по сложности и настраивать у каждого разработчика веб-сервер с нужными пакетами в условиях разных ОС и различной удаленности друг от друга сложная задача. А внедрить все это надо было без ущерба для производства.
  2. Никаких встроенных в IDE систем поддержки git и других «улучшителей вкуса» мы решили не использовать. Во-первых, в нативных командах из консоли нет ничего, чему нельзя научить за пару дней. А во-вторых, меня однажды такая система поддержки сильно подвела — вывела совсем не то, что произошло на самом деле.
  3. Мы ввели правило одна задача — одна ветка. Коммитов в нее может быть много, но чаще 1-2. Сливаем изменения только после завершения задачи.
  4. Все, что не касается напрямую нашего кода мы стараемся исключить из системы контроля версий. С этой задачей до сих пор справляемся хуже всего.
  5. Ввели правило «сервера для тестирования». Каждый раз после сливания изменений от разных разработчиков сайт поступает на тестирование и только потом выходит в продакшн, как бы не торопил заказчик.
  6. Мы стали использовать git в связке с Bitbucket. Система контроля версий без удаленного репозитория и в половину не так хороша. Но это, наверное, тема для отдельной заметки.

И все пошло, как по маслу?

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

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

А какую систему контроля версий используйте вы? И какие сложности были с её внедрением?

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

Jan 8, 2016, 20:56

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

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

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

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

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

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

Код Дурова

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

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

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

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

Jan 5, 2016, 18:48

Я продолжаю разбирать разные компоненты 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 и фраемворков.
В таком случае нам понадобится блок в коде, который принимает запрос и решает какой или какие модули нужно подключить. Именно этот блок и называют Роутером или по-русски Маршрутизатором.

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

Ctrl + ↓ Earlier