{"id":2044,"date":"2017-05-24T16:57:20","date_gmt":"2017-05-24T15:57:20","guid":{"rendered":"https:\/\/www.entropywins.wtf\/blog\/?p=2044"},"modified":"2022-10-10T00:06:26","modified_gmt":"2022-10-09T23:06:26","slug":"generic-entity-handling-code","status":"publish","type":"post","link":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/","title":{"rendered":"Generic Entity handling code"},"content":{"rendered":"<p>In this blog post I outline my thinking on sharing code that deals with different types of Entities in your domain. We\u2019ll cover what Entities are, code reuse strategies, pitfalls such as Shotgun Surgery and Anemic Domain Models and finally Bounded Contexts.<\/p>\n<h3>Why I wrote this post<\/h3>\n<p>I work at <a href=\"https:\/\/software.wikimedia.de\/\">Wikimedia Deutschland<\/a>, where amongst other things, we are working on a software called <a href=\"https:\/\/wikibase.consulting\/what-is-wikibase\/\">Wikibase<\/a>, which is what powers the <a href=\"https:\/\/www.wikidata.org\">Wikidata<\/a> project. We have a dedicated team for this software, called the Wikidata team, which I am not part of. As an outsider that is somewhat familiar with the Wikibase codebase, I came across a writeup of a perceived problem in this codebase and a pair of possible solutions. I happen to disagree with what the actual problem is, and as a consequence also the solutions. Since explaining why I think that takes a lot of general (non-Wikibase specific) explanation, I decided to write a blog post.<\/p>\n<h3>DDD Entities<\/h3>\n<p>Let\u2019s start with defining what an Entity is. Entities are a tactical <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain-driven_design\">Domain Driven Design<\/a> pattern. They are things that can change over time and are compared by identity rather than by value, unlike Value Objects, which do not have an identity.<\/p>\n<p>Wikibase has objects which are conceptually such Entities, though are implemented \u2026 oddly from a DDD perspective. In the above excerpt, the word entity, is confusingly, not referring to the DDD concept. Instead, the Wikibase domain has a concept called Entity, implemented by an abstract class with the same name, and derived from by specific types of Entities, i.e. Item and Property. Those are the objects that are conceptually DDD Entities, yet diverge from what a DDD Entity looks like.<\/p>\n<p>Entities normally contain domain logic (the lack of this is called an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Anemic_domain_model\">Anemic Domain Model<\/a>), and don\u2019t have setters. The lack of setters does not mean they are immutable, it\u2019s just that actions are performed through methods in the domain language (see <a href=\"https:\/\/martinfowler.com\/bliki\/UbiquitousLanguage.html\">Ubiquitous Language<\/a>). For instance \u201cconfirmBooked()\u201d and \u201ccancel()\u201d instead of \u201csetStatus()\u201d.<\/p>\n<h3>The perceived problem<\/h3>\n<p>What follows is an excerpt from a document aimed at figuring out how to best construct entities in Wikibase:<\/p>\n<div style=\"padding-left: 40px;\">\n<p>Some entity types have required fields:<\/p>\n<ul>\n<li>Properties require a data type<\/li>\n<li>Lexemes require a language and a lexical category (both ItemIds)<\/li>\n<li>Forms require a grammatical feature (an ItemId)<\/li>\n<\/ul>\n<p>The ID field is required by all entities. This is less problematic however, since the ID can be constructed and treated the same way for all kinds of entities. Furthermore, the ID can never change, while other required fields could be modified by an edit (even a property\u2019s data type can be changed using a maintenance script).<\/p>\n<p><i>The fact that Properties require the data type ID to be provided to the constructor is problematic in the current code, as evidenced in EditEntity::clearEntity:<\/i><\/p>\n<pre class=\"lang:php decode:true\">\/\/ FIXME how to avoid special case handling here?\nif ( $entity instanceof Property ) {\n  \/** @var Property $newEntity *\/\n  $newEntity-&gt;setDataTypeId( $entity-&gt;getDataTypeId() );\n}\n<\/pre>\n<p>&#8230;as well as in EditEntity::modifyEntity():<\/p>\n<pre class=\"lang:php decode:true\">\/\/ if we create a new property, make sure we set the datatype\nif ( !$exists &amp;&amp; $entity instanceof Property ) {\n  if ( !isset( $data['datatype'] ) ) {\n     $this-&gt;errorReporter-&gt;dieError( 'No datatype given', 'param-illegal' );\n  } elseif ( !in_array( $data['datatype'], $this-&gt;propertyDataTypes ) ) {\n     $this-&gt;errorReporter-&gt;dieError( 'Invalid datatype given', 'param-illegal' );\n  } else {\n     $entity-&gt;setDataTypeId( $data['datatype'] );\n  }\n}<\/pre>\n<p>Such special case handling will not be possible for entity types defined in extensions.<\/p>\n<\/div>\n<p>It is very natural for (DDD) Entities to have required fields. That is not a problem in itself. For examples you can look at our <a href=\"https:\/\/www.entropywins.wtf\/blog\/2016\/11\/24\/implementing-the-clean-architecture\/\">Fundraising software<\/a>.<\/p>\n<p>So what is the problem really?<\/p>\n<h3>Generic vs specific entity handling code<\/h3>\n<p>Normally when you have a (DDD) Entity, say a <code>Donation<\/code>, you also have dedicated code that deals with those <code>Donation<\/code> objects. If you have another entity, say <code>MembershipApplication<\/code>, you will have other code that deals with it.<\/p>\n<p>If the code handling <code>Donation<\/code> and the code handing <code>MembershipApplication<\/code> is very similar, there <em>might<\/em> be an opportunity to share things via composition. One should be very careful to not do this for things that happen to be the same but are conceptually different, and might thus change differently in the future. It\u2019s very easy to add a lot of complexity and coupling by extracting small bits of what would otherwise be two sets of simple and easy to maintain code. This is a topic worthy of its own blog post, and indeed, I might publish one titled <a href=\"https:\/\/www.entropywins.wtf\/blog\/2017\/09\/06\/the-fallacy-of-dry\/\">The Fallacy of DRY<\/a> in the near future.<\/p>\n<p>This sharing via composition is not really visible \u201cfrom outside\u201d of the involved services, except for the code that constructs them. If you have a <code>DonationRepository<\/code> and a <code>MembershipRepository<\/code> interface, they will look the same if their implementations share something, or not. Repositories might share cross-cutting concerns such as logging. Logging is not something you want to do in your repository implementations themselves, but you can easily create simple logging <a href=\"https:\/\/en.wikipedia.org\/wiki\/Decorator_pattern\">decorators<\/a>. A <code>LoggingDonationRepostory<\/code> and <code>LoggingMembershipRepository<\/code> could both depend on the same <code>Logger<\/code> class (or interface more likely), and thus be sharing code via composition. In the end, the <code>DonationRepository<\/code> still just deals with <code>Donation<\/code> objects, the <code>MembershipRepository<\/code> still just deals with <code>Membership<\/code> objects, and both remain completely decoupled from each other.<\/p>\n<p>In the Wikibase codebase there is an attempt at code reuse by having services that can deal with all types of Entities. Phrased like this it sounds nice. From the perspective of the user of the service, things are great at first glance. Thing is, those services then are forced to actually deal with all types of Entities, which almost guarantees greater complexity than having dedicated services that focus on a single entity.<\/p>\n<p>If your <code>Donation<\/code> and <code>MembershipApplication<\/code> entities both implement <code>Foobarable<\/code> and you have a <code>FoobarExecution<\/code> service that operates on <code>Foobarable<\/code> instances, that is entirely fine. Things get dodgy when your Entities don\u2019t always share the things your service needs, and the service ends up getting instances of object, or perhaps some minimal <code>EntityInterface<\/code> type.<\/p>\n<p>In those cases the service can add a bunch of \u201cif has method <code>doFoobar<\/code>, call it with these arguments\u201d logic. Or perhaps you\u2019re checking against an interface instead of method, though this is by and large the same. This approach leads to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Shotgun_surgery\">Shotgun Surgery<\/a>. It is particularly bad if you have a general service. If your service is really only about the <code>doFoobar<\/code> method, then at least you won\u2019t need to poke at it when a new Entity is added to the system that has nothing to do with the Foobar concept. If the service on the other hands needs to fully save something or send an email with a summary of the data, each new Entity type will force you to change your service.<\/p>\n<p>The \u201cif <code>doFoobar<\/code> exists\u201d approach does not work if you want plugins to your system to be able to use your generic services with their own types of Entities. To enable that, and avoid the Shotgun Surgery, your general service can delegate to specific ones. For instance, you can have an <code>EntityRepository<\/code> service with a save method that takes an <code>EntityInterface<\/code>. In it\u2019s constructor it would take an array of specific repositories, i.e. a <code>DonationRepository<\/code> and a <code>MembershipRepository<\/code>. In its save method it would loop through these specific repositories and somehow determine which one to use. Perhaps they would have a <code>canHandle<\/code> method that takes an <code>EntityInterface<\/code>, or perhaps <code>EntityInterface<\/code> has a <code>getType<\/code> method that returns a string that is also used as keys in the array of specific repositories. Once the right one is found, the <code>EntitiyInterface<\/code> instance is handed over to its save method.<\/p>\n<pre class=\"lang:php decode:true\">interface Repository {\n    public function save( EntityInterface $entity );\n    public function canHandle( EntityInterface $entity ): bool;\n}\n\nclass DonationRepository implements Repository { \/**\/ }\nclass MembershipRepository implements Repository { \/**\/ }\n\nclass GenericEntityRepository {\n    \/**\n     * @var Repository[] $repositories\n     *\/\n    public function __construct( array $repositories ) {\n        $this-&gt;repositories = $repositories;\n    }\n\n    public function save( EntityInterface $entity ) {\n        foreach ( $this-&gt;repositories as $repository ) {\n            if ( $repository-&gt;canHandle( $entity ) ) {\n                $repository-&gt;save( $entity );\n                break;\n            }\n        }\n    }\n}<\/pre>\n<p>This delegation approach is sane enough from a OO perspective. It does however involve specific repositories, which begs the question of why you are creating a general one in the first place. If there is no compelling reason to create the general one, just stick to specific ones and save yourself all this not needed complexity and vagueness.<\/p>\n<p>In Wikibase there is a generic web API endpoint for creating new entities. The users provide a pile of information via JSON or a bunch of parameters, which includes the type of Entity they are trying to create. If you have this type of functionality, you are forced to deal with this in some way, and probably want to go with the delegation approach. To me having such an API endpoint is very questionable, with dedicated endpoints being the simpler solution for everyone involved.<\/p>\n<p>To wrap this up: dedicated entity handling code is much simpler than generic code, making it easier to write, use, understand and modify. Code reuse, where warranted, is possible via composition inside of implementations without changing the interfaces of services. Generic entity handling code is almost always a bad choice.<\/p>\n<p>On top of what I already outlined, there is another big issue you can run into when creating generic entity handling code like is done in Wikibase.<\/p>\n<h3>Bounded Contexts<\/h3>\n<p><a href=\"https:\/\/martinfowler.com\/bliki\/BoundedContext.html\">Bounded Contexts<\/a> are a key strategic concept from Domain Driven Design. They are key in the sense that if you don\u2019t apply them in your project, you cannot effectively apply tactical patterns such as Entities and Value Objects, and are not really doing DDD at all.<\/p>\n<blockquote><p>\u201cStrategy without tactics is the slowest route to victory. Tactics without strategy are the noise before defeat.\u201d &#8212; Sun Tzu<\/p><\/blockquote>\n<p>Bounded Contexts allow you to segregate your domain models, ideally having a Bounded Context per subdomain. A detailed explanation and motivation of this pattern is out of scope for this post, but suffice to say is that Bounded Contexts allow for simplification and thus make it easier to write and maintain code. For more information, I can recommend <a href=\"https:\/\/www.goodreads.com\/book\/show\/28602719-domain-driven-design-distilled\">Domain-Driven Design Destilled<\/a>.<\/p>\n<p>In case of Wikibase there are likely a dozen or so relevant subdomains. While I did not do the analysis to create a comprehensive picture of which subdomains there are, which types they have, and which Bounded Contexts would make sense, a few easily stand out.<\/p>\n<p>There is the so-called core Wikibase software, which was created for Wikidata.org, and deals with structured data for Wikipedia. It has two types of Entities (both in the Wikibase and in the DDD sense): Item and Property. Then there is (planned) functionality for Wiktionary, which will be structured dictionary data, and for Wikimedia Commons, which will be structured media data. These are two separate subdomains, and thus each deserve their own Bounded Context. This means having no code and no conceptual dependencies on each other or the existing <a href=\"https:\/\/www.entropywins.wtf\/blog\/2014\/03\/17\/big-ball-of-mud\/\">Big Ball of Mud<\/a> type &#8220;Bounded Context&#8221; in the Wikibase core software.<\/p>\n<h3>Conclusion<\/h3>\n<p>When standard approaches are followed, Entities can easily have required fields and optional fields. Creating generic code that deals with different types of entities is very suspect and can easily lead to great complexity and brittle code, as seen in Wikibase. It is also a road to not separating concepts properly, which is particularly bad when crossing subdomain boundaries.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this blog post I outline my thinking on sharing code that deals with different types of Entities in your&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[452,331,426,328,373,405,451,197,430,316,427,317,336],"class_list":["post-2044","post","type-post","status-publish","format-standard","hentry","category-programming","tag-anti-patterns","tag-architecture","tag-bounded-contexts","tag-clean-code","tag-design-patterns","tag-domain-driven-design","tag-entities","tag-planet-wikimedia","tag-software-architecture","tag-software-design","tag-strategic-design","tag-wikibase","tag-wmde"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Generic Entity handling code - Blog of Jeroen De Dauw<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Generic Entity handling code - Blog of Jeroen De Dauw\" \/>\n<meta property=\"og:description\" content=\"In this blog post I outline my thinking on sharing code that deals with different types of Entities in your&hellip;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog of Jeroen De Dauw\" \/>\n<meta property=\"article:published_time\" content=\"2017-05-24T15:57:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-10-09T23:06:26+00:00\" \/>\n<meta name=\"author\" content=\"Jeroen\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/JeroenDeDauw\" \/>\n<meta name=\"twitter:site\" content=\"@JeroenDeDauw\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeroen\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/\"},\"author\":{\"name\":\"Jeroen\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"headline\":\"Generic Entity handling code\",\"datePublished\":\"2017-05-24T15:57:20+00:00\",\"dateModified\":\"2022-10-09T23:06:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/\"},\"wordCount\":1724,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"keywords\":[\"Anti-patterns\",\"Architecture\",\"Bounded Contexts\",\"Clean Code\",\"Design patterns\",\"Domain Driven Design\",\"Entities\",\"Planet Wikimedia\",\"Software Architecture\",\"Software design\",\"Strategic Design\",\"Wikibase\",\"WMDE\"],\"articleSection\":[\"Programming\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/\",\"url\":\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/\",\"name\":\"Generic Entity handling code - Blog of Jeroen De Dauw\",\"isPartOf\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#website\"},\"datePublished\":\"2017-05-24T15:57:20+00:00\",\"dateModified\":\"2022-10-09T23:06:26+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.entropywins.wtf\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Generic Entity handling code\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#website\",\"url\":\"https:\/\/www.entropywins.wtf\/blog\/\",\"name\":\"Entropy Wins\",\"description\":\"A blog on Software Architecture, Design and Craftsmanship\",\"publisher\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.entropywins.wtf\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\",\"name\":\"Jeroen\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\",\"caption\":\"Jeroen\"},\"logo\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/jeroendedauw\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/JeroenDeDauw\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Generic Entity handling code - Blog of Jeroen De Dauw","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/","og_locale":"en_US","og_type":"article","og_title":"Generic Entity handling code - Blog of Jeroen De Dauw","og_description":"In this blog post I outline my thinking on sharing code that deals with different types of Entities in your&hellip;","og_url":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/","og_site_name":"Blog of Jeroen De Dauw","article_published_time":"2017-05-24T15:57:20+00:00","article_modified_time":"2022-10-09T23:06:26+00:00","author":"Jeroen","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/JeroenDeDauw","twitter_site":"@JeroenDeDauw","twitter_misc":{"Written by":"Jeroen","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#article","isPartOf":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/"},"author":{"name":"Jeroen","@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"headline":"Generic Entity handling code","datePublished":"2017-05-24T15:57:20+00:00","dateModified":"2022-10-09T23:06:26+00:00","mainEntityOfPage":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/"},"wordCount":1724,"commentCount":0,"publisher":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"keywords":["Anti-patterns","Architecture","Bounded Contexts","Clean Code","Design patterns","Domain Driven Design","Entities","Planet Wikimedia","Software Architecture","Software design","Strategic Design","Wikibase","WMDE"],"articleSection":["Programming"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/","url":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/","name":"Generic Entity handling code - Blog of Jeroen De Dauw","isPartOf":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#website"},"datePublished":"2017-05-24T15:57:20+00:00","dateModified":"2022-10-09T23:06:26+00:00","breadcrumb":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.entropywins.wtf\/blog\/2017\/05\/24\/generic-entity-handling-code\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.entropywins.wtf\/blog\/"},{"@type":"ListItem","position":2,"name":"Generic Entity handling code"}]},{"@type":"WebSite","@id":"https:\/\/www.entropywins.wtf\/blog\/#website","url":"https:\/\/www.entropywins.wtf\/blog\/","name":"Entropy Wins","description":"A blog on Software Architecture, Design and Craftsmanship","publisher":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.entropywins.wtf\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7","name":"Jeroen","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g","caption":"Jeroen"},"logo":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/in\/jeroendedauw\/","https:\/\/x.com\/https:\/\/twitter.com\/JeroenDeDauw"]}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p74TBF-wY","jetpack-related-posts":[{"id":1287,"url":"https:\/\/www.entropywins.wtf\/blog\/2014\/03\/20\/status-of-the-new-wikibase-deserialization-code\/","url_meta":{"origin":2044,"position":0},"title":"Status of the new Wikibase (de)serialization code","author":"Jeroen","date":"2014-03-20","format":false,"excerpt":"A quick update on the status of the new serialization and deserialization code for Wikibase, the software behind Wikidata. For a long time now, we've had two serialization formats. One intended for external usage, and one intended for internal usage. The former one is the format our web API uses.\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/www.entropywins.wtf\/blog\/category\/software\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1165,"url":"https:\/\/www.entropywins.wtf\/blog\/2013\/12\/23\/wikibase-datamodel-released\/","url_meta":{"origin":2044,"position":1},"title":"Wikibase DataModel released!","author":"Jeroen","date":"2013-12-23","format":false,"excerpt":"I\u2019m happy to announce the 0.6 release of Wikibase DataModel. This is the first real release of this component. DataModel? Wikibase is the software behind Wikidata.org. At its core, this software is about describing entities. Entities are collections of claims, which can have qualifiers, references and values of various different\u2026","rel":"","context":"In \"Component\"","block_context":{"text":"Component","link":"https:\/\/www.entropywins.wtf\/blog\/tag\/component\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2278,"url":"https:\/\/www.entropywins.wtf\/blog\/2018\/08\/14\/bounded-contexts-in-the-wikimedia-fundraising-software\/","url_meta":{"origin":2044,"position":2},"title":"Bounded Contexts in the Wikimedia Fundraising Software","author":"Jeroen","date":"2018-08-14","format":false,"excerpt":"In this follow-up to rewriting the Wikimedia Deutschland fundraising I tell the story of how we reorganized our codebases along the lines of the DDD strategic pattern Bounded Contexts. In 2016 the FUN team at Wikimedia Deutschland rewrote the Wikimedia Deutschland fundraising application. This new codebase uses The Clean Architecture\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"Diagram depicting Clean Architecture + Bounded Contexts","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/Such-Clean-Diagram.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/Such-Clean-Diagram.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/Such-Clean-Diagram.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/Such-Clean-Diagram.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/Such-Clean-Diagram.png?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":2358,"url":"https:\/\/www.entropywins.wtf\/blog\/2018\/09\/09\/clean-architecture-bounded-contexts-diagram\/","url_meta":{"origin":2044,"position":3},"title":"Clean Architecture + Bounded Contexts diagram","author":"Jeroen","date":"2018-09-09","format":false,"excerpt":"I\u2019m happy to release a two Clean Architecture + Bounded Contexts diagrams into the public domain (CC0 1.0). I created these diagrams for Wikimedia Deutchland with the help of Jan Dittrich, Charlie Kritschmar and Hanna Petruschat. They represent the architecture of our fundraising codebase. I explain the rules of this\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/09\/FunArchitecture.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/09\/FunArchitecture.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/09\/FunArchitecture.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/09\/FunArchitecture.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/09\/FunArchitecture.png?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":1337,"url":"https:\/\/www.entropywins.wtf\/blog\/2014\/05\/06\/the-wikidata-phase3-software-components\/","url_meta":{"origin":2044,"position":4},"title":"The Wikidata phase3 software components","author":"Jeroen","date":"2014-05-06","format":false,"excerpt":"Work on the long awaited query functionality for the Wikidata project has already happened during a period of several months. Since queries are a completely disjoint feature set from the existing functionality, we decided to put it into a new component part of the Wikibase software. This component is called\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2210,"url":"https:\/\/www.entropywins.wtf\/blog\/2018\/08\/14\/clean-architecture-bounded-contexts\/","url_meta":{"origin":2044,"position":5},"title":"Clean Architecture + Bounded Contexts","author":"Jeroen","date":"2018-08-14","format":false,"excerpt":"In this follow-up to Implementing the Clean Architecture I introduce you to a combination of The Clean Architecture and the strategic DDD pattern known as Bounded Contexts. At Wikimedia Deutschland we use this combination of The Clean Architecture and Bounded Contexts for our fundraising applications. In this post I describe\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/CleanArchitecture_DomainDrivenDesign.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/CleanArchitecture_DomainDrivenDesign.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/CleanArchitecture_DomainDrivenDesign.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/CleanArchitecture_DomainDrivenDesign.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2018\/08\/CleanArchitecture_DomainDrivenDesign.png?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/2044","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/comments?post=2044"}],"version-history":[{"count":5,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/2044\/revisions"}],"predecessor-version":[{"id":2899,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/2044\/revisions\/2899"}],"wp:attachment":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/media?parent=2044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/categories?post=2044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/tags?post=2044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}