Retrospective of 2020. Plans for 2021.

I’ve never done such analysis before, but this year I found that planning actually works (at least for me). So this time, I want to share my achievements in 2020 and plans for 2021.

Achievements of 2020

  • This blog was created this year. Sometimes I’m too lazy to add new articles, but despite that, every time a new post added, I have a feeling that I’ve found something new in that topic. It doesn’t matter if it is a book review, short programming article, or digression about life – always new insights and thoughts are popping up in my head during writing. I highly recommend blog posting for people, how sometimes moving too fast in their life to analyze previous events and use that knowledge in the future.
  • I started running and reached 100 runs and 800km in 2020. You could read more about that here. This is a really big achievement for me because it is something, which requires a big commitment in a long term.
  • I’ve read 7 books. Well, not too much be honest, but each of them was certainly amazing. Especially I want to highlight Factfulness: Ten Reasons We’re Wrong About the World—and Why Things Are Better Than You Think by Hans Rosling. Highly recommend it to everyone! (my full profile on good reads here)
My 2020 in books
  • 3/5 courses in Leading People and Teams Specialization was finished. I found it very important to develop not only “hard” skills as a developer and a technical geek, but also “soft” skills. In the end, we don’t live in Matrix where we communicate with computers only. Cooperation between team members is crucial for the success of any project (not only software one).
  • Since September I’m a proud Samoyed’s owner. That’s not my personal achievement, but rather a big event in my life. A dog changed my life in many aspects and brought a looooooot of positive emotions. Also, thanks to Maya (my dog’s name), I have a more organized day now, which helps me to be more productive.

Plans for 2021

Here I create a list of all goals I want to achieve in next year, not every one of them will be SMART, because I’m not so good at planning for the whole year ahead, nevertheless as time will go and goal will be achieved – list item will be marked as checked.

  1. Finish the Leading People and Teams Specialization
  2. Recieve Microsoft Certified: Azure Solutions Architect Expert certificate
  3. Run at least 100 runs with a minimum of 500km distance and take part in a race
  4. Read at least 10 books
  5. Solve 30 HackerRank problems
  6. Learn 1 additional programming language
  7. Post at least 12 new posts in the blog
  8. Contribute to at least one open-source project on Github
  9. Receive a Professional Scrum Developer certificate
  10. Get English certificate (IELTS minimum 6.0 or similar)
  11. Visit at least 2 new countries.
  12. Hike to Gerlach peak
  13. Sleep at least 1 night in a tent
  14. Donate at least 1.5 liter of blood (3 times)
  15. Complete First Aid Course
  16. Meaningful work-related change
  17. Visit a technical conference or meetup (min 2)
  18. Start investing money
  19. Sleep 8+ hours
  20. Do some crazy adrenaline rush thing (paraglide, glider)
  21. Do some gym (at least 1 per week or 52 in a year)
  22. Do skying (3 times+)
  23. Add at least 2 new board games to the home collection

Some of these points are more important, some of them less important. Known fact, that a lot of the New Year’s resolutions fail (actually success rate is only about 8%) and as Doris Day sang – “You can’t have everything”. So achieving >= 50% of goals might be a reasonable approach.

Final thoughts

2020 was very special in many aspects. COVID-19 turned the life of almost every person on the planet upside down and I wasn’t an exception – social distance, restrictions in travel and movement, canceling 95% of the planned events, work from home, etc. All these things probably have changed our vision of the world for decades and now is impossible to predict all consequences of the pandemic. But the only thing every one of us could do – make this world a bit better, every day, peace by peace! Let’s keep our fingers crossed and hope that in 2021 all our plans will be fulfilled!

Happy and Healthy New 2021 Year! 😉

DDD & CQRS & Event Sourcing. Part 3: Test Domain Model

Before we start, I recommend checking my previous post where I described designing a domain model with events and which benefits it brings for business and engineers.

Let’s start with the basic class for domain model, let’s call it Aggregate (you could find more about this keyword in DDD here):

public abstract class Aggregate
{
public Guid Id { get; private set; }
private readonly IList<object> _events = new List<object>();

public ICollection<object> DequeueEvents()
{
    var events = _events.ToList();
    _events.Clear();
    return events;
}

private void Enqueue(object @event)
{
    _events.Add(@event);
}

protected void Process(object @event)
{
    Type thisType = GetType();
    if (thisType == null) throw new NotSupportedException($"Current this type is null!");
    
    MethodInfo methodInfo = thisType.GetMethod("Apply",  BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, new [] { @event.GetType()}, null );
    if (methodInfo == null) throw new NotSupportedException($"Missing handler for event {@event.GetType().Name}");
    
    try
    {
        methodInfo.Invoke(this, new[] { @event } );
    }
    catch(TargetInvocationException ex)
    {
        ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
    }
    Enqueue(@event);
}
}

As you could see, we have 3 main methods here:

  • Enqueue – simply add a new event to private event collection
  • Dequeue – returns the private event collection and clean the queue, so Aggregate event collection could not be changed in any way from outside.
  • Process – Try to find and call a proper method Apply (by method parameter type) and add anew event to the private event collection.

Also you could see private _events variable for storing events and Id property, which is common for every Aggregate object.

So our specific Aggregate will look like this:

public class User: Aggregate
{
public string Email { get; private set; }

public User(Guid id, string email) => Process(new Events.V1.UserCreated(userId:id, email: email ));

public void ChangeEmail(string userEmail) => Process(new Events.V1.UserEmailChanged(userId: Id, email: userEmail));

private void Apply(Events.V1.UserCreated @event)
{
    Id = @event.UserId;
    SetUserEmail(@event.Email);
}

private void Apply(Events.V1.UserEmailChanged @event) => SetUserEmail(@event.Email);

private void SetUserEmail(string email)
{
    email = email?.Trim();
    CheckNullOrEmpty(email, "Email");
    CheckMaxLength(50, email, "Email");
    CheckIsMatch(Constants.EmailTemplate, email, "Email");
    Email = email;
}
}

* For the simplicity of the example, I’ve omitted implementation details of methods CheckNullOrEmpty, CheckMaxLength, and CheckIsMatch. Anyway, if you are interested, you could find it in Github Repo here.

User domain model contains:

  • Email property (in addition to Id property from Aggregate class). Please be sure it has a private setter
  • SetUserEmail – a method for set and check if the email is correct
  • 2 private Apply methods for changing the internal state of the Domain Model
  • Public constructor
  • public ChangeEmail method for changing the email property

So when are speaking about the testing, we could check several things in the domain model:

  • It has a proper state – eg. User has not empty id and email
  • It generates a proper event – e.g. User generates UserCreated Event
  • Generated event has a proper state – UserCreated Event contains User Id and Email

Let’s see an example of such tests. I’m using Xunit, but you could use any test framework you like:

public class UserCreateTests
{
private readonly Domain.User _createdUser;
private readonly (Guid Id, string Password, string Email) _userData;

public UserCreateTests()
{
    _userData = (Id: Guid.NewGuid(), Password: "Testing123!", Email: "test@email.com");
}

[Fact]
public void ShouldBeCreatedWithCorrectData()
{
    Assert.NotNull(_createdUser);
    Assert.Equal(_userData.Id, _createdUser.Id);
    Assert.Equal(_userData.Email, _createdUser.Email);
}

[Fact]
public void ShouldGenerateUserCreatedEvent()
{
    var events = _createdUser.DequeueEvents();
    Assert.Single(events);
    Assert.Equal(typeof(Events.V1.UserCreated), events.Last().GetType());
}

[Fact]
public void UserCreatedEventShouldContainsCorrectData()
{
    var @event = (Events.V1.UserCreated) _createdUser.DequeueEvents().Last();
    Assert.Equal(_createdUser.Id, @event.UserId);
    Assert.Equal(_userData.Email, @event.Email);
}
}

Firstly, ShouldBeCreatedWithCorrectData checks if the User object is in a valid state after creation. Next, there are 2 tests for the events: ShouldGenerateUserCreatedEvent – checks if the event which has been generated has an expected type, and UserCreatedEventShouldContainsCorrectData checks if this event contains correct data.

As you could see, there is no big difference between unit testing regular objects, and those which are using Events for building their state. I hope this article helped you to understand better the philosophy of Event Sourcing. In the next post, I will describe the persistence of the aggregate using the Marten library. CU 🙂

The latest code base version of the project could be found on Github Org Page.

Always remember about IQueryable when using Expressions in LINQ!

Today I’ve faced unexpected behavior during querying data and JSON deserialization while playing with Marten library which uses PostgreSQL Database as storage. So let’s imagine we have a very dummy 2 classes, one for saving data (in JSON format) and one class for the projection (as a response of some Web API for instance):

Origin class for data storing:

public class User
{
    private User() { }

    public User(int id, string name)
    {
        Id = id;
        Name = name;
        Status = "Pending";
    }

    public int Id { get; private set; }
    public string Name { get; private set; }
    public string Status { get; private set; }
}

Projection class

public class ReadOnlyUser
{
    public string Name { get; set; }
    public string Status { get; set; }
}

So as you see, the User class has private setters and due to MSDN Deserialization behavior, JSON Serializer ignores read-only properties. This means that this code will always create a User instance with Status Pending

var stringData = "{\"Id\": \"1\", \"Status\": \"Active\",\"Name\": \"John\"}";

var stream = new MemoryStream(Encoding.ASCII.GetBytes(stringData));
var textReader = new JsonTextReader(new StreamReader(stream));

var user = new JsonSerializer().Deserialize<User>(textReader);
Result: 

Output object:
User Id: 1 
User Name: John 
User Status: Pending

So if we follow the example above, making a projection from such class, will produce the ReadOnlyUser which also will have a Status Pending:

 var stringArrayData = "[{\"Id\": \"1\", \"Status\": \"Active\",\"Name\": \"John\"}]";
 JsonSerializer serializer = new JsonSerializer();

 var stream = new MemoryStream(Encoding.ASCII.GetBytes(stringArrayData));
 var reader = new JsonTextReader(new StreamReader(stream));

 var user = serializer
   .Deserialize<IEnumerable<User>>(reader)
   .Where(usr => usr.Id == "1")
   .Select(usr => new ReadOnlyUser {Name=usr.Name, Status=usr.Status})
   .FirstOrDefault();

 Console.WriteLine($"\r\nOutput object:\r\nUser Name: {user.Name} \r\nUser Status: {user.Status}");
Result:

Output object:
User Name: John 
User Status: Pending

But what if we are not querying from a string variable, but rather from the database? Most probably instead of IEnumerable, IQueryable interface will be used.

In a nutshell, IQueryable brings 1 huge benefit – it knows how to execute expressions on special data sources. (For instance Where statement will be implemented in the database, not on the memory side)

So, coming back to the previous example, this code will also return User with Status Pending, won’t it?

return await _session.Query<User>() //Returns IQueryable<User> from db
   .Where(usr => usr.Id == "1")
   .Select(usr => new ReadOnlyUser {Name=usr.Name, Status=usr.Status})
   .FirstOrDefaultAsync();
Result:

Output object:
User Name: John 
User Status: Active
Me at that moment

So how did it happen, why Status is Active if the User has a private setter on that field?

In the first example, as we used IEnumerable, all of the operations are processed in our App memory. The order of commands was like that:

  1. Deserialize the JSON to IEnumerable list of Users (by using the only 1 public constructor which set Status to Pending without possibility to set it to Active because of private setter)
  2. Use Where statement to filter the Users with Id = “1”
  3. Use the Select projection for creating a new ReadOnlyUser

In the example with an IQueryable interface, steps 1 and 2 were “outsourced” to the database. So commands look so:

  1. Find by Object Type a proper table from which data should be fetched and create a query like “Select * from User”
  2. Add Where the statement “Where Id = ‘1’ ” to the query from step 1
  3. Execute a query in the database and return the result as a JSON object
  4. Use JsonSerializer for deserialization from JSON to ReadOnlyUser

So as you see, in the second scenario, many steps executed on the database side, but in that particular case, we gain even more profit because we could omit the limitation of Newtonsoft.Json of ignoring read-only fields during deserialization. In fact, we are not creating a User object but just go directly to the creation of ReadOnlyUser projection.

Please be aware, that every implementation of an IQueryable interface has its own rules of converting command and using expression tree. So before relying on “outsourcing processing”, just spend a few minutes to check what exactly will be executed.