<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tim Sommer</title>
    <description>The latest articles on Forem by Tim Sommer (@sommertim).</description>
    <link>https://forem.com/sommertim</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F427540%2Fb04b846d-ee8a-4a85-8d9b-3c28bf2b72b4.jpg</url>
      <title>Forem: Tim Sommer</title>
      <link>https://forem.com/sommertim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sommertim"/>
    <language>en</language>
    <item>
      <title>Architectural Decision Record</title>
      <dc:creator>Tim Sommer</dc:creator>
      <pubDate>Thu, 08 Apr 2021 06:53:59 +0000</pubDate>
      <link>https://forem.com/sommertim/architectural-decision-record-4oom</link>
      <guid>https://forem.com/sommertim/architectural-decision-record-4oom</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.timsommer.be%2Fcontent%2Fimages%2F2021%2F04%2Fkaleidico-26MJGnCM0Wc-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.timsommer.be%2Fcontent%2Fimages%2F2021%2F04%2Fkaleidico-26MJGnCM0Wc-unsplash.jpg" alt="Architectural Decision Record"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I firmly believe there is no such thing as a "bad" or a "good" architecture. It either fits the business needs from a technical perspective, or it doesn't. A technical design is always the result of a series of "choices" and "decisions" throughout the lifetime of that design. But it's not good or bad, it's a matter of how &lt;a href="https://www.timsommer.be/using-fitness-functions-to-create-evolving-architectures/" rel="noopener noreferrer"&gt;&lt;em&gt;fit&lt;/em&gt; the design is&lt;/a&gt;, given the &lt;em&gt;current and historical constraints and requirements&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It's critical that you hold a good "record" or "log" of those design decisions. Because that's the reason why any design is at a certain state, at any given point in time. This post is meant to aid developers and architects into creating such "decision logs". And for this, we will use Architectural Decision Records (or ADR's).&lt;/p&gt;

&lt;h2&gt;
  
  
  The art of decision making
&lt;/h2&gt;

&lt;p&gt;Having to make decisions on a regular basis can create a great deal of uncertainty and anxiety. Especially if that decision has an impact on the evolvability of your design. &lt;em&gt;Did I think this decision over long enough? Did I take enough data into consideration?&lt;/em&gt; But in the end, you'll find that you never could take enough data into consideration. &lt;em&gt;The data for any given situation is infinite&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And as such, worriers are people who think of all the variables beyond their control, and what might happen, and as a result are afraid to make the wrong decision.&lt;/p&gt;

&lt;p&gt;To be clear, I'm not implying that you shouldn't think about your decisions. But you &lt;em&gt;should never be afraid to make one&lt;/em&gt;. Even if every decision you make throughout the path of your evolving design is wrong, as long as your design is evolving, you're on the correct path. And as long as you record your decision process, you open new doors down the road, to correct the incorrect.&lt;/p&gt;

&lt;h2&gt;
  
  
  ADR's
&lt;/h2&gt;

&lt;p&gt;Your technical documentation should have different "types". A high level (system-) design, an application design, infrastructure details, etc.&lt;br&gt;&lt;br&gt;
ADR's are a bit a-typical, but they should &lt;strong&gt;not (!)&lt;/strong&gt; be regarded as a replacement for other types of technical documentation!&lt;/p&gt;

&lt;p&gt;The Architectural Decision Record (as the name implies) is a log of decisions made by a team while they evolve the design of their application. It can be documented in many ways, with all sorts of templates. It should, however, always include the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ADR Lead&lt;/strong&gt;
The person(s) taking charge of the ADR. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status&lt;/strong&gt;
The status of the ADR in its lifecycle. Examples could be "Draft", "In Review", "Decision Presented", "Implementation started", "Implemented", "Closed".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt;
The context of the problem for which the ADR will provide a solution. What are you trying to decide? What problem are you trying to solve? &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution(s)&lt;/strong&gt;
Once you've defined the problem you should think about different solutions. Always try to define more than one! This motivates out-of-the-box thinking, weighing up benefits versus drawbacks, implementation costs, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk analysis&lt;/strong&gt;
Some sort of risk calculation. What degree of risk does the current problem introduce. How will the different solutions work towards mitigation of those risks?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requirements&lt;/strong&gt;
What requirements must be met? You can use the &lt;a href="https://en.wikipedia.org/wiki/MoSCoW_method" rel="noopener noreferrer"&gt;MoSCoW method&lt;/a&gt;, or any other system you like. Make sure your requirements are crystal clear! &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimations&lt;/strong&gt;
How much will each solution cost? This will impact the final decision, so this is an important part of the ADR. The most elegant solution will not always be the right solution. It should be realistic, and for this, cost/benefit evaluation is critical. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The decision!&lt;/strong&gt;
Eventually, you'll have to make a decision. Which in turn will be presented to project management. You should be able to explain what you want to do, why you need to do it and how much time you will need.
Notice that all previous steps are formal checkpoints to allow you to make the best possible choice and to take into account as much data as possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So an ADR, once integrated in your technical workflow, allows you to &lt;em&gt;document&lt;/em&gt; &lt;em&gt;informed decisions in a formal way&lt;/em&gt;.  A &lt;em&gt;design record is created for future reference&lt;/em&gt;, and can be used to &lt;em&gt;present your decisions to management&lt;/em&gt; in a formal and conclusive way.&lt;/p&gt;

&lt;p&gt;A solution summary will look something like the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.timsommer.be%2Fcontent%2Fimages%2F2021%2F04%2F2021-04-06-11_38_23-Edit---ADR.004---SonarQube-Metrics---QFRAME-Algemeen---Confluence---Mozilla-Fire-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.timsommer.be%2Fcontent%2Fimages%2F2021%2F04%2F2021-04-06-11_38_23-Edit---ADR.004---SonarQube-Metrics---QFRAME-Algemeen---Confluence---Mozilla-Fire-1.png" alt="Architectural Decision Record"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision process
&lt;/h2&gt;

&lt;p&gt;So, I've explained the what, who and why of ADR's. Let's take a look at the how. When documenting ADR's, keep the following in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The main goal is to document the decision process.&lt;/li&gt;
&lt;li&gt;An ADR should always have one person in the "lead", someone who is &lt;em&gt;responsible for researching the problem&lt;/em&gt;. Choosing a r_ecommended solution is a team responsibility_. Giving a &lt;em&gt;green light for that solution is a management responsibility&lt;/em&gt;.
&lt;/li&gt;
&lt;li&gt;The whole team should be involved in the finalization of the ADR. Everyone should understand the research and the decision process. The conclusion should be &lt;em&gt;unanimous&lt;/em&gt;. &lt;strong&gt;An ADR is a living document&lt;/strong&gt;! Everyone has a say, everyone can view, and everyone has a vote. The more people involved, the better the decision will be. &lt;/li&gt;
&lt;li&gt;Allow all members of your team to take lead on ADR's. This allows them to become more experienced, to learn to think outside the box and gain more confidence in the decision making process. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Architectural Decision Records are a powerful tool for documenting the design decision making process.&lt;br&gt;&lt;br&gt;
Does that mean that you will now automatically make all the right decisions with these ADR's? Nope. But it will provide insights as to why certain choices were made. If the decision turns out wrong, the most valuable part is &lt;em&gt;getting a grasp on why&lt;/em&gt; it was wrong. Who made the call, did he/she have the right information, did anyone else see the problem in a different way? This information is extremely valuable for evolving your design in the way you want, and to gain more experience in the process.&lt;/p&gt;

&lt;p&gt;Big thanks to &lt;a href="https://www.linkedin.com/in/karinwauters/" rel="noopener noreferrer"&gt;Karin Wauters&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/marijke-walgraeve-7320846b/" rel="noopener noreferrer"&gt;Marijke Walgraeve&lt;/a&gt; for reviewing this post.&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@kaleidico?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Kaleidico&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>development</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The "Pavarotti-String" Design Pattern</title>
      <dc:creator>Tim Sommer</dc:creator>
      <pubDate>Tue, 25 Aug 2020 10:19:15 +0000</pubDate>
      <link>https://forem.com/sommertim/the-pavarotti-string-design-pattern-1np9</link>
      <guid>https://forem.com/sommertim/the-pavarotti-string-design-pattern-1np9</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wOxDwwEE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/08/fotis-fotopoulos-LJ9KY8pIH3E-unsplash-1-.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wOxDwwEE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/08/fotis-fotopoulos-LJ9KY8pIH3E-unsplash-1-.jpg" alt="The"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First things fist: the "Pavarotti-String" design pattern, is not a design pattern :). It's more of a programming practice; and the idea was pitched to me about 3 or 4 years ago. But it can be a real pain if it's ignored in large code bases; and a solution can be applied pretty easily.&lt;br&gt;&lt;br&gt;
Calling it the "Pavarotti-String Design Pattern" is a simple but effective trick to help you remember implementing it. But more on that later :).&lt;/p&gt;
&lt;h3&gt;
  
  
  Strings everywhere
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tMdfIRzv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/08/2ks3pk-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tMdfIRzv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/08/2ks3pk-1.jpg" alt="The"&gt;&lt;/a&gt;&lt;/p&gt;

  



&lt;p&gt;It's a common mistake. Having strings (or other value-type objects) placed throughout your code. Think of names of connection-string, queue names, table names, etc.&lt;br&gt;&lt;br&gt;
Floating string values scattered trough your code-base will impair your ability to refactor your code efficiently. Worst case should one of those strings need to change? Find-replace..&lt;/p&gt;

&lt;p&gt;Let us look at the following code sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await _servicebusSenderClient.GetMessageSender("superduper-datapersistence-queue")
                             .SendAsync(message);

exporter.Verify(c =&amp;gt; c.ExportToCrmAsync(It.Is&amp;lt;CrmContract&amp;gt;(x =&amp;gt;
                x.Component != "NotSpecified" &amp;amp;&amp;amp;
                x.Component == "aDefaultComponent" &amp;amp;&amp;amp;
                x.Process == "theDefaultProcess" &amp;amp;&amp;amp;
                x.Type == "domeDefaultType" &amp;amp;&amp;amp;
                x.Label == "SomeLabel"
                ), string.Empty));               
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;MessageBus&lt;/code&gt; can be used as a primary example. The first line of code sends a message to the &lt;code&gt;"superduper-datapersistence-queue"&lt;/code&gt; queue.&lt;br&gt;&lt;br&gt;
The main problem with using a string like this is that you can only search your entire code base for that string to see where something is put on that queue.&lt;br&gt;&lt;br&gt;
And if you want to change the queue name; you can only use 'Find-Replace'. In modern programming techniques that is a bad practice; and violates SOLID principles.&lt;/p&gt;

&lt;p&gt;The same goes for &lt;em&gt;some&lt;/em&gt; of the string values in the second line. The constant (or default in these cases) values are used to get a set of objects that matches the parameters. The &lt;code&gt;x.label&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a default one; and as such; we will not touch it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fixing it
&lt;/h3&gt;

&lt;p&gt;Fixing is fairly easy. We move the default string values into a separate static &lt;code&gt;Constants&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static class Constants
{
     public static class QueueNames
     {
            public const string DatapersistenceQueue = "superduper-datapersistence-queue";
            public const string SomeOtherQueue = "someother-queue";
     }

     public static class StringValues
     {
            public const string Unspecified = "NotSpecified";
            public const string DefaultComponent = "aDefaultComponent";
            public const string DefaultProcess = "theDefaultProcess";
            public const string Type = "domeDefaultType";
     }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This now enables us to use &lt;code&gt;Constants.QueueNames.DatapersistenceQueue&lt;/code&gt; instead of the string value. Same goes for the &lt;code&gt;StringValues&lt;/code&gt; for &lt;em&gt;default&lt;/em&gt; values.&lt;/p&gt;

&lt;p&gt;Our code sample will then look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await _servicebusSenderClient.GetMessageSender(Constants.QueueNames.DatapersistenceQueue)
                             .SendAsync(message);

exporter.Verify(c =&amp;gt; c.ExportToCrmAsync(It.Is&amp;lt;CrmContract&amp;gt;(x =&amp;gt;
                x.Component != Constants.StringValues.Unspecified &amp;amp;&amp;amp;
                x.Component == Constants.StringValues.DefaultComponent &amp;amp;&amp;amp;
                x.Process == Constants.StringValues.DefaultProcess &amp;amp;&amp;amp;
                x.Type == Constants.StringValues.DefaultType &amp;amp;&amp;amp;
                x.Label == "SomeLabel"
                ), string.Empty));               
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The advantages should be obvious. You can simply change a string value in the &lt;code&gt;Constants&lt;/code&gt; class, and the change is incorporated in your whole code base. It also results in much cleaner code. You can do safe refactoring and you can move away from the "Find/Replace" functionality.&lt;/p&gt;

&lt;p&gt;This also works for other value types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var dbMax = Constants.DbValues.MaxSelectCount;
var pageCount = Constants.Paging.PageCount;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Pavarotti?
&lt;/h3&gt;

&lt;p&gt;So why call it the "Pavarotti-design pattern"? It is actually meant as a joke; and provides a simple way for remembering it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Luciano_Pavarotti"&gt;Pavarotti&lt;/a&gt; was an Italian Opera legend. I mean absolutely no harm or offense; he was one of the greatest opera singers ever!  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Te7rW9La--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/08/48954537_303.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Te7rW9La--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/08/48954537_303.jpg" alt="The"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, he was also quite large..&lt;br&gt;&lt;br&gt;
The idea is that every time you see a floating string value in your code-base; imagine Pavarotti in a string (yes, the underpants in this case). That's how much it should hurt if your see string value violations. And the mental image should motivate you to apply a fix immediately ;).&lt;/p&gt;

&lt;p&gt;Hope you enjoyed the read; happy coding !&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@ffstop?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Fotis Fotopoulos&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/coding?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>cleancode</category>
      <category>development</category>
    </item>
    <item>
      <title>On the art of learning and the imposter syndrome</title>
      <dc:creator>Tim Sommer</dc:creator>
      <pubDate>Thu, 18 Jun 2020 06:20:37 +0000</pubDate>
      <link>https://forem.com/sommertim/on-the-art-of-learning-and-the-imposter-syndrome-5d9e</link>
      <guid>https://forem.com/sommertim/on-the-art-of-learning-and-the-imposter-syndrome-5d9e</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BehrCy7A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/06/nick-morrison-FHnnjk1Yj7Y-unsplash-min.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BehrCy7A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/06/nick-morrison-FHnnjk1Yj7Y-unsplash-min.jpg" alt="On the art of learning and the imposter syndrome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this post, I would like to address how I learn, how I teach and how I deal with anxiety around the "imposter syndrome".&lt;/p&gt;

&lt;h2&gt;
  
  
  Always learning
&lt;/h2&gt;

&lt;p&gt;Every developer, certainly in modern times, spends a lot of time learning new things. Improving and adding skills to your skill-set, adding new tools to your tool-belt and deepening your technical knowledge.&lt;br&gt;&lt;br&gt;
You might feel, like me, that you're behind; all of the time.&lt;br&gt;&lt;br&gt;
Despite popular though, this is true for everyone. I have more than 10 years of development experience and I constantly need to learn new things. Not only because new technology stacks and/or frameworks pop up constantly; but also because it takes a while (and a lot of effort) to become a true "expert" in any subject.&lt;br&gt;&lt;br&gt;
Unlearning stuff is also just as important. Patterns you develop might not be up-to-date, or just plain wrong.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Half of wisdom is learning what to unlearn.” -Larry Niven&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The road to success is always a never ending cycle, for juniors and seniors alike:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--icRlJ9tR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/02/2020-02-28-16_16_26-18012017-T4T---What-is-your-superPower.pptx---PowerPoint.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--icRlJ9tR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/02/2020-02-28-16_16_26-18012017-T4T---What-is-your-superPower.pptx---PowerPoint.png" alt="On the art of learning and the imposter syndrome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can imagine that this can seem a bit daunting. Maybe even create some anxiety, especially among the younger readers. But learning new things should also be fun! If it isn't, you are most likely doing it wrong, working in a wrong environment or (let's hope not!!) started a career as a developer without fully understanding what that actually means.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ways to learn
&lt;/h3&gt;

&lt;p&gt;We all learn differently. Some like to take the biggest (I imagine) book they can find and start ploughing trough thousands of pages of technical specs.&lt;br&gt;&lt;br&gt;
Others like to listen to podcasts or view tutorials online on platforms like Pluralsight.&lt;br&gt;&lt;br&gt;
And then others got to conferences, read blogs, do research or just hack through something until they hit a concrete wall thick enough that they simply have to defer to the manual.&lt;/p&gt;

&lt;p&gt;In learning &lt;strong&gt;there is no correct way&lt;/strong&gt; , but there is &lt;strong&gt;a correct way for you.&lt;/strong&gt; Most likely it will be a combination of the things listed above. It is, however, really important that you learn ways to &lt;strong&gt;formalize your learning process&lt;/strong&gt;. If you want to get better, you have to find ways to continuously improve your skill-set. Think of it of a Continuous Integration framework for your learning process!  &lt;/p&gt;

&lt;h3&gt;
  
  
  Times to learn
&lt;/h3&gt;

&lt;p&gt;Figure out the time when you are most productive. For me this is mostly in the morning and early afternoon. I tend to do most of my complex programming tasks in that time window, leaving administrative and repetitive tasks for the afternoon.&lt;/p&gt;

&lt;p&gt;Remember that, even though it might &lt;em&gt;feel&lt;/em&gt; that it is absolutely vital to know a certain technology by a certain point in time, setting deadlines might be contra-productive. It's entirely possible that you have extended periods where you are able to work late into the evening, or even into the night.&lt;br&gt;&lt;br&gt;
But remember, your body should always come first. It does not listen to deadlines. When you are tired, or simply not in the mood, obligating yourself to work through technical documentation or difficult code bases can have a negative effect. Leaving you with a feeling of defeat. Sometimes it is better to allow your body to recover, to let yourself energize for the road ahead. Because there certainly will be times where you will just have to work through everything to reach a certain point.&lt;br&gt;&lt;br&gt;
But hopefully you can limit that to the absolute minimum. For me, taking time to get "unconnected" is absolutely vital; that's the time I need to recharge my batteries.&lt;/p&gt;

&lt;p&gt;Try to listen to and respect your body and mind. If you treat yourself with respect, the return of investment will be a great reward.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "imposter syndrome"
&lt;/h3&gt;

&lt;p&gt;Let go of the feeling that you have to know everything about everything. You can't, it's as simple as that. There are so many different tools, frameworks and technologies around making it impossible for you to know them all. &lt;strong&gt;This goes for everyone&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once you get the feeling that your colleagues know more than you; and you just nod along with the technical gibberish that comes out of their mouths, you're experiencing something we call the "imposter syndrome".&lt;br&gt;&lt;br&gt;
The anxiety you experience around being exposed as an imposter; a somehow "lesser" developer than other members of your team/company.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O-kF6QaO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/06/687b664850f0f5e359ab12f7bc9ee035.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O-kF6QaO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/06/687b664850f0f5e359ab12f7bc9ee035.jpg" alt="On the art of learning and the imposter syndrome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you do feel like most of the words you hear from you colleagues are absolute gibberish (and are afraid to ask them to explain them), simply write them down and research them later. It takes a while; but you will get there. Remember; we all experience it! Speaking and asking for an explanation can be challenging; but it can be rewarding too. It's one of the ways we learn; and grow; as a person.&lt;/p&gt;

&lt;p&gt;Remember, everyone experiences it. The only real difference is that; once you have enough experience; the anxiety will not be as big of a deal. It might never go away completely, but the more you believe in yourself, the less afraid you'll become.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bqRF4iZD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/06/imposter.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bqRF4iZD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/06/imposter.png" alt="On the art of learning and the imposter syndrome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a general rule: it is always better to start with a &lt;strong&gt;broad knowledge base&lt;/strong&gt; (knowing what something is without ever having come in touch with it) than a &lt;strong&gt;deep knowledge base&lt;/strong&gt; (knowing a technology backwards and forwards).&lt;/p&gt;

&lt;h3&gt;
  
  
  Final words
&lt;/h3&gt;

&lt;p&gt;You should regard your knowledge base as something ever changing. Like a computer, which tends to be a good metaphor, since most of my readers are IT minded ;).&lt;/p&gt;

&lt;p&gt;Your memory has both RAM and SSD storage. Your job is to load as lot of knowledge in your RAM as you possibly can, but only regarding topics you're working on at that moment. If you use a certain technology, pattern or tool a lot; that RAM gets placed into you SSD. Even this knowledge will fade away over time; but not as quickly. If you don't use the 'data' enough, it will be erased for newer things.&lt;br&gt;&lt;br&gt;
But developers should be (and not always are) respected for &lt;em&gt;their compute value&lt;/em&gt;. Their CPU Power if you will. The power that combines your memory with the skills to write good code, to research new things and learn new specs quickly.&lt;/p&gt;

&lt;p&gt;And, if you are a PC tweaker like I am, one general rule of thumb: &lt;u&gt;&lt;em&gt;Don't ever let your system overheat ;).&lt;/em&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@nickmorrison?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Nick Morrison&lt;/a&gt; on &lt;a href="https://unsplash.com"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programmer</category>
      <category>learning</category>
    </item>
    <item>
      <title>Human readable Dependency Injection in .NET Core</title>
      <dc:creator>Tim Sommer</dc:creator>
      <pubDate>Fri, 24 Apr 2020 06:56:21 +0000</pubDate>
      <link>https://forem.com/sommertim/human-readable-dependency-injection-in-net-core-5d0b</link>
      <guid>https://forem.com/sommertim/human-readable-dependency-injection-in-net-core-5d0b</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6CHBWAHr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/04/markus-spiske-466ENaLuhLY-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6CHBWAHr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2020/04/markus-spiske-466ENaLuhLY-unsplash.jpg" alt="Human readable Dependency Injection in .NET Core"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In many applications and development teams, &lt;em&gt;dependency injection&lt;/em&gt; (or DI) with &lt;em&gt;inversion of control&lt;/em&gt; (or IoC) has become standard practice for creating better software design. It allows for &lt;strong&gt;loosely coupled modules&lt;/strong&gt; , &lt;strong&gt;better unit tests&lt;/strong&gt; (or even TDD) and a better implementation of &lt;strong&gt;SOLID principles&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Over the years we all got used to our favorite IoC frameworks; including Autofac, Ninject, Windsor and many others. But, with the release of ASP.NET Core, we now have DI built right into the framework! It is intentionally designed to have less features, lowering the learning curve for those who are unfamiliar with the concept. And, should the built-in IoC container not meet all your needs, a third-party IoC container plugin can be used quite easily.&lt;/p&gt;

&lt;p&gt;With this post I would like to show you how you can write "human readable" dependency registrations. While this is framework agnostic, the code samples use the .NET Core DI framework.&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with dependency injection in ASP.NET Core, please review the documentation provided by Microsoft &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, let's dive in!&lt;/p&gt;

&lt;h3&gt;
  
  
  Standard registrations
&lt;/h3&gt;

&lt;p&gt;We use the &lt;code&gt;IServiceCollection&lt;/code&gt; to do registrations in the &lt;code&gt;Startup&lt;/code&gt; class of the client application. Which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton&amp;lt;IApp&amp;gt;(new App("switching-api"));
    services.AddDbContext&amp;lt;SomebContext&amp;gt;(o =&amp;gt;
                        o.UseSqlServer(SqlServerConnectionString))
    services.AddTransient&amp;lt;IRepository, Repository&amp;gt;();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Layered Application
&lt;/h3&gt;

&lt;p&gt;As a general practice, move your registration to the responsible layer. If you have a data access layer (DAL), all registrations should be located within its boundaries. This follows the DRY (don't repeat yourself) principle and increases the level of maintainability (remember SOLID).&lt;/p&gt;

&lt;p&gt;We can use an extension method to achieve exactly that. In the DB project, we add a file containing the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static IServiceCollection RegisterDbModule(this IServiceCollection services, string connectionString)
{
    services.AddDbContext&amp;lt;SomebContext&amp;gt;(
       options =&amp;gt; options.UseSqlServer(connectionString));
    services.AddDbContext&amp;lt;ReadReplicaContext&amp;gt;(
       options =&amp;gt; options.UseSqlServer(connectionString));
    services.AddTransient&amp;lt;IRepository, Repository&amp;gt;();
    services.AddTransient&amp;lt;IFastReadService, FastReadService&amp;gt;();

    return services;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All the DB related registrations are moved to the DAL. Our startup class is now much cleaner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton&amp;lt;IApp&amp;gt;(new App("switching-api"));
    services.RegisterDbModule(SqlServerConnectionString);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Advantages should be clear at this point. We can use the &lt;code&gt;RegisterDbModule&lt;/code&gt; wherever we want. Multiple clients (and multiple &lt;code&gt;Startup&lt;/code&gt; classes) are not subject to change any more. If we need extra registrations in the DAL, we only need to change the extension method.&lt;/p&gt;

&lt;h3&gt;
  
  
  N-Tier and Micro-Services
&lt;/h3&gt;

&lt;p&gt;If you have a lot of layers, a lot of micro services, an N-Tier or message/event driven application; the &lt;code&gt;RegisterDbModule&lt;/code&gt; will not be enough.&lt;br&gt;&lt;br&gt;
Enter human readable registrations!&lt;/p&gt;

&lt;p&gt;Moving on with the sample, we could split up the code even further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static IServiceCollection WithDbContext(this IServiceCollection services, string connectionString)
{
    services.AddDbContext&amp;lt;SomebContext&amp;gt;(
       options =&amp;gt; options.UseSqlServer(connectionString));

    return services;
}

public static IServiceCollection WithFastReadReplica(this IServiceCollection services, string connectionString)
{
    services.AddDbContext&amp;lt;ReadReplicaContext&amp;gt;(
       options =&amp;gt; options.UseSqlServer(connectionString));
    services.AddTransient&amp;lt;IFastReadService, FastReadService&amp;gt;();

    return services;
}

public static IServiceCollection WithRepositories(this IServiceCollection services)
{
    services.AddTransient&amp;lt;IRepository, Repository&amp;gt;();

    return services;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which then gives you more control regarding dependency availability for each client application. With the sample above, our &lt;code&gt;Startup&lt;/code&gt; class now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton&amp;lt;IApp&amp;gt;(new App("switch-api"));

    //no fast read service required for this client
    services.WithDbContext(SqlServerConnectionString)
            .WithRepositories();

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or, with the fast-read service required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    //fast read service required for this client
    services.WithDbContext(SqlServerConnectionString)
            .WithFastReadReplica(SqlServerConnectionString)
            .WithRepositories();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is, of course, an overly simplistic sample.&lt;br&gt;&lt;br&gt;
If you are working on a an application where the registrations get more complex, the advantages are enormous.&lt;/p&gt;

&lt;p&gt;Let's take a look at a bootstrap &lt;code&gt;Startup&lt;/code&gt; class of a fairly complex application using Azure Service Bus, Azure BlobStorage and Azure functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Startup : FunctionsStartup

    public override void Configure(IFunctionsHostBuilder builder)
    {
        var config = new ConfigurationBuilder().AddEnvironmentVariables().Build();
        var connectionStore = new AzureCredentialStore(config);

        builder.Services.AddSingleton&amp;lt;IApp&amp;gt;(new App("some-app"));

        builder.Services
               .PerformDefaultRegistrationForFunction(connectionStore)
               .WithAzureBlobStorage(typeof(AzureBlobContainer).Assembly)
               .WithDbContext(connectionStore)
               .WithRectificationTraceService()
               .WithRetryHandling()
               .WithEventModule()
               .WithEntityCollectors()
               .WithMarketExport();

        builder.Services.AddLogging();

    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, the code is very clear and transparent. It only takes a second to analyze what will be available for this client during its run-time.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed the read and happy coding!&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Markus Spiske&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnetcore</category>
      <category>di</category>
      <category>dependencyinjection</category>
    </item>
    <item>
      <title>(Don't?) Keep It Simple Stupid!</title>
      <dc:creator>Tim Sommer</dc:creator>
      <pubDate>Tue, 07 May 2019 08:37:55 +0000</pubDate>
      <link>https://forem.com/sommertim/don-t-keep-it-simple-stupid-55d1</link>
      <guid>https://forem.com/sommertim/don-t-keep-it-simple-stupid-55d1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y7-wr22r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2019/05/Optimized-hans-peter-gauster-252751-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y7-wr22r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.timsommer.be/content/images/2019/05/Optimized-hans-peter-gauster-252751-unsplash.jpg" alt="(Don't?) Keep It Simple Stupid!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For as long as I can remember, the &lt;a href="https://en.wikipedia.org/wiki/KISS_principle"&gt;KISS&lt;/a&gt; (Keep It Simple Stupid) principle has been around to remind developers and businesses to approach a given problem with the easiest (or most simple) solution as possible.&lt;br&gt;&lt;br&gt;
Which basically means that the complexity of a software design should always be correlated to the complexity of the problem it tries to solve.&lt;br&gt;&lt;br&gt;
So, to put it simple: simple problem, simple solution, complex problem, complex solution..&lt;br&gt;&lt;br&gt;
Simple, right?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The art of simplicity is a puzzle of complexity. -Douglas Horton&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Architecturing things
&lt;/h2&gt;

&lt;p&gt;I've been a software architect for a couple of years now. I've solved very big "problems" and I've solved small ones. One of the many things I've learned in my career is that &lt;a href="https://www.timsommer.be/using-fitness-functions-to-create-evolving-architectures/"&gt;Software Design has to evolve&lt;/a&gt;, and that you have to be able to evaluate how changes impact the important characteristics of the architecture and prevent degradation of those characteristics over time. These changes can include changes in the technical landscape, changes in your team, changes in requirements, etc.&lt;/p&gt;

&lt;p&gt;In the last couple of years (probably even more so since the first major release of NodeJS in 2009) new technology stacks have been introduced at lightning speed in the .NET development community. CQS, CQRS, AngularJS, AngularX (2,3,4,5,6), React, VueJS, VueX, .NET Core, JS Functional Programming, CLI tooling, bower (or is it Yarn now), NPM, event sourcing, docker, parallel computing, AI and even Quantum Computing.. The list goes on and on and on.&lt;/p&gt;

&lt;p&gt;We currently have the possibility to solve the most complex problems with the most advanced solutions. But it is up to you to keep up. And in my opinion, here lies the biggest problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges of an always changing Development Landscape
&lt;/h3&gt;

&lt;p&gt;As an architect you have to evolve alongside the changes of your technical landscape. You've got to keep up, so that you can provide the best and most up-to-date solution for the problem you are trying to solve.&lt;br&gt;&lt;br&gt;
But that is not always easy. With an always changing landscape it is becoming very hard -maybe even impossible- to stay on top of things. When you start learning a new technology, language or framework today; it is not unlikely that that technology will become outdated, upgraded or obsolete before you get the chance to master it. Staying on top of things is a bit like a hypothetical dog, trying to catch its own tail.&lt;/p&gt;

&lt;p&gt;The complexity of a given problem is just one of the factors (let's call them &lt;em&gt;dimensions&lt;/em&gt;) that you take into account when deciding on your software design. The team of developers you have to work with is an equally important dimension (are they familiar with web technologies, do they work remotely, which software methodologies do they use, etc.). Another important dimension is deciding where the "heart" of your software design lies, and how and what you will use to test its evolution.&lt;/p&gt;

&lt;p&gt;And maybe most important of all, which technologies will you incorporate. Which design patterns will you choose? Does the design need to be reusable? How long will the design be used?&lt;br&gt;&lt;br&gt;
You'll have to get it just right, iterate over your ideas and make changes accordingly.&lt;/p&gt;

&lt;p&gt;It seems -in Belgium at least- that one of those practical lesson learned after years of being an application architect somehow got forgotten over the years. You've got to keep things suited for the problem at hand. Never forget that adding complexity is always a vicious circle. Just like worrying, where you eventually find that you worry because you worry, because you worry. Adding complexity is much like that. Which is neither good or bad, it just is; but you have to know what you are doing, and what the consequences of your actions are. When you start adding complexity just for the sake of adding complexity, things tend to get out of control, fast.&lt;/p&gt;

&lt;p&gt;Let's try a use case: Say we have a web application that at a certain point in time has to deal with more load than it can handle. The application uses an in-memory cache to avoid round trips to the Database Server. Because of the new load (= new complexity) we have to change our caching mechanism to a distributed cache so that we can scale out (deploy your app on multiple servers). &lt;em&gt;So, we add complexity to incorporate the new complexity!&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Because we are now using a distributed cache, all our developers will also need access to a local distributed cache. We will need to add it into our development cycle, we'll have to add automation, add integration tests, teach our developers what they need to know and setup distributed caches for our different environments.&lt;br&gt;&lt;br&gt;
A fairly simple change in complexity is like throwing pebble in a pool. Each ripple you create is like a new layer of complexity, spanning not only to the development itself, but across the whole development and deployment process (from development into production).&lt;/p&gt;

&lt;p&gt;Always remember, the most complex -or coolest- solution is not always the right solution. Just because you can, does not mean you should! There are many dimensions that drive software designs, technology stack is just one of them.&lt;br&gt;&lt;br&gt;
If you are using something just to use something (because it's cool, because it's bleeding edge), which does not add the right amount of business value or is not suited for your business case or architectural domains; sorry, in my opinion, you are doing it wrong.&lt;/p&gt;

&lt;p&gt;Let me be clear, I'm not saying I'm against changing or upgrading technology stacks or adding complexity in your software design. I am not. As a community we need to strive to move forward and it truly is an amazing time to be a .NET developer. But if you've decided to use a full blown CQRS solution with asynchronous event-sourcing, with an Angular - Redux front-end; to allow your users to perform CRUD operations on a couple of lists (real-life example); sorry, you've over engineered the sh*t out of your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;

&lt;p&gt;In Belgium a lot of companies are choosing Angular as their main front-end technology. I've not hidden the fact that I'm not a fan of AngularX. The -I'm assuming- breaking changes with every release (which is what, every two months or so?), the level of complexity, the CLI, the opinionated dependency on TypeScript; everything about it is just something I'm not a fan of. A front-end application, for me, should be kept as simple as possible, to view and edit your data as simple as possible.&lt;/p&gt;

&lt;p&gt;Also remember the ripple effect. Your developers do not only have to learn AngularX, if only that was the case. They need to learn TypeScript, the .tsconfig file, webpack (don't get me started on that),  sixteen different package managers (I might be exaggerating a bit), the CLI, E2E JavaScript testing, NPM, build configurations for different environments, different debugging tools and even, in most cases, a completely new IDE..&lt;/p&gt;

&lt;p&gt;And if your team consists of only seniors, I am inclined to say, go for it. Go wild! But I hope you realize how unrealistic this is. Teams change, juniors and/or mediors will work on your code. And with framework as complex as AngularX is, especially in combination with Redux or Flux, maintaining your application will be challenging to say the least..&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zgFZIltg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.timsommer.be/content/images/2019/04/legacy-code.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zgFZIltg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.timsommer.be/content/images/2019/04/legacy-code.gif" alt="(Don't?) Keep It Simple Stupid!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On docker, Kubernetes and the "Dev-ops Culture"
&lt;/h2&gt;

&lt;p&gt;With the rise of .NET Core, the incorporation of Microservices was fully introduced into the .NET world. With Microservices came CQRS and Event Sourcing. With Microservices came Docker, container-based application development, better or more consistent DDD implementations, and Linux deployments, and eventually maintainability using Kubernetes. Each technology is cool, "new" and awesome to create.&lt;/p&gt;

&lt;p&gt;But to maintain.. Oh dear. With a system wide failure using Async CQRS you are not only risking downtime; you're risking data corruption throughout your system. If it's not implemented correctly, a simple bug can have truly catastrophic results..&lt;br&gt;&lt;br&gt;
As I talk to software engineers implementing such complex and vast applications I tend to challenge them om maintainability. Because that's the Achilles heel, that's where everything could go entirely wrong. And when I talk to them about the management of these containerized applications, they all get that wild stare in their eyes. Knowing of Kubernetes, but never worked with.. Thinking about massive system failure and how it might impact their data. Getting notified if a container goes down, or even worse, the (shared) data container goes corrupt. They simply have no idea! They are developing applications of which they have no clue, not even if their life depended on it, what to do with the system should it go down.&lt;br&gt;&lt;br&gt;
In their defense, you could argue that they should not need to know these things. That they should have the shared responsibility with a Dev-ops team specialized in their field, so they can assist the developer if need be. So he/she can focus on development, not on maintaining. But this shared responsibility is slowly, but surely, fading away.&lt;/p&gt;

&lt;p&gt;There used to be a time where development teams worked with Dev-ops teams to maintain production applications. But that differentiation is more and more a thing of a past. We don't talk about Dev-ops teams any more, we talk about a "Dev-ops" culture. Where developers should learn how to deploy, manage and maintain production applications as well. Which isn't all that strange when you look at it. You cannot expect a member of a Dev-ops team to maintain an application where expert knowledge of every container is required. You simply can't. But putting all the responsibility with the developer is not a good idea as well.. The design is just too complex, the lines between the responsibilities and functionalities of Dev-ops and programmers have faded to much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This might be a more "negative" read for you as I've tried to put my frustrations about the roller-coaster of technological advances in our world into words. You might get the wrong idea. I really am not against changing and evolving, I love learning new things, I love guiding a client into this new era we are now in as software developers.&lt;/p&gt;

&lt;p&gt;But I also see it as it sometimes is. As a train riding with enormous speed, going faster with each iteration, each new framework, each new technology stack. And, in Belgium at least, I see the point where that train could possibly derail. Everything is simply going too fast.&lt;/p&gt;

&lt;p&gt;If you are an architect, or software engineer, I urge you to take responsible choices. Take decisions, iterate on those decisions, and adapt your visions and architectural dimensions as you write your code. Incorporate new ideas and technologies if you need them, not because someone told you they are cool and everyone is doing it nowadays. And always, &lt;strong&gt;Keep It (as) Simple (as possible)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/photos/3y1zF4hIPCg"&gt;Hans-Peter Gauster&lt;/a&gt; on &lt;a href="https://unsplash.com"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>kiss</category>
      <category>development</category>
    </item>
  </channel>
</rss>
