Archive for the ‘Domain-Driven Design’ Category

BuildStuff 2016: Single Value Objects in .NET – Using structs to build custom scalars a Domain-Driven way

Monday, November 21st, 2016

Today I was one of the speakers during the BuildStuff 2016 Kiev conference. The site announced my talk with the following introduction:

This talk focuses on how to make Single Value Objects. Value objects that represent just a single scalar/primitive type using value types/structures as provided by the .NET platform.

Value Objects are essential to Domain-Driven Design, and help to make richer, type safe models. Modelling Single Value Objects as explained during this talk, will make your live easier, because of its lightweightness, and because of its re-usability characteristics (i.e. the behaviour for an IBAN, email address, etc. is unlikely to be different in different domains). It can be widely (re)used both within and outside a Domain-Driven context.

We will deep-dive into how to create a structure in .NET that fulfils these needs, like JSON and XML serialization, parsing, formatting, etc.

I hope my message came across. For those who missed it, or want to view the powerpoint. It can be downloaded here: www.corniel.nl/download

The (prepared) code snippets can be found at my Github repository:
github.com/Corniel/HelloWorld/HelloWorld/Buildstuff2016

The Open (Single Value Object) Source library Qowaiv can be found both on github and NuGet.

If you have any comments, feel free to reply.

Single Value Objects as C# structs

Wednesday, June 8th, 2016

Domain-Driven Design bottom-up – a talk

Some time ago, I decided that would like to be come a speaker at tech events. Speaking about software development is besides coding itself just so fun to do! The talks/presentations a gave for colleagues in the past where always nice, and it was about time to speak somewhere out in the wild. When a friend of mine told me that Searchlite was organizing small events and searching for speakers I did not hesitate, and applied.

The talk was about designing structs to represent Single Value Objects, the most elementary building blocks of your Entities and Value Objects within Domain-driven Design. The idea behind it, is that it results to cleaner code, that is easier to read, maintain and validate, than when you use only the default primitives of your language of choice (in this case C#).

Pitching Qowaiv

It was also the first time that I pitched Qowaiv, an open source .NET library (and NuGet package) that contains some of these Single Value Objects. The (closed source)  predecessor is used by my previous company, and Qowaiv is used within Exact Online, the on-line platform of my current company. But I think that it deserves a wider usage than that, so I gave it a try.

Looking back (and forward)

Overall I think it was an okay talk. The feedback from the audience was positive. Apparently, I was able to to bring the enthusiasm I have for software development in general and this topic in particularity, across. I’m really looking forward to BuildStuff Kiev, where I will be a speaker!

Download

Too bad, there is no live recording of the talk, but you can download the PowerPoint here:
corniel.nl/../2016-06-08_Single_Value_Objects_as_CSharp_structs.odp

Example of handling cookies Domain-driven

Wednesday, November 5th, 2014

A lot of web applications use cookies for enabling special features. For my company (Exact) for example, we use a cookie to store the latest division (code) that was selected by a user. This is not modelled DDD right now. How should it look like if it did? How to tackle the fact that an HTTP cookie is sealed, as we don’t want to introduce some (static) tooling or helper class?

First of all, I created an abstract wrapped cookie class. This allows developers to add extra (factory) methods, constructors, and properties based on the domain where the specific cookie has to be used. A cookie is a quiet generic thing, and we want to model domain specific implementations. Note that, as a result of that, the Value and Values property of the HTTP cookie are not publicly exposed.

In this case, the base class has besides the required wrapping a constructor with a user ID (GUID) and a static method to create a cookie name, as that is the default for our company. That is not necessarily something everybody should need.

For the specific cookie we have one public constructor, that creates an instance based on the user ID and its division code (a custom value object, containing that logic). Because, in the end, that is what this cookie is all about in our domain.

In this case it is extremely important that is always possible to (implicitly) cast between the wrapped and the original cookie. That makes the usage if the class way more easy.

using System;
using System.Web;

namespace HelloWorld.Web
{
	/// <summary>Represents a cookie that stores the last division visited by an user (ID).</summary>
	public class DivisionCodeCookie : WrappedCookie
	{
		/// <summary>The key for the division code.</summary>
		private const string DivisionCodeKey = "Division";

		/// <summary>Initializes a new division code cookie.</summary>
		/// <param name="userId">The user ID.</param>
		/// <param name="code">The division code.</param>
		public DivisionCodeCookie(Guid userId, DivisionCode code)
			: base(userId)
		{
			this.Code = code;
		}

		/// <summary>Initializes a new division code cookie.</summary>
		private DivisionCodeCookie(HttpCookie cookie) : base(cookie) { }

		/// <summary>Gets and set the division code of the cookie.</summary>
		public DivisionCode Code
		{
			get { return DivisionCode.TryParse(UnderlingCookie.Values[DivisionCodeKey]); }
			set { UnderlingCookie.Values[DivisionCodeKey] = value.ToString(); }
		}

		/// <summary>Creates a copy of the division code cookie.</summary>
		public DivisionCodeCookie Copy() { return new DivisionCodeCookie(this.UserId, this.Code); }

		/// <summary>Casts an HTTP Cookie to a Division code cookie.</summary>
		/// <remarks>
		/// Making the cast implicit allows the use of wrapped cookie when a HTTP cookie is asked.
		/// </remarks>
		public static implicit operator DivisionCodeCookie(HttpCookie http) { return new DivisionCodeCookie(http); }
	}
}

The base class.

using System;
using System.Diagnostics;
using System.Web;

namespace HelloWorld.Web
{
	/// <summary>Represents a cookie.</summary>
	/// <remarks>
	/// It is a wrapper that allows to add custom logic to the cookie.
	/// </remarks>
	[DebuggerDisplay("{DebuggerDisplay}")]
	public abstract class WrappedCookie
	{
		/// <summary>Initials a new wrapped cookie based on an HTTP cookie.</summary>
		protected WrappedCookie(HttpCookie httpCookie)
		{
			if (httpCookie == null) { throw new ArgumentNullException("httpCookie"); }
			this.UnderlingCookie = httpCookie;
		}

		/// <summary>Initials a new wrapped cookie based on an user ID.</summary>
		protected WrappedCookie(Guid userId) : this(GetCookieName(userId)) { }

		/// <summary>Initials a new wrapped cookie based on cookie name.</summary>
		protected WrappedCookie(string name): this(new HttpCookie(name)){}

		/// <summary>Gets or set the underlying HTTP cookie.</summary>
		protected HttpCookie UnderlingCookie { get; set; }

		/// <summary>Gets or set the user ID of the cookie.</summary>
		public Guid UserId
		{
			get
			{
				Guid userid;

				if (this.Name.StartsWith("ExactServer{")&& Guid.TryParseExact(this.Name.Substring(11), "B", out userid))
				{
					return userid;
				}
				return Guid.Empty;

			}
			set { this.Name = GetCookieName(value); }
		}

		/// <summary>Gets or set the name of the cookie.</summary>
		public string Name 
		{ 
			get { return UnderlingCookie.Name;  }
			set{ UnderlingCookie.Name = value;}
		}
		/// <summary>Gets or set the domain of the cookie.</summary>
		public string Domain
		{
			get { return UnderlingCookie.Domain; }
			set { UnderlingCookie.Domain = value; }
		}
		/// <summary>Gets or set the path of the cookie.</summary>
		public string Path
		{
			get { return UnderlingCookie.Path; }
			set { UnderlingCookie.Path = value; }
		}
		/// <summary>Gets or set the expiration date of the cookie.</summary>
		public DateTime Expires
		{
			get { return UnderlingCookie.Expires; }
			set { UnderlingCookie.Expires = value; }
		}
		
		/// <summary>Gets or set a value that specifies whatever a cookie is accessible by client-side script.</summary>
		public bool HttpOnly
		{
			get { return UnderlingCookie.HttpOnly; }
			set { UnderlingCookie.HttpOnly = value; }
		}
		/// <summary>Gets or set a value indicating specifies whatever to transmit the cookie Secure Sockets Layers (SSL)--that is, over HTTPS only.</summary>
		public bool Secure
		{
			get { return UnderlingCookie.Secure; }
			set { UnderlingCookie.Secure = value; }
		}
		/// <summary>Determines whatever the cookie is allowed to participate in output caching.</summary>
		public bool Shareable
		{
			get { return UnderlingCookie.Shareable; }
			set { UnderlingCookie.Shareable = value; }
		}

		/// <summary>Casts a wrapped cookie (back) to an HTTP cookie.</summary>
		/// <remarks>
		/// Making the cast implicit allows the use of wrapped cookie when an HTTP cookie is asked.
		/// </remarks>
		public static implicit operator HttpCookie(WrappedCookie wrapped) { return wrapped.UnderlingCookie; }

		/// <summary>Cleans the cookie up by clearing the value and set the expire date in the past.</summary>
		public void Cleanup()
		{
			UnderlingCookie.Expires = DateTime.Now.AddMinutes(-1);
			UnderlingCookie.Values.Clear();
		}

		/// <summary>Gets the name for the cookie based on the user ID.</summary>
		public static string GetCookieName(Guid userId)
		{
			return string.Format("ExactServer{0:B}", userId);
		}

		/// <summary>Gets a debugger display for the wrapped cookie.</summary>
		protected virtual string DebuggerDisplay { get { return string.Format("Cookie[{0}], Value: {1}, Expires: {2:yyyy-MM-dd HH:mm}", this.Name, this.UnderlingCookie.Value, this.Expires); } }
	}
}