Coding like a sex

61
Максим Аршинов IT–гуру, μISV Обрел просветление в разработке ПО

description

Coding like a sex

Transcript of Coding like a sex

Page 1: Coding like a sex

Максим Аршинов

IT–гуру, μISVОбрел просветление в разработке ПО

Page 2: Coding like a sex

Программирование – это как секс

• DDD• CQRS• Event Sourcing• Эволюционный рефакторинг• Горизонтальное масштабирование и облачная архитектура• Эффективное взаимодействие между командами

Один раз ошибешься, а потом поддерживать всю жизнь

Page 3: Coding like a sex

Программирование – это как секс

А проектирование – это как петтинг

Page 4: Coding like a sex

Распределенные и/или нагруженные бизнес-приложения

• Система продажи билетов• Трейдинговая площадка• Баннерная сеть для порно-сайтов

Page 5: Coding like a sex

Проблемы

• Специфическая терминология• Сложная предметная область, не

очевидные бизнес-правила• Бизнес-логика может часто меняться• Высокая и/или неравномерная нагрузка

Page 6: Coding like a sex

Цели разработчика

• Сохранять темпы разработки• Повысить bus factor• Обеспечить горизонтальное

масштабирование системы

Page 7: Coding like a sex

«Архитектура»

• Что это такое?• Чем отличается от «инфраструктуры»?

Page 8: Coding like a sex

Всему свое время

Page 9: Coding like a sex

Трёхуровневая архитектура

UI

Business Rules

Data Access Layer

Page 10: Coding like a sex

Metal Gear

• S – Single responsibility principle• O – Open/closed principle• L – Liskov substitution principle• I – Interface segregation principle• D – Dependency inversion principle

Page 11: Coding like a sex

Как структурировать бизнес-логику?

Page 12: Coding like a sex

Как структурировать бизнес-логику?

• DDD (Domain Driven Design)• Инфраструктура – не домен!• Persistence ignorance• Aggregation Roots• Anemic Domain Model Rich Models• Active Record Unit of Work• Controller Service Layer• using(var uow = new UoW()), Singleton, Registry

IOC

Page 13: Coding like a sex

Единый язык (Ubiquitous language)

ticket.State = TicketState.Sold; ticketRepository.Update(ticket); var ticket = cashdesk.Sale (seat);

Page 14: Coding like a sex

DDD vs OOP

• Гвоздь суше воды• DDD про отделение мух от котлет домена от

инфраструктуры• DDD про взаимодействие с бизнесом

Page 15: Coding like a sex

Entity

• Есть Id• У вас есть, у гвоздя – нет• Наличие или отсутствие Id может зависеть

от контекста

Page 16: Coding like a sex

CRUD

Page 17: Coding like a sex

Что не так с Repository?

public interface IRepository<T>{

T GetById(int id);IEnumerable<T> GetAll();

bool Add(T entity);bool Remove(T entity);

}

Page 18: Coding like a sex

Что не так с Repository?class AccountRepository : IRepository<Account>{

public Account GetByName(string name);public Account GetByEmail(string email);

public Account GetByAge(int age);

// ...

public Account GetByAreYouFuckingKiddingMe(SomeCriteria c);}

Page 19: Coding like a sex

Что не так с Repository?

• 100500 методов, в т.ч. в интерфейсе IAccountRepository

• Не удобно тестировать• Многа-букаф, чтобы написать новый метод• Приходится прокидывать сигнатуры в

сервисный слой• Рефакторинг затруднен

Page 20: Coding like a sex

Ок, я понял

public interface IRepository<T>{

T GetById(int id);//во имя луныIQueryable<T> GetAll();

bool Add(T entity);bool Remove(T entity);

}

Page 21: Coding like a sex

Что не так с Repository?

repo.GetAll().Where(a => a.IsDeleted = false);

repo.GetAll().Where(a => a.IsDeleted = false &&

a.Balance > 0);

repo.GetAll().Where(a => a.CreationDate < getCurrentDate());

Page 22: Coding like a sex
Page 23: Coding like a sex

Specification Pattern

public interface ISpecification<T>{

bool IsSatisfiedBy(T candidate);}

Page 24: Coding like a sex

Expression Specification

public interface ISpecification<T>{

Expression<Func<T, bool>> IsSatisfiedBy();}

Page 25: Coding like a sex

Стало лучшеIEnumerable<T> GetBySpecifications(

IEnumerable<ISpecification<T>> specifications,params IFetchStrategy<T>[] fetchStrategies);

Page 26: Coding like a sex

FilterPolicy (Value Object)public class FilterPolicy<T>{

public IEnumerable<ISpecification<T>> Specifications { get; private set; }public IEnumerable<IFetchStrategy<T>> FetchStrategies { get; private set; }

public FilterPolicy( IEnumerable<ISpecification<T>> specifications, IEnumerable<IFetchStrategy<T>> fetchStrategies) { Specifications = specifications; FetchStrategies = fetchStrategies; }}

Page 27: Coding like a sex

Более подробно о Value Object

• Не Entity• Immutable• Value - не Reference

Page 28: Coding like a sex

Защитное программирование на страже инварианта

public class FilterPolicy(IEnumerable<ISpecification<T>> specifications,IEnumerable<IFetchStrategy<T>> fetchStrategies)

{if(specifications == null) throw new ArgumentException(

"specifications can\'t be null", "specifications");if(fetchStrategies == null) throw new ArgumentException(

"fetchStrategies can\'t be null", "fetchStrategies");

Specifications = specifications;FetchStrategies = fetchStrategies;

}

Page 29: Coding like a sex

Composite

• OrSpecification• AndSpecification• ActiveAccountSpecification …

Page 30: Coding like a sex

Compositepublic class OrSpecification<T> : ISpecification<T>{

private readonly ISpecification<T>[] _specs;

public OrSpecification(params ISpecification<T>[] specs){

if(specs.Length == 0) throw new ArgumentException("specs length must be > 0", "specs");

_specs = specs;}

public Expression<Func<T, bool>> IsSatisfiedBy(){

throw new NotImplementedException();}

}

Page 31: Coding like a sex

Декларативный стиль > императивного

• DSL• Функциональное программирование,

монады• Мета-программирование и AOP, Code

Contracts• Кодогенерация• Динамическая компиляция

Page 32: Coding like a sex

Монада Maybestring postCode;if (person != null){

if (HasMedicalRecord(person) && person.Address != null){

CheckAddress(person.Address);if (person.Address.PostCode != null)postCode = person.Address.PostCode.ToString();elsepostCode = "UNKNOWN";

}}

public static TResult With<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)where TResult : class where TInput : class

{if (o == null) return null;return evaluator(o);

}

string postCode = this.With(x => person) .With(x => x.Address) .With(x => x.PostCode)

.Return(x => "UNKNOWN");

Page 33: Coding like a sex

Conventions > configuration

[DisplayName("Категории продуктов")][DataContract]public class ProductCategory : EntityBase{

[Display(Name = "Название")][Column(TypeName = "VARCHAR"), StringLength(255), Required][DataMember(IsRequired = true)]public string Name { get; set; }

public override string ToString(){

return Name;}

}

Page 34: Coding like a sex

Иногда лучше по-быстрому, чем SRP, если знаешь как будешь рефакторить

public class ProductCategoryController : AdminControllerBase<ProductCategory>{

public ProductCategoryController(DbContext dbContext) : base(dbContext){}

}

Например, INotifyPropertyChanged

Page 35: Coding like a sex

Дай разработчику дефолтное поведение и он будет штамповать формочки весь день. Научи как переопределить

его…

• Во FreeBSD ты можешь настроить все, и ты %$@ть будешь настраивать все

• ASP.NET MVC• WCF

Page 36: Coding like a sex

Разделяй и властвуй

• Module aka Package• Onion - архитектура• SOA

Page 37: Coding like a sex

Bounded Context

• Anti-Corruption Layer• Контекстов может быть много

Page 38: Coding like a sex

Anti-Corruption Layer. How To?class Messy{

String concat(String param, String str) { /* ... */ }bool contains(String param, String s) { /* ... */ }bool isEmpty(String param) { /* ... */ }bool matches(String param, String regex) { /* ... */ }bool startsWith(String param, String prefix) { /* ... */ }

}

class Reasonable // anti-corruption layer{

String param;Messy messy = new Messy();

Reasonable(String param){

this.param = param; }

String concat(String str) { return messy.concat(param, str); }bool contains(String s) { return messy.contains(param, s); }bool isEmpty() { return messy.isEmpty(param); }bool matches(String regex) { return messy.matches(param, regex); }bool startsWith(String prefix) { return messy.startsWith(param, prefix); }

}

Page 39: Coding like a sex

Разгрузочный слайд

Page 40: Coding like a sex

Shared DB

Page 41: Coding like a sex

Реляционная база данных – узкое место

Page 42: Coding like a sex

Оптимизация БД

• Убираем ORM для лучшей оптимизации• Оптимизируем индексы• Убираем весь код выборки в хранимые

процедуры• Строим/оптимизируем индексы• Денормализуем данные (когда ничего не

помогает)

Page 43: Coding like a sex

Стратегии денормализации

• Убрать JOIN’ы, добавить денормализованные колонки

• Создаем отдельные таблицы/view• Хранилище с «плоскими» данными

Page 44: Coding like a sex

Теорема CAP

• Consistency (согласованность данных)• Availability (доступность)• Partition tolerance (устойчивость к

разделению)

Page 45: Coding like a sex

2 из 3

• Consistency + Availability (традиционные СУБД)• Consistency + Partition tolerance

(пессимистические блокировки)• Availability + Partition tolerance (NOSQL-решения)

Page 46: Coding like a sex

CQS

• Command–query separation• Commands – update state (C, U, D)• Queries – fetch results (R)

Page 47: Coding like a sex

CQS – зачем?

• Отсутствие сайд-эффектов• Поддержка декларативного стиля (WCF)• Горизонтальное масштабирование

Page 48: Coding like a sex

Query Object как альтернатива Repository

• Абстракция от ORM (но велосипед)• Не надо городить кучу IEntityRepository• Просто тестировать• SRP

Page 49: Coding like a sex

QueryObject и QueryBuilderpublic interface IQueryFor<out T>{

T With(ISpecification<T> specification)T ById(int id);IEnumerable<T> All();

}

public interface IQueryBuilder{

IQueryFor<TResult> For<TResult>();}

var account = queryBuilder.For<Account>().With(new LoginSpecification("Вася")).All();

Page 50: Coding like a sex

Command Pattern

public interface ICommand{

void Execute();}

Page 51: Coding like a sex

Не все CQS by design

• Например Стек• Помним про Bounded Context

Page 52: Coding like a sex

Синхронизация хранилищ

• Синхронно (C,U,D)

Page 53: Coding like a sex

Синхронизация хранилищ

• Асинхронно

Page 54: Coding like a sex

Команды и шина

• bus.Send(command);• Диспетчеризация• Логирование

Page 55: Coding like a sex

Минусы

• Eventually consistent• Архитектура гораздо сложнее, чем Shared

DB• Обработка ошибок• UX Issues

Page 56: Coding like a sex

Горизонтальное масштабирование записи данных

• Очередь сообщений (Producer-Consumer pattern)

• RabbitMQ• IronMQ• NServiceBus

Page 57: Coding like a sex

Разгрузочный слайд

Page 58: Coding like a sex

Event Sourcing – вспомнить все

Page 59: Coding like a sex

Проблемы

• Рефакторинг• Сложность системы, Bus factor• Сторонние сервисы• Выбор Aggregation Root• Tool Support

Page 60: Coding like a sex

Взаимодействие между командами, границы применимости

• И снова Bounded Context• UI-команда – клиент для Backend-команды• Сначала интерфейс, потом реализация• CQRS и ES могут жить в подсистеме• Code Review – не блажь, а необходимость• Парное программирование для сложных

задач

Page 61: Coding like a sex

Вопросы?