Understand how we could simplify Specifications
and code readability
- Identify what could make this code more readable
- You can write a new version of it
public int Filter(DateTime postedAfter)
=> _blogRepository
.FetchAll()
.Where(blog => new ActivatedBlogSpecification().IsSatisfiedBy(blog))
.SelectMany(blog => blog.Posts)
.Count(post => new ActivatedSpecification()
.And(new NotRemovedSpecification())
.And(new NotBannedSpecification())
.And(new CreatedAfterSpecification(postedAfter)).IsSatisfiedBy(post));
- We can improve the usage and readability of
Specification
code by creating extensions- For
Linq
for example - You can extend repository to do so
- For
public static class QueryExtensions
{
public static int Count<TSource>(this IEnumerable<TSource> source, Specification<TSource> specification)
=> source.Count(specification.IsSatisfiedBy);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
Specification<TSource> specification)
=> source.Where(specification.IsSatisfiedBy);
}
- Let's take a few minutes to inspect the new
Specification
code
public int CountValidPostsAfter(DateTime postedAfter)
=> _blogRepository
.FetchAll()
.Where(_specifications.For<Blogs.Blog>()
.Activated())
.SelectMany(blog => blog.Posts)
.Count(_specifications.For<Post>()
.Activated()
.NotRemoved()
.NotBanned()
.CreatedAfter(postedAfter));
- It works with extension methods on
ISpecification<T>
public static class DomainSpecifications
{
public static ISpecification<Blogs.Blog> Activated(this ISpecification<Blogs.Blog> specification)
=> specification.And(blog => blog.Activated.HasValue && IsAccessible(blog));
private static bool IsAccessible(Blogs.Blog blog)
=> !blog.Banned.HasValue
&& !blog.Removed.HasValue;
public static ISpecification<Post> Activated(this ISpecification<Post> specification)
=> specification.And(post => post.Activated.HasValue);
public static ISpecification<Post> NotRemoved(this ISpecification<Post> specification)
=> specification.And(post => !post.Removed.HasValue);
public static ISpecification<Post> NotBanned(this ISpecification<Post> specification)
=> specification.And(post => !post.Banned.HasValue);
public static ISpecification<Post> CreatedAfter(this ISpecification<Post> specification, DateTime date)
=> specification.And(post => post.Created >= date);
}
- Open the
MovieKata
solution - Implement the missing
Specification(s)
to pass the tests
Given a customer living in Russia and major When they wants to play a movie on Putin Then they gets a rejection
Given a customer living in France and major When they wants to play a movie on Putin Then they gets an approval
Given a minor customer When they wants to play an "olé olé" movie Then they gets a rejection
Given a major customer When they wants to play an "olé olé" movie Then they gets an approval
- Which other rules / specification could be added?
- More granular regarding MPAA maybe?
Discuss about the 2 Specification
implementation seen (OO oriented, more FP oriented)
- Which one do you prefer and why?
- How would we want to use it on our production code?
Implementation solution available here