Пишу свои мысли про управление it-проектами, командой разработки и профессиональном росте.
Связаться со мной можно по почте viktor@koreysha.ru

Later Ctrl + ↑

«Лендинг» — это новый «сайт-визитка»

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

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

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

С услугами все не так. Ты не можешь знать результат заранее. Когда ты нанял садовника, что бы он фигурно подстриг кусты, то ты можешь получить, как «шары» так и «кубы». Если садовник опытный, то он обязательно уточнит заранее, что ты хочешь увидеть, но и с самым подробным ТЗ, результат все равно не определен, пока кусты не подстрижены. То же самое и с другими услугами. И чем сложнее услуга, тем больше переменных, которые влияют на результат. Очень сложно продавать то, чего еще не существует. Особенно сложно, когда заказчик не представляет себе конечный результат.

Постоянно работать вместе с клиентом для получения хорошего результата тяжело. А вот продать ему «сайт-визитку» просто, особенно, если есть пример. По этому, многие разработчики пошли по пути наименьшего сопротивления. Что плохого, если клиент получит понятный результат за понятные деньги? Если все стороны понимают это и согласны, то ничего. Только дело в том, что я не встречал клиентов, которым зачем-то нужен именно такой сайт. Как правило, все же нужен какой-то результат для бизнеса, а вот его такая концепция не учитывает.

Вот и дырка в абстракции. Когда человек приходит за телевизором, то знает, что хочет каждый вечер смотреть какой-нибудь сериал. И он может подобрать себе то, что нужно или спросить совета у консультанта. А потом может пойти в Яндекс.маркет и сравнить цены на телевизоры с такими параметрами. Но сайт — результат долгой совместной работы. Нельзя заказать «сайт-визитку» в двух разных студиях и получить одинаковый результат. Точнее можно, если этот результат нулевой.

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

А что-же лендинги? Это понятие уже родилось мертвым. И так же имело своей целью облегчить продажи. А, говоря прямо, пропихнуть халтурный конвеер штамповки одинаковых html страниц, как разработку сайта.

И вот недавно услышал от клиента, что им нужен лендинг с двадцатью страницами. Где будет каталог, контакты, а еще страница «о компании». Как говорил герой Мета Деймона, Локи в замечательном фильме Догма, «речи, знакомые до боли».

 3 comments    6   2016   web   мысли

Еще немного о удаленной работе

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

Вот приходит сотрудник и говорит: «Ребята, хватит жить в прошлом веке. Есть скайп, почта и телефон. Я могу брать задачи и выдавать результат, зачем мне каждый день терять два часа в пробках?» Решили попробовать. Договорились, что пока не каждый день, но некоторые дни работать удаленно.

И вот первый же «тестовый» день. Мелкий вопрос мы обсуждали письменно в скайпе полтора часа (с перерывами на 3-5 минут), тогда, как очно ушла бы пара минут. Просьбу «сделать более подробное описание» в одной из задач нашего таск-менеджера сотрудник выполнить не смог, так как был страшно занят. Отчет, о котором мы договаривались так же подготовить не успел. А на следующий день пришлось потратить еще час, что бы узнать, чем занимался сотрудник. Выяснилось, что не тем.

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

Вы скажете, что я сам дурак. Ну зачем было переписываться полтора часа, когда можно позвонить? Да по тому, что сразу это не очевидно. Я не думал, что маленькая сложность может вызвать такие затруднения. Да и неправильно понятая фраза завела разговор в тупик дважды.

И я не против такой системы работы в целом. Просто считаю, что она не всем подходит. Например, про себя я знаю, что если есть одна большая задача, то без проблем смогу работать удаленно. Смогу сделать результат своей работы очевидным. Смогу показывать прогресс в недельной задаче и «прибивать гвоздями» ключевые точки. Но решить 10 мелких операционных вопросов за день удаленно я не смогу. А если смогу, то разгребать непонятки еще неделю потом.

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

Как найти копирайтера?

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

Сразу оговорюсь, что текстов нужно много (о каждом товаре) и недостаточно просто перечислить характеристики. Задача — ответить на вопросы покупателей, помочь им выбрать то, что им нужно.

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

Этого текста бы не было, если бы все пошло по плану. Мы пробовали писать подробное ТЗ. Пробовали давать более общую задачу, с надеждой, что профессионал найдет источники информации, которые ему нужны. Пробовали искать самых дорогих специалистов. И каждый раз получали от клиента недоуменный взгляд и немой (а иногда и не немой) вопрос «Что это за ерунда? Полное незнание предмета и аудитории. Такой текст выкладывать нельзя». В общем, заплатили за десяток текстов, которые ушли в ведро.

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

Тогда я написал с просьбой о совете Сергею Капличному. Огромное ему спасибо — в тот же день получил подробный ответ. Кроме прочего, в ответе присутствовал совет поискать нужного человека на бирже труда Максима Ильяхова. Всего там сейчас 25 комментариев. Из них 3 без прямых контактов. Примерно половина тех, кто написал, что не пишут технические тексты. Из оставшихся, я выбрал 6 человек и разослал письма.

Я ждал чего угодно. Огромного ценника. Сообщении о том, что проект не интересен. Сообщения о высокой загрузке. Но никак не молчания. В итоге получил всего один(!) отклик от Романа Скрупника о том, что он не может сейчас взять новый проект.

Друзья, откуда вы берете хорошие тексты на технические темы?

 6   2016   web   мысли

Абстрактная фабрика и примеси в PHP (Часть 2)

Первая часть

Однако, вернемся к нашему случаю. Допустим тут в комнату входит начитанный разработчик (НР), смотрит на код и вспоминает, что по условиям игры все светлые умеют лечить, а все темные становятся невидимыми. Добавим соответствующие методы.

<?php

abstract class Infantry {
    //общие для всей пехоты методы
    abstract public function Attack();
    abstract public function Defend();
}
abstract class Archer {
    abstract public function Shoot();
}
abstract class SiegeWeapons {
    abstract public function Fire();
}

class GoodInfantry extends Infantry {
    //Спецэфическая реализация для доброго пехотинца
    public function Attack();
    public function Defend();
    
    public function Treat();
}
class GoodArcher extends Archer{
    public function Shoot();
    
    public function Treat();
}
class GoodSiegeWeapons extends SiegeWeapons{
    public function Fire(); 
    
    public function Treat();
}

class EvilInfantry extends Infantry{
    //Спецэфическая реализация для злого пехотинца
    public function Attack();
    public function Defend();
    
    public function Invisible();
}
class EvilArcher extends Archer{
    public function Shoot();
    
    public function Invisible();
}
class EvilSiegeWeapons extends SiegeWeapons{
    public function Fire();
    
    public function Invisible();
}

abstract class AbstractFactory
{
    abstract public function createInfantry();
    abstract public function createArcher();
    abstract public function createSiegeWeapons();
}

class GoodFactory extends AbstractFactory
{
    /**
     * @return Infantry
     */
    public function createInfantry()
    {
        return new GoodInfantry();
    }

    /**
     * @return Archer
     */
    public function createArcher()
    {
        return new GoodArcher();
    }

    /**
     * @return SiegeWeapons
     */
    public function createSiegeWeapons()
    {
        return new GoodSiegeWeapons();
    }
}

class EvilFactory extends AbstractFactory
{
    /**
     * @return Infantry
     */
    public function createInfantry()
    {
        return new EvilInfantry();
    }

    /**
     * @return Archer
     */
    public function createArcher()
    {
        return new EvilArcher();
    }

    /**
     * @return SiegeWeapons
     */
    public function createSiegeWeapons()
    {
        return new EvilSiegeWeapons();
    }
}

Код стал не таким красивым по тому, что появились методы, которые приходится копировать. В php нет множественного наследования и приходится выбирать наследоваться белому лучнику от белых или от лучников. Мы априори выбрали второй вариант и теперь думаем, как сделать наш код красивее, а его поддержку удобнее. НР предлагает использовать примеси (trait), которые появились в php 5.4. Вынесем обшие методы в примесь.

<?php

abstract class Infantry {
    //общие для всей пехоты методы
    abstract public function Attack();
    abstract public function Defend();
}
abstract class Archer {
    abstract public function Shoot();
}
abstract class SiegeWeapons {
    abstract public function Fire();
}

trait Good {
    public function Treat();
}

trait Evil {
    public function Invisible();
}

class GoodInfantry extends Infantry {
    use Good;
    
    //Спецэфическая реализация для доброго пехотинца
    public function Attack();
    public function Defend();
}
class GoodArcher extends Archer{
    use Good;
    public function Shoot();
}
class GoodSiegeWeapons extends SiegeWeapons{
    use Good;
    public function Fire();
}

class EvilInfantry extends Infantry{
    use Evil;
    
    //Спецэфическая реализация для злого пехотинца
    public function Attack();
    public function Defend();
}
class EvilArcher extends Archer{
    use Evil;
    public function Shoot();
}
class EvilSiegeWeapons extends SiegeWeapons{
    use Evil;
    public function Fire();
}

abstract class AbstractFactory
{
    abstract public function createInfantry();
    abstract public function createArcher();
    abstract public function createSiegeWeapons();
}

class GoodFactory extends AbstractFactory
{
    /**
     * @return Infantry
     */
    public function createInfantry()
    {
        return new GoodInfantry();
    }

    /**
     * @return Archer
     */
    public function createArcher()
    {
        return new GoodArcher();
    }

    /**
     * @return SiegeWeapons
     */
    public function createSiegeWeapons()
    {
        return new GoodSiegeWeapons();
    }
}

class EvilFactory extends AbstractFactory
{
    /**
     * @return Infantry
     */
    public function createInfantry()
    {
        return new EvilInfantry();
    }

    /**
     * @return Archer
     */
    public function createArcher()
    {
        return new EvilArcher();
    }

    /**
     * @return SiegeWeapons
     */
    public function createSiegeWeapons()
    {
        return new EvilSiegeWeapons();
    }
}

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

P.S. Мне очень хотелось бы услышать критику моего изложения общеизвестных вещей и моего варианта использования примесей от коллег. Я открыл для себя паттерны проектирования пару лет назад, но использовать их начал только сейчас.
И если будут у кого-то вопросы, то с радостью попробую ответить.

Абстрактная фабрика и примеси в PHP (Часть 1)

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

Мне хотелось бы описать связь между различными практиками программирования, которые я встречал в своих проектах. Если опыт будет удачным, то попробую сделать цикл подобных постов.

#Джуниор-разработчик и игра
Допустим, мы хотим написать браузерную игру, в которой «добро» борется со «злом». Пусть у обеих сторон есть пехота, лучники и осадные орудия. Для начала посадим за IDE джуниора. Через некоторое время мы, скорее всего, увидим следуюшие классы:

class GoodInfantry{}
class GoodArcher{}
class GoodSiegeWeapons{}

class EvilInfantry{}
class EvilArcher{}
class EvilSiegeWeapons{}

#Опытный разработчик и абстрактная фабрика

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

ОР знает, что «добрая» сторона обязательно будет иметь свои особенности, отличные от «злой». При этом так же понятно, что пехота с обоих сторон так же будет иметь нечто общее. Таким образом каждый юнит фактически должен унаследовать какие-то свойства от своей стороны, а какие-то от своего типа.

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

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

Вспомним так же, что все пехотинцы будут наследовать класс Infantry. И подумаем о том, что фабрики, вероятно, будут иметь одинаковый набор методов, а значит хорошо бы им унаследовать единый абстрактный класс. Такой подход гарантирует нам, что ОР, создав абстрактные классы может идти курить и доверить написание реализации джуниору, ведь любая ошибка в реализации будет сразу видна. То, что у нас получилось, фактически, и есть паттерн Абстрактная фабрика. стрелки без подписи «создает» обозначают наследование.

Такая структура — пример хорошего кода для общего случая создания групп связанных обьектов. То есть всегда, когда у нас есть необходимость создавать экземпляры классов не в ручном режиме и когда у нас есть группы связанных объектов (в нашем случае все светлые и все темные связаны) паттерн подходит. Удобно то, что он раширяется, как горизонтально (можно добавлять еще стороны, кроме света и тьмы), так и вертикально без переписывания кода многократно.

<?php

abstract class Infantry {
    //общие для всей пехоты методы
    abstract public function Attack();
    abstract public function Defend();
}
abstract class Archer {
    abstract public function Shoot();
}
abstract class SiegeWeapons {
    abstract public function Fire();
}

class GoodInfantry extends Infantry {
    //Спецэфическая реализация для доброго пехотинца
    public function Attack();
    public function Defend();
}
class GoodArcher extends Archer{
    public function Shoot();
}
class GoodSiegeWeapons extends SiegeWeapons{
    public function Fire();
}

class EvilInfantry extends Infantry{
    //Спецэфическая реализация для злого пехотинца
    public function Attack();
    public function Defend();
}
class EvilArcher extends Archer{
    public function Shoot();
}
class EvilSiegeWeapons extends SiegeWeapons{
    public function Fire();
}

abstract class AbstractFactory
{
    abstract public function createInfantry();
    abstract public function createArcher();
    abstract public function createSiegeWeapons();
}

class GoodFactory extends AbstractFactory
{
    /**
     * @return Infantry
     */
    public function createInfantry()
    {
        return new GoodInfantry();
    }

    /**
     * @return Archer
     */
    public function createArcher()
    {
        return new GoodArcher();
    }

    /**
     * @return SiegeWeapons
     */
    public function createSiegeWeapons()
    {
        return new GoodSiegeWeapons();
    }
}

class EvilFactory extends AbstractFactory
{
    /**
     * @return Infantry
     */
    public function createInfantry()
    {
        return new EvilInfantry();
    }

    /**
     * @return Archer
     */
    public function createArcher()
    {
        return new EvilArcher();
    }

    /**
     * @return SiegeWeapons
     */
    public function createSiegeWeapons()
    {
        return new EvilSiegeWeapons();
    }
}

Причем же тут примеси? Продолжение следует.

Earlier Ctrl + ↓