{"id":20715741,"url":"https://github.com/tpierrain/value","last_synced_at":"2025-04-23T11:13:41.223Z","repository":{"id":60773987,"uuid":"65945316","full_name":"tpierrain/Value","owner":"tpierrain","description":"a pico library (or code snippets shed) to help you to easily implement Value Types in your C# projects without making errors nor polluting your domain logic with boiler-plate code.","archived":false,"fork":false,"pushed_at":"2023-08-28T12:26:58.000Z","size":1240,"stargazers_count":89,"open_issues_count":5,"forks_count":16,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-23T11:13:35.527Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tpierrain.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-08-17T22:04:54.000Z","updated_at":"2025-03-01T16:59:55.000Z","dependencies_parsed_at":"2022-10-04T15:24:14.575Z","dependency_job_id":"e282510f-03d9-4aa8-8f30-30a94d4be5a8","html_url":"https://github.com/tpierrain/Value","commit_stats":{"total_commits":103,"total_committers":2,"mean_commits":51.5,"dds":0.009708737864077666,"last_synced_commit":"045717618f70fc4814446e6d2234793b0edc05e4"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tpierrain%2FValue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tpierrain%2FValue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tpierrain%2FValue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tpierrain%2FValue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tpierrain","download_url":"https://codeload.github.com/tpierrain/Value/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250421906,"owners_count":21427851,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T02:39:42.620Z","updated_at":"2025-04-23T11:13:41.202Z","avatar_url":"https://github.com/tpierrain.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build status](https://ci.appveyor.com/api/projects/status/ju5m6t3fm2xsl0o9/branch/master?svg=true)](https://ci.appveyor.com/project/tpierrain/value/branch/master)\r\n\r\n# Value\r\n\r\nis a pico library (or code snippets shed) to help you to __easily implement Value Types__ in your C# projects without making errors nor polluting your domain logic with boiler-plate code.\r\n\r\n![Value](https://github.com/tpierrain/Value/blob/master/Value-small.jpg?raw=true)\r\n\r\n## Value Types?\r\n__Domain Driven Design (DDD)__'s *Value Object* being an oxymoron (indeed, an object has a changing state by nature), we now rather use the \"*Value Type*\" (instance) terminology. But the concept is the same as described within Eric Evan's Blue book.\r\n\r\n__A Value Type:__\r\n - is __immutable__ (every field must be read-only after the Value Type instantiation; no 'setter' is allowed)\r\n - is __rich with domain logic and behaviours__. The idea is to swallow (and encapsulate) most of our business complexity within those classes\r\n - embraces the __Ubiquitous Language__ of our business context: cure to primitive obsession, the usage of Value Types is an opportunity for us to embrace the language of our business within our code base\r\n - __exposes, uses and combines functions__ to provide business (domain) value. Functions usually return new instance(s) of Value Types ('*closure of operations*' describing an operation whose return type is the same as the type of its argument(s))\r\n\r\n```c#\r\n    // e.g.: the following Add function does not change any existing Amount instance, it just returns a new one\r\n    public Amount Add(Amount otherAmount) \r\n```\r\n\r\n - __considers ALL its attributes for Equality and Uniqueness__ (and \"all\" *is-a-must* here)\r\n - is __auto-validating__ (via *transactional* constructors __with business validation inside__ and throwing exception if necessary)\r\n\r\n\r\n### Reverse the trend! (we need more Value Types, and fewer Entities)\r\n\r\nAn *Entity* is an object that has a changeable state (often made by combining Value Objects) for which we care about its identity. Whether to use an Entity or Value Object will strongly depend on your business context (*there is no silver bullet*). Here are some basic samples to better grasp the difference between *Value Types* and *Entities*:\r\n \r\n - __*Value types*__: cards of a poker hand, a speed of 10 mph, a bank note of 10 euros (unless you are working for a Central Bank which need then to trace every bank note --\u003e Entity), a user address\r\n\r\n - __*Entities*__: a user account, a customer's basket with items, a customer, ...\r\n\r\nOur OO code bases are usually full of types with states and contain very few Value Type instances.\r\nDDD advises us to reverse the trend by not having *Entities* created by default, and to strongly increase our __usage of Value Types__. \r\n\r\nThis __will helps us to reduce side-effects within our OO base code__. A simple reflex, for great benefits.\r\n\r\n### Side effects, you said?\r\n\r\nYes, because one of the problem we face when we code with Object Oriented (OO) languages like C# or java is the presence of __side-effects__. Indead, the ability for object instances to have their own state changed by other threads or by a specific combination of previous method calls (temporal coupling) __makes our reasoning harder__. Doing Test Driven Development helps a lot, but is not enough to ease the reasoning about our code.\r\n\r\nBeing inspired by functional programming (FP) languages, __DDD suggests us to make our OO design more FP oriented in order to reduce those painful side-effects__. They are many things we can do for it. E.g.: \r\n - to use and combine __functions__ instead of methods (that impact object states)\r\n - to embrace __CQS pattern__ for *Entity* objects (i.e. a paradigm where read methods never change state and write methods never return data)\r\n - to implement *Closure of Operations* whenever it's possible (to reduce coupling with other types)\r\n - to use __*Value Types*__ by default and to keep *Entity* objects only when needed.\r\n\r\n\r\n### You are not alone\r\n\r\nSince there is no first-class citizen for immutability and *Value Types* in C#, the goal of this pico library is to help you easily implement Value Types without caring too much on the boiler-plate code. \r\n\r\n__Yeah, let's focus on our business value now!__\r\n\r\n--- \r\n\r\n## What's inside the box?\r\n\r\n - __ValueType\u003cT\u003e__: making all your Value Types deriving from this base class will allow you to __properly implement Equality__ (IEquatable) __and Unicity__ (GetHashCode()) on ALL your fields __in 1 line of code__. Very Handy!\r\n```c#\r\n    // 1. You inherit from ValueType\u003cT\u003e like this:\r\n    public class Amount : ValueType\u003cAmount\u003e\r\n    {\r\n        private readonly decimal quantity;\r\n        private readonly Currency currency;\r\n\t\t\r\n        public decimal Quantity { get { return this.quantity; } }\r\n        public Currency Currency { get { return this.currency; } }\r\n\r\n\t...\r\n\r\n\t// 2. You (are then forced to) implement the abstract method returning the list of all your fields\r\n\tprotected override IEnumerable\u003cobject\u003e GetAllAttributesToBeUsedForEquality()\r\n        {\r\n            return new List\u003cobject\u003e() { this.quantity, this.currency }; // The line of code I was talking about\r\n        }\r\n\r\n        // And that's all folks!\r\n    }\r\n\r\n\r\n```\r\n\r\n - __ListByValue\u003cT\u003e__: A list with equality based on its content and not on the list's reference (i.e.: 2 different instances containing the same items in the same order will be equals). This collection decorator is __very useful for any ValueType that aggregates a list__\r\n\r\n ```c#\r\n      // when one of your ValueType aggregates a IList like this\r\n      private readonly List\u003cCard\u003e cards;\r\n\r\n      //...\r\n\r\n      protected override IEnumerable\u003cobject\u003e GetAllAttributesToBeUsedForEquality()\r\n      {\r\n          // here, you can use the ListByValue decorator to ensure a \"ByValue\" equality of your Type.\r\n          return new List\u003cobject\u003e() { new ListByValue\u003cCard\u003e(this.cards) };\r\n      }\r\n```\r\n\r\n - __SetByValue\u003cT\u003e__: A Set with equality based on its content and not on the Set's reference (i.e.: 2 different instances containing the same items will be equals whatever their storage order). This collection decorator is __very useful for any ValueType that aggregates a set__\r\n\r\n```c#\r\n      // when one of your ValueType aggregates a Set like this\r\n      private readonly HashSet\u003cCard\u003e cards;\r\n      \r\n      //...\r\n     \r\n      protected override IEnumerable\u003cobject\u003e GetAllAttributesToBeUsedForEquality()\r\n      {\r\n          // here, you can use the SetByValue decorator to ensure the \"ByValue\" equality of your Type.\r\n          return new List\u003cobject\u003e() { new SetByValue\u003cCard\u003e(this.cards) };\r\n      }\r\n```\r\n\r\n--- \r\n\r\n## Usage samples of ValueTypes\r\n\r\n__Disclaimer:__ for the sake of clarity, the following code samples don't have behaviours to only focus here on the Equality concern. __Of course, a ValueType in DDD must embed behaviours to swallow complexity (it's not just a DTO or a POCO without responsibilities).__\r\n\r\nCode Sample of a properly implemented ValueType:\r\n\r\n```c#\r\n    /// \u003csummary\u003e\r\n    /// Proper implementation of a ThreeeCards ValueType since the order of the cards doesn't matter during\r\n    /// Equality. Note: the Card type is also a ValueType.\r\n    /// \u003c/summary\u003e\r\n    public class ThreeCards : ValueType\u003cThreeCards\u003e\r\n    {\r\n        private readonly HashSet\u003cCard\u003e cards;\r\n\r\n        public ThreeCards(string card1Description, string card2Description, string card3Description)\r\n        {\r\n            this.cards = new HashSet\u003cCard\u003e();\r\n\r\n            this.cards.Add(Card.Parse(card1Description));\r\n            this.cards.Add(Card.Parse(card2Description));\r\n            this.cards.Add(Card.Parse(card3Description));\r\n        }\r\n\r\n        protected override IEnumerable\u003cobject\u003e GetAllAttributesToBeUsedForEquality()\r\n        {\r\n            // we decorate our standard HashSet with the SetByValue helper class.\r\n            return new List\u003cobject\u003e() { new SetByValue\u003cCard\u003e(this.cards) };\r\n        }\r\n    }\r\n```\r\n\r\nCode Sample of a bad ValueType implementation: \r\n\r\n```c#\r\n    /// \u003csummary\u003e\r\n    /// Bad ValueType implementation of ThreeCards since the GetAllAttributesToBeUsedForEquality() method \r\n    /// returns the set directly, without decoring it with the SetByValue helper.\r\n    /// \u003c/summary\u003e\r\n    public class ThreeCardsBadlyImplementedAsValueType : ValueType\u003cThreeCards\u003e\r\n    {\r\n        private readonly HashSet\u003cCard\u003e cards;\r\n\r\n        public ThreeCardsBadlyImplementedAsValueType(string card1Description, string card2Description, string card3Description)\r\n        {\r\n            this.cards = new HashSet\u003cCard\u003e();\r\n\r\n            this.cards.Add(Card.Parse(card1Description));\r\n            this.cards.Add(Card.Parse(card2Description));\r\n            this.cards.Add(Card.Parse(card3Description));\r\n        }\r\n\r\n        protected override IEnumerable\u003cobject\u003e GetAllAttributesToBeUsedForEquality()\r\n        {\r\n            // BAD IMPLEMENTATION HERE: should have returned \"new SetByValue\u003cCard\u003e(this.cards)\" instead of \"this.cards\"\r\n            return new List\u003cobject\u003e() { this.cards };\r\n        }\r\n    }\r\n```\r\n\r\nNow, let's have a look a 2 tests that clarify the impact of those 2 implementations:\r\n\r\n```c#\r\n        [Test]\r\n        public void Should_consider_equals_two_ValueType_instances_that_aggregates_equivalent_SetByValue()\r\n        {\r\n            var threeCards = new ThreeCards(\"AS\", \"QD\", \"2H\");\r\n            var sameThreeCards = new ThreeCards(\"2H\", \"QD\", \"AS\");\r\n\r\n            Check.That(threeCards).IsEqualTo(sameThreeCards);\r\n        }\r\n\r\n        [Test]\r\n        public void Should_consider_Not_equals_two_badly_implemented_ValueType_instances_that_aggregates_equivalent_HashSet()\r\n        {\r\n            var threeCards = new ThreeCardsBadlyImplementedAsValueType(\"AS\", \"QD\", \"2H\");\r\n            var sameThreeCards = new ThreeCardsBadlyImplementedAsValueType(\"2H\", \"QD\", \"AS\");\r\n\r\n            Check.That(threeCards).IsNotEqualTo(sameThreeCards);\r\n        }\r\n```\r\n \r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftpierrain%2Fvalue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftpierrain%2Fvalue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftpierrain%2Fvalue/lists"}