{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Блог Корейши Виктора, posts tagged: программирование",
    "home_page_url": "https:\/\/koreysha.ru\/?go=tags\/programmirovanie\/",
    "feed_url": "https:\/\/koreysha.ru\/?go=tags%2Fprogrammirovanie%2Fjson%2F",
    "icon": "https:\/\/koreysha.ru\/user\/userpic@2x.jpg",
    "author": {
        "name": "Корейша Виктор",
        "url": "https:\/\/koreysha.ru\/",
        "avatar": "https:\/\/koreysha.ru\/user\/userpic@2x.jpg"
    },
    "items": [
        {
            "id": "28",
            "url": "https:\/\/koreysha.ru\/?go=all\/skolko-chelovek-delayut-sayt-prodolzhenie\/",
            "title": "Сколько человек делают сайт: продолжение",
            "content_html": "<p>Писал как-то полу-шуточную заметку о том <a href=\"http:\/\/koreysha.ru\/all\/skolko-chelovek-delayut-odin-sayt\/\">сколько программистов оптимально для проекта<\/a>. Оказывается не меня одного волнует эта тема. Вот вариант ответа на этот вопрос от commitstrip.com<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/1466261845122291044.jpg\" width=\"648\" height=\"636\" alt=\"\" \/>\n<\/div>\n",
            "date_published": "2016-07-04T14:27:40+05:00",
            "date_modified": "2016-07-04T14:28:22+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/1466261845122291044.jpg",
            "_date_published_rfc2822": "Mon, 04 Jul 2016 14:27:40 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/skolko-chelovek-delayut-sayt-prodolzhenie\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/1466261845122291044.jpg"
                ]
            }
        },
        {
            "id": "27",
            "url": "https:\/\/koreysha.ru\/?go=all\/pochemu-ya-ne-lyublyu-bitriks\/",
            "title": "Почему я не люблю Битрикс",
            "content_html": "<p>Почему-то существует огромный пласт клиентов, максимально лояльных к Битриксу. Настолько, что они готовы переплатить только, что бы их сайт был на нем сделан. Так получилось, что я ни разу не писал сайты на Битриксе с 0, но мне часто приходилось их поддерживать и развивать.<br \/>\nНе знаю, дело в моем везении или в чем-то другом, но каждый раз в таком проекте код максимально плохой. Почему-то, всегда логика запихана в представление и наоборот. Так написано в официальный гайдах Битрикса?<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/nobitrix.jpg.png\" width=\"560\" height=\"536\" alt=\"\" \/>\n<\/div>\n<p>А вот сегодня, например, была банальная задача — подправить верстку. Вроде, ничего экстраординарного. Но где находится эта верстка в проекте найти не удавалось никак. В итоге путь получился примерно такой:<\/p>\n<p>\/bitrix\/templates\/template.main\/components\/ma\/catalog\/template1\/ma\/catalog.element\/.default\/<\/p>\n<p>И в этой папке лежал и HTML и CSS и, даже, картинки. «Джентельменский набор» для отображения одного из блоков на странице. Все остальная верстка лежала вообще не там. Но самая жесть, присмотритесь — скрытая диррректория. По умолчанию в Linux, если название начинается с точки, то фаил или папке не отображаются. И, разумеется, <a href=\"http:\/\/yiiframework.ru\/forum\/viewtopic.php?t=2942\">не синхронизируются с IDE<\/a>.<\/p>\n<p>Что заставило разработчиков сделать именно так? Не надо так.<\/p>\n",
            "date_published": "2016-05-20T18:04:32+05:00",
            "date_modified": "2016-05-20T18:04:23+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/nobitrix.jpg.png",
            "_date_published_rfc2822": "Fri, 20 May 2016 18:04:32 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/pochemu-ya-ne-lyublyu-bitriks\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/nobitrix.jpg.png"
                ]
            }
        },
        {
            "id": "23",
            "url": "https:\/\/koreysha.ru\/?go=all\/bstraktnaya-fabrika-i-primesi-v-php-chast-2\/",
            "title": "Абстрактная фабрика и примеси в PHP (Часть 2)",
            "content_html": "<p><a href=\"http:\/\/koreysha.ru\/all\/bstraktnaya-fabrika-i-primesi-v-php-chast-1\/\">Первая часть<\/a><\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/sochinenie_dobro_i_zlo_2_1.jpg\" width=\"1500\" height=\"896\" alt=\"\" \/>\n<\/div>\n<p>Однако, вернемся к нашему случаю. Допустим тут в комнату входит начитанный разработчик (НР), смотрит на код и вспоминает, что по условиям игры все светлые умеют лечить, а все темные становятся невидимыми. Добавим соответствующие методы.<\/p>\n<pre style=\"background: #0c1021; color: #f8f8f8;\">&lt;?php\r\n\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">Infantry<\/span> {\r\n    <span style=\"color: #aeaeae;\">\/\/общие для всей пехоты методы<\/span>\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">Archer<\/span> {\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">SiegeWeapons<\/span> {\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodInfantry<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Infantry<\/span> {\r\n    <span style=\"color: #aeaeae;\">\/\/Спецэфическая реализация для доброго пехотинца<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n    \r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Treat<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodArcher<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Archer<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n    \r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Treat<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodSiegeWeapons<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">SiegeWeapons<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>(); \r\n    \r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Treat<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilInfantry<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Infantry<\/span>{\r\n    <span style=\"color: #aeaeae;\">\/\/Спецэфическая реализация для злого пехотинца<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n    \r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Invisible<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilArcher<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Archer<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n    \r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Invisible<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilSiegeWeapons<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">SiegeWeapons<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n    \r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Invisible<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodFactory<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Infantry\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodInfantry<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Archer\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodArcher<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> SiegeWeapons\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodSiegeWeapons<\/span>();\r\n    }\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilFactory<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Infantry\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilInfantry<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Archer\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilArcher<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> SiegeWeapons\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilSiegeWeapons<\/span>();\r\n    }\r\n}\r\n<\/pre>\n<p>Код стал не таким красивым по тому, что появились методы, которые приходится копировать. В php нет множественного наследования и приходится выбирать наследоваться белому лучнику от белых или от лучников. Мы априори выбрали второй вариант и теперь думаем, как сделать наш код красивее, а его поддержку удобнее. НР предлагает использовать примеси (trait), которые появились в php 5.4. Вынесем обшие методы в примесь.<\/p>\n<pre style=\"background: #0c1021; color: #f8f8f8;\">&lt;?php\r\n\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">Infantry<\/span> {\r\n    <span style=\"color: #aeaeae;\">\/\/общие для всей пехоты методы<\/span>\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">Archer<\/span> {\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">SiegeWeapons<\/span> {\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n}\r\n\r\n<span style=\"color: #d8fa3c;\">trait<\/span> <span style=\"color: #d8fa3c;\">Good<\/span> {\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Treat<\/span>();\r\n}\r\n\r\n<span style=\"color: #d8fa3c;\">trait<\/span> <span style=\"color: #d8fa3c;\">Evil<\/span> {\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Invisible<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodInfantry<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Infantry<\/span> {\r\n    <span style=\"color: #fbde2d;\">use<\/span> <span style=\"color: #8da6ce;\">Good<\/span>;\r\n    \r\n    <span style=\"color: #aeaeae;\">\/\/Спецэфическая реализация для доброго пехотинца<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodArcher<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Archer<\/span>{\r\n    <span style=\"color: #fbde2d;\">use<\/span> <span style=\"color: #8da6ce;\">Good<\/span>;\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodSiegeWeapons<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">SiegeWeapons<\/span>{\r\n    <span style=\"color: #fbde2d;\">use<\/span> <span style=\"color: #8da6ce;\">Good<\/span>;\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilInfantry<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Infantry<\/span>{\r\n    <span style=\"color: #fbde2d;\">use<\/span> <span style=\"color: #8da6ce;\">Evil<\/span>;\r\n    \r\n    <span style=\"color: #aeaeae;\">\/\/Спецэфическая реализация для злого пехотинца<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilArcher<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Archer<\/span>{\r\n    <span style=\"color: #fbde2d;\">use<\/span> <span style=\"color: #8da6ce;\">Evil<\/span>;\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilSiegeWeapons<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">SiegeWeapons<\/span>{\r\n    <span style=\"color: #fbde2d;\">use<\/span> <span style=\"color: #8da6ce;\">Evil<\/span>;\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodFactory<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Infantry\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodInfantry<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Archer\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodArcher<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> SiegeWeapons\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodSiegeWeapons<\/span>();\r\n    }\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilFactory<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Infantry\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilInfantry<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Archer\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilArcher<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> SiegeWeapons\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilSiegeWeapons<\/span>();\r\n    }\r\n}\r\n<\/pre>\n<p>Теперь, какой бы сложной не была реализация лечения и невидимости, нам придется написать еге всего один раз и править в едином месте. Про абстрактную фабрику и про примеси есть куча литературы, но я ни разу не видел их описание в одной статье. А тем временем, практически каждое использование этого паттерна приводит к необходимости введения общих методов и свойств для групп обьектов, которые мы разделили нашими фабриками.<\/p>\n<p>P.S. Мне очень хотелось бы услышать критику моего изложения общеизвестных вещей и моего варианта использования примесей от коллег. Я открыл для себя паттерны проектирования пару лет назад, но использовать их начал только сейчас.<br \/>\nИ если будут у кого-то вопросы, то с радостью попробую ответить.<\/p>\n",
            "date_published": "2016-03-22T10:29:41+05:00",
            "date_modified": "2016-03-22T10:29:29+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/sochinenie_dobro_i_zlo_2_1.jpg",
            "_date_published_rfc2822": "Tue, 22 Mar 2016 10:29:41 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/bstraktnaya-fabrika-i-primesi-v-php-chast-2\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/sochinenie_dobro_i_zlo_2_1.jpg"
                ]
            }
        },
        {
            "id": "22",
            "url": "https:\/\/koreysha.ru\/?go=all\/bstraktnaya-fabrika-i-primesi-v-php-chast-1\/",
            "title": "Абстрактная фабрика и примеси в PHP (Часть 1)",
            "content_html": "<p>Существует очень много статей о различных инструментах программирования и практиках их применения. Не бывает боевых проектов, которые реализуют единственный шаблон проектирования или используют единственный инструмент. В реальных условиях всегда приходится миксовать знания и опыт.<\/p>\n<p>Мне хотелось бы описать связь между различными практиками программирования, которые я встречал в своих проектах. Если опыт будет удачным, то попробую сделать цикл подобных постов.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/sochinenie_dobro_i_zlo_2.jpg\" width=\"1500\" height=\"896\" alt=\"\" \/>\n<\/div>\n<p>#Джуниор-разработчик и игра<br \/>\nДопустим, мы хотим написать браузерную игру, в которой «добро» борется со «злом». Пусть у обеих сторон есть пехота, лучники и осадные орудия. Для начала посадим за IDE джуниора. Через некоторое время мы, скорее всего, увидим следуюшие классы:<\/p>\n<pre style=\"background: #0c1021; color: #f8f8f8;\">class GoodInfantry{}\r\nclass GoodArcher{}\r\nclass GoodSiegeWeapons{}\r\n\r\nclass EvilInfantry{}\r\nclass EvilArcher{}\r\nclass EvilSiegeWeapons{}\r\n<\/pre>\n<p>#Опытный разработчик и абстрактная фабрика<\/p>\n<p>Придет опытный разработчик (ОР) и скажет, что это же класика для шаблона проектирования «абстрактная фабрика». Шаблоны проектирования разбирали уже тысячи раз на различных языках, но все же я хочу сделать статью самодостаточной и опишу еще разок. Если вы знаете «банду четырех», как свои пять пальцев, то перейдите к следующему подзаголовку.<\/p>\n<p>ОР знает, что «добрая» сторона обязательно будет иметь свои особенности, отличные от «злой». При этом так же понятно, что пехота с обоих сторон так же будет иметь нечто общее. Таким образом каждый юнит фактически должен унаследовать какие-то свойства от своей стороны, а какие-то от своего типа.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/-.png\" width=\"403\" height=\"613\" alt=\"\" \/>\n<\/div>\n<p>Для того чтобы система оставалась независимой от специфики той или иной стороны необходимо использовать общие интерфейсы для всех основных типов юнитов. Это означает, что необходимо использовать три абстрактных базовых класса для каждого типа воинов. Производные от них классы будут реализовывать специфику соответствующего типа воинов той или иной армии.<\/p>\n<p>Второй момент, который стоит учесть, связан с тем, что юнитов в игре будет много и создавать их будет не программист, а игрок. То есть программист не сможет просто прописать в коде нужное количество раз создание, допустим, пехотинца. Вместо этого он должен учесть создание пехотинца какой-то функцией. А, вспомнив, что мы находимся в концепции ООП, скорее методом какого-то более общего объекта. Допустим, что юнитов создает у нас «фабрика света» на «доброй» стороне и «фабрика тьмы» на «злой». Светлая фабрика будет выглядеть так:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/-_1.png\" width=\"453\" height=\"203\" alt=\"\" \/>\n<\/div>\n<p>Вспомним так же, что все пехотинцы будут наследовать класс Infantry. И подумаем о том, что фабрики, вероятно, будут иметь одинаковый набор методов, а значит хорошо бы им унаследовать единый абстрактный класс. Такой подход гарантирует нам, что ОР, создав абстрактные классы может идти курить и доверить написание реализации джуниору, ведь любая ошибка в реализации будет сразу видна. То, что у нас получилось, фактически, и есть паттерн Абстрактная фабрика. стрелки без подписи «создает» обозначают наследование.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/-_2.png\" width=\"864\" height=\"690\" alt=\"\" \/>\n<\/div>\n<p>Такая структура — пример хорошего кода для общего случая создания групп связанных обьектов. То есть всегда, когда у нас есть необходимость создавать экземпляры классов не в ручном режиме и когда у нас есть группы связанных объектов (в нашем случае все светлые и все темные связаны) паттерн подходит. Удобно то, что он раширяется, как горизонтально (можно добавлять еще стороны, кроме света и тьмы), так и вертикально без переписывания кода многократно.<\/p>\n<pre style=\"background: #0c1021; color: #f8f8f8;\">&lt;?php\r\n\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">Infantry<\/span> {\r\n    <span style=\"color: #aeaeae;\">\/\/общие для всей пехоты методы<\/span>\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">Archer<\/span> {\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">SiegeWeapons<\/span> {\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodInfantry<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Infantry<\/span> {\r\n    <span style=\"color: #aeaeae;\">\/\/Спецэфическая реализация для доброго пехотинца<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodArcher<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Archer<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodSiegeWeapons<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">SiegeWeapons<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilInfantry<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Infantry<\/span>{\r\n    <span style=\"color: #aeaeae;\">\/\/Спецэфическая реализация для злого пехотинца<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Attack<\/span>();\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Defend<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilArcher<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">Archer<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Shoot<\/span>();\r\n}\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilSiegeWeapons<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">SiegeWeapons<\/span>{\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">Fire<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">abstract<\/span> <span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>();\r\n    <span style=\"color: #fbde2d;\">abstract public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>();\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">GoodFactory<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Infantry\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodInfantry<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Archer\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodArcher<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> SiegeWeapons\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">GoodSiegeWeapons<\/span>();\r\n    }\r\n}\r\n\r\n<span style=\"color: #fbde2d;\">class<\/span> <span style=\"color: #ff6400;\">EvilFactory<\/span> <span style=\"color: #fbde2d;\">extends<\/span> <span style=\"color: #ff6400; font-style: italic;\">AbstractFactory<\/span>\r\n{\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Infantry\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createInfantry<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilInfantry<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> Archer\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createArcher<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilArcher<\/span>();\r\n    }\r\n\r\n    <span style=\"color: #aeaeae;\">\/**\r\n     * <span style=\"color: #fbde2d;\">@return<\/span> SiegeWeapons\r\n     *\/<\/span>\r\n    <span style=\"color: #fbde2d;\">public <\/span><span style=\"color: #fbde2d;\">function<\/span> <span style=\"color: #ff6400;\">createSiegeWeapons<\/span>()\r\n    {\r\n<span style=\"color: #fbde2d;\">        return<\/span> <span style=\"color: #fbde2d;\">new<\/span> <span style=\"color: #8da6ce;\">EvilSiegeWeapons<\/span>();\r\n    }\r\n}\r\n<\/pre>\n<p>Причем же тут примеси? Продолжение следует.<\/p>\n",
            "date_published": "2016-03-18T16:43:36+05:00",
            "date_modified": "2016-03-18T16:43:06+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/sochinenie_dobro_i_zlo_2.jpg",
            "_date_published_rfc2822": "Fri, 18 Mar 2016 16:43:36 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/bstraktnaya-fabrika-i-primesi-v-php-chast-1\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/sochinenie_dobro_i_zlo_2.jpg",
                    "https:\/\/koreysha.ru\/pictures\/-.png",
                    "https:\/\/koreysha.ru\/pictures\/-_1.png",
                    "https:\/\/koreysha.ru\/pictures\/-_2.png"
                ]
            }
        },
        {
            "id": "20",
            "url": "https:\/\/koreysha.ru\/?go=all\/migracii-bazy-dannyh-v-web-razrabotke\/",
            "title": "Как я открыл для себя миграции",
            "content_html": "<p>Как правило, перенос сайта с одного сервера на другой состоит из двух этапов: перенос файлов и базы данных. Когда мы говорим о разработке и поддержке серьезного проекта, обычно, мы имеем несколько серверов с разными версиями. Например сервер разработки (DEV), сервер тестирования (TEST) и «боевой» (PROD). А иногда, по копии сайта  <a href=\"http:\/\/koreysha.ru\/all\/kak-my-vvodili-git\/\">для каждого разработчика<\/a>.<\/p>\n<p>При такой схеме с двухфакторный перенос вызывает серьезные сложности. Во-первых, кто-то может не уследить и версия кода разойдется с версией базы данных, что может привести к сложно-обнаруживаемым багам и даже <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\">гейзенбагам<\/a>.<br \/>\nВо-вторых, обычно бывает так, что структура базы данных на сервере разработчиков поменялась при очередной итерации доработок, но и сами данные на «боевом сервере» обновились. А это значит, что нужно сначала слить актуальные данные и актуальную структуру, а только потом базу можно подключать. Я однажды при такой операции перепутал окошко консоли и удалил обновленную структуру данных. Возможности восстановить её автоматически не было и пришлось следующие несколько часов вносить изменения заново. В этот момент я был бы счастлив, если бы прочитал эту свою сегодняшнюю заметку.<\/p>\n<p>Решение, как все гениальное, кажется очевидным, когда ты его знаешь. Как избавится от двух этапов переноса? Сделать так, что бы один этап автоматически «подтягивал» второй. Например, хранить все изменения для БД в файловой системе. Благо, SQL нам в этом помогает очень сильно. Такие изменения назвали миграциями.<\/p>\n<p>Я впервые познакомился с механизмом миграций в CMS  yupe, на базе фраемворка Yii. По этому все, что напишу далее относится к этой конкретной реализации, хотя идея, в целом, остается неизменной везде.<\/p>\n<p>Итак, если мы хотим внести изменения в базу, то вместо того, что бы лезть туда руками, мы создаем скрипт, который знает что нужно делать для применения изменений и для их отмены. Например, для этого создается класс с двумя методами up(), который создает новую таблицу, и down(), который её удаляет. Все остальное, что ему нужно он наследует от системного класса.<\/p>\n<p>Далее, в системе есть способ (специальный скрипт), который для применения миграции создает объект этого класса и выполняет up, а для отмены down. Разумеется, в базе нам так же нужно хранить информацию о том, какие миграции к ней уже применились, а какие еще нет. Так же важен механизм очередности миграций, который так же зашит где-то в системе. Таким образом мы:<\/p>\n<ol start=\"1\">\n<li>Всегда уверены в актуальности бд. Всегда точно знаем, что к ней уже применилось, а что еще нет.<\/li>\n<li>Храним всю историю в системе контроля версий вместе со всей остальной историей разработки.<\/li>\n<li>Можем в любой момент откатить не только состояние кода, но и базы данных к любому этапу.<\/li>\n<li>Легко сливаем изменения от нескольких разработчиков. Теоретически, могут возникнуть конфликты, но на практике ни разу у меня не возникали.<\/li>\n<\/ol>\n<p>Для того, что бы этот механизм принес максимум пользы, я выделил для себя ряд правил «гигиены».<\/p>\n<ol start=\"1\">\n<li>Создавать всю базу с самого начала миграциями. Казалось бы, в начале разработки, до того, как сайт перекочует дальше с первого сервера разработки проблем, о   которых я писал в начале, не должно быть. Но, если уж начал делать миграции становится сложно остановиться. А серьезно, такое правило позволяет с самого начала делать все по одной схеме и не будет такого, что вот до этого момента мы можем посмотреть все изменения базы, а ранее она монолитна.<\/li>\n<li>Стараться делать миграции с привязкой к коммитам. Идеально: одна задача — один коммит — одна миграция. Последней конечно может и не быть. Сами задачки при этом должны быть небольшими 1-4 часа.<\/li>\n<li>При соблюдении предыдущего правила в название миграции хорошо бы включать id задачи. Но не ограничиваться только им, а написать еще и на человекопонятном языке.<\/li>\n<\/ol>\n",
            "date_published": "2016-03-13T12:12:22+05:00",
            "date_modified": "2016-03-13T12:11:49+05:00",
            "_date_published_rfc2822": "Sun, 13 Mar 2016 12:12:22 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/migracii-bazy-dannyh-v-web-razrabotke\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "19",
            "url": "https:\/\/koreysha.ru\/?go=all\/gikovskiy-sayt\/",
            "title": "Гиковский сайт",
            "content_html": "<p>В блоге <a href=\"http:\/\/eax.me\">«Записки программиста»<\/a> нашел ссылку на суперминималистичный сайт <a href=\"http:\/\/andre.life\">Андрея Прокопюка<\/a>. Решил пофантазировать на тему, как можно сделать сайт еще более гиковским?<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/_326.jpg\" width=\"820\" height=\"262\" alt=\"\" \/>\n<\/div>\n<p>Представляю вашему вниманию мою первую <a href=\"http:\/\/victor.koreysha.ru\/\">попытку<\/a>. Буду рад отзывам, замечаниям и предложениям.<\/p>\n",
            "date_published": "2016-03-03T14:48:05+05:00",
            "date_modified": "2016-03-03T14:47:48+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/_326.jpg",
            "_date_published_rfc2822": "Thu, 03 Mar 2016 14:48:05 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/gikovskiy-sayt\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/_326.jpg"
                ]
            }
        },
        {
            "id": "18",
            "url": "https:\/\/koreysha.ru\/?go=all\/kak-my-vvodili-git\/",
            "title": "Как мы вводили git",
            "content_html": "<p>Git — это одна из популярных систем контроля версий. Код — это, прежде всего, текст. Такой текст, который правят многократно и по чуть-чуть в разных местах. Хранить только последнюю версию кода не дальновидно, по тому, что часто какие-то правки приходится отменять, а в каких-то случаях надо посмотреть «как оно работало раньше». Хранить каждую новую версию кода, то есть копировать всю директорию, допустим раз в день, не удобно по двум причинам: во-первых, занимает много места, а во-вторых, не дает никакого понимания о том, что именно изменилось.<br \/>\nУмные программисты придумали решение этих проблем. Оно заключается в том, что бы хранить какую-то базовую версию, а после сохранять только маску изменений. Например, мы храним 1000 строк кода и после изменений запоминаем, что поменялись 387 строка и 425.<br \/>\nТакое решение дало еще один неожиданный плюс. Оно позволило работать над одним и тем же кодом разным людям одновременно. Первый программист поменял вторую, третью и четвертую строку, а второй — девятую и десятую. Система сама поняла, что может применить к начальному коду и те изменения и эти. И только, если возникнет конфликт, придется разруливать людям.<\/p>\n<h2>Америка<\/h2>\n<p>Впрочем, если вы так или иначе связаны с разработкой программного обеспечения, скорее всего, Америку я вам не открыл. Во всем мире различные системы контроля версий — неотъемлемый атрибут любого программиста. Читая профессиональные форумы, блоги известных web-разработчиков и доклады с различных конференций сложно себе представить, что кто-то может жить без git-а или svn-а. Однако, в наших реалиях куча небольших веб студий и одиночек-фрилансеров работают «по-старинке». Так получилось, что и я на первых своих местах работы с системами контроля версий познакомился только заочно. До сих пор стыдно признаться, что несколько лет я писал код без таких систем.<br \/>\nВпрочем, я был такой не один. И так получилось, что у нас собралась команда из четырех человек, где никто полноценно с контролем версий не работал. У меня был до этого опыт, где все настроили до меня и оставалось только коммитить, то есть записывать изменения которые я внес. Еще у двоих членов команды был подобный опыт. Однако никто из нас не представлял, как полностью должна работать система от компьютера программиста до «боевого сервера».<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/git.png\" width=\"1920\" height=\"1280\" alt=\"\" \/>\n<\/div>\n<p>Как ни странно, гугление не могло ответить на те вопросы, которые возникали у меня в первую очередь. Например гугл на вопрос «<a href=\"https:\/\/www.google.ru\/?gws_rd=ssl#newwindow=1&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\">Как смержить ветки git<\/a>» дает около 700 результатов и вся первая страница по делу. А на запрос «<a href=\"https:\/\/www.google.ru\/?gws_rd=ssl#newwindow=1&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\">git локально или на сервере<\/a>» дает 275 тыс ответов и я не смог найти что-то в тему.<\/p>\n<h2>Наши правила<\/h2>\n<p>Многое мне было непонятно. Но в итоге чтения кучи статей и советов я принял ряд решений.<\/p>\n<ol start=\"1\">\n<li>Мы отказались от гита локально на каждом компьютере разработчика. Вместо этого, мы используем IDE и копию проекта на нашем сервере. У каждого разработчика есть своя локальная копия и своя удаленная копия. Уже на сервере стоит гит и туда надо зайти что бы провести с ним какие-то операции. Такое решение я принял по целому ряду причин. Основная причина в том, что мы взяли курс на проекты выше среднего по сложности и настраивать у каждого разработчика веб-сервер с нужными пакетами в условиях разных ОС и различной удаленности друг от друга сложная задача. А внедрить все это надо было без ущерба для производства.<\/li>\n<li>Никаких встроенных в IDE систем поддержки git и других «улучшителей вкуса» мы решили не использовать. Во-первых, в нативных командах из консоли нет ничего, чему нельзя научить за пару дней. А во-вторых, меня однажды такая система поддержки сильно подвела — вывела совсем не то, что произошло на самом деле.<\/li>\n<li>Мы ввели правило одна задача — одна ветка. Коммитов в нее может быть много, но чаще 1-2. Сливаем изменения только после завершения задачи.<\/li>\n<li>Все, что не касается напрямую нашего кода мы стараемся исключить из системы контроля версий. С этой задачей до сих пор справляемся хуже всего.<\/li>\n<li>Ввели правило «сервера для тестирования». Каждый раз после сливания изменений от разных разработчиков сайт поступает на тестирование и только потом выходит в продакшн, как бы не торопил заказчик.<\/li>\n<li>Мы стали использовать git в связке с Bitbucket. Система контроля версий без удаленного репозитория и в половину не так хороша. Но это, наверное, тема для отдельной заметки.<\/li>\n<\/ol>\n<h2>И все пошло, как по маслу?<\/h2>\n<p>В начале было очень тяжко. Постоянно забывали новую схему работы и то вносили какие-то правки прямо на «живом сервере», то забывая про это пытались залить туда изменения с сервера разработки. Постоянно получали конфликты и не понимали, как их решать. Самое сложное было постоянно заставлять всех работать только через систему контроля версий. Каждый раз хотелось «сделать последний разок по-простому». И каждый раз приходилось останавливать и себя и команду.<\/p>\n<p>С тех пор прошло уже достаточно много времени, и я теперь я с уверенностью могу сказать, что это было одно из самых правильных управленческих решений. Сколько раз спасала нас эта схема сложно описать. Сколько недовольства клиентов мы смогли избежать за счет аккуратного подхода к переносу на «боевой», трудно себе даже представить.<\/p>\n<p>А какую систему контроля версий используйте вы? И какие сложности были с её внедрением?<\/p>\n",
            "date_published": "2016-01-15T22:10:04+05:00",
            "date_modified": "2016-01-15T22:09:38+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/git.png",
            "_date_published_rfc2822": "Fri, 15 Jan 2016 22:10:04 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/kak-my-vvodili-git\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/git.png"
                ]
            }
        },
        {
            "id": "16",
            "url": "https:\/\/koreysha.ru\/?go=all\/router-kak-komponent-veb-sistemy-chast-1\/",
            "title": "Роутер, как компонент веб-системы. Часть 1.",
            "content_html": "<p>Я продолжаю разбирать разные компоненты CMS. Предыдущие заметки по теме:<\/p>\n<ul>\n<li><a href=\"http:\/\/koreysha.ru\/all\/cms-dlya-razrabotchikov\/\">CMS для разработчиков<\/a><\/li>\n<li><a href=\"http:\/\/koreysha.ru\/all\/shablonnaya-sistema\/\">Шаблонная система<\/a><\/li>\n<\/ul>\n<p>Любая страница сайта доступна по какому-то адресу (URL). Бывает, конечно, что у одной и то же страницы несколько адресов. Или наоборот, при какой-то динамической погрузке контента, в итоге пользователь по одному и тому же адресу увидит разные страницы (Что является грубой ошибкой, но ою этом как-нибудь потом). Но в целом какое-то соответствие адреса и страницы есть всегда.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/network-115500_1920.jpg\" width=\"1900\" height=\"877\" alt=\"\" \/>\n<\/div>\n<p>К радости начинающих и ленивых разработчиков, это соответствие уже работает на стороне web-сервера. Сначала, он с помощью механизма Виртуальных Хостов определяет корневую директорию сайта и сам ищет в ней фаил index, который и становится главной страницей. Потом, каждой папке <b>dir<\/b> ставит в соответствие адрес <b>mysite.ru\/dir\/<\/b>. Для простых сайтов без сложной внутренней архитектуры этого вполне достаточно.<\/p>\n<h2>Что же не так?<\/h2>\n<p>Но при построении CMS возникает ряд сложностей с такой системой:<\/p>\n<ol start=\"1\">\n<li>Хочется из административной панели управлять URL-ами. А это значит, надо дать возможность оттуда создавать и удалять папки. Это не безопасно давать администратору сайта такие серьезные права на сервере. С ними он может снести весь сайт. А право управления URL фактически приравняется к праву администратора сервера.<\/li>\n<li>Перенос кода из одних папок в другие сильно осложнит разработчикам жизнь. Такая неразбериха противоречит идеям контроля версий кода. Кроме того, усложняет задание относительных путей внутри системы.<\/li>\n<li>Код разбросанный по разным папкам по принципу отношения к разделам, прямо скажем, очень плохое архитектурное решение. Нам важно минимизировать дублирование кода и упростить разработчикам поиск места «где считается вот-такая-вот циферка». И та и другая задача решены в этом случае крайне плохо.<\/li>\n<li>URL должен быть удобен для пользователя и понятен поисковым роботам, а внутренняя система директорий должна быть удобна и понятна разработчикам. Нет никакого смысла усложнять жизнь одним, в угоду других. Этот пункт частично пересекается с предыдущими, но думаю, что его стоит выделить.<\/li>\n<\/ol>\n<p>Все эти сложности и, возможно, еще какие-то заставили разработчиков искать выход. Я наблюдал в разных системах несколько вариантов таких выходов. Принципиально можно выделить два подхода.<\/p>\n<h2>В каждой папке подключаем ядро<\/h2>\n<p>Оставляем маршрутизацию на совесть web сервера, но отказываемся от кода внутри каждого раздела. Все, что мы делаем — это запоминаем что это за раздел (например записываем его ID) и дальше подключаем «ядро системы», которое уже обрабатывает запрос, готовит контент и т.д.<br \/>\nВ этом случае внутри папки <b>about<\/b> будет примерно такой код:<\/p>\n<pre style=\"background:#181818;color:#f8f8f8\">$section <span style=\"color:#cda869\">=<\/span> <span style=\"color:#8f9d6a\">‘22’<\/span>;\r\ninclude(<span style=\"color:#8f9d6a\">‘\/includes\/core.php’<\/span>);\r\n<\/pre>\n<p>А вся остальная система уже разворачивается из <b>core.php<\/b>.<\/p>\n<p>Плюсы такого подхода в том, что он работает по умолчанию на любом web-сервере. То есть у нас не будет проблем при переезде с <b>Apache<\/b> на <b>Nginx<\/b>. Так же не будет проблем при переезде на хостинг, где нам запретили что-либо менять в настройках web-сервера, в том числе с помощью файла <b>.htaccess<\/b> и ему подобных.<\/p>\n<p>Минусы в том, что пользователь все-же из административной панели управляет созданием и удалением папок. Это может привести к трудноуловимым ошибкам. Например, если администратор сайта создаст раздел <b>lib<\/b>, а у нас есть такая папка и она содержит важные для нас библиотеки, то либо он её удалит и прекратит работать вообще все, либо не сможет создать раздел и опечалится.<\/p>\n<h2>Единая точка входа<\/h2>\n<p>Более распространенный в крупных системах вариант — это единая точка входа. Тут основная идея простая. Что бы не запросил пользователь мы должны всегда отправить его в один и тот же фаил, где уже разобрать его запрос и решить какой контент стоит отдать. Обычно при таком подходе вариант по умолчанию все равно остается и помогает подключать скрипты картинки и т.д. Но для основных адресов сайта паки не создаются. Вместо этого мы так настраиваем наш web-сервер, что бы при невозможности найти папку мы всех отправляли в единый фаил. А в нем уже решаем валидный это адрес для нашей системы или надо отдать какую-нибудь ошибку.<br \/>\nВот пример простого <b>.htaccess<\/b> для такого подхода:<\/p>\n<pre style=\"background:#181818;color:#f8f8f8\"><span style=\"color:#cf6a4c\">RewriteEngine<\/span> on\r\n\r\n<span style=\"color:#cf6a4c\">RewriteCond<\/span> <span style=\"color:#9b859d\">%{REQUEST_FILENAME}<\/span> <span style=\"color:#8f9d6a\">!-d<\/span>\r\n<span style=\"color:#cf6a4c\">RewriteCond<\/span> <span style=\"color:#9b859d\">%{REQUEST_FILENAME}<\/span> <span style=\"color:#8f9d6a\">!-f<\/span>\r\n<span style=\"color:#cf6a4c\">RewriteRule<\/span> <span style=\"color:#e9c062\">^.*$<\/span> <span style=\"color:#8f9d6a\">\/core.php<\/span> <span style=\"color:#e9c062\">[NC,L]<\/span>\r\n<\/pre>\n<p>Тут написано, что если ни фаил ни дириктория не найдены, то отправлять все в <b>core.php<\/b>.<\/p>\n<p>Главный плюс такого подхода — бОльшая гибкость. Ну а минус — сложности при переносе на дешевые хостинги.<br \/>\nОтдельно хочу отметить, что этот подход очень хорошо сделан в Yii фраемворке. Все файлы, которые нужно находить «встроенной»  навигацией находятся в папке public, а все «внутренности» в отдельной папке protected. Такое распредление позволяет достаточно безопасно настроить права доступа.<\/p>\n<p>#После точки входа<br \/>\nВ обоих подходах всегда есть общая точка входа. И у же в ней идет формирование того, что мы отдадим пользователю. Как правило эта точка входа построена в два этапа. В первом этапе подключаются и инициализируются срикпты, которые должны работать на сайте всегда, не зависимо от того, куда хотел попасть пользователь. Это, например, подключение к базе данных.<br \/>\nА второй этап, как правило, зависит от того, что запросил пользователь. Конечно, можно прописать в ядре какой-то гигантский оператор <b>switch<\/b> и при добавлении каждого нового функционала дописывать к нему опции. Но это подход человека, который не слышал об архитектуре приложении. Более же правильный путь — создать набор модулей. И по надобности подключать тот или иной модуль. Именно так устроены большинство CMS и фраемворков.<br \/>\nВ таком случае нам понадобится блок в коде, который принимает запрос и решает какой или какие модули нужно подключить. Именно этот блок и называют <b>Роутером<\/b> или по-русски <b>Маршрутизатором<\/b>.<\/p>\n<p>Уф. Большое получилось вступление. Пожалуй, остановлюсь тут и продолжу во второй части.<\/p>\n",
            "date_published": "2016-01-05T18:48:57+05:00",
            "date_modified": "2016-01-05T18:48:24+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/network-115500_1920.jpg",
            "_date_published_rfc2822": "Tue, 05 Jan 2016 18:48:57 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/router-kak-komponent-veb-sistemy-chast-1\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/network-115500_1920.jpg"
                ]
            }
        },
        {
            "id": "14",
            "url": "https:\/\/koreysha.ru\/?go=all\/novogodniy-snezhok-na-sayt\/",
            "title": "Новогодний снежок на сайт",
            "content_html": "<p>Один из наших клиентов попросил поставить новогоднюю заставку на сайт. Польза — рассказать клиентам, что до конца праздников они не работают и вернутся только с 11-го января. Ну а заодно, повеселить пользователей новогодним видом сайта. Для этого мы сделали гифку с новогодними игрушками и снегопадом.<\/p>\n<p>Пока ставили все это на сайт стали обсуждать с коллегами, что прикольно было бы на весь сайт пустить снег. В интернете нашлись уже разные исполнения нашей задумки, но на боевой проект их бездумно ставить страшно. Во-первых, многие тормозят, ведь не у всех клиентов быстрый интернет и современные браузеры. Во-вторых, ставить чужие скрипты опасно в принципе.<\/p>\n<p>В общем, не хочу больше затягивать, я за пол часика собрал наше «легкое» исполнение. Идею подсмотрел, но убрал все лишнее и сделал под себя. Хочу им поделится с читателями. Почитать будет полезно тем, кто только изучает джаваскрипт. А итог могут использовать на своих проектах все желающие. Так же буду рад критике коллег.<\/p>\n<h2>Результат<\/h2>\n<iframe height='315'  scrolling='no' src='\/\/codepen.io\/koreysha\/embed\/dGpNer\/?height=315&theme-id=0&default-tab=result' frameborder='no' allowtransparency='true' allowfullscreen='true' style='max-width: 800px; width: 100%;'>See the Pen <a href='http:\/\/codepen.io\/koreysha\/pen\/dGpNer\/'>dGpNer<\/a> by Viktor Koreysha (<a href='http:\/\/codepen.io\/koreysha'>@koreysha<\/a>) on <a href='http:\/\/codepen.io'>CodePen<\/a>.\r\n<\/iframe>\n<h2>Процесс<\/h2>\n<p>Эта часть для тех, кто только изучает джаваскрипт. Всем остальным, думаю, будет не очень интересно.<br \/>\nВсе, что нам понадобится в HTML, это canvas с идентефикатором snow. И я запустил скрипт по событию на BODY onload=“init()”. Это не лучшее решение, но оно за рамками самого «снега», так что оставлю его на совесть того, кто будет код использовать.<br \/>\nВесь наш код состоит из четырех функций.<br \/>\n<b>function init()<\/b> — тут мы делаем подготовку к запуску и запускаем. В этой функции должны быть все операции, которые нужно произвести до основного кода.<br \/>\n<b>function draw()<\/b> — отвечает за отрисовку текущего состояния снега.<br \/>\n<b>function update()<\/b> — отвечает за установку нового состояния. Оно будет отрисовано на следующем шаге.<br \/>\n<b>function mousemove(event)<\/b> — отвечает за отслеживание положения мыши. Эту функцию я добавил по тому, что захотелось какого-то интерактива. Снег не должен всегда падать только вниз, в жизни его сдувает ветром то туда, то сюда. Я решил, что за ветер будет отвечать курсор. Чем дальше он от центра экрана (горизонтално), тем сильнее ветер в эту сторону. Если интерактив не нужен, то от этой части можно отказаться.<\/p>\n<h2>Подробнее<\/h2>\n<p>Начну разбор с инициализации. Для начала я накидал что-то подобное:<\/p>\n<pre style=\"background:#000;color:#f8f8f8\"><span style=\"color:#99cf50\">function<\/span> <span style=\"color:#89bdff\">init<\/span>() {\r\n  <span style=\"color:#aeaeae;font-style:italic\">\/\/Canvas init<\/span>\r\n  <span style=\"color:#e28964\">var<\/span> canvas <span style=\"color:#e28964\">=<\/span> document.getElementById(<span style=\"color:#65b042\">‘snow’<\/span>);\r\n\r\n  <span style=\"color:#aeaeae;font-style:italic\">\/\/Canvas resize<\/span>\r\n  <span style=\"color:#e28964\">var<\/span> W <span style=\"color:#e28964\">=<\/span> window.innerWidth;\r\n  <span style=\"color:#e28964\">var<\/span> H <span style=\"color:#e28964\">=<\/span> window.innerHeight;\r\n  canvas.<span style=\"color:#dad085\">width<\/span> <span style=\"color:#e28964\">=<\/span> W;\r\n  canvas.<span style=\"color:#dad085\">height<\/span> <span style=\"color:#e28964\">=<\/span> H;\r\n\r\n  <span style=\"color:#aeaeae;font-style:italic\">\/\/Get context<\/span>\r\n  <span style=\"color:#e28964\">var<\/span> ctx <span style=\"color:#e28964\">=<\/span> canvas.getContext(<span style=\"color:#65b042\">‘2d’<\/span>);\r\n  ctx.strokeStyle <span style=\"color:#e28964\">=<\/span> <span style=\"color:#65b042\">‘white’<\/span>;\r\n\r\n  <span style=\"color:#aeaeae;font-style:italic\">\/\/Prepare array of particles<\/span>\r\n  <span style=\"color:#e28964\">var<\/span> mp <span style=\"color:#e28964\">=<\/span> <span style=\"color:#3387cc\">100<\/span>;\r\n  <span style=\"color:#e28964\">var<\/span> particles <span style=\"color:#e28964\">=<\/span> [];\r\n  <span style=\"color:#e28964\">for<\/span> (<span style=\"color:#e28964\">var<\/span> i <span style=\"color:#e28964\">=<\/span> <span style=\"color:#3387cc\">0<\/span>; i &lt; mp; i<span style=\"color:#e28964\">+<\/span><span style=\"color:#e28964\">+<\/span>) {\r\n    particles.<span style=\"color:#dad085\">push<\/span>({\r\n      <span style=\"color:#dad085\">x<\/span><span style=\"color:#e28964\">:<\/span> <span style=\"color:#9b859d\">Math<\/span>.<span style=\"color:#dad085\">random<\/span>() <span style=\"color:#e28964\">*<\/span> W,\r\n      y<span style=\"color:#e28964\">:<\/span> <span style=\"color:#9b859d\">Math<\/span>.<span style=\"color:#dad085\">random<\/span>() <span style=\"color:#e28964\">*<\/span> H,\r\n      r<span style=\"color:#e28964\">:<\/span> <span style=\"color:#9b859d\">Math<\/span>.<span style=\"color:#dad085\">random<\/span>() <span style=\"color:#e28964\">*<\/span> <span style=\"color:#3387cc\">3<\/span> <span style=\"color:#e28964\">+<\/span> <span style=\"color:#3387cc\">1<\/span>\r\n    })\r\n  }\r\n}\r\n<\/pre>\n<p>Первые три блока можно скопировать из любого «Самоучителя по Canvas для чайников». Получаем конвас, растягиваем на всю страницу и готовимся рисовать белым цветом.<\/p>\n<p>В последнем блоке создаем массив, который будет отвечать за снежинки. Particles — массив снежинок. А каждая снежинка это объект, который «помнит» о своих координатах и диаметре. Для каждой снежинки задаем её начальное состояние: она должна быть где-то на нашем канвасе (случайным образом) и должна получить диаметр от 1 до 4 пикселей.<\/p>\n<p>После этого переходим к отрисовке текущего состояния нашего снега.<\/p>\n<pre style=\"background:#000;color:#f8f8f8\"><span style=\"color:#99cf50\">function<\/span> <span style=\"color:#89bdff\">draw<\/span>(<span style=\"color:#3e87e3\">W<\/span>,<span style=\"color:#3e87e3\"> H<\/span>,<span style=\"color:#3e87e3\"> particles<\/span>,<span style=\"color:#3e87e3\"> mp<\/span>,<span style=\"color:#3e87e3\"> ctx<\/span>) {\r\n  <span style=\"color:#aeaeae;font-style:italic\">\/\/Clearing<\/span>\r\n  ctx.clearRect(<span style=\"color:#3387cc\">0<\/span>, <span style=\"color:#3387cc\">0<\/span>, W, H);\r\n\r\n  <span style=\"color:#aeaeae;font-style:italic\">\/\/Set white whith opacity 0.8<\/span>\r\n  ctx.fillStyle <span style=\"color:#e28964\">=<\/span> <span style=\"color:#65b042\">“rgba(255, 255, 255, 0.8)”<\/span>;\r\n\r\n  <span style=\"color:#aeaeae;font-style:italic\">\/\/Drowing<\/span>\r\n  ctx.beginPath();\r\n  <span style=\"color:#e28964\">for<\/span> (<span style=\"color:#e28964\">var<\/span> i <span style=\"color:#e28964\">=<\/span> <span style=\"color:#3387cc\">0<\/span>; i &lt; mp; i<span style=\"color:#e28964\">+<\/span><span style=\"color:#e28964\">+<\/span>) {\r\n    <span style=\"color:#e28964\">var<\/span> p <span style=\"color:#e28964\">=<\/span> particles[i];\r\n    ctx.<span style=\"color:#dad085\">moveTo<\/span>(p.<span style=\"color:#dad085\">x<\/span>, p.y);\r\n    ctx.arc(p.<span style=\"color:#dad085\">x<\/span>, p.y, p.r, <span style=\"color:#3387cc\">0<\/span>, <span style=\"color:#9b859d\">Math<\/span>.<span style=\"color:#cf6a4c\">PI<\/span> <span style=\"color:#e28964\">*<\/span> <span style=\"color:#3387cc\">2<\/span>, <span style=\"color:#3387cc\">true<\/span>);\r\n  }\r\n  ctx.fill();\r\n}\r\n<\/pre>\n<p>Тут то же все просто. Чистим поле и заново рисуем каждую снежинку на её координатах и с её диаметром. Для новичков хочу обратить нимание, что мы сначала «накидываем» все в контакст. И только один раз отрисовываем с помощью <b>ctx.fill();<\/b><\/p>\n<p>Переходим к анимации. Пишем функцию, которая будет смещать все снежинки вниз. Если их скорость будет одинаковой будет скучно. По этому мы представляем, что большие снежинки ближе, потому и падают быстрее.<\/p>\n<pre style=\"background:#000;color:#f8f8f8\"><span style=\"color:#99cf50\">function<\/span> <span style=\"color:#89bdff\">update<\/span>(W, H, particles, mp, ctx) {\r\n  <span style=\"color:#e28964\">for<\/span> (<span style=\"color:#e28964\">var<\/span> <span style=\"color:#e28964\">i<\/span> = <span style=\"color:#3387cc\">0<\/span>; <span style=\"color:#e28964\">i<\/span><span style=\"color:#e28964\"> &lt; <\/span>mp; <span style=\"color:#e28964\">i<\/span><span style=\"color:#e28964\">+<\/span><span style=\"color:#e28964\">+<\/span>) {\r\n    <span style=\"color:#e28964\">var<\/span> p = particles[<span style=\"color:#e28964\">i<\/span>];\r\n    p.y<span style=\"color:#e28964\"> +<\/span>= <span style=\"color:#3387cc\">1<\/span><span style=\"color:#e28964\"> + <\/span>p.r<span style=\"color:#e28964\">\/<\/span><span style=\"color:#3387cc\">2<\/span>;\r\n\r\n    <span style=\"color:#e28964\">if<\/span> (p.y<span style=\"color:#e28964\"> > <\/span>H) {\r\n      particles[<span style=\"color:#e28964\">i<\/span>] = {\r\n        x<span style=\"color:#e28964\">: <\/span>Math.random()<span style=\"color:#e28964\"> * <\/span>W,\r\n        y<span style=\"color:#e28964\">: <\/span><span style=\"color:#e28964\">-<\/span><span style=\"color:#3387cc\">10<\/span>,\r\n        r<span style=\"color:#e28964\">: <\/span>p.r\r\n      };\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<p>Скорость падения зависит от радиуса. Можно добавить какой-нибудь дополнительный случайный параметр, который вместо радиуса будет влиять на скорость. Но мне показалось, что и так не плохо. Если снежинка вылетела за поле вниз, то сразу перемещаем её в выше верха и смещаем случайно по оси X. Ничего хитрого.<\/p>\n<p>Когда мы все это подготовили нам осталось запустить отрисовку по таймеру. Для этого добавляем в <b>init<\/b>:<\/p>\n<pre style=\"background:#000;color:#f8f8f8\"><span style=\"color:#dad085\">setInterval<\/span>(function() {\r\n    <span style=\"color:#dad085\">draw<\/span>(W, H, particles, mp, ctx);\r\n  }, <span style=\"color:#3387cc\">50<\/span>);\r\n<\/pre>\n<p>И после отрисовки сразу общитывать новое состояние. Для этого вызываем <b>update<\/b> в конце <b>draw<\/b>:<\/p>\n<pre style=\"background:#000;color:#f8f8f8\"><span style=\"color:#89bdff\">update<\/span>(<span style=\"color:#3e87e3\">W<\/span>, <span style=\"color:#3e87e3\">H<\/span>, <span style=\"color:#3387cc\">particles<\/span>, <span style=\"color:#3387cc\">mp<\/span>, <span style=\"color:#3387cc\">ctx<\/span>);\r\n<\/pre>\n<h2>Интерактивчик<\/h2>\n<p>Все. Простой снег готов. Но мне захотелось добавить интерактива. А то никакого профита, что налету снег обсчитываем. Добавляем функцию, которая отслеживает движения мыши и всгда записывает её положение. Для записи я расширил объект body, который точно есть у нашей веб-страницы. Добавляем в <b>init<\/b>:<\/p>\n<pre style=\"background:#000;color:#f8f8f8\">document.body.myData = {\r\n    x<span style=\"color:#e28964\">: <\/span><span style=\"color:#3387cc\">0<\/span>,\r\n    y<span style=\"color:#e28964\">: <\/span><span style=\"color:#3387cc\">0<\/span>\r\n  };\r\n  document.onmousemove = mousemove;\r\n<\/pre>\n<p>Теперь по умолчанию мышка у нас в верхнем левом углу, но как только пользователь её сдвинет, мы обновим координаты.<br \/>\nЗаписывать при сдвиге мыши будем с помощью такой функции:<\/p>\n<pre style=\"background:#000;color:#f8f8f8\"><span style=\"color:#99cf50\">function<\/span> <span style=\"color:#89bdff\">mousemove<\/span>(event) {\r\n<span style=\"color:#e28964\">var<\/span> mouse_x = mouse_y = <span style=\"color:#3387cc\">0<\/span>;\r\n<span style=\"color:#e28964\">if<\/span> (document.attachEvent != <span style=\"color:#e28964\">null<\/span>) {\r\nmouse_x = <span style=\"color:#9b859d\">window<\/span>.event.clientX;\r\nmouse_y = <span style=\"color:#9b859d\">window<\/span>.event.clientY;\r\n} <span style=\"color:#e28964\">else<\/span> <span style=\"color:#e28964\">if<\/span> (!document.attachEvent<span style=\"color:#e28964\"> &amp;<\/span><span style=\"color:#e28964\">&amp; <\/span>document.addEventListener) {\r\nmouse_x = event.clientX;\r\nmouse_y = event.clientY;\r\n}\r\ndocument.body.myData.x = mouse_x;\r\ndocument.body.myData.y = mouse_y;\r\n}\r\n<\/pre>\n<p>Отследить то мы отследили. Осталось добавить скорость вдоль горизонтальной оси Ox:<\/p>\n<pre style=\"background:#000;color:#f8f8f8\"><span style=\"color:#e28964\">var<\/span> speed_x = (document.body.myData.x<span style=\"color:#e28964\"> – <\/span>(W<span style=\"color:#e28964\"> \/ <\/span><span style=\"color:#3387cc\">2<\/span>))<span style=\"color:#e28964\"> \/ <\/span>W;\r\n<\/pre>\n<p>Смотрим в какой половине мышь: в правой или левой. И как далеко она от центра. Чем дальше, тем «сильнее ветер».<\/p>\n<p>И осталось добавить сдвиг по Ox:<\/p>\n<pre style=\"background:#000;color:#f8f8f8\">p<span style=\"color:#e28964\">.<\/span>x <span style=\"color:#e28964\">+=<\/span> speed_x * <span style=\"color:#3387cc\">10<\/span>;\r\n<\/pre>\n<h2>Вместо послесловия<\/h2>\n<p>Приглашаю уважаемых коллег критиковать мой код и предлагать, как было бы сделать лучше. А новичков задавать вопросы.<\/p>\n",
            "date_published": "2015-12-24T22:27:20+05:00",
            "date_modified": "2015-12-24T22:41:10+05:00",
            "_date_published_rfc2822": "Thu, 24 Dec 2015 22:27:20 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/novogodniy-snezhok-na-sayt\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "12",
            "url": "https:\/\/koreysha.ru\/?go=all\/shablonnaya-sistema\/",
            "title": "Шаблонная система",
            "content_html": "<p>В заметке <a href=\"http:\/\/koreysha.ru\/all\/cms-dlya-razrabotchikov\/\">CMS для разработчиков<\/a> я пообещал, что рассмотрю более подробно  выбор CMS для подхода «Инструменты для удобства разработки». Пока я обдумывал, что написать по этому вопросу, пришел к выводу, что не смогу вести разговор без единого понятийного аппарата, иными словами без «системы координат». Кроме того, вопрос показался мне слишком сложным для одной заметки.<br \/>\nПродолжая эти мысль, я решил не писать сразу о выборе такого многопланового инструмента, как CMS, а остановиться, для начала, на конкретных компонентах. Сегодня таким компонентом станет шаблонная система.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/koreysha.ru\/pictures\/templates.png\" width=\"1920\" height=\"1271\" alt=\"\" \/>\n<\/div>\n<p>После того, как фронтенд-разработчики выдали готовую верстку, а бекэнд-разработчики построили систему взаимодействия с базой данных,  наступает момент, когда необходимо указать системе какую информацию она должна брать и куда вставлять. Эту операцию иногда называют «повесить на админку». Конечно, я утрирую, и далеко не всегда это делается после всех остальных работ, а не вперемешку с ними. Но для нас сейчас это не важно. А важно то, что  такая операция существует и её цель построить однозначные связи между информацией полученной или сгенерированной бекэндом и отображением для пользователя.<\/p>\n<h2>PHP, как шаблонная система<\/h2>\n<p>На заре развития веб технологий, примерно для этой цели и создали PHP. Это можно понять и из современной расшифровки акронима — «препроцессор гипертекста», а гипертекст это HTML, конечно. Ну а согласно <a href=\"https:\/\/ru.wikipedia.org\/wiki\/PHP\">вики<\/a> начиналось все вообще с «интерпретатора форм для персональной домашней страницы», то есть фактически PHP когда-то был всего лишь шаблонной системой к конкретному сайту.<\/p>\n<p>Этот позорный факт часто ставят в укор PHP-разработчикам, которых итак не особо жалуют в «продвинутом» IT собществе. Но об этом поговорим как-нибудь в другой раз. Сегодня нас интересует другое. А именно то мнение, что раз этот язык изначально задумывался, как шаблонная система, то зачем «городить огород» из разных технолгий. Давайте писать шаблоны, вставляя «php-врезки» в верстку сайта.<\/p>\n<p>Такого метода придерживаются многие популярные CMS системы — WordPress, 1C-Bitrix, NetCat (частично) и другие.<\/p>\n<h3>Что в этом методе хорошего?<\/h3>\n<ul>\n<li>Не надо обучать разработчиков отдельно шаблонной системе. Они уже знают php и смогут быстро включится в проект.<\/li>\n<li>Разработчик всегда может найти в коде конкретную переменную или функцию и посмотреть откуда она берется или что делает.<\/li>\n<li>Это быстрее работает, т.к. нет лишнего звена между интерпретатором языка и шаблоном.<\/li>\n<\/ul>\n<h3>Что тут не так?<\/h3>\n<ul>\n<li>Велик соблазн вставить кусок логики в шаблон. Такие действия не пресекаются на уровне системы.<\/li>\n<li>Больше мусора. Как минимум открывающий и закрывающий теги его создают.<\/li>\n<li>Вывод в шаблон привязан к особенностям системы. Если мы поменяем функцию, то нам придется менять её и в шаблоне. Мы открываем свой «внутренний мир» тому, кто привязывает шаблон к бекэнду.<\/li>\n<li>Если ошибка произойдет прямо в шаблоне то нам сложно будет её найти и разобрать. Это связано с тем, что часть страницы на тот момент уже выведется и мы можем на понять, что ошибка произошла перед каким-нибудь закрывающим тегом из-за чего у нас полная каша.<\/li>\n<\/ul>\n<h2>Отдельная шаблонная система<\/h2>\n<p>По моему опыту, все же хорошо, когда есть отдельная шаблонная система. Основная идея тут простая. Разработчики заранее договариваются, какими метками в HTML-верстке обозначить места для вывода той или иной информации. Эта договоренность может быть разовая для конкретного случая, или общая для всего проекта (а в идеале и для всех последующих проектов, но это утопия). Метки могут быть самыми разными от маркеров вида:<\/p>\n<p><b>%title%<\/b><\/p>\n<p>до блоков типа:<\/p>\n<p><b>{foreach from=$myArray item=foo}<\/b><br \/>\n<b>{$foo}<\/b><br \/>\n<b>{\/foreach}<\/b><\/p>\n<p>При определенном идет таких договоренностей верстальщик может сразу сделать из HTML-верстки нужный шаблон для внедрения. Ну или по крайней мере подготовить его к этому. Это экономически целесообразно, хотя на практике целиком такое получается крайне редко. Такого подхода придерживатся: Umi.cms , Drupal(опционально),  Symfony framework и многие другие проекты.<\/p>\n<h3>Что в этом методе хорошего?<\/h3>\n<ul>\n<li>Пропадает необходимость контролировать разработчиков по разделению логики представления от бизнес-логики. Используя «шаблонизатор» мы точно уверены, что никакая часть бизнес-логики  не «просочится» в шаблон.<\/li>\n<li>Шаблон в итоге выглядит чище. Это не абсолютное правило, но тенденция.<\/li>\n<li>Мы можем разделить права. К примеру дать кому-то права изменять только шаблоны и мы будем уверены, что он не «докопается» до базы данных, например.<\/li>\n<\/ul>\n<h3>Что тут не так?<\/h3>\n<ul>\n<li>Меньше скорость работы. Однако, при использовании кеширования этот минут сходит на нет.<\/li>\n<li>Требует отдельного изучения. Правда, как правило, структура шаблона достаточно простая для понимания разработчиками.<\/li>\n<\/ul>\n<h2>Вывод<\/h2>\n<p>В этой заметке я не ставил цели разобраться с тем, что правильно использовать, а что нет. Моя задача: показать читателю выбор инструментов разработки для конкретных проектов. В данном случае, выбор между использованием отдельной шаблонной системы и нативным PHP кодом стоит принимать исходя из обозначенных плюсов и минусов.<\/p>\n",
            "date_published": "2015-12-20T00:36:55+05:00",
            "date_modified": "2015-12-20T00:36:49+05:00",
            "image": "https:\/\/koreysha.ru\/pictures\/templates.png",
            "_date_published_rfc2822": "Sun, 20 Dec 2015 00:36:55 +0500",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/koreysha.ru\/?go=all\/shablonnaya-sistema\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/koreysha.ru\/pictures\/templates.png"
                ]
            }
        }
    ],
    "_e2_version": 3335,
    "_e2_ua_string": "E2 (v3335; Aegea)"
}