пятница, 28 декабря 2018 г.

Принцип Открытости/Закрытости


Введение
Принцип открытости закрытости (OCP) говорит о том, что элементы программного обеспечения (такие как классы, модули, функции и т.д.) должны быть открыты для расширения, но закрыты для модификации. Это значит, что подобные элементы позволяют расширять свое поведение без модификации исходного кода.
Класс закрыт, так как он может быть скомпилирован, хранится в библиотеке, и использоваться клиентскими классами. Но также он открыт, так как любой новый класс может использовать его в качестве родителя, и добавлять новые возможности. Когда наследуемый класс объявлен, то нет нужды изменять оригинал или беспокоить его клиентов.


Практические примеры
Нарушение OCP
Давайте скажем, что у нас есть класс Rectangle. Как большинство прямоугольников которые нам встречались, у него его высота и ширина.


     
class Rectangle

{
    public $width;
    public $height;
}

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





Class AreaCalculator

{
    /**
     * Calculate the total area of the rectangles.
     *
     * @param  Illuminate\Support\Collection  $rectangles
     * @return float
     */
    public function Area($rectangles)
    {
        $area = 0;
        $rectangles->each(function ($rectangle) use (&$area) {
            $area += ($rectangle->width * $rectangle->height);
        });
        return $area;
    }
}

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


class
AreaCalculator

{
    /**
     * Calculate the total area of the shapes.
     *
     * @param  Illuminate\Support\Collection  $shapes
     * @return float
     */
    public function Area($shapes)
    {
        $area = 0;
        $shapes->each(function ($shape) use (&$area) {
            switch (gettype($shape)) {
                case "Rectangle":
                    $area += ($shape->width * $shape->height);
                    break;
                case "Circle":
                    $area += (PI * pow($circle->radius, 2));
                    break;
            }
        });
        return $area;
    }
}

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

Соблюдение OCP
Вот самый простой способ для этого. Мы знаем что для каждой фигуры мы хотим вычислить площадь. Для того что бы алгоритм работал хорошо, мы можем создать интерфейс, который назовем Shape, таким образом все фигуры должны поддерживать метод getArea, и мы можем сказать с уверенностью, что наш код не словается и его можно расширять.


interface
Shape

{
    /**
     * Calculate the area of the shape.
     *
     * @return mixed
     */
    public function getArea();
}

class Rectangle implements Shape
{
    public $width;
    public $height;

    public function getArea()
    {
        return $this->width * $this->height;
    }
}

class Circle implements Shape
{
    public $radius;

    public function getArea()
    {
        return pow($this->radius, 2) * PI;
    }
}

/**
     * Calculate the total area of the shapes.
     *
     * @param  Illuminate\Support\Collection  $shapes
     * @return float
     */
    public function Area($shapes)
    {
        $area = 0;
        $shapes->each(function ($shape) use (&$area) {
           $area += $shape->getArea();
        });
        return $area;
    }
}
Теперь наш код представленный выше будет всегда работать с любым элементом который реализует интерфейс Shape.
Это демонстрирует принцип открытости/закрытости – код закрыт для модификации, посколько основная функциональность уже написана, но открыт дя расширения, поскольку теперь мы можем передать любую фигуру, которая реализует интерфейс Shape.
Выводы
Принцип открытости/закрытости разработан для того что бы вы писали ваш код в такой манере, что основная функциональность была бы однозначной и локаничной, насколько это возможно.
Пример показанный выше просто берет коллекцию фигур и вычисляет их площадь. Нам не нужно исследовать эти медоты и менять их логику вычисления площади, но мы можем добавить новые фигуры, и они будут обработаны все без исключения.

среда, 21 ноября 2018 г.

Справочник по современной разработке на JavaScript


Вы занимались разработкой REST API на протяжении последних 5 лет. Или оптимизировали поиск для гигантской базы данных вашей организации. Может быть вы писали программное обеспечение для микроволновки? Так или иначе, прошло уже достаточно времени с тех пор когда вы использовали Prototype.js для того что бы сделать нормальный ООП для браузера. И сейчас вы решили что пора заново прокачать ваши навыки для фронт-енда. Вы осмотрелись и увидели примерно вот такую картинку перед собой.
Конечно же вы не ищете Вальдо. Вы ищете 25 случайных людей но даже не знаете как их зовут. Такое чувство переполнения настолько распространено в мире JavaScript, что на самом деле существует термин “Усталось JavaScript”. Если у вас будет немного времени посмеятся по этому поводу, то вот этот пост описывает феномен просто великолепно.
Но у вас же нету на это время сейчас. Вы в большом лабиринте и вам нужен справочник. Я сделал его для вас.
Для начало небольшое отречение: Список представленный ниже предназанчен для того что бы вы могли сразу приступать к работе не тратя времени на анализ возможных решений которые в приципе подходят для ваших задач. Я полагаюсь на некоторые инстументы которые могут работать вместе для фронт-енд разработки вцелом. Это позволит вам работать достаточно приятно с вашим окружением и избавит вас от всевозможных головных болей. Как только вы с этим разберетесь, вы будете способны сами решать какие звено из вашего стека вы можете заменить на что то более подходящее.

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

 Управление пакетами
 - Проблема: требуется организовать ваш проект и все ваши зависимости
 - Решение: NPM и Yarn
- Причина: NPM – это по сути менеджер пакетов по умолчанию. Yarn работает поверх NPM но оптимизирует разрешение зависимостей и удерживает блокировку файла для конкретной версии вашей библиотеки (использует в тандеме с семантикой версионности NPM, они не исключают а дополняют друг друга)
 - Альтернативы: Да в принципе и нету
Аромат JavaScript
 - Проблема: проблемы старых версий JavaScript
 - Решение: ES6
 - Причина: Это будущее JavaScript которое вы можете использовать уже сейчас. Включает много полезных вещей которые есть и в других языках программирования уже долгое время. Интересные новые возможности: стрелочные функции, импорт/экспорт модуле, де-структуризация, строковые темплейты, let & const, генераторы, promise. Если вы Python-разработчик вы почевствуете себя как дома.

 - Альтернативы: TypeScript, CoffeeScript, PureScript, Elm
Преобразования
- Проблема: Есть много браузеров, которые по прежнему не реализуют ES6. Поэтому вам нужна программа, способная преобразовать (transpile) ваш современный код ES6 на эквивалетный, который поддерживается более старыми браузерами.
 - Решение: Babel
 - Причина: Работает прекрасно и по сути является стандартом. Преобразует серверную сторону.
 - Альтернативы: Traceur

 - Примечание: Вы будете использовать загрузчик-babel от WebPack (более подробно об этом позже). Вам нужно делать преобразования если вы планируете использовать разные версии JavaScript.
Анализаторы
- Проблема: существуют миилионы способов написать код на JavaScript и очень сложно добится последовательности. Поэтому некоторые ошибки можно предотвратить с помощью анализаторов (linter).
 - Решение: ESLint
 - Причина: Великолепное понимание кода и очень хорошая возможности конфигурирования. Предустановка Airbnb – это все что вам нужно для того что бы начать работу. Действительно помогает писать правильно.

 - Альтернативы: JSLint
Пакетирование
 - Проблема: Вы больше не используете файл или последовательность файлов. Зависимости должны быть разрешены и загружены корректно.
 - Решение: Webpack
 - Причина: Хорошо конфигурируется. Может загружать все виды зависимостей и настроек. Поддерживает плагины. Практически пакетировщик по умолчанию для проектов React.
 - Альтернативы: Browserify
 - Недостатки: По началу может быть сложным для конфигурирования

 - Примечание: Вам потребуется потратить некоторое время для того что бы как следует разобраться как все работает. Вы изучите основные загрузчики: babel-loader, style-loader, css-loader, file-loader, url-loader.

Тестирование
- Проблема: Ваше приложение хрупкое. Оно может сломаться. Вам нужно его тестировать.
 - Решение: Jest
 - Причина: Батарейки включены, тестирование снимков, может определить тесты по вашим изменениям и выполнить только их, хорошо работает с одним репозиторием, изначально появился с CRA – который разработывалмя Facebook.
 - Альтернативы: Jasmine, Mocha, Tape
Управление состоянием / UI фреймворк
 - Проблема:  Это одна и самых больших вопросов. Одностраничные приложния становятся все более и более сложными. Изменяемое состояние особенно затруднительно.
 - Решение: React & Redux
 - Причины использования React: Удивительный сдвиг парадигмы, разрушающий много догм, старых как веб, и делает это прекрасно. Лучшее разделение проблем по сравнению с традиционным подходом: вместо разделении по технилогии (HTML/CSS/JavaScript) вы разделяете вещи по их функциональности (сплоченые компоненты). Выш UI это чистая функция вашего состояния.
 - Причины использования Redux: Если ваше приложение не тривиально, то вам необходим способ управлять состоянием (иначе вам придется делать гимнастику для ваших компонентов и разговаривать с каждым из них, изучать взаимодействие между компонентами и сталкиваться с ограничениями). Любое руководство по web описывает странный и астрактный паттерн Flux и его реализации. Избавьте себя от всей этой информации и испольуйте Redux. Он реализует паттерн в самой простой манере. Даже фейсбук использует его. Дополнительная прелесть: перегрузка и хранение состояния приложения, путешествие во времени, возможность тестирования.
 - Альтернативы: Angular2, Vuew.js
 - Предупреждение: Первое время у вас возможно появится желание сделать что нибудь со своими глазами что бы развитеть синтаксис JSX с которым приходится тут работать. Сопротивляйте соблазну найти форум и кричать от возмущения. Это всего лишь когнитивный диссонанс вызванный годами воспитания. Смешиваение HTML, JavaScript и CSS в одном файле на самом деле прекрасно. Поверьте мне! – Достижение разблокировано для использования двух кривых ссылок в одной пуле.
Манипуляции с DOM и анимация
 - Проблема: Знаете что? Вам по прежнему иногда нужно что то быстро починить и для это нужно использовать селекторы и выполнять операции непосредственно с DOM.
 - Решение: Чистый ES6 или JQuery
- Причина: Да, JQuery живет и здравствует. React и JQuery не исключают друг друга. Хотя имейте ввиду что желательно все нужно делать с использованием чистого ReactquerySelector). Добавление JQuery увеличит немного размер вашего бандла. Вообще то использовать JQuery поверх React – признак плохого подхода и вам следует этого по возможности избегать. Но если вы видите что стандартными средствами добится желаемого невозможно, например, вы имеет дело с некоторым кросс-браузерным фиксом, то JQuery может спасти ситуацию.
 - Альтернативы: Dojo (он все еще существует?)
Стилизация
 - Проблема: Теперь когда у вас есть модули, вы наверняка захотите сделать их самодостаточными, что бы можно было повторно использовать. Стилизация компонентам должна быть такая же мобильная как и сам компонент.
 - Решение: CSS модули
 - Причина: Насколько я люблю возможность описывать стили в коде (и часто это использую), настолько же я понимаю ограниченность данного подхода. Да, это абсолютно нормально использовать стили в коде в React, но вы не можете указывать селекторы для псевдо-классов (например :hover), которые очень важны в некоторых случаях.   
 - Альтернатива: Инлайн стили. Что я люблю в инлайн стилях в React, это то что они позволяют обращаться со стилями также как и с другими JavaScript объектами, и позволяют их обрабатывать программно. Кроме того они существуют в том же файле что и компонент, что делать процесс поддержки супер удобным. Некоторые люди по прежнему говорят о преимуществах SASS/SCSS/LESS. Эти языки требуют дополнительного шага при построении и не являются такими же мобильными как модули или инлайн CSS но вместо с тем они весьма эффективны.
О макетах
Проекты-макеты (boilerplate) такие как Create React App могут решить некоторые из проблем описанных выше. Когда вы используете макет, вы по прежнему должны понимать что  происходит под капотом – иначе вы никогда не будете контролировать свое приложение.
Вот и все
Теперь у вас есть метрическая штука для дальнейшего изучения. По крайней мере вам не придется занимать вопросами выбора. Вам кажется я что то пропусил? Я где то потерял мячик? Оставляйте свои коментарии или пишите мне в твиттер @bug_factory.