89
Что нам стоит DAL построить? Акуляков Артём

Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

Embed Size (px)

Citation preview

Page 1: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

Что нам стоит DAL построить?

Акуляков Артём

Page 2: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

кто я естьdotnet в основномpython в свободное времяfunctional programming еще

докладчик dotnetconf, d2dорганизатор d2d

2

Page 3: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

в чем проблема?

3

Page 4: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

dal

data access layer

4

Page 5: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

dal

data access layer● persistence ignorance для bl

5

Page 6: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

dal

data access layer● persistence ignorance для bl● обработка данных это ключевая функция

программы

6

Page 7: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

dal

data access layer● persistence ignorance для bl● обработка данных это ключевая функция

программы● большая часть проблем с

производительностью связана с доступом к данным

7

Page 8: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

противоречие

8

Page 9: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

как построить dal?

9

Page 10: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository

10

Page 11: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v1public interface IRepository<TEntity>

where TEntity: class

{

IEnumerable<TEntity> GetAll();

TEntity GetById(int id);

void Add(TEntity obj);

void Update(TEntity obj);

void Remove(TEntity obj);

}

11

Page 12: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v1public interface IPostsRepository : IRepository<Post>

{

Post GetByTitle(string title);

}

12

Page 13: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v1 # проблемы

● разрастание интерфейса

13

Page 14: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v1public interface IPostsRepository : IRepository<Post>

{

Post GetByTitle(string title);

IEnumerable<Post> SearchByContent(string text);

IEnumerable<Post> GetOnlyWithComments();

… +100500 методов

}

14

Page 15: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v1 # проблемы

● разрастание интерфейса● разрастание зависимостей● разрастание ответственности

15

Page 16: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v1public PostsRepository(IDbContext context,

ISearchEngine searchEngine,

ITokenizer tokenizer,

IPostComparator comparator,

ITransactionManager transactionManager,

… +100500 зависимостей)

{

}

16

Page 17: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

что делать с операциями чтения?

17

Page 18: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

IQueryable<T>

18

Page 19: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2public interface IRepository<TEntity>

where TEntity : class

{

IQueryable<TEntity> Query();

void Add(TEntity obj);

void Update(TEntity obj);

void Remove(TEntity obj);

}

19

Page 20: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2public IEnumerable<Post> GetActivePosts() {

return _repository.Query< Post>()

.Where(p => !p.IsDeleted)

.Include(p => p.Author).ToArray();

}

public IEnumerable<Post> GetTopPosts() {

return _repository.Query< Post>()

.Where(p => !p.IsDeleted)

.Where(p => p.Comments.Count() > 50)

.Include(p => p.Author).ToArray();

}

20

Page 21: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2 # проблемы

● дублирование запросов

21

Page 22: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2public IEnumerable<Post> GetActivePosts() {

return _repository.Query< Post>()

.Where(p => !p.IsDeleted)

.Include(p => p.Author).ToArray();

}

public IEnumerable<Post> GetTopPosts() {

return _repository.Query< Post>()

.Where(p => !p.IsDeleted)

.Where(p => p.Comments.Count() > 50)

.Include(p => p.Author).ToArray();

}

22

Page 23: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2 # проблемы

● дублирование запросов● дублирование подгрузки

23

Page 24: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2public IEnumerable<Post> GetActivePosts() {

return _repository.Query< Post>()

.Where(p => !p.IsDeleted)

.Include(p => p.Author).ToArray();

}

public IEnumerable<Post> GetTopPosts() {

return _repository.Query< Post>()

.Where(p => !p.IsDeleted)

.Where(p => p.Comments.Count() > 50)

.Include(p => p.Author).ToArray();

}

24

Page 25: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

include

- EntityFramework- System.Data.Entity

- QueryableExtensions- Include(...) + 2 overloads

25

Page 26: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2 # проблемы

● дублирование запросов● дублирование подгрузки● include

26

Page 27: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

specification

27

Page 28: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

specificationpublic interface ISpecification<TEntity>

where TEntity : class

{

Expression<Func<TEntity, bool>> Filter { get; }

}

28

Page 29: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

specificationpublic class NotDeleted : ISpecification<Post>

{

public Expression<Func<Post, bool>> Filter

{

get { return x => x.IsDeleted == false; }

}

}

29

Page 30: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2 # уже лучшеpublic IEnumerable<Post> GetActivePosts() {

return _repository.Query< Post>()

.Where(_isActiveSpecification.Filter)

.Include(p => p.Author).ToArray();

}

public IEnumerable<Post> GetTopPosts() {

return _repository.Query< Post>()

.Where(_isActiveSpecification.Filter)

.Where(p => p.Comments.Count() > 50)

.Include(p => p.Author).ToArray();

}

30

Page 31: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

немного “сахара”public static IQueryable<TEntity>

Apply<TEntity>(this IQueryable<TEntity> query,

ISpecification<TEntity> spec)

where TEntity : class

{

return query.Where(spec.Filter);

}

31

Page 32: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2 # еще лучшеpublic IEnumerable<Post> GetActivePosts() {

return _repository.Query< Post>()

.Apply(_isActiveSpecification)

.Include(p => p.Author).ToArray();

}

public IEnumerable<Post> GetTopPosts() {

return _repository.Query< Post>()

.Apply(_isActiveSpecification)

.Where(p => p.Comments.Count() > 50)

.Include(p => p.Author).ToArray();

}

32

Page 33: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2 # проблемы

● дублирование запросов● дублирование подгрузки● include

33

Page 34: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

collector

34

Page 35: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

collectorpublic interface ICollector<TEntity>

where TEntity : class

{

IEnumerable<Expression<Func<TEntity, object>>> Includes

{

get;

}

}

35

Page 36: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

collectorpublic class PostCollector : ICollector<Post>

{

public IEnumerable<Expression<Func<Post, object>>> Includes

{

get

{

yield return p => p.Author;

yield return p => p.Comments;

}

}

}

36

Page 37: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

как применить collector с repository?

37

Page 38: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

collectorpublic interface IRepository<TEntity>

where TEntity : class;

{

IQueryable<TEntity> Query(

ICollector<TEntity> collector = null)

}

38

Page 39: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repository v2 # совсем хорошоpublic IEnumerable<Post> GetTopPosts() {

return _repository

.Query<Post>(_postWithAuthorCollector)

.Apply(_onlyActiveSpecification)

.Where(p => p.Comments.Count() > 50)

.ToArray();

}

39

Page 40: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

пример из реальной жизни

40

Page 41: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

пример из жизниpublic void BanAuthor(string login) {

var author = _authorsRep.Query().Single(a => a.Login == login);

var posts = _postsRep.Query().Where(p => p.Author.Id == author.Id);

foreach (var post in posts) {

post.IsDeleted = true;

_postsRep.Update(post);

}

author.Karma = 0;

author.IsReadOnly = true;

authorsRepository.Update(author);

} 41

Page 42: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

unit of work

42

Page 43: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

unit of workpublic interface IUnitOfWork : IDisposable

{

void Commit();

}

43

Page 44: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

repositorypublic interface IRepository<TEntity>

where TEntity : class

{

IQueryable<TEntity> Query(

ICollector<TEntity> collector = null);

void Add(TEntity obj);

void Remove(TEntity obj);

}

44

Page 45: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

как связать unit of work и repository?

45

Page 46: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

unit of work + repository = factorypublic interface IDalFactory

{

IRepository<TEntity> GetRepository<TEntity>()

where TEntity : class;

IUnitOfWork GetUnitOfWork();

}

46

Page 47: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

unit of workusing (var uow = _dalFactory.GetUnitOfWork()){

var postsRep = _dalFactory.GetRepository< Post>();

var authorsRep = _dalFactory.GetRepository< Author>();

var author = authorsRep.Query().Single(a => a.Login == login);

var posts = postsRep.Query().Where(p => p.Author.Id == author.Id);

foreach (var post in posts) post.IsDeleted = true;

author.Karma = 0;

author.IsReadOnly = true;

uow.Commit();

} 47

Page 48: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

profit?

48

Page 49: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

итог

● repository● unit of work● factory● specifications● collectors

49

Page 50: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

проблемы

● IQueryable<T> - дырявая абстракция

50

Page 51: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

проблемы

● IQueryable<T> - дырявая абстракция● cложно

51

Page 52: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

проблемы

● IQueryable<T> - дырявая абстракция● cложно● много абстракций

52

Page 53: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

как избавиться от этих недостатков?

53

Page 54: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

размышления

● cRud

54

Page 55: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

размышления

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

55

Page 56: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

масштабирование # как?

● индексы & оптимизация

56

Page 57: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

масштабирование # как?

● индексы & оптимизация● просто sql & Dapper.NET

57

Page 58: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

масштабирование # как?

● индексы & оптимизация● просто sql & Dapper.NET● кластер

58

Page 59: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

масштабирование # как?

● индексы & оптимизация● просто sql & Dapper.NET● кластер● совсем не много денормализации

- много денормализации- очень много денормализации

59

Page 60: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

масштабирование # как?

● индексы & оптимизация● просто sql & Dapper.NET● кластер● совсем не много денормализации

- много денормализации- очень много денормализации

● NoSQL- MongoDB, Redis, RavenDB, RethinkDB

60

Page 61: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

как спроектировать dal устойчивый к масштабированию?

61

Page 62: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

нужно чуть больше супер силы

62

Page 63: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

command-query responsibility segregation

63

Page 64: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs

64

command-query

dispatcher handler

Page 65: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs

● commands & query

65

Page 66: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrspublic class PublishPostCommand : IValidatable {

public Guid PostUid { get; set; }

public DateTime PublishDate { get; set; }

}

public class PostsByDateQuery : IValidatable {

public DateTime PublicationDate { get; set; }

}66

Page 67: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs

● commands & queries● handlers

67

Page 68: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrspublic interface ICommandHandler<in TCommand>

where TCommand : IValidatable

{

void Handle(TCommand command);

}

public interface IQueryHandler<in TQuery,out TResult>

where TQuery : IValidatable

{

TResult Handle(TQuery query);

}68

Page 69: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # примерpublic class PostByDateQueryHandler :

IQueryHandler<PostsByDateQuery, Post>

{

public PostByDateQueryHandler(IDbContext dbContext,

IMongoClient mongoClient)

{…}

public Post Handle(PostsByDateQuery query)

{…}

}69

Page 70: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # можно реализовать blpublic class PostByDateQueryHandler :

IQueryHandler<PostsByDateQuery, Post>

{

public PostByDateQueryHandler(

IRepository<Post> dbContext,

IFullPostCollector collector)

{…}

public Post Handle(PostsByDateQuery query)

{…}

} 70

Page 71: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs

● commands & queries● handlers● dispatcher

71

Page 72: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrspublic interface IDispatcher

{

void Dispatch<TCommand>(TCommand command)

where TCommand: IValidatable;

TResult Dispatch<TQuery, TResult>(TQuery query)

where TQuery : IValidatable;

}

72

Page 73: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # dispatcher

● ioc container● message bus● conventions● …

73

Page 74: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # dispatcherpublic class Dispatcher : IDispatcher {

public Dispatcher(IComponentContext componentContext)

{ _componentContext = componentContext; }

public void Dispatch<TCommand>(TCommand command)

where TCommand : IValidatable {

_componentContext

.Resolve<ICommandHandler<TCommand>>()

.Handle(command);

}

} 74

Page 75: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # используемpublic Post ReadPost()

{

var query = new PostsByDateQuery

{

PublicationDate = DateTime.Now

};

return _dispatcher

.Dispatch<PostsByDateQuery, Post>(query);

}75

Page 76: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs

76

MyApp.Domain MyApp.DAL

Entites, Services, Managers …

CommandsQueriesIDispatcher

IQueryHandlerICommandHandlerCommandHandlersQueryHandlersDispatcher

Page 77: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

а что про масштабирование?

77

Page 78: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

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

78

db

ui

domain dalcommands

dal : thin query modelqueries

Page 79: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

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

79

writedb

ui

domain dalcommands

dal : thin query modelqueries

readdb

Page 80: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

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

80

writedb

ui

domain dalcommands

dal : thin query modelqueries

readdb

Page 81: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # достоинства

● очень чистый домен

81

Page 82: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # достоинства

● очень чистый домен● сложность системы растет линейно

82

Page 83: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # достоинства

● очень чистый домен● сложность системы растет линейно● легко использовать специфичные

функции бд

83

Page 84: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # недостатки

● crud делать неудобно

84

Page 85: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # недостатки

● crud делать неудобно● консистентность данных

85

Page 86: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

cqrs # недостатки

● crud делать неудобно● консистентность данных● мало кто знает как готовить правильно

86

Page 87: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

почитать- http://cqrs.nu/- http://martinfowler.com/bliki/CQRS.html- http://blog.byndyu.ru/2014/07/command-and-query-responsibility.html- http://blog.byndyu.ru/2014/05/blog-post.html- http://blog.byndyu.ru/2013/03/dapper-queryobject-orm.html- http://blog.byndyu.ru/2011/08/repository.html- http://blog.byndyu.ru/2011/01/domain-driven-design-repository.html- http://martinfowler.com/eaaCatalog/repository.html- http://martinfowler.com/eaaCatalog/unitOfWork.html- http://martinfowler.com/bliki/SpecificationByExample.html- http://martinfowler.com/apsupp/spec.pdf- http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/

87

Page 88: Что нам стоит DAL построить? Акуляков Артём D2D Just.NET

хорошая архитектура по - это баланс между гибкостью и сложностью

88