воскресенье, 14 августа 2016 г.

Web Tools: Gulp

Web Tools: Gulp

Objectives and Outcomes

In this exercise, you will learn to use Gulp, the task runner. You will install Gulp CLI and install Gulp plugins using NPM. Thereafter you will configure a Gulp file with a set of tasks to build and serve your web project. At the end of this exercise, you will be able to:
  • Install Gulp CLI and Gulp plugins in your project
  • Configure a Gulp file with a set of tasks to build a web project from a source, and serve the built project using a server.

Clean node_modules Folder

  • Go to the node_modules folder in conFusion, and delete all the folders/files there. We will not be using the Grunt modules existing there for this exercise.

воскресенье, 7 августа 2016 г.

Some useful Grunt plagin.

I 'm going to poste here some useful plagin for web-app.

Что такое GruntJS?

Что такое GruntJS


Большинство JS разработчиков уже используют какие-то инструменты компоновки для своих разработок, даже если не знают или не используют этот термин. Они объединяют файлы при разработке, уменьшают код JavaScript-а, чтобы ускорить загрузку страниц и конвертировать Sass, или уменьшают количество файлов в CSS для браузера, и много чего другого. Чаще всего это разные инструменты, что есть не очень удобно. 

Grunt помогает управлять всеми этими шагами в одном месте и организовать сторонние компоненты.

Grunt - инструмент для сборки javascript проектов. Установка

Grunt — это инструмент для сборки javascript проектов из командной строки с использованием задач. В этой статье рассмотрены основы Grunt, его установка и использование. 

Что такое npm, еще одна полезная статья.

Еще одна очень полезная статья про npm.

NPM - named pipe mechanism

NPM - пакетный менеджер node.js, с помощью которого можно управлять модулями и зависимостями.
NPM

воскресенье, 14 февраля 2016 г.

Принцип разделения интерфейса

Принцип разделения интерфейса

Формулировка: клиенты не должны зависеть от методов, которые они не используют

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


Примеры
Лишняя абстракция в наследовании
Проблема
Речь идет о базовых классах, которые вынуждают своих наследников знать и делать слишком много. Печально известный пример – класс MembershipProvider. Для использования этого класса нужно реализовать 27 абстрактных методов и свойств.
Рассмотрим пример из жизни. Это, конечно, не скопированный код один в один, но очень приближено к тому, что было. Есть базовый класс для аудиторов EntityAuditor. Он унаследован от класса AuditorBase, который предоставляет ORM, и реализует методAuditEntityFieldSet этого базового класса. Также EntityAuditor добавляет свой абстрактный метод CreateLogRow, который используется в методе AuditEntityFieldSet и должен быть переопределен в конкретных реализациях:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class EntityAuditor : AuditorBase
{
    public override void AuditEntityFieldSet(IEntityCore entity, int fieldIndex, object originalValue)
    {
        // ...
         
        CreateLogRow(...
         
        // ...
    }
  
    protected abstract LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity);
}
После этого начинаем реализовывать наследников. Например, создадим аудитор для класса Product:
?
1
2
3
4
5
6
7
public class ProductAuditor : EntityAuditor
{
    protected override LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity)
    {
        // ...
    }
}
Сейчас добавлению наследников ничего не мешает. Теперь представим, что в методе AuditEntityFieldSet понадобилась дополнительная логика, при которой нужно вызвать метод UpdateDuplicates. Этот метод также является абстрактным и требует реализации в наследниках:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public abstract class EntityAuditor : AuditorBase
{
    public override void AuditEntityFieldSet(IEntityCore entity, int fieldIndex, object originalValue)
    {
        // ...
         
        CreateLogRow(...
  
        UpdateDuplicates(...
         
        // ...
    }
  
    protected abstract LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity);
  
    protected abstract void UpdateDuplicates(IEntityCore entity, decimal fieldId, object current);
}
  
  
public class ProductAuditor : EntityAuditor
{
    protected override LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity)
    {
        // ...
    }
  
    protected override void UpdateDuplicates(IEntityCore entity, decimal fieldId, object current)
    {
        // реализация
    }
}
  
public class AccountAuditor : EntityAuditor
{
    protected override LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity)
    {
        // ...
    }
  
    protected override void UpdateDuplicates(IEntityCore entity, decimal fieldId, object current)
    {
        // здесь ничего нет!
    }
}
EntityAuditor требует реализации метода UpdateDuplicates даже в тех наследниках, где он не нужен, как, например, в AccountAuditor. Проблема в том, что частный случай (UpdateDuplicates), который используется только в половине наследников, мы сделали общим, т.е. обязательным для всех наследников нашего EntityAuditor. Получается, что чем больше наследников будет у EntityAuditor, тем больше бесполезного кода мы будем писать, тем больше наследники будут знать лишнего о своем базовом классе. Это может сильно помешать нам в дальнейшем при рефакторинге или изменении логики в EntityAuditor.

Решение
В данном случае решение очень простое. Если наследникам класса EntityAuditor не нужна функция UpdateDuplicates, то и реализовывать ее они не должны. В С# это делается простой заменой ключевого слова abstract на virtual:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class EntityAuditor : AuditorBase
{
    public override void AuditEntityFieldSet(IEntityCore entity, int fieldIndex, object originalValue)
    {
        // ...
         
        CreateLogRow(...
  
        UpdateDuplicates(...
         
        // ...
    }
  
    protected abstract LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity);
  
    protected virtual void UpdateDuplicates(IEntityCore entity, decimal fieldId, object current)
    {
    }
}
Теперь наследники отчищены от ненужной связности:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ProductAuditor : EntityAuditor
{
    protected override LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity)
    {
        // ...
    }
  
    protected override void UpdateDuplicates(IEntityCore entity, decimal fieldId, object current)
    {
        // реализация
    }
}
  
public class AccountAuditor : EntityAuditor
{
    protected override LogRowEntity CreateLogRow(decimal? fieldId, string oldValue, string newValue, IEntityCore entity)
    {
        // ...
    }
}
В других случаях могут быть другие решения этой проблемы. Если у вас есть примеры из практики, давайте разбирать их в комментариях.

«Жирный» интерфейс
Проблема
У нас есть интерфейс ISpecification. С помощью него мы можем узнать подходит ли продукт заявке – метод IsSuitable и является ли поле продукта измененным – методIsFieldChanged:
?
1
2
3
4
5
6
public interface ISpecification
{
    bool IsSuitable(Product realty, Offer offer);
     
    bool IsFieldChanged(Product oldValue, Product newValue);
}
Чем является наш модуль для сторонних клиентов? Он является набором интерфейсов, с помощью которых модуль может быть использован. В данном случае проблема заключается в том, что клиентом первой функции является консольное приложение, а второй – класс хранилища:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public interface ISpecification
{
    bool IsSuitable(Product realty, Offer offer);
  
    bool IsFieldChanged(Product oldValue, Product newValue);
}
  
/// <summary>
/// Хранилище для продуктов
/// </summary>
public class ProductRepository : IRepository<product>
{
    public void Save(Product product)
    {
        // ...
  
        specification.IsFieldChanged(...
  
        // ...
    }
}
  
/// <summary>
/// Программа расчета подходящих продуктов
/// </summary>
public class Program
{
    public static void Main(string[] args)
    {
        // ...
  
        specification.IsSuitable(...
    }
}
</product>
Допустим, что мы уже написали несколько конкретных спецификаций:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class PriceSpecification : ISpecification
{
    public bool IsSuitable(Product realty, Offer offer)
    {
        // ...
    }
  
    public bool IsFieldChanged(Product oldValue, Product newValue)
    {
        // ...
    }
}
  
...
Уже видно, что полученный результат нас не устраивает. При рефакторинге или изменении логики в консольном приложении и методе IsSuitable, нам придется затронуть все классы, которые реализовали интерфейс ISpecification. Например, представьте, что будет если в метод IsSuitable мы захотим добавить еще один параметр? А если конкретных спецификаций накопилось уже с десяток? Основная мысль в том, что теперь различные части системы зависят друг от друга, хоть и косвенно. Консольное приложение зависит от логики хранилища и наоборот.

Решение
Главное правило в данном случае звучит так: если клиенты интерфейса разделены, то и интерфейс должен быть разделен соответствующим образом.
После разделения получаем:
?
1
2
3
4
5
6
7
8
9
public interface ISpecification
{
    bool IsSuitable(Product realty, Offer offer);
}
  
public interface IChangeFieldDetector
{
    bool IsFieldChanged(Product oldValue, Product newValue);
}
Теперь консольное приложение работает интерфейсом ISpecification, а хранилище работает с интерфейсом IChangeFieldDetector. Проблема с зависимостью решена.
Кроме этого, мы решили еще и проблему с наследниками первой реализацииISpecification. Теперь класс может реализовывать только один интерфейс, за счет чего его на много проще поддерживать:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class PriceSpecification : ISpecification
{
    public bool IsSuitable(Product realty, Offer offer)
    {
        // ...
    }
}
  
class PriceChangeFieldDetector : IChangeFieldDetector
{
    public bool IsFieldChanged(Product oldValue, Product newValue)
    {
        // ...
    }
}
Вся информация взята с этого блога.