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

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

Apr 16, 2017

Download

Software

dev2devConf
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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