<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0">

<channel>

<title>Блог Корейши Виктора, posts tagged: web</title>
<link>https://koreysha.ru/?go=tags/web/</link>
<description></description>
<generator>E2 (v3335; Aegea)</generator>

<item>
<title>Ищу начинающего дизайнера</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/ischu-nachinayuschego-dizaynera/</guid>
<link>https://koreysha.ru/?go=all/ischu-nachinayuschego-dizaynera/</link>
<comments>https://koreysha.ru/?go=all/ischu-nachinayuschego-dizaynera/</comments>
<description>
&lt;p&gt;Друзья, нам в &lt;a href="https://phoenix-cg.ru/"&gt;студии «Феникс»&lt;/a&gt; не хватает рабочих рук. Ищем начинающего дизайнера в Екатеринбурге.&lt;/p&gt;
&lt;h2&gt;Кто мы такие&lt;/h2&gt;
&lt;p&gt;Мы делаем сайты, а так же ЦРМ, ЕРПи и другие системы автоматизации процессов на веб-технологиях. Работаем в офисе в центре Екатеринбурга. Наши клиенты — крупные застройщики, интернет-магазины и все, для кого сайт может стать «верхушкой айсберга» от которого мы будет растить, невидимые во вне, системы автоматизации внутрь компании.&lt;br /&gt;
Мы стараемся улучшать все наши проекты не только из наших мыслей и мыслей клиента, но и основываясь на статистике.&lt;/p&gt;
&lt;h2&gt;Кто нам нужен&lt;/h2&gt;
&lt;p&gt;Мы ищем человека в компанию, который будет ежедневно трудится с нами над большими и сложными проектами. Мы не научились пока работать с удаленными сотрудниками, поэтому ищем человека в офис. Мы готовы взять новичка и обучить его всему, что сами знаем, но можем рассмотреть и уже состоявшегося профессионала.&lt;/p&gt;
&lt;h3&gt;Минимальные системные требования:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Умение работать хотя бы с одним графическим редактором. Нам будет проще, если это Фотошоп.&lt;/li&gt;
&lt;li&gt;Иметь в портфолио один-два веб-проекта, о которых вы сможете рассказать.&lt;/li&gt;
&lt;li&gt;Желание и возможность работать.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Если вы подходите под это описание, то пишите мне&lt;br /&gt;
на почту &lt;a href="mailto:koreysha@phoenix-cg.ru"&gt;koreysha@phoenix-cg.ru&lt;/a&gt;&lt;br /&gt;
или в Телеграм &lt;a href="https://telegram.me/koreysha"&gt;@koreysha&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Буду очень благодарен, если кто-то посоветует нашу вакансию друзьям или знакомым.&lt;/p&gt;
</description>
<pubDate>Thu, 30 Mar 2017 11:52:33 +0500</pubDate>
</item>

<item>
<title>Сколько человек делают сайт: продолжение</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/skolko-chelovek-delayut-sayt-prodolzhenie/</guid>
<link>https://koreysha.ru/?go=all/skolko-chelovek-delayut-sayt-prodolzhenie/</link>
<comments>https://koreysha.ru/?go=all/skolko-chelovek-delayut-sayt-prodolzhenie/</comments>
<description>
&lt;p&gt;Писал как-то полу-шуточную заметку о том &lt;a href="http://koreysha.ru/all/skolko-chelovek-delayut-odin-sayt/"&gt;сколько программистов оптимально для проекта&lt;/a&gt;. Оказывается не меня одного волнует эта тема. Вот вариант ответа на этот вопрос от commitstrip.com&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/1466261845122291044.jpg" width="648" height="636" alt="" /&gt;
&lt;/div&gt;
</description>
<pubDate>Mon, 04 Jul 2016 14:27:40 +0500</pubDate>
</item>

<item>
<title>Почему я не люблю Битрикс</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/pochemu-ya-ne-lyublyu-bitriks/</guid>
<link>https://koreysha.ru/?go=all/pochemu-ya-ne-lyublyu-bitriks/</link>
<comments>https://koreysha.ru/?go=all/pochemu-ya-ne-lyublyu-bitriks/</comments>
<description>
&lt;p&gt;Почему-то существует огромный пласт клиентов, максимально лояльных к Битриксу. Настолько, что они готовы переплатить только, что бы их сайт был на нем сделан. Так получилось, что я ни разу не писал сайты на Битриксе с 0, но мне часто приходилось их поддерживать и развивать.&lt;br /&gt;
Не знаю, дело в моем везении или в чем-то другом, но каждый раз в таком проекте код максимально плохой. Почему-то, всегда логика запихана в представление и наоборот. Так написано в официальный гайдах Битрикса?&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/nobitrix.jpg.png" width="560" height="536" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;А вот сегодня, например, была банальная задача — подправить верстку. Вроде, ничего экстраординарного. Но где находится эта верстка в проекте найти не удавалось никак. В итоге путь получился примерно такой:&lt;/p&gt;
&lt;p&gt;/bitrix/templates/template.main/components/ma/catalog/template1/ma/catalog.element/.default/&lt;/p&gt;
&lt;p&gt;И в этой папке лежал и HTML и CSS и, даже, картинки. «Джентельменский набор» для отображения одного из блоков на странице. Все остальная верстка лежала вообще не там. Но самая жесть, присмотритесь — скрытая диррректория. По умолчанию в Linux, если название начинается с точки, то фаил или папке не отображаются. И, разумеется, &lt;a href="http://yiiframework.ru/forum/viewtopic.php?t=2942"&gt;не синхронизируются с IDE&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Что заставило разработчиков сделать именно так? Не надо так.&lt;/p&gt;
</description>
<pubDate>Fri, 20 May 2016 18:04:32 +0500</pubDate>
</item>

<item>
<title>«Лендинг» — это новый «сайт-визитка»</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/lending-eto-novy-sayt-vizitka/</guid>
<link>https://koreysha.ru/?go=all/lending-eto-novy-sayt-vizitka/</link>
<comments>https://koreysha.ru/?go=all/lending-eto-novy-sayt-vizitka/</comments>
<description>
&lt;p&gt;Не знаю, кто и когда придумал термин «сайт-визитка». Но думаю, что он был рожден вместе с понятиями «интернет-портал» и «корпоративный сайт». В чем беда всех этих терминов? Да в том, что никто не знает, что все это значит. Ну, точнее, многие думают, что понимают. Но, проблема в том, что понимают они совершенно разные вещи.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/site-vizit-to-lp.jpg.png" width="1755" height="488" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Почему же эти понятия вообще появились? По тому, что они помогают превратить услугу «разработка сайта» в товар «сайт-визитка». Но это &lt;a href="http://russian.joelonsoftware.com/Articles/LeakyAbstractions.html"&gt;дырявая абстракция&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Товары легче продавать по тому, что они, с некоторыми допущениями, одинаковые. Вся яблоки одного сорта и из одно партии похожи на вкус и примерно одинаковые по энергетической ценности. Все телевизоры с одинаковым артикулом имеют одни и те же характеристики. А если что-то пошло не так — червивое яблоко или сломанный телевизор, то их, как правило, можно поменять или починить. Машину можно взять на тест-драйв, а куртку померить перед покупкой.&lt;/p&gt;
&lt;p&gt;С услугами все не так. Ты не можешь знать результат заранее. Когда ты нанял садовника, что бы он фигурно подстриг кусты, то ты можешь получить, как «шары» так и «кубы». Если садовник опытный, то он обязательно уточнит заранее, что ты хочешь увидеть, но и с самым подробным ТЗ, результат все равно не определен, пока кусты не подстрижены. То же самое и с другими услугами. И чем сложнее услуга, тем больше переменных, которые влияют на результат. Очень сложно продавать то, чего еще не существует. Особенно сложно, когда заказчик не представляет себе конечный результат.&lt;/p&gt;
&lt;p&gt;Постоянно работать вместе с клиентом для получения хорошего результата тяжело. А вот продать ему «сайт-визитку» просто, особенно, если есть пример. По этому, многие разработчики пошли по пути наименьшего сопротивления. Что плохого, если клиент получит понятный результат за понятные деньги? Если все стороны понимают это и согласны, то ничего. Только дело в том, что я не встречал клиентов, которым зачем-то нужен именно такой сайт. Как правило, все же нужен какой-то результат для бизнеса, а вот его такая концепция не учитывает.&lt;/p&gt;
&lt;p&gt;Вот и дырка в абстракции. Когда человек приходит за телевизором, то знает, что хочет каждый вечер смотреть какой-нибудь сериал. И он может подобрать себе то, что нужно или спросить совета у консультанта. А потом может пойти в Яндекс.маркет  и сравнить цены на телевизоры с такими параметрами. Но сайт — результат долгой совместной работы. Нельзя заказать «сайт-визитку» в двух разных студиях и получить одинаковый результат. Точнее можно, если этот результат нулевой.&lt;/p&gt;
&lt;p&gt;Но это еще пол беды. Понятие «визитки» быстро приобрело для клиентов и совсем другое значение. А именно — самое дешевое «пакетное предложение». И расцвет такого понимания пришелся, думаю, на кризис 2008-2009. И до сих пор, когда переговоры начинаются с фразы «нам нужен сайт-визитка», это следует понимать, как «мы не готовы тратить деньги на сайт». К сожалению, часто это значит, что на этом месте переговоры можно и заканчивать.&lt;/p&gt;
&lt;p&gt;А что-же лендинги? Это понятие уже родилось мертвым. И так же имело своей целью &lt;a href="http://tema.livejournal.com/1987841.html"&gt;облегчить продажи&lt;/a&gt;. А, говоря прямо, пропихнуть халтурный конвеер штамповки одинаковых html страниц, как разработку сайта.&lt;/p&gt;
&lt;p&gt;И вот недавно услышал от клиента, что им нужен лендинг с двадцатью страницами. Где будет каталог, контакты, а еще страница «о компании». Как говорил герой Мета Деймона, Локи в замечательном фильме Догма, «речи, знакомые до боли».&lt;/p&gt;
</description>
<pubDate>Fri, 29 Apr 2016 20:50:50 +0500</pubDate>
</item>

<item>
<title>Как найти копирайтера?</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/kak-nayti-kopiraytera/</guid>
<link>https://koreysha.ru/?go=all/kak-nayti-kopiraytera/</link>
<comments>https://koreysha.ru/?go=all/kak-nayti-kopiraytera/</comments>
<description>
&lt;p&gt;Первый раз столкнулся с тем, что клиенту не все равно, какие тексты на его сайте. Вроде бы это должно обрадовать. Но к кому пришел клиент с вопросом, как правильно наполнить сайт? Это, конечно, разработчик. То есть к нам.&lt;/p&gt;
&lt;p&gt;Сразу оговорюсь, что текстов нужно много (о каждом товаре) и недостаточно просто перечислить характеристики. Задача — ответить на вопросы покупателей, помочь им выбрать то, что им нужно.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/fountain-pen-442066_1920.jpg" width="1920" height="925" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Первое, что мы сделали в этой ситуации, предложили собрать информацию о товарах от производителей с сайтов, бумажных каталогов и прайс-листов. Добавить к этому информацию о самих производителях, о брендах и материалах, которая есть в открытом доступе. Часть удалось осуществить в автоматическом режиме, но, в основном, конечно это был ручной труд. Дальше планировалось пойти на биржу копирайтеров, дать имеющийся материал о каждом товаре и группах товаров и получить на выходе текст, который будет помогать покупателю понять что тут к чему.&lt;/p&gt;
&lt;p&gt;Этого текста бы не было, если бы все пошло по плану. Мы пробовали писать подробное ТЗ. Пробовали давать более общую задачу, с надеждой, что профессионал найдет источники информации, которые ему нужны. Пробовали искать самых дорогих специалистов. И каждый раз получали от клиента недоуменный взгляд и немой (а иногда и не немой) вопрос «Что это за ерунда? Полное незнание предмета и аудитории. Такой текст выкладывать нельзя». В общем, заплатили за десяток текстов, которые ушли в ведро.&lt;/p&gt;
&lt;p&gt;Параллельно с этим, пытались помочь найти человека в штат. Сначала назвали вакансию “Копирайтер”, но не получили ни одного адекватного отзыва. Потом, пробовали найти «Маркетолога», по тому, что пришли к выводу, что такие люди должны смочь разобраться в рынке и понять, что волнует покупателей.&lt;/p&gt;
&lt;p&gt;Тогда я написал с просьбой о совете &lt;a href="http://skaplichniy.ru/"&gt;Сергею Капличному&lt;/a&gt;. Огромное ему спасибо —  в тот же день получил подробный ответ. Кроме прочего, в ответе присутствовал совет поискать нужного человека на &lt;a href="http://maximilyahov.ru/blog/all/hire/"&gt;бирже труда Максима Ильяхова&lt;/a&gt;. Всего там сейчас 25 комментариев. Из них 3 без прямых контактов. Примерно половина тех, кто написал, что не пишут технические тексты. Из оставшихся, я выбрал 6 человек и разослал письма.&lt;/p&gt;
&lt;p&gt;Я ждал чего угодно. Огромного ценника. Сообщении о том, что проект не интересен. Сообщения о высокой загрузке. Но никак не молчания. В итоге получил всего один(!) отклик от Романа Скрупника о том, что он не может сейчас взять новый проект.&lt;/p&gt;
&lt;p&gt;Друзья, откуда вы берете хорошие тексты на технические темы?&lt;/p&gt;
</description>
<pubDate>Sat, 09 Apr 2016 13:12:38 +0500</pubDate>
</item>

<item>
<title>Абстрактная фабрика и примеси в PHP (Часть 2)</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/bstraktnaya-fabrika-i-primesi-v-php-chast-2/</guid>
<link>https://koreysha.ru/?go=all/bstraktnaya-fabrika-i-primesi-v-php-chast-2/</link>
<comments>https://koreysha.ru/?go=all/bstraktnaya-fabrika-i-primesi-v-php-chast-2/</comments>
<description>
&lt;p&gt;&lt;a href="http://koreysha.ru/all/bstraktnaya-fabrika-i-primesi-v-php-chast-1/"&gt;Первая часть&lt;/a&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/sochinenie_dobro_i_zlo_2_1.jpg" width="1500" height="896" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Однако, вернемся к нашему случаю. Допустим тут в комнату входит начитанный разработчик (НР), смотрит на код и вспоминает, что по условиям игры все светлые умеют лечить, а все темные становятся невидимыми. Добавим соответствующие методы.&lt;/p&gt;
&lt;pre style="background: #0c1021; color: #f8f8f8;"&gt;&amp;lt;?php

&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Infantry&lt;/span&gt; {
    &lt;span style="color: #aeaeae;"&gt;//общие для всей пехоты методы&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Archer&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;SiegeWeapons&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodInfantry&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Infantry&lt;/span&gt; {
    &lt;span style="color: #aeaeae;"&gt;//Спецэфическая реализация для доброго пехотинца&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
    
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Treat&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodArcher&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Archer&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
    
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Treat&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodSiegeWeapons&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;SiegeWeapons&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;(); 
    
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Treat&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilInfantry&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Infantry&lt;/span&gt;{
    &lt;span style="color: #aeaeae;"&gt;//Спецэфическая реализация для злого пехотинца&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
    
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Invisible&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilArcher&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Archer&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
    
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Invisible&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilSiegeWeapons&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;SiegeWeapons&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
    
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Invisible&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodFactory&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Infantry
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodInfantry&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Archer
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodArcher&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; SiegeWeapons
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodSiegeWeapons&lt;/span&gt;();
    }
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilFactory&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Infantry
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilInfantry&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Archer
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilArcher&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; SiegeWeapons
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilSiegeWeapons&lt;/span&gt;();
    }
}
&lt;/pre&gt;
&lt;p&gt;Код стал не таким красивым по тому, что появились методы, которые приходится копировать. В php нет множественного наследования и приходится выбирать наследоваться белому лучнику от белых или от лучников. Мы априори выбрали второй вариант и теперь думаем, как сделать наш код красивее, а его поддержку удобнее. НР предлагает использовать примеси (trait), которые появились в php 5.4. Вынесем обшие методы в примесь.&lt;/p&gt;
&lt;pre style="background: #0c1021; color: #f8f8f8;"&gt;&amp;lt;?php

&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Infantry&lt;/span&gt; {
    &lt;span style="color: #aeaeae;"&gt;//общие для всей пехоты методы&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Archer&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;SiegeWeapons&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
}

&lt;span style="color: #d8fa3c;"&gt;trait&lt;/span&gt; &lt;span style="color: #d8fa3c;"&gt;Good&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Treat&lt;/span&gt;();
}

&lt;span style="color: #d8fa3c;"&gt;trait&lt;/span&gt; &lt;span style="color: #d8fa3c;"&gt;Evil&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Invisible&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodInfantry&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Infantry&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;use&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;Good&lt;/span&gt;;
    
    &lt;span style="color: #aeaeae;"&gt;//Спецэфическая реализация для доброго пехотинца&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodArcher&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Archer&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;use&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;Good&lt;/span&gt;;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodSiegeWeapons&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;SiegeWeapons&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;use&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;Good&lt;/span&gt;;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilInfantry&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Infantry&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;use&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;Evil&lt;/span&gt;;
    
    &lt;span style="color: #aeaeae;"&gt;//Спецэфическая реализация для злого пехотинца&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilArcher&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Archer&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;use&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;Evil&lt;/span&gt;;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilSiegeWeapons&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;SiegeWeapons&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;use&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;Evil&lt;/span&gt;;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodFactory&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Infantry
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodInfantry&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Archer
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodArcher&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; SiegeWeapons
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodSiegeWeapons&lt;/span&gt;();
    }
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilFactory&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Infantry
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilInfantry&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Archer
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilArcher&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; SiegeWeapons
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilSiegeWeapons&lt;/span&gt;();
    }
}
&lt;/pre&gt;
&lt;p&gt;Теперь, какой бы сложной не была реализация лечения и невидимости, нам придется написать еге всего один раз и править в едином месте. Про абстрактную фабрику и про примеси есть куча литературы, но я ни разу не видел их описание в одной статье. А тем временем, практически каждое использование этого паттерна приводит к необходимости введения общих методов и свойств для групп обьектов, которые мы разделили нашими фабриками.&lt;/p&gt;
&lt;p&gt;P.S. Мне очень хотелось бы услышать критику моего изложения общеизвестных вещей и моего варианта использования примесей от коллег. Я открыл для себя паттерны проектирования пару лет назад, но использовать их начал только сейчас.&lt;br /&gt;
И если будут у кого-то вопросы, то с радостью попробую ответить.&lt;/p&gt;
</description>
<pubDate>Tue, 22 Mar 2016 10:29:41 +0500</pubDate>
</item>

<item>
<title>Абстрактная фабрика и примеси в PHP (Часть 1)</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/bstraktnaya-fabrika-i-primesi-v-php-chast-1/</guid>
<link>https://koreysha.ru/?go=all/bstraktnaya-fabrika-i-primesi-v-php-chast-1/</link>
<comments>https://koreysha.ru/?go=all/bstraktnaya-fabrika-i-primesi-v-php-chast-1/</comments>
<description>
&lt;p&gt;Существует очень много статей о различных инструментах программирования и практиках их применения. Не бывает боевых проектов, которые реализуют единственный шаблон проектирования или используют единственный инструмент. В реальных условиях всегда приходится миксовать знания и опыт.&lt;/p&gt;
&lt;p&gt;Мне хотелось бы описать связь между различными практиками программирования, которые я встречал в своих проектах. Если опыт будет удачным, то попробую сделать цикл подобных постов.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/sochinenie_dobro_i_zlo_2.jpg" width="1500" height="896" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;#Джуниор-разработчик и игра&lt;br /&gt;
Допустим, мы хотим написать браузерную игру, в которой «добро» борется со «злом». Пусть у обеих сторон есть пехота, лучники и осадные орудия. Для начала посадим за IDE джуниора. Через некоторое время мы, скорее всего, увидим следуюшие классы:&lt;/p&gt;
&lt;pre style="background: #0c1021; color: #f8f8f8;"&gt;class GoodInfantry{}
class GoodArcher{}
class GoodSiegeWeapons{}

class EvilInfantry{}
class EvilArcher{}
class EvilSiegeWeapons{}
&lt;/pre&gt;
&lt;p&gt;#Опытный разработчик и абстрактная фабрика&lt;/p&gt;
&lt;p&gt;Придет опытный разработчик (ОР) и скажет, что это же класика для шаблона проектирования «абстрактная фабрика». Шаблоны проектирования разбирали уже тысячи раз на различных языках, но все же я хочу сделать статью самодостаточной и опишу еще разок. Если вы знаете «банду четырех», как свои пять пальцев, то перейдите к следующему подзаголовку.&lt;/p&gt;
&lt;p&gt;ОР знает, что «добрая» сторона обязательно будет иметь свои особенности, отличные от «злой». При этом так же понятно, что пехота с обоих сторон так же будет иметь нечто общее. Таким образом каждый юнит фактически должен унаследовать какие-то свойства от своей стороны, а какие-то от своего типа.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/-.png" width="403" height="613" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Для того чтобы система оставалась независимой от специфики той или иной стороны необходимо использовать общие интерфейсы для всех основных типов юнитов. Это означает, что необходимо использовать три абстрактных базовых класса для каждого типа воинов. Производные от них классы будут реализовывать специфику соответствующего типа воинов той или иной армии.&lt;/p&gt;
&lt;p&gt;Второй момент, который стоит учесть, связан с тем, что юнитов в игре будет много и создавать их будет не программист, а игрок. То есть программист не сможет просто прописать в коде нужное количество раз создание, допустим, пехотинца. Вместо этого он должен учесть создание пехотинца какой-то функцией. А, вспомнив, что мы находимся в концепции ООП, скорее методом какого-то более общего объекта. Допустим, что юнитов создает у нас «фабрика света» на «доброй» стороне и «фабрика тьмы» на «злой». Светлая фабрика будет выглядеть так:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/-_1.png" width="453" height="203" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Вспомним так же, что все пехотинцы будут наследовать класс Infantry. И подумаем о том, что фабрики, вероятно, будут иметь одинаковый набор методов, а значит хорошо бы им унаследовать единый абстрактный класс. Такой подход гарантирует нам, что ОР, создав абстрактные классы может идти курить и доверить написание реализации джуниору, ведь любая ошибка в реализации будет сразу видна. То, что у нас получилось, фактически, и есть паттерн Абстрактная фабрика. стрелки без подписи «создает» обозначают наследование.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/-_2.png" width="864" height="690" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Такая структура — пример хорошего кода для общего случая создания групп связанных обьектов. То есть всегда, когда у нас есть необходимость создавать экземпляры классов не в ручном режиме и когда у нас есть группы связанных объектов (в нашем случае все светлые и все темные связаны) паттерн подходит. Удобно то, что он раширяется, как горизонтально (можно добавлять еще стороны, кроме света и тьмы), так и вертикально без переписывания кода многократно.&lt;/p&gt;
&lt;pre style="background: #0c1021; color: #f8f8f8;"&gt;&amp;lt;?php

&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Infantry&lt;/span&gt; {
    &lt;span style="color: #aeaeae;"&gt;//общие для всей пехоты методы&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Archer&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;SiegeWeapons&lt;/span&gt; {
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodInfantry&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Infantry&lt;/span&gt; {
    &lt;span style="color: #aeaeae;"&gt;//Спецэфическая реализация для доброго пехотинца&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodArcher&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Archer&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodSiegeWeapons&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;SiegeWeapons&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilInfantry&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Infantry&lt;/span&gt;{
    &lt;span style="color: #aeaeae;"&gt;//Спецэфическая реализация для злого пехотинца&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Attack&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Defend&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilArcher&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;Archer&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Shoot&lt;/span&gt;();
}
&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilSiegeWeapons&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;SiegeWeapons&lt;/span&gt;{
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;Fire&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;abstract&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;();
    &lt;span style="color: #fbde2d;"&gt;abstract public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;();
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;GoodFactory&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Infantry
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodInfantry&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Archer
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodArcher&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; SiegeWeapons
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;GoodSiegeWeapons&lt;/span&gt;();
    }
}

&lt;span style="color: #fbde2d;"&gt;class&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;EvilFactory&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;extends&lt;/span&gt; &lt;span style="color: #ff6400; font-style: italic;"&gt;AbstractFactory&lt;/span&gt;
{
    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Infantry
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createInfantry&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilInfantry&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; Archer
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createArcher&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilArcher&lt;/span&gt;();
    }

    &lt;span style="color: #aeaeae;"&gt;/**
     * &lt;span style="color: #fbde2d;"&gt;@return&lt;/span&gt; SiegeWeapons
     */&lt;/span&gt;
    &lt;span style="color: #fbde2d;"&gt;public &lt;/span&gt;&lt;span style="color: #fbde2d;"&gt;function&lt;/span&gt; &lt;span style="color: #ff6400;"&gt;createSiegeWeapons&lt;/span&gt;()
    {
&lt;span style="color: #fbde2d;"&gt;        return&lt;/span&gt; &lt;span style="color: #fbde2d;"&gt;new&lt;/span&gt; &lt;span style="color: #8da6ce;"&gt;EvilSiegeWeapons&lt;/span&gt;();
    }
}
&lt;/pre&gt;
&lt;p&gt;Причем же тут примеси? Продолжение следует.&lt;/p&gt;
</description>
<pubDate>Fri, 18 Mar 2016 16:43:36 +0500</pubDate>
</item>

<item>
<title>Как я открыл для себя миграции</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/migracii-bazy-dannyh-v-web-razrabotke/</guid>
<link>https://koreysha.ru/?go=all/migracii-bazy-dannyh-v-web-razrabotke/</link>
<comments>https://koreysha.ru/?go=all/migracii-bazy-dannyh-v-web-razrabotke/</comments>
<description>
&lt;p&gt;Как правило, перенос сайта с одного сервера на другой состоит из двух этапов: перенос файлов и базы данных. Когда мы говорим о разработке и поддержке серьезного проекта, обычно, мы имеем несколько серверов с разными версиями. Например сервер разработки (DEV), сервер тестирования (TEST) и «боевой» (PROD). А иногда, по копии сайта  &lt;a href="http://koreysha.ru/all/kak-my-vvodili-git/"&gt;для каждого разработчика&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;При такой схеме с двухфакторный перенос вызывает серьезные сложности. Во-первых, кто-то может не уследить и версия кода разойдется с версией базы данных, что может привести к сложно-обнаруживаемым багам и даже &lt;a href="https://ru.wikipedia.org/wiki/%D0%93%D0%B5%D0%B9%D0%B7%D0%B5%D0%BD%D0%B1%D0%B0%D0%B3"&gt;гейзенбагам&lt;/a&gt;.&lt;br /&gt;
Во-вторых, обычно бывает так, что структура базы данных на сервере разработчиков поменялась при очередной итерации доработок, но и сами данные на «боевом сервере» обновились. А это значит, что нужно сначала слить актуальные данные и актуальную структуру, а только потом базу можно подключать. Я однажды при такой операции перепутал окошко консоли и удалил обновленную структуру данных. Возможности восстановить её автоматически не было и пришлось следующие несколько часов вносить изменения заново. В этот момент я был бы счастлив, если бы прочитал эту свою сегодняшнюю заметку.&lt;/p&gt;
&lt;p&gt;Решение, как все гениальное, кажется очевидным, когда ты его знаешь. Как избавится от двух этапов переноса? Сделать так, что бы один этап автоматически «подтягивал» второй. Например, хранить все изменения для БД в файловой системе. Благо, SQL нам в этом помогает очень сильно. Такие изменения назвали миграциями.&lt;/p&gt;
&lt;p&gt;Я впервые познакомился с механизмом миграций в CMS  yupe, на базе фраемворка Yii. По этому все, что напишу далее относится к этой конкретной реализации, хотя идея, в целом, остается неизменной везде.&lt;/p&gt;
&lt;p&gt;Итак, если мы хотим внести изменения в базу, то вместо того, что бы лезть туда руками, мы создаем скрипт, который знает что нужно делать для применения изменений и для их отмены. Например, для этого создается класс с двумя методами up(), который создает новую таблицу, и down(), который её удаляет. Все остальное, что ему нужно он наследует от системного класса.&lt;/p&gt;
&lt;p&gt;Далее, в системе есть способ (специальный скрипт), который для применения миграции создает объект этого класса и выполняет up, а для отмены down. Разумеется, в базе нам так же нужно хранить информацию о том, какие миграции к ней уже применились, а какие еще нет. Так же важен механизм очередности миграций, который так же зашит где-то в системе. Таким образом мы:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Всегда уверены в актуальности бд. Всегда точно знаем, что к ней уже применилось, а что еще нет.&lt;/li&gt;
&lt;li&gt;Храним всю историю в системе контроля версий вместе со всей остальной историей разработки.&lt;/li&gt;
&lt;li&gt;Можем в любой момент откатить не только состояние кода, но и базы данных к любому этапу.&lt;/li&gt;
&lt;li&gt;Легко сливаем изменения от нескольких разработчиков. Теоретически, могут возникнуть конфликты, но на практике ни разу у меня не возникали.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Для того, что бы этот механизм принес максимум пользы, я выделил для себя ряд правил «гигиены».&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Создавать всю базу с самого начала миграциями. Казалось бы, в начале разработки, до того, как сайт перекочует дальше с первого сервера разработки проблем, о   которых я писал в начале, не должно быть. Но, если уж начал делать миграции становится сложно остановиться. А серьезно, такое правило позволяет с самого начала делать все по одной схеме и не будет такого, что вот до этого момента мы можем посмотреть все изменения базы, а ранее она монолитна.&lt;/li&gt;
&lt;li&gt;Стараться делать миграции с привязкой к коммитам. Идеально: одна задача — один коммит — одна миграция. Последней конечно может и не быть. Сами задачки при этом должны быть небольшими 1-4 часа.&lt;/li&gt;
&lt;li&gt;При соблюдении предыдущего правила в название миграции хорошо бы включать id задачи. Но не ограничиваться только им, а написать еще и на человекопонятном языке.&lt;/li&gt;
&lt;/ol&gt;
</description>
<pubDate>Sun, 13 Mar 2016 12:12:22 +0500</pubDate>
</item>

<item>
<title>Гиковский сайт</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/gikovskiy-sayt/</guid>
<link>https://koreysha.ru/?go=all/gikovskiy-sayt/</link>
<comments>https://koreysha.ru/?go=all/gikovskiy-sayt/</comments>
<description>
&lt;p&gt;В блоге &lt;a href="http://eax.me"&gt;«Записки программиста»&lt;/a&gt; нашел ссылку на суперминималистичный сайт &lt;a href="http://andre.life"&gt;Андрея Прокопюка&lt;/a&gt;. Решил пофантазировать на тему, как можно сделать сайт еще более гиковским?&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/_326.jpg" width="820" height="262" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Представляю вашему вниманию мою первую &lt;a href="http://victor.koreysha.ru/"&gt;попытку&lt;/a&gt;. Буду рад отзывам, замечаниям и предложениям.&lt;/p&gt;
</description>
<pubDate>Thu, 03 Mar 2016 14:48:05 +0500</pubDate>
</item>

<item>
<title>Как мы вводили git</title>
<guid isPermaLink="true">https://koreysha.ru/?go=all/kak-my-vvodili-git/</guid>
<link>https://koreysha.ru/?go=all/kak-my-vvodili-git/</link>
<comments>https://koreysha.ru/?go=all/kak-my-vvodili-git/</comments>
<description>
&lt;p&gt;Git — это одна из популярных систем контроля версий. Код — это, прежде всего, текст. Такой текст, который правят многократно и по чуть-чуть в разных местах. Хранить только последнюю версию кода не дальновидно, по тому, что часто какие-то правки приходится отменять, а в каких-то случаях надо посмотреть «как оно работало раньше». Хранить каждую новую версию кода, то есть копировать всю директорию, допустим раз в день, не удобно по двум причинам: во-первых, занимает много места, а во-вторых, не дает никакого понимания о том, что именно изменилось.&lt;br /&gt;
Умные программисты придумали решение этих проблем. Оно заключается в том, что бы хранить какую-то базовую версию, а после сохранять только маску изменений. Например, мы храним 1000 строк кода и после изменений запоминаем, что поменялись 387 строка и 425.&lt;br /&gt;
Такое решение дало еще один неожиданный плюс. Оно позволило работать над одним и тем же кодом разным людям одновременно. Первый программист поменял вторую, третью и четвертую строку, а второй — девятую и десятую. Система сама поняла, что может применить к начальному коду и те изменения и эти. И только, если возникнет конфликт, придется разруливать людям.&lt;/p&gt;
&lt;h2&gt;Америка&lt;/h2&gt;
&lt;p&gt;Впрочем, если вы так или иначе связаны с разработкой программного обеспечения, скорее всего, Америку я вам не открыл. Во всем мире различные системы контроля версий — неотъемлемый атрибут любого программиста. Читая профессиональные форумы, блоги известных web-разработчиков и доклады с различных конференций сложно себе представить, что кто-то может жить без git-а или svn-а. Однако, в наших реалиях куча небольших веб студий и одиночек-фрилансеров работают «по-старинке». Так получилось, что и я на первых своих местах работы с системами контроля версий познакомился только заочно. До сих пор стыдно признаться, что несколько лет я писал код без таких систем.&lt;br /&gt;
Впрочем, я был такой не один. И так получилось, что у нас собралась команда из четырех человек, где никто полноценно с контролем версий не работал. У меня был до этого опыт, где все настроили до меня и оставалось только коммитить, то есть записывать изменения которые я внес. Еще у двоих членов команды был подобный опыт. Однако никто из нас не представлял, как полностью должна работать система от компьютера программиста до «боевого сервера».&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://koreysha.ru/pictures/git.png" width="1920" height="1280" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Как ни странно, гугление не могло ответить на те вопросы, которые возникали у меня в первую очередь. Например гугл на вопрос «&lt;a href="https://www.google.ru/?gws_rd=ssl#newwindow=1&amp;q=%D0%BA%D0%B0%D0%BA+%D1%81%D0%BC%D0%B5%D1%80%D0%B6%D0%B8%D1%82%D1%8C+%D0%B2%D0%B5%D1%82%D0%BA%D0%B8+git"&gt;Как смержить ветки git&lt;/a&gt;» дает около 700 результатов и вся первая страница по делу. А на запрос «&lt;a href="https://www.google.ru/?gws_rd=ssl#newwindow=1&amp;q=git+%D0%BB%D0%BE%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE+%D0%B8%D0%BB%D0%B8+%D0%BD%D0%B0+%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%B5"&gt;git локально или на сервере&lt;/a&gt;» дает 275 тыс ответов и я не смог найти что-то в тему.&lt;/p&gt;
&lt;h2&gt;Наши правила&lt;/h2&gt;
&lt;p&gt;Многое мне было непонятно. Но в итоге чтения кучи статей и советов я принял ряд решений.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Мы отказались от гита локально на каждом компьютере разработчика. Вместо этого, мы используем IDE и копию проекта на нашем сервере. У каждого разработчика есть своя локальная копия и своя удаленная копия. Уже на сервере стоит гит и туда надо зайти что бы провести с ним какие-то операции. Такое решение я принял по целому ряду причин. Основная причина в том, что мы взяли курс на проекты выше среднего по сложности и настраивать у каждого разработчика веб-сервер с нужными пакетами в условиях разных ОС и различной удаленности друг от друга сложная задача. А внедрить все это надо было без ущерба для производства.&lt;/li&gt;
&lt;li&gt;Никаких встроенных в IDE систем поддержки git и других «улучшителей вкуса» мы решили не использовать. Во-первых, в нативных командах из консоли нет ничего, чему нельзя научить за пару дней. А во-вторых, меня однажды такая система поддержки сильно подвела — вывела совсем не то, что произошло на самом деле.&lt;/li&gt;
&lt;li&gt;Мы ввели правило одна задача — одна ветка. Коммитов в нее может быть много, но чаще 1-2. Сливаем изменения только после завершения задачи.&lt;/li&gt;
&lt;li&gt;Все, что не касается напрямую нашего кода мы стараемся исключить из системы контроля версий. С этой задачей до сих пор справляемся хуже всего.&lt;/li&gt;
&lt;li&gt;Ввели правило «сервера для тестирования». Каждый раз после сливания изменений от разных разработчиков сайт поступает на тестирование и только потом выходит в продакшн, как бы не торопил заказчик.&lt;/li&gt;
&lt;li&gt;Мы стали использовать git в связке с Bitbucket. Система контроля версий без удаленного репозитория и в половину не так хороша. Но это, наверное, тема для отдельной заметки.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;И все пошло, как по маслу?&lt;/h2&gt;
&lt;p&gt;В начале было очень тяжко. Постоянно забывали новую схему работы и то вносили какие-то правки прямо на «живом сервере», то забывая про это пытались залить туда изменения с сервера разработки. Постоянно получали конфликты и не понимали, как их решать. Самое сложное было постоянно заставлять всех работать только через систему контроля версий. Каждый раз хотелось «сделать последний разок по-простому». И каждый раз приходилось останавливать и себя и команду.&lt;/p&gt;
&lt;p&gt;С тех пор прошло уже достаточно много времени, и я теперь я с уверенностью могу сказать, что это было одно из самых правильных управленческих решений. Сколько раз спасала нас эта схема сложно описать. Сколько недовольства клиентов мы смогли избежать за счет аккуратного подхода к переносу на «боевой», трудно себе даже представить.&lt;/p&gt;
&lt;p&gt;А какую систему контроля версий используйте вы? И какие сложности были с её внедрением?&lt;/p&gt;
</description>
<pubDate>Fri, 15 Jan 2016 22:10:04 +0500</pubDate>
</item>


</channel>
</rss>