<![CDATA[Development Simply Put]]>https://www.developmentsimplyput.com/blogRSS for NodeThu, 20 Jun 2024 01:06:47 GMT<![CDATA[Why Optimize Code for Performance]]>https://www.developmentsimplyput.com/post/why-optimize-code-for-performance658b8401a6bcd64ded69f776Mon, 25 Dec 2023 23:00:00 GMTAhmed TarekHere is the answer.


Why Optimize Code For Performance .NET DotNet C# CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek


This is a question I get from time to time.


Some developers are convinced that optimizing code for performance is overrated especially when we know that hardware is getting so powerful day by day.


However, other developers think that the answer to this question lies in the question itself; simply because we want our applications to perform the best.


I think I know where the confusion is coming from. Both sides have some of the truth but they are confusing something to another. This is what we are going to discuss in the next sections.




Why Optimize Code For Performance .NET DotNet C# CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek


Premature Optimization


It is the excessive, uncalled-for, time-consuming optimizations. In other words, it is the kind of optimization which consume too much time and effort to optimize a piece of code without actually having a good reason.


This kind of optimization should not be accepted in the world of software developers as, besides being too expensive, it opens the door wide to anti-patterns and bad practices.


This is because these optimizations are most probably focused on low-level code analysis. You start examining the code line by line figuring out how each line would be translated into machine code and then you start designing your high-level code accordingly. Is this something good?


The short answer is no. In order to achieve this level of control, you might violate too many best practices so that you can get the kind of minor optimizations you want.


For example, you might think of dropping abstractions. Why?


Because when the compiler deals with design time classes, it knows how to apply optimizations like which method implementation to call. However, when it deals with abstractions like interfaces or abstract classes or even virtual methods, it is not able to apply these optimizations and it then needs to postpone some evaluations to the run time, which is for sure less performant.


Having said that, back to our main problem, developers confuse Premature Optimization with what is called Performance Abiding Practices.







Why Optimize Code For Performance .NET DotNet C# CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek


Performance Abiding Practices


These are the practices that are proved to be efficient to the extent that they are considered defaults.


For example, once we know that using StringBuilder is much better and performant than using string concatenation, it is not acceptable to use string concatenation just because we are not sure yet if we would need to apply performance optimizations. This is not an acceptable excuse.


Also, once we know that using the sealed keyword is proven to be a best practice from the design and performance point of view, we should also refuse not using it for the same excuse as above.


Note: If you don’t know much about the sealed keyword and how it could yield a performance boost, you can read the article Compiler-Friendly Code: Sealed Keyword in .NET C#.


Our goal should always be to follow these best practices unless there is a strong reason not to.




Why Optimize Code For Performance .NET DotNet C# CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek


Why Optimize?


Optimize because in the software world, there is always something new. What you think is enough today would not be in a short period of time.


What your software system offers today might be good, but your customers’ needs grow day by day, and to keep up with the new needs, your system needs to expand and adapt. However, if your system is not built for being a highly performant system, you would hit a brick wall stopping you from expanding.


Additionally, your software system is not the only system out there. You have competitors and to be able to win the race, you need to always be ready and growing. What could actually stop you from doing this is having a low-performing system.


Therefore, optimizing your software system is not a luxury, it is a need.




Why Optimize Code For Performance .NET DotNet C# CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Final Thoughts


My advice, keep an eye on your system needs and always try to follow the best practices. Whenever you spot a bottleneck in your system, you can then investigate and act accordingly.


Hope you find reading this article as interesting as I found writing it.



]]>
<![CDATA[Converting an Enum to Another In .NET C#]]>https://www.developmentsimplyput.com/post/converting-an-enum-to-another-in-net-c658b7f87443edd257d521fb9Mon, 11 Dec 2023 23:00:00 GMTAhmed TarekGuide on how to convert an Enum to another in .NET C#


Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek


While working on your software system you might find yourself dealing with different modules and some of these modules could be out of your full control.


This could happen for different reasons, may be due to some access restrictions, ownership, policy,…


In this kind of situations, you might face some challenges related to mapping different entities, classes, interfaces, enums,… to each other. It would not be a ship-stopper, but still you have to handle this in the best possible way.


In this article, we would explain more than one way to handle mapping different Enums to each other.




Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek


The Example


First, let’s agree on an example to use throughout the different article sections.


Let’s say that we have the following two Enums which we would like to handle converting between them both ways.



In the following article sections, we would discuss more than one method to handle the conversions.







Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

On this method, we would assume that we don’t have any edit privileges on both Enums; ItemSize and StandardItemSize. This means that we can’t apply any changes on both of them.

In this case, what we can do is to create extension methods to handle the conversion between them.


Therefore, following this way of thinking, we would end up with something like this:



As you can see, we are just handling the conversions in a switch-case manner.


Then we can start using these extension methods as follows:



And the result would be as follows:


Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Nice, it is working as expected.




Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

On this method, we would assume that we don’t have any edit privileges on ItemSize but we own StandardItemSize. This means that we can’t apply any changes on ItemSize but we can apply the required changes on StandardItemSize.


This is different than the case on Method 1 as now we can make use of the fact that we can do some minor modifications to StandardItemSize.


So, instead of handling the conversion into a switch-case manner in a separate extension method, we can do some tagging on the enum itself and then use this tagging in the extension method.


This would be so useful as now the mapping between both enums would be consistent, readable and encapsulated into the StandardItemSize enum itself.


Therefore, following this way of thinking, we would define a new Attribute to be used for tagging the StandardItemSize enum members to map each of them to its related member in ItemSize.


It should be as follows:



And now we can use it as follows:



Then we can update the ToItemSize extension method as follows:



As you can notice here, we are writing code to depend on the RelatedItemSizeAttribute attribute on each StandardItemSize enum member to finally get the corresponding member of ItemSize enum.


Also, now we can update the ToStandardItemSize extension method as follows:



As you can notice here, we are writing code to depend on the RelatedItemSizeAttribute attribute on each StandardItemSize enum member to finally return the StandardItemSize member which is tagged with a RelatedItemSizeAttribute attribute corresponding to the passed in ItemSize member.


Now you might be concerned about the performance of these extension methods and I can understand you. You really need to check your application performance and see if it suits your needs or not.


You also need to keep in mind that you can always get back to Method 1 for the direct mapping between both enums if you are not satisfied by the performance on this method.


Now, as usual we can start using these extension methods as follows:



And the result would be as follows:


Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Nice, it is working as expected.







Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

On this method, we would assume that we own both ItemSize and StandardItemSize. This means that we can apply any changes on both of them.


So, what we would actually do here is extending the solution we came up with on Method 2.


So, we would define RelatedStandardItemSizeAttribute as follows:



And update ItemSize as follows:



And update ToStandardItemSize as follows:



Now, as usual we can start using these extension methods as follows:



And the result would be as follows:


Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Nice, it is working as expected.




Convert Enum to another DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Final Thoughts


In this article, we discussed more than one way to handle mapping and conversion between two enums when we have and don’t have control on both of them.


As I said before, you might have your doubts about the performance and for sure you have the right to think so. That’s why my advice to you is to check the impact and evaluate according to your needs.


That’s it, hope you found reading this article as interesting as I found writing it.



]]>
<![CDATA[When using += Is Not Good In .NET C#]]>https://www.developmentsimplyput.com/post/when-using-is-not-good-in-net-c658b7bdd17f25f887569df06Sun, 03 Dec 2023 23:00:00 GMTAhmed TarekA case where blindly using += in .NET C# would drive you crazy.


+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

The main goal of this article is to demonstrate how a simple detail in our code could cause huge problems which are so hard to diagnose and troubleshoot.


As an example, we would use the += operator.


Have you ever imagined that blindly using the += operator could drive you crazy?


In this article, I would show you how this could happen and how to fix it.




+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Example Base Code


Before diving into the explanation, let’s start with writing some base code for the example we are going to use.


First, we would define an Employee class.



As you can see it is just a simple class with only one defined property, Salary.


Now, let’s say that we have a RaiseCalculator class that would be used to calculate the raise for an Employee. The code would be as follows:



As you can see the code is simple. We have:

  • private static readonly object _lock field defined to be used for locking.

  • public decimal Calculate(Employee employee) method which applies the actual calculation.


That’s it, now we have the foundation code for our example. Let’s now proceed with the rest of the explanation.







+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Brain Teaser


Now, let me show you something interesting.


Let’s say that we want to start using this RaiseCalculator class to calculate the raise of an Employee.


Then, we can write some code like this:



What we can notice here:

  • We are using one instance of the RaiseCalculator class.

  • Then we have a loop for 10 times. We are using this loop to see if the result we get would always be the same for multiple runs.

  • Inside the loop, we are defining a new Employee and we set its Salary to 1000.

  • Then, we create two tasks to be run in parallel.

  • The first task is increasing the employee's salary with the raise calculated by the calculator.

  • Also, the second task is doing the same.

  • Then we wait for both tasks to finish and finally print the final salary of the same employee.


What we should keep in mind is that, although the two tasks would run in parallel, the calculations should be applied in series as there is locking inside the RaiseCalculator class.


Let me quickly remind you. The code was as follows:



Therefore, what we should expect is:

  • The task to set the lock first should see the input Salary as 1000, then the raise should be 500 and finally, the new Salary should be 1000 + 500 = 1500.

  • The task to come later should see the input Salary as 1500, then the raise should be 1000 and finally, the new Salary should be 1500 + 1000 = 2500.


This means that the message to appear in the console for each iteration should be “Final: 2500”. However, would it actually be so?


When we run the code, we would get something like this:


+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

See, the result is not the same every time. Sometimes it is 1500 or 2500 or even 2000.


I can hear now screaming:


Let me tell you…




+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

A Glimpse Under The Hood


First, let me tell you that this code which we used:



Is actually equivalent to this code:



That’s obvious, right?


However, what needs more attention is what is actually happening with the locking.


+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

In the line of code employee.Salary + calculator.Calculate(employee); we start with capturing the current value of the employee.Salary. This is done outside the locking scope.


This means that while both tasks are racing, they could -it depends on when and how fast the tasks start- both capture the same starting value of the current Salary.


Therefore, even though there is locking inside the RaiseCalculator class, the initial starting value captured by each task might be wrong.


You can check the flow diagram above to fully understand what we are talking about.


Now you see it, right?







+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

The Right Way


Now, let’s see how to fix this problem.


The fix is so simple, just use this code:



Instead of this code:



This way, the flow will be as follows:


+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

This way, capturing the current value of the employee.Salary comes after releasing the lock. Therefore, the first task would have enough time to capture this value and add it to the employee.Salary before the second task proceeds with the calculation.


So, if we run the new code, we would get this result:


+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

I can hear you now saying:




+= Not Good Wrong Bad DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Final Thoughts


I totally agree with you. That’s why if I were going to design this module I would never do it this way.


However, sometimes we can’t redesign some modules because we don’t own them or for other reasons.


Therefore, the main goal of this example is to show you how a small piece of code could cause a lot of trouble.


This is why we need to deal with every line of code as an essential part of the whole system.


That’s it. Hope you find reading this article as interesting as I found writing it.



]]>
<![CDATA[Secrets of the Single Responsibility Principle]]>https://www.developmentsimplyput.com/post/secrets-of-the-single-responsibility-principle658b780d2088dbbd51a4b328Sun, 08 Jan 2023 23:00:00 GMTAhmed TarekUncover the secrets about the Single Responsibility Principle (SRP) of the SOLID Principles.


Single Responsibility Principle SRP of SOLID Principles DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Almost all developers working with Object Oriented Programming (OOP) languages know about the SOLID principles.


SOLID Principles

  • Single Responsibility Principle

  • Open-closed Principle

  • Liskov Substitution Principle

  • Interface Segregation Principle

  • Dependency Inversion Principle


In this article, we are going to explain the S of the SOLID, Single Responsibility Principle, however, what you are going to read here is different…




Single Responsibility Principle SRP of SOLID Principles DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

What is the Single Responsibility Principle


According to Wikipedia:


And for its meaning:


So now enough with the Wikipedia talk, let’s clarify some points.


The main definition of the Single Responsibility Principle is that a class should have only one reason to change.


People might get confused about what is meant by reason and I totally understand where this is coming from.


Let me elaborate…







Single Responsibility Principle SRP of SOLID Principles DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Important Note


To drive your focus to the main topic we are discussing here, some code best practices would be dropped. This means fewer interfaces, abstractions, implementing constructors,… unless needed for the demonstration.




Single Responsibility Principle SRP of SOLID Principles DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

The Confusion


Some developers tend to say that if a class is doing too many things, it is actually violating the Single Responsibility Principle.


Good, but still, what is meant by too many? How to know if a class is doing too many things or not? If a class is doing 2 things, is this too many? What about 3? What about 4? …


In my humble opinion, I find this definition confusing and I can’t blame you if you feel the same. The “too many” term is neither measurable nor understandable.


I can hear you now saying:


Actually no. I have something that could make it more clear so let me elaborate more.


In software, a method -or a function, whatever you like to call it- has two factors to describe it:

  • Knowledge required to do its job.

  • Achievement done when it is finished.


These two factors are different, they are not the same. We should distinguish one from another as there are a lot of consequences based on how each of them scales.


Now, let me walk you through it step by step.




Method Knowledge


Refers to the know-how the method needs to have to be able to do its job. In other words, it is referring to the internal details and steps the method needs to know so that it can get its job done.


For example, let’s have a look at this method:



The method Add should know how to add two numbers. It does it by using the + operator provided by the .NET Framework.


Now, if the developers of the .NET Framework decide to change the internal implementation of the + operator or how it is translated on the machine code level, this should not affect the Add method as it doesn’t care. It just delegates the methodology of adding two integer numbers to the .NET Framework.


Now, let’s assume that the requirements of the system we are developing are changed so that we need to add an extra margin to the Add method.


So, the code should be as follows:



Now, this is different.


Following this new implementation of the Add method, the knowledge of the method itself has changed, and the know-how has changed as now it needs to know about adding an extra margin which was not there before.




Method Achievement


Refers to the work that would be done when the method is finished regardless if the method has the absolute know-how of each step of this work or not.


For example, let’s have a look at this method:



As we can notice here, the amount of work that would be achieved after this method finishes would be huge. However, can we say the same about the knowledge? I don’t think so…


The only knowledge this method has is the knowledge about the steps and order of the actions needed to get an Employee hired, nothing more.


You might argue that the method knows more than that but actually no. Yes, when the HireEmployee method starts an employee would be added to the database, but actually, it doesn’t know how this is done, the Add method of the EmployeeRepository class is the one that owns this knowledge.


The same applies to all of the other methods and this leaves the HireEmployee method simpler than what we could have expected before noticing this, right?




Having said that, let’s now analyze how these two factors could have an impact on the definition of the Single Responsibility Principle.


By now, it should be obvious that when we are evaluating if a class is abiding by the Single Responsibility Principle or not, we should be more concerned about the knowledge than the achievement.


This is because the more the knowledge a class has, the more probable it would violate the Single Responsibility Principle.


Let me elaborate more…







Single Responsibility Principle SRP of SOLID Principles DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek


Moment of Truth


Do you remember the EmployeeManager class we discussed above, let’s say that we have it implemented differently.


Let’s assume that the code is as follows:



As we can notice here, the knowledge required is huge. The HireEmployee method needs to know too many things about the database structure, how to open/close connection, how to do the mathematical operations to calculate taxes and holidays, how to connect/disconnect to/from the mailing server, how to add to the mailing groups,…


This kind of enormous knowledge is a burden the HireEmployee method is carrying around.

If new changes are to be applied to the Employee database table or any of the related tables, the HireEmployee method would need to be updated and this means that the EmployeeManager class would accordingly be updated.


If new changes are to be applied to the mailing server, the HireEmployee method would need to be updated and this means that the EmployeeManager class would accordingly be updated.


And so on…


Eventually, we can conclude that the EmployeeManager class would have too many reasons for changing which is a clear indication that it violates the Single Responsibility Principle.


Now I can hear you saying:


Yes, for sure, it is possible. Let me show you…




Single Responsibility Principle SRP of SOLID Principles DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Better Way


Again, back to the EmployeeManager class. If we want to implement it in the right way so that it abides by the Single Responsibility Principle, we can follow some steps as I show you.


First, we need to get back to the better -but not the best yet- version:



As we said before, the amount of knowledge required here is not as huge as it seems at the first glance.


Actually no, we can do better as follows:



What we did here:

  • Abstracted the knowledge of calculating and adding the tax scheme into a separate TaxManager class.

  • Abstracted the knowledge of calculating and adding the holidays into a separate HolidaysManager class.


This means that the EmployeeManager class now knows less than before. Now, it doesn’t know that to update the tax scheme it needs to first use the TaxCalculator class and then use the EmployeeRespository class. The same applies to updating the holidays.


This leaves the EmployeeManager class with less knowledge and accordingly fewer reasons to change.


Now I can hear you saying:


Yes, I totally agree with you but I can’t see it as a problem.


This is something we can’t avoid as this is the core role of the EmployeeManager class; it handles the flow and steps to be done to hire an employee.


What we always need to keep in mind is that if the requirements change, some code would change. This is inevitable.


However, what we thrive to do is minimize the amount of the surrounding code to be changed or even touched.




Single Responsibility Principle SRP of SOLID Principles DotNet .NET CSharp C# Code Coding Programming Software Design Patterns Development Engineering Architecture Best Practice Knowledge Achievement Ahmed Tarek

Final Thoughts


In this article, we discussed the Single Responsibility Principle -which is also abbreviated as SRP- of the SOLID Principles.


When it comes to this principle, many developers get confused about what is much and less. That’s why this article made it clear once and ever.


Worth to mention, you need to keep in mind that in the software world and with the increasing speed of changes, there would always be some changes that would require a code change as well. This is normal, this is inevitable, and you should not fight it, you should adapt to it.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Why Immutability Is Important in .NET C#]]>https://www.developmentsimplyput.com/post/why-immutability-is-important-in-net-c658b72e8436be4dd45efa099Wed, 04 Jan 2023 23:00:00 GMTAhmed TarekWhy Immutability is a good thing and how to apply it.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

This is one of the most interesting topics to me to the extent that once I start talking about it you might need to fight me to stop


I believe that many of the issues and problems that developers come across could be solved if they apply Immutability as it should.


Don’t believe me? Let me show you.




Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

The Definition


In the software world, Immutability means that you define your classes and structs in a way that the object could not be manipulated or updated once it is created.


For example, let’s say that you have this class:



Now, creating an instance of the Employee class could be as easy as the following:



However, you can still update the FirstName of the object ahmed by doing the following:



In this case, the Employee class is not following the definition of Immutability.


If we want to fix the Employee class to really follow the definition of Immutability, we need to update the class as follows:



As you can notice, we removed the set; from the FirstName property so that the only way to set its value is through the constructor. This means that the object could not be modified after being created.


Now, you might think:


However, there are some mistakes that some developers might do. They might think that they did what is needed to make their classes and structs immutable when they actually didn’t.


Let me show you.







Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Common Mistakes Violating Immutability


These are some of the mistakes that developers might do violating the immutability rules.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Private Setter


Let’s say that we have the following code:



As you can notice here, we don’t have a public setter on the FirstName property, however, we still have a private setter which opens the door to internal manipulations.


This means that any piece of code inside the Employee class can still update the value of the FirstName property which leaves the object mutated.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Internal Manipulative Code


Let’s say that we have the following code:



As you can notice here, the Employee class exposes a Rename method that would update the value of the FirstName property. This for sure leaves the object mutated.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Read/Write Collections


Let’s say that we have the following code:


As you can notice here, the Managed property is not exposing a public setter or even a private one. However, the type of the property itself is a List which is open for write.


This means that we can do the following:



See, here we can add a new Employee instance inside the Manage list. This for sure leaves the object mutated.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

ReadOnly Collections of Mutable Objects


Let’s say that we have the following code:



As you can notice here, the TelephoneNumbers property doesn’t expose any public or private setters, and its type is IReadOnlyCollection which doesn’t allow for adding or removing items from inside.


Now, you might think that your object is safe and no one can mutate it, right?


Let me show you something. Let’s say that we have the following code:



See, we can still manipulate the object because the underlying object inside the IReadOnlyCollection is mutable.







Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Mutable Member Object


Let’s say that we have the following code:



As you can notice here, although the TelephoneNumber property is not exposing any public or private setters, still, the type of the property is TelephoneNumber which is mutable.


This means that we can write some code like this:



This for sure leaves the object mutated.


Now I can hear you saying:


Take it easy, you might think so but actually, it is not impossible.


In the next section, I will show you some practices that can help you with this.




Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

How To Not Violate


There are some golden rules to follow to achieve Immutability:

  • All fields should be readonly.

  • All properties should provide getters only.

  • All members should be of immutable types.

  • All collections should be Immutable. Check this out.

  • In case a method needs to update the internal state, it should keep the internal state untouched and return a whole new object with the new state.


If you follow these rules, you would end up with a fully immutable object.


Ok, now I can hear you asking:


Absolutely. Although it seems too much to follow these rules, believe me, you would get many benefits in return.


Let me show you…







Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Advantages


Based on the fact that the object could not be mutated after being created, there are a lot of advantages we can get.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Thread Safety


Since the object is guaranteed to be immune against any manipulation, we don’t care if the object would be accessed by one thread or more.


At the end, all these threads would not be able to update the object, so, why not to be accessed by more than one thread?


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Singleton


Since the object would always hold one and only one state at a time, then we can use this object as a singleton.


It is like integers; if I tell you that you have an integer with the value 3, would you ask me which instance? I think no as it doesn’t matter, if it is 3 then it will always be 3.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Less Memory Allocations


This is because you can define the object one time and use it many times. You can also define it as a singleton. You can also cache it somewhere.


Additionally, you can avoid automatic copying by passing the object by reference or using the in parameter.


All of this would save some memory allocations.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Compiler Optimizations


Defining a struct as immutable would make it so easy for you to also define it as read-only using the readonly keyword.


This would also help the compiler avoid the defensive copy mechanism which would eventually save processing and memory leading to a performance boost.


Note: If you don’t know much about the defensive copy mechanism, you can read the article Defensive Copy In .NET C#.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Caching


Since the object would not be manipulated after being created, the object could be used as a key in a dictionary, or safely cached in a cache collection.


Additionally, it would be easy to avoid duplications which would save memory.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Comparisons


If you pass the object to a method that would return a new object, it would be easy to compare both objects because you are sure that your original input object would still be the same.


Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Unit Testing


As we mentioned in the Comparisons section above, you can easily compare objects before and after an operation. This would be so helpful while writing your unit tests.




Immutability Why How Apply Important Good Right Immutable Collections Singleton Memory Allocation Compiler Optimization Caching Unit Testing DotNet .NET CSharp C# Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Final Thoughts


That’s it. I hope starting from this moment you will appreciate Immutability and try to apply it as far as you can.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Dangers of Using Optional Parameters In .NET C#]]>https://www.developmentsimplyput.com/post/dangers-of-using-optional-parameters-in-net-c658b6fb6a6bcd64ded69ec8eMon, 02 Jan 2023 23:00:00 GMTAhmed TarekWhen to be cautious while using Optional Parameters in .NET C#


Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek


We all know about Optional Parameters and we love to use them instead of defining too many method overloads.


However, there is something important that you need to keep in mind while using Optional Parameters especially if you are developing your own class library.


In this article, I will show you something that could blow your mind.




Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Brain Teaser


Let’s first show you the problem by example.


You started the development phase of your software system. Regardless of what the system actually does, assume that your system needs to do some mathematical operations.


Instead of creating your own mathematical library, you decided to use a well-known third-party library. Good choice.


Now, for the sake of demonstration, we would write the library ourselves and keep it in the same solution. However, in real life, it is expected that you don’t own the library and it could be delivered as a Nuget package or even a DLL to reference in your project.


So, starting from this point, we would create our solution as in the image below:


Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

In the ThirdPartyLibrary project, we have only one class; the Calculator class.


The code inside this class is so simple as follows:



As you can notice, we have two simple methods with some optional parameters.


We are also writing to the console the values of the passed-in parameters to be used for demonstration.


Now, moving to the OptionalParameters project. Assume that this is your actual software system project.


The project has only one class which is the Program class.


The code inside this class is as follows:



See, we are just using the two methods inside the Calculator class but with different values for the parameters.


Sometimes we pass values to the optional parameters and sometimes we just leave them as defaults.


Now, let’s build the whole solution and browse the \OptionalParameters\bin\Debug directory.







You would notice that the ThirdPartyLibrary.dll copied there is the latest one. You can make sure of that by examining the Date Modified column as in the image below.


Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek


Now, let’s run the application by double-clicking on the OptionalParameters.exe file. We would get the following result:


Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

As expected, right?


Now, let’s do a minor change to the Calculator class. We would change the default values of the optional parameters to 10 instead of 0.


So, the code would be as follows:



Now, from VS, right-click on the ThirdPartyLibrary project and click Build.


When you browse to the \OptionalParameters\bin\Debug directory, you would notice that the ThirdPartyLibrary.dll copied there is not the latest one. You can make sure of that by examining the Date Modified column.


To fix this, let’s browse the \ThirdPartyLibrary\bin\Debug directory and copy the ThirdPartyLibrary.dll and ThirdPartyLibrary.pdb files to the \OptionalParameters\bin\Debug directory. Now, it is the latest one.


Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek


Now, let’s run the application by double-clicking on the OptionalParameters.exe file. We would get the following result:


Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

I can hear you now screaming:


Yes, we did build the ThirdPartyLibrary project and we did copy the latest DLL files. However, this is not enough. Let me explain it to you.


Before explaining what actually happened, let’s quickly try something.


Let’s build the whole solution and run our OptionalParameters project but not from VS itself. Let’s do it by browsing to the \OptionalParameters\bin\Debug directory and double-clicking on the OptionalParameters.exe file.


Doing so, we would get the following result:


Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

See, this is the result we were actually expecting the last time.


Let me tell you…







Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

The Catch


When you call a method with optional parameters and you don’t pass values for some or all of these optional parameters, the default values defined by the method would be used.


But, this is not all. These default values would be integrated into the caller-side compiled code. This means that when the default values are updated into the method definition, this would not reflect in the caller till both projects are re-built, building only one of them is not enough.


Having said that, you need to be so careful while using optional parameters. If there is a possibility that the method provider project could be updated and built without re-building the method caller project, this is a risk.




Method Optional Parameters Issue Problem .NET C# DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Final Thoughts


In this article, I explained the dangers of using Optional Parameters which you need to keep in mind.


You might ask:


My answer would be:

  • Try to use method overloads if possible.

  • You can try to use a default settings class instead of depending on optional parameters.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Defensive Copy In .NET C#]]>https://www.developmentsimplyput.com/post/defensive-copy-in-net-c658b62f59bd45d04e7c303e7Wed, 21 Dec 2022 23:00:00 GMTAhmed TarekUnderstand why Defensive Copy is important and how it affects performance.


Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Did you ever hear about Defensive Copy in .NET C#?


Do you know how important this topic is?


Do you know that you might be wasting memory and processing power because of it?


Let me tell you about it…




Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Brain Teaser


Before jumping into any details, let me show you something interesting.


Let’s say that we have this struct defined as follows:



As you can see, it is a simple Num struct with:

  • An int field called Value .

  • A constructor.

  • A method called Increment which increases Value field by 1.

  • A ToString method override.


Now, let’s say that we have the following code:



In this class, we just defined a private field of type Num, and in the Run method we just increment the field by calling its own Increment method.


If we run this code, we would get this result:


Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

As expected, right?


Now, let’s apply a minor change on the code and see how this would reflect.


Let’s modify the code to be as follows:



As you can notice here, the only change we applied is adding the readonly keyword in the field declaration.


Now, if we run the code again, do you expect a different result than the previous one? Not sure? Let’s give it a try.


When we run the new code, we would get this result:


Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

I can hear you now screaming:


Yes, it is possible and it would actually happen every time as it is not a glitch in the matrix or something


Let me explain it to you.







Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

A Glimpse Under The Hood


What actually happened is what I have been asking you about in the first lines of this article; it is Defensive Copy.


What happened could be broken down into simple steps:

  1. When we marked the field with the readonly keyword, this revealed our intention to keep this field totally untouched. In other words, we don’t want any changes to be applied to the object behind this field.

  2. Therefore, the compiler actually listened to us and understood our intentions. Thus, the compiler decided to help us achieve our goal.

  3. Then, we tried to increment the field by calling its own Increment method.

  4. Thus, this is where the compiler decided to kick in and protect our field object from any changes even if these changes are triggered from inside itself. But how would the compiler do it?

  5. The compiler would do it by first creating a copy of the field object and then applying the Increment call on it, not on the original field object.

  6. Worth mentioning here is that the field object is of the type Num which is a struct. As we know, copying a struct would yield a totally new object.

  7. Therefore, this would eventually protect our field object from any changes.


So, in simple words, this code:



Would eventually be translated into this code:



Now you might ask:


Yes, you are right. It is not expected to apply any changes on the field object but this is not the way the compiler thinks.


The compiler doesn’t inspect the code inside the method and decides if it is going to apply any changes to the object or not.


It just assumes that this could happen and this is good enough for the compiler to be cautious and apply the Defensive Copy mechanism.


I hope you now understand what actually happened. In the next section, we will talk more about the Defensive Copy mechanism.




Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Defensive Copy Mechanism


Now, let’s go through the questions most probably you have in mind right now.


❓ When does it happen?

It happens when a struct object is used in a read-only context, and this object is manipulated.


❓ What do you mean by manipulated?

Manipulated means calling any method on the object. Also, calling a property is the same because the property is a method at the end. However, calling a field would not trigger the mechanism.


❓ What do you mean by read-only context?

It means when the object is declared as one of the following:



readonly field




ref readonly local variable




in parameter



❓ Does it really matter? Should we be concerned about whether Defensive Copy is triggered or not?


It actually depends on the size of the struct and how frequently the Defensive Copy mechanism is triggered.


The bigger the struct is, the more impact we should expect.


The more frequently the Defensive Copy mechanism is triggered, the more impact we should expect.


Let me show you…







Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Performance Impact


Let’s simplify the Num struct and add more fields to it just to make its size bigger. Then, the code should be as follows:



Now, let’s build a benchmarker project to compare the performance of:

Field of the Num struct.

readonly field of the Num struct.



Running this benchmarker project, we would get the following result:


Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

As we can notice from the result, using the field is 4 times faster than using the readonly field.


This could trigger you to ask the following question:


Yes, I understand your point. Sometimes the compiler just triggers the Defensive Copy mechanism even when the calls are not going to apply any changes to the object.


It would be bad if we should always pay the bill just because the compiler wants to be cautious. But, should we??




Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

The Solution


No, we shouldn’t. We are not always enforced to accept pay this bill allocating more memory and wasting processing power. There is a solution.


The fix is as simple as marking the struct as readonly.


When we mark the struct as readonly, the compiler makes sure it is immutable. This means that no one can manipulate the object or change its state.


Accordingly, the compiler gets confident that no calls would manipulate the object, and therefore no Defensive Copy mechanism is needed.


Therefore, if we change the code to be as follows:



Then now if we run the same exact benchmarker project, we would get the following result:


Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

See, marking the struct as readonly removed the Defensive Copy mechanism overhead saving memory and processing power.







Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Means of Detection


Now, you might be asking:


Yes, ErrorProne.NET Structs nuget package.


It is a group of analyzers that help avoid struct and readonly reference performance pitfalls. Using this nuget package you can spot struct-related problems so that you can fix them on the spot.


What you need to keep in mind is that the analyzers emit a diagnostic only when the struct size is >= 16 bytes.


It was said that you can change this threshold using .editorconfig file and adding the following line:





Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

.NET Core


All that we discussed up to this point applies to the .NET Framework. With .NET Core, things have changed.


The same concept of Defensive Copy still exists but the framework is now smarter. Some code that is falsely detected by the .NET Framework as manipulative would not be detected by the .NET Core.




Defensive Copy In .NET C# Struct Memory Allocation Compiler Optimization Enhance Performance Right Good Bad Impact Processing DotNet CSharp Code Coding Programming Software Design Development Engineering Architecture Best Practice Ahmed Tarek

Final Thoughts


I hope by this point you already understood everything about the Defensive Copy mechanism.


My final advice to you is:

Always try to design and implement structs to be immutable.

This would make it so easy to mark structs as readonly.

With structs always try to use fields, not properties. This would help you avoid too many problems.

Even with .NET Core, you should follow the best practices and not only depend on the framework to take care of it.


That’s it. Hope you find reading this article as interesting as I found writing it.



]]>
<![CDATA[Compiler-Friendly Code: Sealed Keyword in .NET C#]]>https://www.developmentsimplyput.com/post/compiler-friendly-code-sealed-keyword-in-net-c658b5ca3043ec46669a3dc66Tue, 20 Dec 2022 23:00:00 GMTAhmed TarekWhy & When Sealed Keyword could lead to a performance boost in .NET C#


Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

What does it mean to write compiler-friendly code?


Any .NET code passes by more than one phase till finally reaches the machine code. Since many factors are involved in this process, there could be lots of details that we miss when we are first writing our code.


However, the more clear and deterministic the code we write is, the more the compiler could assist us and generate optimized machine code.


In this article, we are going to discuss one example of the ways by which we can help the compiler optimize our code. This way is; using the Sealed Keyword.


Enough with the talking and let’s see an example…




Background Check


If you are a .NET developer, even a beginner, you should know by now that there is a keyword in the .NET framework called sealed.


This keyword could be used in a class definition and then it means that the class could not be inherited by any other classes. It looks like this:


Or even in a method declaration and then it means that the method could not be overridden -anymore- by any other method in a child class. In other words, it breaks the method override series at the level where it is used. It looks like this:


Therefore, what we can understand from this is that when we use the sealed keyword, we are actually promising the compiler that we don’t have any intentions to inherit from a class or override a method.


Having said that, let’s now see if that would mean anything to the compiler.







Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Let’s start with some base code to be used throughout the explanation.




BaseClass



This is the base class that we would use as the top parent.


In this class, we have the following members defined:

  • public virtual void DoSomething() method.

  • public void DoSomethingElse() method.




MyClass



This is the class that would inherit from BaseClass but without using the sealed keyword in the definition.


In this class, we are overriding DoSomething method which is inherited from the parent BaseClass class.




MySealedClass



This is the class that would inherit from BaseClass but this time we are using the sealed keyword in the definition.


In this class, we are overriding DoSomething method which is inherited from the parent BaseClass class.


Now, let’s proceed and see if there would be any difference -from the compiler’s point of view- between using MyClass and MySealedClass classes.




Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Calling Virtual Method


To validate if there would be any difference -from the compiler's point of view- between calling a virtual method on both MyClass and MySealedClass classes, we would create a Benchmark project.



Now, running this Benchmark project we would get the following result.


Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

As we can notice here, the performance of calling the virtual method on the sealed class is much better than calling it on the non-sealed class.


But why?!!! Let me tell you.



On Non-Sealed Class


While calling the virtual method on the object created from MyClass class, at that moment the compiler doesn’t know if there is some code that reinitialized the _myClassObject object with a new instance of a child class of MyClass class or not. This assumption is valid because MyClass class is not sealed and this means that it could be inherited.


Based on that assumption, the compiler could not decide -at compile time- if the actual implementation of the DoSomething method would be the one provided by MyClass class or any other child class of it.


Thus, the compiler would write some instructions -to be executed at runtime- to check at the moment of executing the DoSomething method, which implementation would be the right one. This for sure would cost more processing and time.


Note: as you noticed the compiler would suspect that some code could reinitialize the object. You might think that marking the field as readonly would solve the problem but actually no as still the object could be reinitialized inside the constructor.



On Sealed Class


While calling the virtual method on the object created from MySealedClass class, at that moment the compiler doesn’t know if there is some code that reinitialized the _mySealedClassObject object with a new instance or not. However, the compiler is sure that even if this happened, the instance would still be of MySealedClass class as it is sealed and this means that it would never have any child classes.


Based on that, the compiler would decide -at compile time- the actual implementation of the DoSomething method. This is for sure much faster than waiting for the runtime.







Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Calling Non-Virtual Method


To validate if there would be any difference -from the compiler's point of view- between calling a non-virtual method on both MyClass and MySealedClass classes, we would create a Benchmark project.



Now, running this Benchmark project we would get the following result.


Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

As we can notice here, the performance of calling the non-virtual method on the sealed class is better than calling it on the non-sealed class.


However, there is no scientific evidence on why this is happening and actually running the same benchmark project again might get the opposite results.


Therefore, most probably this difference is caused by the benchmarking framework itself as the difference is too small that it could be negligible.




Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Type Checking


To validate if there would be any difference -from the compiler's point of view- between checking the type of an object using the is operator on both MyClass and MySealedClass classes, we would create a Benchmark project.



Now, running this Benchmark project we would get the following result.


Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

As we can notice here, the performance of checking the object type on the sealed class is better than calling it on the non-sealed class.


But why?!!! Let me tell you.



On Non-Sealed Class


While checking if the type of the object is MyClass class, the compiler needs to check if the object is of the type MyClass class or any of its child classes.


Thus, this leads to more instructions and for sure more processing and time.



On Sealed Class


While checking if the type of the object is MySealedClass class, the compiler needs to check if the object is only of the type MySealedClass class, nothing else. This is because MySealedClass class is sealed and this means that it would never have any child classes.


Thus, this leads to fewer instructions and for sure less processing and time.







Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Type Casting


To validate if there would be any difference -from the compiler's point of view- between casting an object using the as operator on both MyClass and MySealedClass classes, we would create a Benchmark project.



Now, running this Benchmark project we would get the following result.


Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

As we can notice here, the performance of casting the object on the sealed class is better than calling it on the non-sealed class.


But why?!!! Let me tell you.



On Non-Sealed Class


While casting the object as MyClass class, the compiler needs to check if the object is of the type MyClass class or any of its child classes.


Thus, this leads to more instructions and for sure more processing and time.



On Sealed Class


While casting the object as MySealedClass class, the compiler needs to check if the object is only of the type MySealedClass class, nothing else. This is because MySealedClass class is sealed and this means that it would never have any child classes.


Thus, this leads to fewer instructions and for sure less processing and time.




Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Storing Object In Array


To validate if there would be any difference -from the compiler's point of view- between storing an object in an array on both MyClass and MySealedClass classes, we would create a Benchmark project.



Now, running this Benchmark project we would get the following result.


Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

As we can notice here, the performance of storing an object in an array on the sealed class is better than calling it on the non-sealed class.


But why?!!! Let me tell you.


Before going into details, let me first remind you of an important point; arrays are covariant.


This means that if we have the following classes defined:



Then the following code would be valid:



Additionally, we can set an item inside arrayOfA to an instance of B as follows:



Having said that, let’s now proceed with our main topic.



On Non-Sealed Class


While setting an item inside the myClassObjectsArray array, the compiler needs to check if the instance myClassObject we are using is of type MyClass class or any of its child classes.


Thus, this leads to more instructions and for sure more processing and time.



On Sealed Class


While setting an item inside the mySealedClassObjectsArray array, the compiler needs to check if the instance mySealedClassObject we are using is only of the type MySealedClass class, nothing else. This is because MySealedClass class is sealed and this means that it would never have any child classes.


Thus, this leads to fewer instructions and for sure less processing and time.







Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Early Failure Detection


In addition to the performance gain we can get by using the sealed keyword, we can also avoid some runtime failures. Let me show you an example.


If we write the following code:



The compiler -at design time- would not show any warnings or errors because actually obj could be of type MyClass class or any of its child classes. Therefore, the compiler needs to wait for the runtime to do the final check.


For sure, if at runtime the real type of obj turns out to not implement IMyInterface, this would cause a runtime exception.


However, if we write the following code:



The compiler would show an error (CS0039) in the design time because obj could only be of type MySealedClass class, nothing else. Therefore, the compiler can instantly check if MySealedClass class implements IMyInterface or not.


Thus, this means that using the sealed keyword enabled the compiler to perform the proper static changes at design time.




Sealed Keyword Performance Enhancement Boost Compiler-Friendly Code Virtual Type Casting Checking Failure Detection Programming Software Development Architecture Engineering Design Best Practice CSharp (C#) DotNet (.NET) Ahmed Tarek

Final Thoughts


I would always recommend using the sealed keyword whenever applicable.


This is not only for the performance gain you might get but also because it is a best practice from the design point of view to the extent that Microsoft was actually thinking about making all classes sealed by default.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Why Split Large Methods Into Smaller Ones?!]]>https://www.developmentsimplyput.com/post/why-split-large-methods-into-smaller-ones658b5749043ec46669a3d992Sun, 10 Jul 2022 22:00:00 GMTAhmed TarekLearn when splitting large methods into smaller ones makes the impossible possible.


Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

Introduction


As a software developer, you have always heard someone telling you that you should not have bulky methods. In other words, you should avoid having too much logic or too many lines of code inside one method.


I can hear you now saying:


Calm down my friend, I am not going to repeat the same thing you are always hearing about this.


I am not going to tell you that if your method is bulky and bloated with too much logic this would be a good indication that it is doing too much, or, may be the whole class is doing too much. In this case you would be violating the Single Responsibility Principle of the (S)OLID Principles.


I know that you already know that. However, I am going to show you something interesting that you might be missing.


In the next sections of this article, I am going to show you that splitting large methods into smaller ones could make a huge difference. Actually, it could make the impossible possible.




Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

What Happens When A Method Is Called


Most probably you know that for each method call a stack frame is created and allocated inside the Stack memory.


Note: If you don’t know much about the Stack memory, may be you can check the article Memory Management In .NET. It would help you understand.


So, let’s say that we have the following simple piece of code.



Assuming that the comments actually represent some code to get executed, when we start calling Function1, this is what is going to happen.


Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

As you can see, at the start of every function, a Stack frame is created and this frame is not deallocated till the function is fully executed. When a child function is called, a child frame is created and so on,…


Worth to mention here, while consecutive and nested Stack frames are being created and allocated into the Stack memory, the allocated memory continues to build up till some frames are deallocated.


Therefore, unless you have an infinite Stack memory, you could have out of memory exceptions, or let’s call it; Stack Overflow exceptions.


You don’t believe me? Let me show you.







Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

Large Method


In this code sample, we are going to simulate a Stack Overflow exception by using Recursion.


Note: If you don’t know much about Recursion, may be you can check the article Curse of Recursion in .NET C#. It would help you understand.



What we can notice here:

  1. We are calling a recursive method which should generate 20,000 method calls.

  2. The logic is not fancy and we should not care much about it for now. It is just for demonstration.


Now, running this code would yield the following result:


Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

This has happened because for each of the 20,000 method call, a new Stack frame is allocated into the Stack memory when the previous one is not cleared yet. Eventually, we ran out of the Stack memory.


Ok, now you might ask:


Whew, I was afraid you would never ask. I have built the whole article based on this question


Let me answer your question; simply no. You don’t drop it but you should bend it a little bit to make it work.


Proceed to the next section and I will show you something interesting…







Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

Small Methods


We are going to apply a so simple/trivial change to our previous code. It is simple/trivial to the extent that you might not believe it would make any difference.


Enough with the talking, let’s see some code.



What we can notice here:

  1. We modified the GetResultRecursively method to get an additional parameter which is the lower boundary iteration number.

  2. This way we can call the GetResultRecursively method and decide where to start counting and where to end.

  3. Then we split the one call of the GetResultRecursively method into two calls. Now instead of having one huge call of 20,000 iterations, it would be two calls where each is of 10,000 iterations only.

  4. The first call starts at 20,000 and ends at 10,000.

  5. While the second call starts at 10,000 and ends at 0.

  6. This way, we are still covering the whole 20,000 range.


I can hear you now saying:


Are you sure? Let’s run the new code and see.


Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

Oh, it worked!!! How is that even possible?!!


Yes my friend, it is possible. The thing is, when we split the 20,000 iterations into 2 calls, the Stack frames allocated inside the Stack memory are only accumulated for 10,000 calls, then cleared relieving some Stack memory, and then the next 10,000 calls are performed and by then there is enough Stack memory.


So, following this pattern, you can actually do more 10,000 calls as you wish like this:



And it would still work. Is it magic? no, just basic knowledge of how method calls work.







Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

Summary


Ok, now I know that you might be confused a little bit, so let me summarize it for you.

Splitting the logic of one method call into two consecutive method calls would return the same logical output but would have different impact on the Stack memory.


Therefore, my advice to you, if you really need a single method to have too much logic, try to split this logic into multiple methods. This would help the Stack memory to breath between the methods calls and eventually avoid encountering a Stack Overflow exception. The only challenge you could encounter is how to reconstruct the final result from these multiple calls.


However, for brevity, you should still think of why your method or class should take care of that much of logic in the first place. This is a sign of something wrong.




Introduction. Learn when splitting large methods into smaller ones makes the impossible possible. Stack Frame Memory Code Coding Programming Software Development Architecture Engineering Design Pattern Best Practice Basics CSharp (C#) DotNet (.NET)

Final Thoughts


In this article we proved that splitting large methods into smaller ones is not just a design rule to beautify your code. It could actually make the impossible possible.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Analysis of Template Method Design Pattern In .NET C#]]>https://www.developmentsimplyput.com/post/analysis-of-template-method-design-pattern-in-net-c658b0ff639ab6f6557748463Sun, 26 Jun 2022 22:00:00 GMTAhmed TarekLearn the Template Method Design Pattern in .NET C# and explore the different possibilities.


What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

What is Template Method Design Pattern?


The Template Method Design Pattern is one of the widely used design patterns, especially when dealing with algorithmic modules or systems. Let me walk you through it step by step.


Sometimes when we are working on a module of our system, we find that we need to follow some specific steps in a certain order. But, we also find that the implementations of these steps are not always the same. In this case, what would we do?


Here the Template Method Design Pattern comes to rescue. It is one of the behavioral design patterns. It allows the developer to define a procedural sequence of an algorithm or a process in a base class which delegates the specific implementations of some steps to the subclasses without changing the overall structure.


Do you get it? No?… Let me show you.




What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

Code Example


Let’s say that our system is a Tax Calculator Console Application. The accountants consulting our team provided us with a general formula for calculating taxes but they told us that some steps of the general formula would differ in calculation from one person to another depending on their marital status.


In other words, all the steps in the general formula should be there in the main sequence but in some cases the way we are calculating some of these steps would be different.


Therefore, our team tried to come up with the best design and decided to use the Template Method Design Pattern as it was recommended by some expert solution architects.


So, following the Template Method Design Pattern our solution would be as in the code below.



TaxCalculator



What we can notice here:

  1. This is an abstract class to represent the base class for all our concrete Tax Calculators.

  2. On the CalculateTaxes method, we are implementing the general formula we got from our accountants.

  3. We defined the three methods CalculateExpenses, CalculateIncomeTax, and CalculateVat as protected abstract because these methods would have different implementations and these implementations would be provided by our concrete Tax Calculators.







TaxCalculator1 and TaxCalculator2



What we can notice here:

  1. These are the two concrete Tax Calculators implementations we have.

  2. They inherit from our base TaxCalculator class.

  3. They provide the implementations of the three methods CalculateExpenses, CalculateIncomeTax, and CalculateVat.

  4. Sometimes one or more of these methods could require a dummy implementation (like returning zero) to act as if they were never called.




Console Application



What we can notice here:

  1. This is the Console Application.

  2. In the Run method we are assuming that we would need to use both TaxCalculator1 and TaxCalculator2 but in the real world it could be only one of them.

  3. Now, when the CalculateTaxes method is called on an instance of TaxCalculator1, the implementations of the three methods provided by TaxCalculator1 would be executed.

  4. On the other hand, when the CalculateTaxes method is called on an instance of TaxCalculator2, the implementations of the three methods provided by TaxCalculator2 would be executed.


Now, running this application would return the expected calculation result as our accountants advised. However, is this the best solution?







What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

Design Challenges


The current design is working, but, it is not the best design we can come up with.


Here are some problems with the current design:

  1. Useless/Dummy method calls are sometimes performed just because we are keeping the general base formula intact. This is not good for performance.

  2. It violates the Interface Segregation Principle of the SOL(I)D principles. It is easy to spot this for the same reason as point 1 above.


Therefore, on the next sections, we would dig deeper into each of these design problems and try to come up with a better design.




What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

Useless/Dummy Method Calls


Here is something that some developers don’t recognize. When a method call is performed, some memory allocations happen for input parameters and return object unless they are passed and returned by reference.


Therefore, when we just call a method even if the call is not needed, this is not the best design.


I can now hear someone saying:


Ok, may be you are right if it is as in the current implementation of our Tax Calculator Application.


However, what if we are dealing with more complex objects and structs that consume more memory?


Or, what if our CalculateTaxes method is called too many times that even the smallest deviation in the memory allocation of one call turns up eventually to be huge?


Let’s say that our code is updated as follows:




Console Application



See, here our CalculateTaxes method is called 10,000,000 times.


Can you imagine the huge difference in memory allocation? No? Let me show you…







What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

Comparing Useless Method Call to No Call


On this section, I am going to show you the difference in performance and memory allocation between calling an empty/dummy/useless method to not calling it at all.


Check the code below:



What we can notice here:

  1. The Calc method is actually doing nothing.

  2. The RunSlow method calls the Calc method 10,000,000 times.

  3. The RunFast method just loops 10,000,000 times.


So, running a Benchmark for these two methods would produce the following result.


What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

See, the difference is huge. Therefore, it would be nice if we can avoid performing useless calls whenever we can.




What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

How To Avoid Useless Calls?


We can do this using more than one approach and in the next sections we will try them one by one.



Using Properties


In this approach, we are going to define three boolean properties to represent the calls that each concrete implementation can provide. Then, we can use these properties to check if a call would be useful or not.


Now, we would update the code to be as follows.




TaxCalculator



Here we just added the following:


And then, we started using these three boolean properties inside the CalculateTaxes method to decide whether a call needs to be performed or not.


Now, I can hear someone saying:


My answer would be yes, it could. However, it might still be better than performing an empty/useless call.


Furthermore, I will show you something interesting at the end of the article so just bear with me.







TaxCalculator1 and TaxCalculator2



Here, we are just overriding the boolean properties to set them to the right values.




Console Application





Using Flagged Enums


In this approach, we are going to define a flagged enum to represent the calls that each concrete implementation can provide. Then, we can use this flagged enum to check if a call would be useful or not.


Note: If you want to learn about Flagged Enums in .NET C#, you can check this the article Flagged Enumerations: How To Represent Features Combinations Into One Field.


Now, we would update the code to be as follows.




TaxCalculationCapabilities



Here we defined the flagged enum TaxCalculationCapabilities.




TaxCalculator



Here we just added the following:


And then, we started using this TaxCalculationCapabilities property inside the CalculateTaxes method to decide whether a call needs to be performed or not.







TaxCalculator1 and TaxCalculator2



Here, we are just overriding the TaxCalculationCapabilities property to set it to the right value.




Console Application





Using Interfaces


In this approach, we are going to split and abstract each of the three methods in its own interface. So, whenever a concrete implementation is capable of providing a reasonable implementation of any of these methods, it just needs to implement the corresponding interface.


Now, we can also remove the abstract definitions of these three methods from the base class as they are not needed anymore.


Furthermore, the base class would now check if the current concrete implementation implements each interface before calling the corresponding method.


This way, we fixed the two problems we mentioned before:

  1. Useless/Dummy method calls.

  2. Violating the Interface Segregation Principle of the SOL(I)D principles.


Now, we would update the code to be as follows.




ICalculateExpenses, ICalculateIncomeTax, and ICalculateVat



It’s clear, right?




TaxCalculator1 and TaxCalculator2



Now as you can see, the contracts are clear and simple. No more useless methods to implement.







TaxCalculator



Also here, the implementation is now clear and simple. Notice that we removed the definitions of the three abstract methods from here as they are not needed anymore and we don’t want to force the concrete implementations to implement them even when not actually needed.




Console Application








What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

Are We Done?


I know you are still waiting for a reply on your argument:


I didn’t want to discuss this point earlier because I wanted then to drive your focus to the importance of not calling useless calls. However, now we can discuss this.


There is a fourth approach which we could follow to avoid the useless calls and also avoid the if condition checks. Getting interested? Let’s do it…




Using Expression Trees


The main idea behind this approach is to write some code which would generate the alternative CalculateTaxes method at runtime. Don’t get it? Let me explain.


Here is what we should think about:

  1. Our optimal goal is to have an implementation of the CalculateTaxes method without any unneeded calls even the if condition checks.

  2. But, we can’t do this as the implementation itself would be different for each concrete implementation.

  3. Therefore, we can’t achieve this by defining the implementation of the CalculateTaxes method at design/development time.

  4. But, what if the implementation of the CalculateTaxes method could change at runtime according to the concrete implementation?


In other words, as an example, what if the implementation of the CalculateTaxes method is automatically changed at runtime to the following for the TaxCalculator1 ?


Also, what if the the implementation of the CalculateTaxes method is automatically changed at runtime to the following for the TaxCalculator2 ?


Wouldn’t that be great? Indeed but how can we do this? We can do this using Expression Trees as follows. In this solution, we are going to use the Properties approach combined with Expression Trees.




TaxCalculator1 and TaxCalculator2



Nothing new here, it is the same implementation of the approach where we were using the Properties.




TaxCalculator



What we should notice here:

  1. We defined the BuildExpression method. This is where the magic happens.

  2. Inside this method we are using the Expression API to build the expression of the CalculateTaxes method that would be executed at runtime.

  3. While doing this, we check the passed in TaxCalculator to know which methods calls should be added to the expression and which should be skipped.

  4. This way the check itself would not be done inside the execution of the CalculateTaxes method which would happen for 10,000,000 times.

  5. This means that calling this BuildExpression method, passing in a certain concrete implementation of TaxCalculator, would return a pure and clean implementation of the CalculateTaxes method for that concrete implementation.

  6. This is what we are dreaming of.

  7. We need also to know that compiling that generated expression into an actual Func<TaxCalculator, decimal> is too costy.

  8. That’s why we need to do it once and for sure outside the CalculateTaxes method call.

  9. And we already did that by defining the Func<TaxCalculator, decimal> field and setting it inside the constructor by calling the BuildExpression method.

  10. Then inside the CalculateTaxes method we just call the Func<TaxCalculator, decimal> saved in the field.







Console Application



I can hear you now asking:


As you can see, the solution would be perfect for runtime performance but it is not that perfect in terms of readability and extensibility. It is not easy to read the code, understand it, and extend it.


Therefore, my recommendation would be to not use this approach unless the performance of a certain module is too critical to the extent that you accept to sacrifice your readability and extensibility.




What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function


Benchmarking


Now you might be asking:


Yes, I agree with you. You should not just trust me on it, you need some proof that it actually works and adds a value. And that’s what I did…


I ran a Benchmarking project as follows:



The first run yielded this result


What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

And the second run yielded this result


What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

So, as you can see, now you could imagine the difference between all the approaches.







What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

Conclusions


Ok, we have discussed more than one approach but now we don’t know how to decide which approach to go with.


If you ask me, I would say:

  1. I prefer to use the Interfaces solution as it is clean.

  2. Don’t use the Expression Tree solution unless you really need it.

  3. Prefer Composition to Inheritance. In my point of view, I think the same result could be achieved by Composition and it would be better in design and maintenance.

  4. Always do your own realistic Benchmarking and Measuring. What could be the best for one solution could be the worst for another.

  5. You should know that there should always be a tradeoff between memory allocation (space) and processing power. Therefore, be wise about it and choose what fits in your case.




What is Template Method Design Pattern. Learn Understand Template Method Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Tackle Challenge Performance Approach Expression Tree Generate Delegate Function

Final Thoughts


In this article we discussed the Template Method Design Pattern in .NET C#.


We also discussed some of the challenges that you could encounter while working on your design and analyzed more than one approach on how to tackle these challenges.


Now you understand what the Template Method Design Pattern is about. However, this is not the end of the story.


You would need to search the internet for more articles and tutorials about the Template Method Design Pattern and its usages. This would help you understand it more.


Finally, I hope you found reading this article as interesting as I found writing it.



]]>
<![CDATA[Unit Testing Best Practices In .NET C#]]>https://www.developmentsimplyput.com/post/unit-testing-best-practices-in-net-c658b08be58c5a961dba41d08Mon, 14 Mar 2022 23:00:00 GMTAhmed TarekTips, tricks and best practices of Unit Testing in .NET C# using NUnit and Moq.


Tips, tricks and best practices of Unit Testing in DotNet (.NET) CSharp (C#) using NUnit and Moq. Coding Code Programming Software Engineering Architecture Development Coverage Mock Stub Abstract Dependency Injection (DI) Test Driven Development (TDD)

The Scope


In this article we are going to highlight some of the important tips and tricks to follow when using NUnit and Moq libraries to cover our .NET C# applications with Unit Tests.


You should not use this article as definitive guide to unit testing as this is not the goal or scope of this article. However, in this article you would find some of the important tips, tricks, and best practices to help you achieve the best results with your .NET C# application unit testing and coverage.




Tips, tricks and best practices of Unit Testing in DotNet (.NET) CSharp (C#) using NUnit and Moq. Coding Code Programming Software Engineering Architecture Development Coverage Mock Stub Abstract Dependency Injection (DI) Test Driven Development (TDD)

Frameworks Used


Unit-testing Framework


Tips, tricks and best practices of Unit Testing in DotNet (.NET) CSharp (C#) using NUnit and Moq. Coding Code Programming Software Engineering Architecture Development Coverage Mock Stub Abstract Dependency Injection (DI) Test Driven Development (TDD)

We are going to use NUnit as the unit-testing framework.


You can find all the NUnit official documentations on this link.


Also, you can specifically find the documentation of all the attributes provided by NUnit on this documentation page.



Mocking Framework


Tips, tricks and best practices of Unit Testing in DotNet (.NET) CSharp (C#) using NUnit and Moq. Coding Code Programming Software Engineering Architecture Development Coverage Mock Stub Abstract Dependency Injection (DI) Test Driven Development (TDD)

We are going to use Moq as the mocking framework. Moq is the most popular and friendly mocking framework for .NET.


If you want to have a boost on how to start using Moq, you can find a quick start guide on this link.


You can find all the Moq official documentations on this link.







Tips, tricks and best practices of Unit Testing in DotNet (.NET) CSharp (C#) using NUnit and Moq. Coding Code Programming Software Engineering Architecture Development Coverage Mock Stub Abstract Dependency Injection (DI) Test Driven Development (TDD)

Tips and Hints


In this section we are going to discuss some tips and hints which would be useful while writing our unit tests.




Setting Up and Tearing Down


When we are writing our unit tests, we usually have some preparations and cleaning up code to be run before and after our unit tests.


NUnit provides us with some attributes to be used for these preparations and cleaning up tasks.



OneTimeSetup: is used to set the code to be executed only once before the first test.


SetUp: is used to set the code to be executed before every test.


TearDown: is used to set the code to be executed after every test.


OneTimeTearDown: is used to set the code to be executed only once after the last test.


If we have like 2 tests, the order of execution would bs as follows:

  1. OneTimeSetup ▶ Before Test #1

  2. SetUp ▶Before Test #1

  3. TearDown ▶After Test #1

  4. SetUp ▶Before Test #2

  5. TearDown ▶After Test #2

  6. OneTimeTearDown ▶ After Test #2




Test Cases


When we are writing our unit tests we might need to cover more than one test case in the form of input and output pairs.


Therefore, instead of writing more than one single test for each of these test cases, we can use the TestCase attribute provided by NUnit.


The TestCase attribute could be used in more than one format.


For example, you can use it this way:



Or you can use it this way:



Or even in more ways. You can always check the official documentation.




Test Cases From a Source


Sometimes we need to share the same test cases between more than one test. In this kind of situations using TestCase attribute would not be enough.


Therefore, NUnit is providing us with the TestCaseSource attribute so that we can set our cases into a shared module and then start using it with different tests.


This is one of the ways we can use the TestCaseSource attribute:



If you want to explore the other ways, you can always check the official documentations.




Multiple Values


Sometimes we need to use more than one value as an input for our test. In this case it would not be good to just duplicate the test for each value.


You might think of using the TestCase attribute and it would work. However, it would be an overkill.


Additionally, what if you have more than one input and each of these inputs could be one of a list of options. You might need to add a TestCase attribute for each combination. This would be a total mess.


Instead of doing all of this, NUnit is providing us with the Values attribute.


For example, if we use it as follows:



This means that the MyTest test would be executed 6 times as follows:


See, using the Values attribute could save us the hassle of explicitly writing all these cases.




A Range


What if we need to do the same but without providing the full list of values? We only want to provide the first value, last value, and the step to move with.


For this kind of cases, NUnit is providing us with the Range attribute.


For example, if we use it as follows:



This means that the MyTest test would be executed 4 times as follows:


See, using the Range attribute could save us the hassle of explicitly writing all these cases.


Worth to mention here that both the Values and Range attributes can be combined as follows:



This means that the MyTest test would be executed 9 times as follows:


Nice, right?




Repeating


Sometimes we find ourselves in the need to repeat running a unit test many times in a continuous manner. Most of the cases we need to do this to test the performance impact or for stress testing some code.


Me myself, in more than one occasion I needed to do this because we were having a unit test which “sometimes” fails on the build server. I suspected that this was caused by some racing which happens or some resources which are not fully controlled.


Therefore, in this case, I used the Repeat attribute that NUnit is providing us with.


For example, if we use it as follows:



This would cause the MyTest test to run for 25 times in a row.


Using the Repeat attribute makes it too easy to detect wobbly tests and find the failure root cause.







Collection Asserts


Sometimes we need to do some asserts on collections. In this case, NUnit is providing us with some useful utilities to use.


Assert.IsEmpty: may be used to test either a string or a collection or IEnumerable. When used with a string, it succeeds if the string is the empty string. When used with a collection, it succeeds if the collection is empty.


Assert.IsNotEmpty: may be used to test either a string or a collection or IEnumerable. When used with a string, it succeeds if the string is not the empty string. When used with a collection, it succeeds if the collection is not empty.


Assert.Contains: is used to test whether an object is contained in a collection or not.

CollectionAssert.AllItemsAreInstancesOfType: is used to test whether all items in a collection are instances of a certain type or not.


CollectionAssert.AllItemsAreNotNull: is used to test whether all items in a collection are not null or not.


CollectionAssert.AllItemsAreUnique: is used to test whether all items in a collection are unique or not.


CollectionAssert.AreEqual: is used to test whether each item in a collection is equal to its corresponding one in another collection. Items are compared according to their order in both collections.


CollectionAssert.AreEquivalent: is used to test whether each item in a collection is equal to a corresponding one in another collection. Items are compared regardless their orders are.


CollectionAssert.AreNotEqual: is the opposite of CollectionAssert.AreEqual.


CollectionAssert.AreNotEquivalent: is the opposite of CollectionAssert.AreEquivalent.


CollectionAssert.DoesNotContain: is used to test whether a collection of items doesn’t contain a certain object or not.


CollectionAssert.IsSubsetOf: is used to test whether a collection of items is a subset of another collection or not.


CollectionAssert.IsNotSubsetOf: is used to test whether a collection of items is a not a subset of another collection or not.


CollectionAssert.IsOrdered: is used to test whether a collection of items is ordered or not.


For any further details, you can always check the official documentations.




Event Handlers


Sometimes you need to test some of your modules which handle events fired by other modules.


In these cases, the best way to handle this is to have the modules which fire the events abstracted so that you can mock them for testing. Let me show you an example.


Let’s say that we have a sensor which reads the acceleration of a car or any object.



As you can see, it is just a simple interface with an event. Although we don’t actually need an implementation for the sake of our example, I just provided a simple one for brevity.


Now, let’s say that we have an AccelerationDashboard module which uses the IAccelerationSensor module to always get the updated acceleration value.



As you can see, our AccelerationDashboard class depends on the IAccelerationSensor module and expects it to be injected through the constructor.


Also, it just handle the AccelerationChanged event raised by the IAccelerationSensor module.


Now, for testing the AccelerationDashboard module, this is what we can do:



See, it is that easy. Using Moq we can mock the IAccelerationSensor module and trigger the AccelerationChanged event in order to then assert the Acceleration value on the AccelerationDashboard module.







Timers


One of the challenges you might face when your system works with Timers is how to fully cover your system with unit tests.


To do so, you will need to abstract the Timer class and do some tweaks to achieve your goals.

I had already published a fully detailed article about this. If you are interested into the topic, you can check my article Best Practice for Using Timers in .NET C#.




DateTime


Also, if your system uses DateTime or DateTimeOffset, you will eventually face some challenges to fully cover your modules with unit tests.


To conquer these challenges, you will need to abstract these classes into providers, define them as dependencies and then you would be able to mock and stub them as needed.


I had already published a fully detailed article about this. If you are interested into the topic, you can check my article DateTime Best Practices In .NET C#.




I/O File and Folder Operations


This is one of the famous challenges that many developers face when their systems heavily depend on I/O file and folder operations.


To fully cover such systems with unit tests the developer must think beyond his near obvious needs. The system design itself must be adapted into some abstracted layers where each layer has a well defined rule in the whole system.


I had already published a fully detailed article about this. If you are interested into the topic, you can check my article How To Fully Cover I/O File Based Applications in .NET C# With Unit Tests.




Console Systems


When dealing with console systems, it becomes so hard to cover the whole system with unit tests when our modules directly depend on System.Console.


That’s why we first need to abstract the console Api and start using them as dependencies. Doing this, it would be much easier to cover our console systems with unit tests.


I had already published a fully detailed article about this. If you are interested into the topic, you can check my article How to Fully Cover .NET C# Console Application With Unit Tests.




Tips, tricks and best practices of Unit Testing in DotNet (.NET) CSharp (C#) using NUnit and Moq. Coding Code Programming Software Engineering Architecture Development Coverage Mock Stub Abstract Dependency Injection (DI) Test Driven Development (TDD)

Final Thoughts


In this article we discussed some of the important tips, tricks, and best practices to follow when using NUnit and Moq libraries to cover our .NET C# applications with Unit Tests.


My advice to you is to do your own research and try to find other resources which might help you understand more about testing techniques and related best practices.


Finally, I hope you found reading this article as interesting as I found writing it.



]]>
<![CDATA[Mistakes Made By Developers]]>https://www.developmentsimplyput.com/post/mistakes-made-by-developers658b04637580fe08af7006fbMon, 21 Feb 2022 23:00:00 GMTAhmed TarekThese are the most common mistakes made by developers.


The most common mistakes made by developers. Code Coding Programming Software Development Engineering Architecture Best Practice

There are some common mistakes which almost all developers have made at some point of their career days.


In this article, we are going to mention some of these mistakes so that we can all learn from them hoping that we can avoid falling for them again and again


The mistakes would be categorized in more than one category as follows:

Mistakes at Preparation phase Mistakes at Coding phase Mistakes at Testing phase Mistakes at Self Development phase


In the next sections, we would go through the mistakes done through each one of these phases. So, buckle up and enjoy the ride.







The most common mistakes made by developers. Code Coding Programming Software Development Engineering Architecture Best Practice

Mistakes at Preparation phase


Trusting that the customer always knows what he needs

This is one of the most common mistakes. You should not always trust that the customer is fully aware of what he actually needs.


Sometimes the customer mixes between what he actually needs for his business to work as expected and what he wants to have.


You might ask:


The problem is that a confused customer would always be a pain in your back. He would always come back with more changes that could sometimes need huge refactoring. You think it is ok, don’t ever underestimate the power of frustration.


Furthermore, helping your customer understand his needs would turn him into a loyal customer.




Missing the big picture


Sometimes a developer becomes too focused on the small parts of the puzzle that he misses the big picture.


This is not good as the developer might miss a lot of details that are so important to solve the whole puzzle, or in other words, deliver the right solution to the right problem.


That’s why the developer should always take a step back to be able to see the big picture, understand what is missing, how modules should interact and collaborate to play one consistent symphony.




Re-inventing the wheel


A developer should always explore his options. Sometimes what a developer wants to achieve is already there but he is missing it because he is driven by the passion of implementing what he has in mind.


As a developer, you should always check if what you really want to implement is already implemented somewhere, may be in the same solution, or in a third party or somewhere else. If this is the case, most probably re-using a well established existing solution would be better and safer on the long run.




Underestimating the workload


Sometimes a developer underestimates the amount of work that a task would need to be completed. Most probably this happens due to a lack of knowledge of the task itself.


A developer should keep breaking down tasks to the smallest possible size to the extent that he really understands each small task and its requirements, then he should be able to put an estimate for each of these small tasks.


The estimate should include all the activities to be held to fully deliver the task including the following:

▶ Designing

▶ Refactoring

▶ Implementing

▶ Covering with automated tests

▶ Testing

▶ Processing code review comments

▶ Updating documentations

▶ Signing off


Dropping any of these might cause an unexpected delay.




Premature coding


Jumping into code before doing any initial analysis is a big mistake that some developers make. Most the times this happens due to being driven by passion to finish a task. Coding is the comfort zone for many developers.


Before jumping into code there are some basis to cover. A developer needs to be aware of the history related to his task. You can’t imagine how asking some simple questions could save you ages of time and enormous amount of effort.


Therefore, my advice to you as a developer is to always do your analysis first and believe me it would pay off.







Over-engineering

Always think about what the system needs, not what you can do. Many times in my career I came across so complicated systems which could have been implemented in a much simpler way.


From where I see it, sometimes a developer keeps complicating things by implementing whatever he knows whether it suits his needs or not. If you know like 10 design patterns, don’t just keep pushing yourself to implement them in your solution. You need to focus on what serves your needs, think about it, analyze it, refine it, and finally start implementing it.




Trying to ace all factors


In the software world, you can’t achieve the best in all aspects. What is the best for some aspect or factor could be the worst for another and that’s is why you would always have to compromise.


Therefore, you need to set your priorities, rank them and then start working on finding the best solution you can come up with to server your needs accordingly.




The most common mistakes made by developers. Code Coding Programming Software Development Engineering Architecture Best Practice

Mistakes at Coding phase


Hiding issues rather than fixing them

Sometimes developers tend to find the shortest path to fix an issue and unfortunately they end up with hiding it rather than fixing it.


It is like when you have a field which is not set at a certain moment and to fix it you keep setting it in many places. Yes, you might end up with the field being set as it was expected in the first place but actually you might be overlooking a disaster to come shortly.


Before fixing an issue, you first need to find the root cause so that you are sure you are fixing the right issue in the right way.




Ignoring logging


Logging is one of the top most important things that every developer should pay attention to. It is that kind of things which you don’t miss until you are in a real disaster.


I noticed many developers tend to ignore logging in their software modules thinking that it is a waste of time. However, they learn the lesson the hard way when their modules fail on production.




Workarounds


Applying workarounds in your code to fix an issue or quickly apply a change would fire back in the future, may be earlier than what you think.


As we said before, when you are working on fixing an issue or applying a change you become too focused on the small details to the extent that you miss the big picture.


Always think of the impact of what you are changing in your code, stay focused on the task but also keep in mind the whole solution design.




Too many responsibilities


One of the mistakes a developer makes is bloating his modules with too many responsibilities. This makes the whole system fragile.


Every module should be responsible for its main role. If you find your module doing too many things that don’t conceptually belong to it, this should be an indicator that something wrong is happening.


Dividing your system into well defined small modules is a skill you gain by time and it would always pay off.







Using magic numbers


Don’t get me started on magic numbers. It is a nightmare to come true.


If you think a module should make use of some constant number, don’t just hide the number somewhere in the code. Instead, it should be well defined in a place visible to all contributors so that it is sound and clear.


Furthermore, check if this number could be defined as a high level constant defined within a system constants module. This way it would be more visible and maintained.




Messy code formatting


Yes, I know it is not something that affects your deliverables in a direct way, but, keep in mind that your code would be processed by other developers.


Therefore, even if you don’t have any problems with your code formatting, other developers might have. So, please try to make it easy on everyone to read your code.




Describing the obvious


What I am talking about right now is adding comments which don’t have any added value.

Your comments should be providing the info which is not obvious from the code. So, adding dummy comments would not help and furthermore it might confuse other developers.


Additionally, worth to mention here is that if you follow the concepts of clean coding you should not be in that need to describe what your code is doing using comments.




Leaving commented code blocks


Some developers keep commented code laying around out of fear of losing it when they need it in the future.


This is a bad practice as the code ends up bloated with too many distractions laying around. Beside, if you are using version control systems, and you should, you can always get back to the removed code whenever you need.




Writing confusing commit messages


Many times when I explore a pull request I find bad commit messages that not only don’t help me understand, but also confuse me.


Your commit messages should be descriptive so that any other developer could understand what your commits are about. This is so important as it also makes it easier to track old commits and deliveries.




Enormous commits


One of the big mistakes that some developers make is committing big changes into one single commit. This makes it so hard to track the changes and review them.


Always try to divide your commits into small single units so that each commit is related to a small part of your changes. This would help so much with the review and tracking and also would make it easy to use these commits in the future for duplication and reversing.







The most common mistakes made by developers. Code Coding Programming Software Development Engineering Architecture Best Practice

Mistakes at Testing phase


Ignoring automated testing


Nowadays software systems tend to be big and complicated. So, depending on manual testing only would be a huge mistake as your system would not be robust enough against rapid changes.


That’s why you should always consider automated testing so that you make sure all your business rules are covered with automated tests. This would make your system more robust against unexpected failures and rapid changes.




Embracing the happy scenario


Testing is good but you have many scenarios to cover. Covering the happy scenario could be a good start but it is not the end.


You should always invest time and effort in defining your business rules and their related test scenarios before jumping into implementation. This would help you cover all the basic, corner cases, and complicated scenarios.




The most common mistakes made by developers. Code Coding Programming Software Development Engineering Architecture Best Practice

Mistakes at Self Development phase


Fear of making mistakes


Don’t ever be afraid of making mistakes as this would constrain you and hold you back from learning and practicing.


You would make mistakes and this is fine. The important thing is that you learn from your mistakes and make sure you don’t repeat them. But, what if you repeat them?… still, try to learn again and this time think of the reason why you couldn’t protect yourself from falling into the same mistake again.


Learning is a long running continuous journey, so do your best to enjoy it.




Believing you are always right


You are not and would not be always right.


Don’t be stubborn, be open to listening to others, learn from them, re-evaluate your way of thinking and decisions. This would eventually help you grow.




Not taking care of your health


You are a human, not a robot, nor a machine. Your health is your own fuel so try to keep it in good shape. That’s it.




Underestimating self development


You should always make a plan for your self development. You need to learn new things and gain skills.


In the software world, everyday there is something new. Standing still is actually equivalent to moving backwards.


My advice to you is to put a plan, schedule it, and follow it. This would help you so much setting measurable goals to achieve.







Fear of asking for help


Some developers think that asking others for help is a sign of weakness which is wrong.


As we said before, no one knows everything and you would not always be right. Therefore, asking for someone’s help should not make you feel or look bad, it is the normal way of sharing and transferring knowledge.




Premature asking for help


On the other hand, some developers hurry for asking for help before investing proper amount of time and effort in trying to find answers to their questions.


As we said, you should not feel ashamed of asking for help, but, a part of your role and work is to find answers to your questions yourself. This would help you grow and gain analytical skills. Otherwise, you would always be dependent on someone else.


Worth to mention here, you should always time-box it. In other words, don’t take forever to find the answers yourself. Be reasonable about it.




Not sharing knowledge


As we said that you should not be afraid of asking for help, you should also provide help whenever possible.


It is a win-win situation. Helping someone would help you solidify your knowledge and would help him learn.


Therefore, I would always advise you to share your knowledge and help others grow.




The most common mistakes made by developers. Code Coding Programming Software Development Engineering Architecture Best Practice

Final Thoughts


We all do mistakes but what really makes a difference is whether we learn from them or not.


In this article I shared some of the most common mistakes that developers make. You could relate to some of them or not, but, at the end, it would always be good to keep them in mind.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Memory Management In .NET]]>https://www.developmentsimplyput.com/post/memory-management-in-net658af532436be4dd45ef5f12Sun, 20 Feb 2022 23:00:00 GMTAhmed TarekAll about memory management in .NET and important related topics.


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Introduction


This article is about memory management in .NET framework and some of the important topics and concepts related to it.


Agenda


These are the topics we are going to cover in this article.


Stack Memory


Heap Memory


Variables Allocation


What About System.String?


Boxing and Unboxing


Garbage Collection

  • Heap Memory Types

  • What Is Garbage?

  • Performance Measures

  • Small Objects Heap (SOH) Memory Generations

  • What About Large Objects Heap (LOH)?

  • Garbage Collection Triggers

  • Garbage Collection Process


Dispose and Finalize

  • Managed and Unmanaged

  • Memory Leak

  • Finalization Process

  • Finalizer Implementation

  • Dispose and Finalize Design Pattern







Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Stack Memory


Stack memory is allocated into computer’s RAM. It is used for static memory allocation.


The advantages of the Stack memory are:

  • Variables allocated are stored directly to the memory.

  • Allocation is done when the program is compiled.

  • Access to this memory is very fast.


Allocations on the Stack are reserved in Last In First Out (LIFO) manner which means that the most recently reserved block is always the next block to be freed. That’s why the Stack memory is used to keep track of the nested functions calls.


Let’s say that we have the following simple piece of code.



Assuming that the comments actually represent some code to get executed, when we start calling Function1, this is what is going to happen.


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

As you can see, at the start of every function, a Stack frame is created and this frame is not deallocated till the function is fully executed. When a child function is called, a child frame is created and so on,…


Worth to mention here is that Stack memory is not shared between threads. In other words, for every thread, a new Stack memory is allocated which is not shared with any other threads.




Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Heap Memory


Heap memory is allocated into computer’s RAM. It is used for dynamic memory allocation.

Allocations on the Heap are done at run time and can be accessed randomly.


Accessing the Heap memory is a bit slower, but the Heap size is only limited by the size of the virtual memory.


The Heap Memory is divided into two parts:

  • Small Objects Heap (SOH)

  • Large Objects Heap (LOH)


More details about this would come later in this article.


Worth to mention here is that Heap memory is shared between threads.







Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Variables Allocation


Any variable used in .NET would be one of two types; Value type or Reference type.

Value types are primitive data types like Byte, SByte, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, Double, Boolean, Char, Decimal, IntPtr, UIntPtr, and Structs.


Reference types are the other types defined by the developer including Classes, Interfaces, Delegates, Strings and Object.


Now, you might ask:


The answer of this question is:

  • A Reference type object is stored in the Heap memory and a reference to it is stored in the Stack memory.

  • A Value type object is always stored in the Stack memory unless it is defined on the first level of a class. In this case, it is stored in the Heap memory.


You don’t believe me? Let me show you.


Let’s say that we defined the following two classes:



Now, let’s say that we have this simple application code:



Here we would examine all cases one by one and see what would be allocated into the Heap memory. To do this, we would use Rider memory tracer which shows us the Heap memory allocations and monitor the changes happening between calls.


The first step is to examine when defining an int as we did on line 6. So, we added a breakpoint on lines 6 and 10. When we hit the breakpoint on line 6, and before the line itself was executed, we refreshed the Heap memory tracer on Rider. Then we hit continue so that the debugger hits the breakpoint on line 10. Then, we refreshed the Heap memory tracer on Rider again to see the difference.


And this was the difference:


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

See, nothing is allocated into the Heap Memory.


Now, let’s examine when defining an instance of a class which doesn’t have any Value type defined on its first level. Also, it has a method where we defined a Value type as a local member of the method.


So, repeating the same steps with breakpoints on lines 10 and 15, we would get the following result:


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

See, we have only one new entry allocated into the Heap memory for the instance of the class itself. However, we don’t have any allocations for the int id variable defined inside the method F1 into the Heap memory.


Now, let’s examine when defining an instance of a class which has a Value type defined on its first level.


So, repeating the same steps with breakpoints on lines 15 and 17, we would get the following result:


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

See, we have only one new entry allocated into the Heap memory for the instance of the class itself. However, when we check this entry into the Heap memory, we would find that it also includes the int Id class member.


Therefore, as a quick summary:

  • Reference types are always stored into Heap memory with a reference into Stack memory.

  • If a Value type is defined into a function, it would be stored into the Stack memory.

  • If a Value type is defined as a class first citizen (on the first level of a class), it would be stored into the Heap memory.


If you are interested into watching a video with an explanation of this topic, I really recommend watching Nick Chapsas's video. I stumbled on it while preparing for this article and I liked so much the way he simplified the whole thing.



Thanks Nick Chapsas for this great video


Worth to mention here, I had already published an article about the different ways of passing a parameter to a method in .NET C#


It is important to know about this topic as well. Therefore, if you are interested, you can read the article Passing Parameters to a .NET C# Method.







Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

What About System.String?


As a .NET developer, you might have heard about that nature of System.String. It is somehow unique and with this uniqueness comes some abnormalities.


When dealing with System.String, you need to keep in mind that it is not just a Reference type, it is a special one. Understanding this would for sure affect the way you are dealing with strings in your application.


I have already written an fully detailed article about this. I really recommend that you read it. If you are interested, you can read the article How String In .NET C# Works.




Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Boxing and Unboxing


If you are a .NET developer, most probably you heard before about Boxing and Unboxing.

Let me show you a quick code sample:



At line 1, we defined an int. On line 2, we defined a new Object variable and set it to the same int we defined on line 1.


What happens behind the scenes is that the int variable is wrapped into an object and stored into the Heap memory. This is what we are calling Boxing.


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

On line 3, we are casting the Object variable back to an int. Therefore, the object is unwrapped back to an int. This is what we are calling Unboxing.


Now, you might ask:


Actually no. Sometimes Boxing and Unboxing happens without you even know due to the design of some .NET built in functions and modules.


Let me show you something interesting. Let’s say that you are implementing a simple function which would accept any kind of object as a parameter and do some basic thing like calling .ToString() on this object.


You might think that this is a good way of doing it:


It would work and do the trick but it would also trigger Boxing if you call this function passing in an int or some struct.


Do want to know how to fix this? Let me show you.



And calling these methods would be as follows:



And the memory analysis would be as follows:


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

See, this is actually one of the benefits of using Generics. However, this is not always an easy option…


In our example, it is easy to write the same function using Generics because it is only about one parameter. However, what if it is about unlimited number of parameters which could have different types?


Let’s examine the implementation of String.Format in .NET


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Do you notice the expected parameters? they could be of any count and any type. Therefore, if we try to implement this method using Generics, we would fail.


Therefore, in this kind of cases, we can’t avoid Boxing.


Furthermore, just as a fun fact, when you do something like this:


You are actually doing Boxing because this would eventually use String.Format method.







Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Garbage Collection


In some languages like C and C++, the developer is responsible for cleaning up the allocated objects which is an overhead beside the risk of missing some allocated objects which would cause a memory leak at the end.


In .NET, it is different. The .NET framework takes over the task of allocating objects into the Heap and it manages object allocations on your behalf.


As a .NET developer, all what you need to do is to define your variables and .NET will take care of creating, initializing and placing the object on the right memory.


Furthermore, .NET keeps track of your objects and knows when an object is not needed anymore so that it could be deallocated.


So, now you might ask:


Before answering this question, let me tell you about some important things that you first need to understand before jumping to garbage collection.




Heap Memory Types


As we said before, the Heap memory is divided into two parts; Small Objects Heap (SOH) and Large Objects Heap (LOH).


The Small Object Heap (SOH) holds the allocated objects that are less than 85K in size.


The Large Object Heap (LOH) holds the allocated objects that are greater than 85K in size.


The SOH and LOH are different in the way that the .NET framework manages them. Just keep this in mind and we will get back later to this point.



What Is Garbage?


The word Garbage refers to the objects allocated which are not used anymore and could be totally removed and deallocated by the Common Language Runtime (CLR) from the memory.


Now, you might ask:


The answer is simply by checking if the object is referenced -directly or indirectly- by a root.


I know that you might ask:


A root could be one of the following:

  • Reference in Stack memory.

  • Global object.

  • Static object.


When we say that an object is directly referenced by a root, this means that the object is referenced by one of the root types described above.


On the other hand, when we say that an object is indirectly referenced by a root, this means that the object is referenced by another object in the Heap which is already referenced -directly or indirectly- by a root.


This means that there could be a series of references between objects and unless the first object in the series is directly referenced by a root, the whole series is considered as Garbage.


What the CLR does is that it maintains an updated graph of rooted objects to be used whenever the CLR needs to check if a certain object is rooted or not.


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Therefore, now the CLR has all the information needed to decide if an object is Garbage or not, right?




Performance Measures


Now we know how the CLR decides if a certain object is Garbage or not. However, we need to keep in mind the number of objects allocated into the Heap.


At a certain moment, there could be a huge number of objects already allocated into the Heap. Therefore, if the CLR just checks all these objects every time some memory is needed for a new object to get allocated, this would have a bad impact on the overall performance.


That’s why the CLR needed to follow another approach when analyzing and handling memory allocations.


Genius minds at Microsoft thought of a great idea to tackle this challenge.




Small Objects Heap (SOH) Memory Generations


The genius minds at Microsoft decided to divide the SOH into three parts so that the CLR can only analyze and process one part at a time.


This means that the CLR would be able to deal with fewer number of objects every time instead of dealing with the huge number of objects.


Now, you might ask:


This is a good question. The idea behind the three parts is based on the nature of objects being allocated into the SOH.


Simply, new objects tend to get deallocated faster than older objects which could be referenced by global or static roots.


Based on that concept, the CLR divides the SOH into three parts which we call Generations.


This means that the SOH is divided into:

  • Generation 0: Objects allocated here tend to get deallocated faster than objects in Generation 1 and 2.

  • Generation 1: Objects allocated here tend to get deallocated faster than objects in Generation 2.

  • Generation 2: Objects allocated here tend to stay for longer time.



Now, you might ask:


The answer is simply no.


The sizes of these three generations are decided by the CLR at runtime based on the number of objects that get allocated into each generation.


In other words, the CLR adapts the sizes of these three generations at runtime aiming for the best performance based on the history of objects allocations.




What About Large Objects Heap (LOH)?


The CLR manages objects allocations in the LOH in a different way. It is not divided into parts or generations.


Actually, people call the LOH as Generation 3 just to follow the same naming convention but in the real world, it doesn’t follow the same process as the SOH.


The LOH is not compacted because as we said before the objects allocated into the LOH are large objects and it would take too long to copy these large objects on top of unused ones. This would have a bad impact on the whole performance.


That’s why the LOH tracks all the free and used memory locations and space, and attempts to allocate new objects into the most appropriately-sized free slots left behind by collected objects.


Now you might ask:


The short answer is Fragmentation.


The LOH needs to undergo fragmentation from time to time to collapse the free spaces between allocated objects so that there is more available appropriately-sized slots for new objects to get allocated.




Garbage Collection Triggers


Now we know what Garbage is and how the CLR decides which objects to mark as Garbage.


Now you might ask:


In SOH, and for each one of the three generations, the CLR sets a threshold so that when this threshold is reached, the CLR triggers the collection mechanism for this generation and all the younger ones.


In other words:

  • When threshold of Generation 0 is reached, collection of Generation 0 is triggered.

  • When threshold of Generation 1 is reached, collection of Generation 1 and Generation 0 is triggered.

  • When threshold of Generation 2 is reached, collection of Generation 2, Generation 1, and Generation 0 is triggered.


Now you might ask:


Actually, I need to tell you something now. The LOH is a part of the Generation 2 of the SOH.


Therefore, whenever Generation 2 collection is triggered, LOH collection is triggered. But, you need to keep in mind that the collection process is not that simple and the algorithm is somehow complex to summarize in a few lines.







Garbage Collection Process


As a quick recap, up till now you know the following:

  • We have four generations (Gen 0, Gen 1, Gen 2, and Gen 3)

  • Each generation has a threshold set and adapted by the CLR.

  • When a generation threshold is reached, collection process of this generation is triggered and followed by firing the collection of younger generations.


Now, let’s proceed with more details about the collection process.


When the collection process of a certain generation is fired, the objects allocated into this generation are analyzed and processed as follows:

  1. Rooted objects are spotted and marked using the graph which the CLR has already built. We refer to these objects as Survived objects.

  2. The other objects are now marked as unrooted and ready for collection.

  3. The collection process starts as described before (copying and overwriting for SOH and appropriately-sized replacements for LOH).

  4. Survived objects are promoted to the one level higher generation.


Here is a step by step gif for you to help you visualize the Garbage Collection process.


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Hope it makes it easier for you to understand.




Important Notes About Garbage Collection

  1. When the Garbage Collection process starts, it halts everything else. This is why the excessive triggering of the Garbage Collection process would have a bad impact on the performance of the whole system.

  2. Garbage Collection process could be triggered manually by calling System.GC.Collect() method.




Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Dispose and Finalize


If you have been a .NET developer for a while, most probably you heard about Dispose and Finalize and the design pattern related to implementing them.


However, before jumping into details, I prefer to discuss some important basics related to this topic.


Therefore, let’s take it step by step.




Managed and Unmanaged


In .NET world we have two types of resources and code; managed and unmanaged.


Simply, the managed code is the code that is compiled and maintained by the .NET framework. In this case, the code is compiled into the Microsoft Intermediate Language (MSIL) which is a common language and then run by the .NET framework. This gives the .NET framework the full control over the code, execution, memory allocation, exception checking,….


On the other hand, the unmanaged code is the code that is compiled and maintained outside the boundaries of the .NET framework. In this case, the code is written into another foreign language, compiled into machine language and executed by the operating system directly. This is why the .NET framework has no control over the code, nor the execution, nor the memory allocation,…. Examples of the unmanaged code are file streams, data connections, …

Therefore, if your .NET system deals with some unmanaged code, the .NET framework can’t help you manage the memory allocation done by the unmanaged code. This is not good as the .NET framework needs to know how to deallocate these resources whenever needed.


Therefore, since the .NET framework doesn’t know how to deallocate these resources whenever needed, the .NET framework decided to delegate this responsibility to the developer as he should be the one aware of this.


Now, you might ask:


The simple answer to this question is through implementing a finalizer.


However, to understand what this statement means, proceed to the next section.







Memory Leak


Do you remember when we discussed the Garbage Collection process? Actually, there are some more details which I didn’t mention in order to focus on the GC process itself. But now, this is the right time.


When an object is marked by the CLR as unrooted and ready to be collected, at this point the CLR doesn’t know if this object is using any unmanaged resource or not.


This is a big problem as this means that the object could be using unmanaged resources and if these resources are not deallocated properly there would be a memory leak. By memory leak here we mean that there would be some memory allocations which would live as long as the whole system lives although they are not actually needed.


Furthermore, this memory leak could get bigger and bigger by time whenever the same type of object is created and collected without proper deallocation of contained unmanaged resources.


Now, you might ask:


There is an agreement between the developer and the .NET framework that both sides should commit to.


This agreement is simply that whenever the developer implements a Finalizer to an object, the CLR should mark this object as using unmanaged resources.


Now, the next question is:


Again, to answer this question, let’s proceed to the next sections.




Finalization Process


Now you might want to know how to implement a Finalizer. What I am going to ask you now is to wait a little bit and I will show you this shortly.


For now, let’s assume that you know how to implement a Finalizer and you already implemented it for some of your system objects.


Now, back to the Garbage Collection process. When an object is allocated into the Heap, the CLR checks if this object implements a Finalizer or not.


If not, nothing special happens as we explained in the previous sections.


However, if the object implements a Finalizer, the CLR would add a reference to this object in a special data structure maintained by the CLR. This data structure is known as the Finalize Queue.


Then, when an object is ready for collection, the CLR checks if this object is referenced into the Finalize Queue or not.


If not, nothing special happens as we explained in the previous sections.


However, if the object is referenced into the Finalize Queue, the CLR removes this reference from the Finalize Queue and creates a new reference to the same object into another special data structure maintained by the CLR. This data structure is known as the Freachable Queue.


Till this point, the object is not collected yet as the CLR knows that a Finalizer on this object should be called before the collection of this object.


The Freachable Queue is maintained by a separate run-time thread. If the queue is empty, the thread sleeps till a new entry is added to the queue and then the thread starts calling the Finalizer of all the objects into the Freachable Queue.


This is why it is always recommended to never try to depend on the time the Finalizer would be called as it is -by design- an undetermined process.


Once the Finalizer is called, the reference to the object in the Freachable Queue is removed, but still, the object is not collected yet.


Then, when the Garbage Collection process is triggered again, the CLR is now sure that the object is ready for collection as it is neither rooted, nor referenced by the Finalize Queue, nor referenced by the Freachable Queue.


That’s why it is known that when an object implements a Finalizer, it lives longer for one more Garbage collection cycle.


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)


Finalizer Implementation


In .NET C#, we can implement the Finalizer by defining a Destructor as follows:



Or by overriding the Finalize method as follows:



However, is this the best practice to follow?


No, there is a design pattern to follow when implementing a Finalizer.




Dispose and Finalize Design Pattern


Before diving into the details of the design pattern, let me tell you more about the Dispose and Finalize methods.


Mainly both of them are responsible for clearing the unmanaged resources. The main difference is that the Dispose method is called explicitly by the developer while the Finalize method is called by the CLR in an un-deterministic way as we explained in the previous sections.


There are other differences between them but these are the most important ones for now.


Now, let’s check the implementation of the Dispose and Finalize Design Pattern.


Let’s say I have the following MyClass class:



As you can see, inside our class we are creating an instance of the System.Timers.Timer class which is already implementing IDisposable interface. This is an indicator that we need to call the Dispose method of this timer before disposing our MyClass object.


Therefore, following the Dispose and Finalize Design Pattern as recommended by Microsoft:



What we can notice here:

  • We defined the private field m_IsDisposed to be used to check if the object has already been disposed before.

  • We defined protected virtual void Dispose(bool disposing) to centralize the cleanup logic.

  • If the passed in parameter is true, this means that it is being called by the Dispose method. In this case, everything is cleaned up.

  • If not, this means that it is being called by the Finalize method. In this case, only the unmanaged resources are cleaned up.

  • Keep in mind that it is a best practice to check if the managed resource is not already null before calling its Dispose method.

  • On the public void Dispose() method, we call GC.SuppressFinalize(this); to tell the CLR to skip calling the Finalize method for this object as we are already going to take care of the unmanaged resources while disposing.


Now, let’s say that we have MyChildClass class inheriting from MyClass as follows:



Now, we need to implement the Dispose and Finalize Design Pattern as follows:



What we should notice here:

  • We didn’t implement the public void Dispose() method again.

  • We overridden the protected virtual void Dispose(bool disposing) method.

  • We called base.Dispose(disposing); at the end of the protected override void Dispose(bool disposing) method.


Worth to mention here, implementing Finalizers is not something that you should always do. As we said before, when the CLR recognizes that an object implements a Finalizer, this would extend the life of the object to one more Garbage Collection cycle.


Therefore, only implement a Finalizer when your object is using an unmanaged resource.


Bonus: Read about System.Runtime.InteropServices.SafeHandle and how to use it instead of Finalizers.


Memory Management In .NET. All about memory management in DotNet (.NET) and important related topics. Stack Heap Variables String Boxing Unboxing Garbage Collection Performance Small Objects Heap (SOH) Memory Generations Large Objects Heap (LOH) Dispose Finalize Managed Unmanaged Leak Finalization Finalizer Design Pattern Code Coding Programming Software Development Architecture Engineering Best Practice Basics CSharp (C#)

Final Thoughts


In this article we have covered memory allocation in .NET framework and some of the important topics related to it.


I encourage you to do your own research and read more about this topic. as you can see, there are a lot of details and that’s why it is not easy to cover all of them in one article.


Also, I had published an article before about Recursion and its impact on memory. May be you would like to check it. If you are interested, you can read the article Curse of Recursion in .NET C#.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[How String In .NET C# Works]]>https://www.developmentsimplyput.com/post/how-string-in-net-c-works658aec0b0c31914d9352cb8cTue, 15 Feb 2022 23:00:00 GMTAhmed TarekAll about String and its immutability in .NET C#


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice

Some developers get confused about String in .NET. The confusion comes from the fact that String is an Object -which is a Reference type- but still acts as a Value type.


Another thing, all developers know that String is an immutable type but some developers don’t understand how and why.


Therefore, in this article we are going to discuss how String works in .NET C# trying to cover all the basic knowledge we need to have about this topic.




All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice

Memory Allocation


To understand how String works in .NET C#, we need to understand how memory is allocated while creating and manipulating a String.


Therefore, let’s work through some simple examples step by step to see what actually happens in the background in terms of memory allocation.




Changing Value After Initialization




At line 1, we defined a variable called s0 and set its value to “Ahmed”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


At line 2, we changed the value of s0 to “Tarek”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


Since String is immutable, what actually happens is that a new memory location in the Heap memory is created and filled with “Tarek”. Then, the address of s0 is updated to the new memory location.

Therefore, at line 3, the result would be as follows:




Initializing Multiple Variables With Same Value



At line 1, we defined a variable called s1 and set its value to “Ahmed”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


At line 2, we defined a variable called s2 and set its value to “Ahmed”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


Since String is immutable, what actually happens here is that the Heap acts as if it is a dictionary where the value of the String is the key.


So, whenever a new String is to be created and allocated into the Heap, if the same String value already exists, no new allocation happens and the same existing memory allocation is used.


Therefore, in our case, the address of s2 is updated to the same address of s1.


Therefore, at line 3 and 4, the result would be as follows:







Initializing Variable Using “new String()”



At line 1, we defined a variable called s3 and set its value to “Ahmed”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


From line 3 to 12, we defined a variable called s4, initialized it with new String() passing in an array of characters corresponding to “Ahmed”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice



Since we used the new String() to create a new instance of String, a unique action happens now. Let me explain.


When we use a string value directly to initialize a variable (like var s3 = “Ahmed”), the allocation happens on a special pool in the Heap memory. Any allocation happens on this special pool is shared between all String variables which are initialized directly as well.


However, whenever new String() is used, a memory location is allocated but outside this special pool.


Therefore, from line 14 to 23, we defined a variable called s5, initialized it with new String() passing in an array of characters corresponding to “Ahmed”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


See, another new memory allocation is set for the variable s5.


Therefore, at line 25, 26, and 27, the result would be as follows:


For line 25, the result is True because they all have the same value.


For line 26, the result is False because they are not sharing the same memory allocation and they are actually two different references.


The same for line 27, the result is False because they are not sharing the same memory allocation and they are actually two different references.




Implicit Setting Variable By Reference



At line 1, we defined a variable called s6 and set its value to “Ahmed”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


At line 2, we defined a variable called s7 and set its reference implicitly to s6.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


What happened here is that the address of s6 is copied to s7. Therefore, they are both referring to the same Heap memory allocation.


At line 3, we set the value of the variable s6 to “Tarek”.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


As we explained before, what actually happens here is that a new memory location in the Heap memory is created and filled with “Tarek”. Then, the address of s6 is updated to the new memory location.


However, s7 would not be updated. This means that it would still refer to the memory location where “Ahmed” is saved.


Therefore, at lines 4 and 5, the result would be as follows:


For line 4, the result is Tarek because now s6 is referring to the memory location where “Tarek” is saved.


For line 5, the result is Ahmed because now s7 is still referring to the memory location where “Ahmed” is saved.







Explicit Setting Variable By Reference



What would happen here is similar to what happened on the Implicit Setting Variable By Reference case.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice


And at lines 6 and 7, the result would be as follows:




All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice

Advantages of String Being Immutable


Now, you might ask:


The answer is somehow logical. Let me explain.




Thread Safety


Since the String is immutable, on the memory allocation level, we are sure that its value would not be changed at all.


Therefore, we don’t expect any racing problems to happen as even if more than one thread is accessing a String variable, its value would always be the same.




Consistency


If we have the following:


Then we decide to change the value of s1 as follows:


What would actually happen is that only the value of s1 would be changed to “Tarek”. However, the values of s2 and s3 would still be “Ahmed”.




Memory Optimization


Again, if we have the following:


In this case, only one memory location would be allocated in the Heap memory and its value would be set to “Ahmed”.


So, following the same pattern, imagine that we have like hundreds or even thousands of instances of a certain string, the performance would not be affected as String is memory optimized by default.




Easy Copying


Since the String is immutable, we can simply return this when we need a copy. Why? simply because it acts as a value type as its value would never change.







All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice

Important Note


As we said before, running some code like this:



Would create 5000 memory allocations in the Heap memory which is not good at all.


Here is the memory allocation for this code:


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice

Therefore, for such cases when you find yourself creating too many memory allocations for your String variables, you need to use StringBuilder.


Therefore, we can update the code above this way:



This way, you would get the same output result but with optimized memory allocation.


All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice

See, the difference is huge.




All about String in DotNet (.NET) CSharp (C#). Immutable StringBuilder Memory Performance Optimization Optimisation thread Safe Copy Clone Stack Heap Code Coding Programming Software Design Development Engineering Architecture Best Practice

Final Thoughts


Now you should understand the commons basics about String in .NET framework.


Furthermore, there is an interesting article about String.GetHashCode which you might like to read. The article is When String.GetHashCode() in .NET C# Drives You Crazy.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[DateTime Best Practices In .NET C#]]>https://www.developmentsimplyput.com/post/datetime-best-practices-in-net-c658ae6997580fe08af6ff780Sat, 12 Feb 2022 23:00:00 GMTAhmed TarekBest practices to follow when using DateTime in .NET C#


Best practices to follow when using DateTime and DateTimeOffset in DotNet (.NET) CSharp (C#) Static Abstracted Unit Test Testing Cover Coverage TDD Dependency Injection (DI) Inversion Of Control (IOC) Code Coding Programming Software Development Engineering Architecture

Introduction


In almost all the software systems we are working on we need to use DateTime to represent a timestamp for some actions.


However, what I noticed is that sometimes we do some mistakes which could be fatal in some occasions.


Therefore, I decided to write this article to share with you some of the best practices to follow when dealing with DateTime in .NET C#




Best practices to follow when using DateTime and DateTimeOffset in DotNet (.NET) CSharp (C#) Static Abstracted Unit Test Testing Cover Coverage TDD Dependency Injection (DI) Inversion Of Control (IOC) Code Coding Programming Software Development Engineering Architecture

Agenda


In this article we are going to cover the following topics:

  1. DateTime vs DateTimeOffset.

  2. Note when value initialized.

  3. Unify the source.

  4. Static vs Abstracted.


Now, you can buckle up and enjoy the trip.




DateTime vs DateTimeOffset


I am sure that all .NET developers know about DateTime, however, not all of them know about DateTimeOffset. There is a significant difference between both of them.


There is a great article published by Steve Smith about this topic and I encourage you to read it.


As a quick summary, let’s check the notes below.



DateTime


When using DateTime, the current system date is saved and encapsulated inside the variable but without saving or linking to the time zone.


Therefore, this would eventually cause problems if more than one machine with different time zones are used.



DateTimeOffset


On the contrary, DateTimeOffset links the current value to the time zone by saving an offset to the UTC date time.


This way the value saved could be unified as it is saved in a format which could then be transformed to different time zones without messing with the value itself.



Conclusion


I would always recommend using DateTimeOffset whenever you can and the great thing is that it is fully supported by famous modules and frameworks even MS SQL.







Note When Value Initialized


What I noticed is that sometimes developers get sloppy with when to initialize the DateTime or DateTimeOffset value especially when this value would be used in more than one place with a business need to keep using the same value in all places. Let me emphasize more.


Let’s study this small piece of code.



What we are doing here is that we want to call the two methods DoSomething1 and DoSomething2 passing in the same date time stamp which is corresponding to Now.


So, in the code sample, we are doing it in two ways to show the differences. We are doing it on BadTiming and GoodTiming methods.




Bad Timing



Here, when calling the DoSomething1 method we are passing in DateTimeOffset.Now and we are doing the same when calling the DoSomething2 method.


What we should expect now is that the DateTimeOffset values that are being passed to the methods are different as they are captured at different time stamps.




Good Timing



Here, when calling both DoSomething1 and DoSomething2 methods we are passing in the same pre-captured DateTimeOffset value which is already saved in the now variable.


Therefore, it is now obvious that the DateTimeOffset values that are being passed to the methods are identical as they are captured at the same exact time stamp.




Running the Code


When we run the whole code, we will end up with this output.


You notice the difference? when running the BadTiming method, the time stamp is different between the two methods. On the other hand, when running the GoodTiming method, the time stamp is similar between the two methods.







Unify the Source


When working on a software system, whenever you are capturing the DateTime or the DateTimeOffset value, try to unify the machine where these values are captured.


I noticed that some developers mix between the ways they are capturing these values, sometimes from a browser (client side), sometimes from a server, sometimes from a certain machine,… and so on.


The problem with this approach is that if there is a slight difference between the clocks on these different sources, there could be inconsistency in the data. Additionally, imagine if the difference is big, not just a slight one.


Not applying this best practice could cause you fatal problems with your application and the data saved. You could end up with a disaster if the corrupted data is sensitive like money transfer transactions in a banking system.




Static vs Abstracted


One of the bad practices I always come through is encapsulating the usage of DateTime or DateTimeOffset inside the logic without providing any abstractions. Let me explain.


Let’s assume that we are having a dummy console application where we define a Logger class. This class should define only one Log method which accepts a string message and it returns the same message but prefixed with a date time stamp.




The Static Way


One way to go with this is like this:



So, now running the application, you should get this result:


Best practices to follow when using DateTime and DateTimeOffset in DotNet (.NET) CSharp (C#) Static Abstracted Unit Test Testing Cover Coverage TDD Dependency Injection (DI) Inversion Of Control (IOC) Code Coding Programming Software Development Engineering Architecture

Simple, right?


If you are only concerned with the runtime result, then it is ok. However, if you are also concerned with your code quality and testability, this would not be that good. Let me emphasize.


Let’s say that we want to cover our Logger class with unit tests. This is what we can do:



As you can see, the best you can do here is to ignore the date time stamp part of the message and only assert that the real message is a part of the actual resulting message.


This means that if someone applies a change on the Logger class, as long as the real message is still a part of the final message, the same test would still pass.


Furthermore, the test is actually not paying any attention to the usage of the DateTimeOffset class. Therefore, a part of the business logic is totally ignored and not covered by tests.







The Abstracted Way


However, the other way to go with this is like this:



What we are doing here is that we abstracted DateTimeOffset.Now into the interface IDateTimeProvider and defined the default implementation SystemDateTimeProvider as a thin wrapper of DateTimeOffset.Now.


Now, our Logger class defines the IDateTimeProvider as a dependency which we can Mock or Stub while testing.


Therefore, as we mentioned testing, this is what we can end up with:



See, now we can fully cover the business logic with unit tests without ignoring any business rules.




Best practices to follow when using DateTime and DateTimeOffset in DotNet (.NET) CSharp (C#) Static Abstracted Unit Test Testing Cover Coverage TDD Dependency Injection (DI) Inversion Of Control (IOC) Code Coding Programming Software Development Engineering Architecture

Final Thoughts


In this article I shared with you some best practices to follow while using DateTime and DateTimeOffset in .NET C#.


Is it the end of it? No, I encourage you to do your own research and evaluation as this would help you understand more.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Prototype Design Pattern In .NET C#]]>https://www.developmentsimplyput.com/post/prototype-design-pattern-in-net-c658adeaffa839e814afd81d3Sun, 06 Feb 2022 23:00:00 GMTAhmed TarekLearn about the Prototype Design Pattern in .NET C#


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Prototype in English


In this article we will discuss the Prototype Design Pattern in .NET C#

However, let’s first explore the meaning of the word Prototype in English.


▶ According to dictionary.cambridge.org:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

▶ According to merriam-webster.com:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

As you can see, prototyping is mainly about creating a copy of something to be then extended.







Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Prototype Design Pattern Definition


The Prototype Design Pattern is one of the creational design patterns. It is mainly concerned about creating a new object by copying an already existing one without missing any of its encapsulated internal details and at the same time without depending on the class structure.


Wow, a big definition, right? Let me simplify it for you.


When you use any diagram builder software tools, you always look for the feature of copying one of the diagram shapes you had already added.


Using this feature, you expect the following:

  1. You can duplicate a diagram shape.

  2. Then apply minor changes like changing the color without having to configure all the shape properties from scratch.

  3. The color of the main shape you copied from should not be affected by the new color you set to the duplicate shape.


All what you expected is actually what the Prototype Design Pattern is about. The diagram shape you are copying or duplicating is actually an object created from a class defined in the software code.


Now, to enable the feature you are looking for and to make it work as you expected, this what should happen:

  1. The software should be able to copy the source diagram shape object.

  2. The new copy object should be identical to the source object, yet a totally separate object which is totally disconnected from the source object.

  3. Changing a property or a setting on the copy object should not have any effect on the source object.


Is it that all? Actually no.


As you know, in the software world having something working is not enough. We should always pay attention to other factors like readability, maintainability, extensibility,… and some other goals. One of these goals is to make sure our code is loosely coupled and the least dependent on other modules or classes.


Therefore, one of the goals the Prototype Design Pattern is concerned about is to make sure we can achieve copying an object without actually depending on its class definition.


Now, you might ask:

You are partially right. Your module knows what the object class exposes to the outer world, but this is not all.


The class which defines this object could have other private, or internal, or protected members which your module is totally not aware of.


Based on this fact, we can conclude that your module can’t actually handle the copying task itself as it doesn’t have all the info required. What should actually happen here is to delegate the copying task to the object class itself as it is fully aware of its internals.


Not convinced? let me show you.




Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Hidden Fields Example


Let’s assume that we have a Person class defined as follows:



As you can notice, all members are public except for the private separator field which would be used to evaluate the FullName property.


Now, let’s say that at some module we would have an instance object of the Person class and we want to copy it as follows:



As you can see, on line 4 where we are trying to copy the object, we don’t know what to pass for the separator as we don’t have access to the one already set for the original ahmedTarek object.


This means that we can’t handle this copying task in our module.







Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Nested Objects Example


Let’s assume that we have a Node class defined as follows:



Now let’s create a series of nested nodes as follows:



Running this should end up with the following result:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Now we want to create a copy of node1. Someone might think that the right way to do it is as follows:



But actually running this would end up with this:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

This is wrong as the new copy of Node 1 is referring to Node 2, not a copy of Node 2, and so on…


To fix this, we need to follow a more complex approach. We need to create a copy of each node and make everyone referring to the next copy.


Following this, we should do something like this:



And running this we would get the following result:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Now, it is working fine but we can notice that the code tends to be complex.







Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Prototype Design Pattern Comes to the Rescue


As we now understand, copying an object on a separate module could be either impossible due to the existence of hidden members or possible but complex. The Prototype Design Pattern offers the solution.


In .NET C#, there is already an implementation of the pattern represented into the ICloneable interface. If we extend our classes by implementing this interface, we would have a public object Clone() method to implement.


However this approach already exists and supported by the .NET framework itself, I have some concerns about it. But, let me walk you through using this approach first and then we can discuss my concerns.




Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Using ICloneable


In this section we are going to use ICloneable with the Hidden Fields and the Nested Objects examples to see if it is actually going to work or not.



Using ICloneable With Hidden Fields Example


Let’s get back to our Person class example. However, this time, it would implement ICloneable as follows:



See, now on line 18 we are creating a new instance of the Person class and we have access to all the private fields. It is easy.


Now, using this would be easy as follows:



And running this would end up with this result:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

See, it is working as charm.




Using ICloneable With Nested Objects Example


Let’s get back to our Node class example. However, this time, it would implement ICloneable as follows:



See, now on line 28 we are creating a new instance of the Node class and we are using the Clone method of the Next node to copy it as well. It is easy.


Note: A problem here is that the way we are naming the copy of each node is hardcoded and encapsulated inside the Node class itself. This is something that we would fix later, so stay tuned.


Now, using this would be easy as follows:



And running this would end up with this result:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

See, it is working as charm.







Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

My Concerns About ICloneable


Although using ICloneable seems to work, I believe that it has some serious problems.



Immutable Copy


ICloneable provides us with a public object Clone() method which we can use for copying an object. But, what if the object is immutable? in other words, what if even the public properties of the object can not be set after the object is created?


In this case, the object we got back from calling the Clone method could not be manipulated by any means which is useless in most of the cases. Let’s think about it.


When we are trying to copy an object, most probably we are doing this because we need to have an exact copy of an existing object and then follow it with some updates to the copy, right? Now, if I tell you that the copy you got can not be updated, in this case, it is worthless.


The only case where using ICloneable would be useful if you just need an exact copy without following it with any updates.



Returning Object


As you noticed, ICloneable provides us with a public object Clone() method which returns object, not Person or Node. That’s why we needed to cast the returned object from the Clone method to Person or Node.


It is not a big deal actually if you are doing it for few times but it would be a problem if you are doing this too many times too frequently. This would impact the overall performance.




Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

The Other Way


First, let me highlight that I believe copying an object most probably should be a class-specific task. This is because every class would define its own members and also define which of these members is immutable and which is not.


Having that said, let’s now show you another ways of handling copying objects.




Better Solution For Hidden Fields Example


Back to our Person class:



Notice that FirstName and LastName are both immutable.


Let’s say that the Person class would allow itself to be copied. In this case the Person class should define a Clone method that would return a copy of the current Person object. However, just returning an immutable object might be useless to the caller module as it needs to apply some updates on the copied object.


To allow this, we can do something like this:



See what we did here? we added a Clone method where the caller has an opportunity to override any of the properties. Then, the returned object would still be immutable.


Additionally, the Clone method now returns a Person, not an Object.


Furthermore, we added a simpler parameter-less Clone method which would return an exact copy without any overrides.


Now, using this would be as follows:



And running this would end up with this:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Tremendous, working like charm.







Better Solution For Nested Objects Example


Back to our Node class:



So, following the same concept as before, we can do something like this:



So, as you can notice here, the caller of the Clone method would have more than one option; either to override or not.


Additionally, now the logic of setting the name of the copied Node is delegated to the caller, not the Node class itself.


Now, running this would end up with this:


Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Great, right?




Prototype Design Pattern. Learn the Prototype Design Pattern in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Clone Copy Deep Reference Immutable Override Extend

Final Thoughts


In this article we discussed the Prototype Design Pattern in .NET C#. We showed some examples and analyzed them.


What I want to mention here is that one of the common usages of the Prototype Design Pattern is in the Builder Design Pattern itself. If you want to know more about this, you can read my article Builder Design Pattern in .NET C#.


Someone might argue that following the enhanced implementation provided into this article is not providing any abstracted layer which different system modules can depend on. However, my reply would be that we can still abstract the different Clone methods we provided. I didn’t do it here to avoid distractions but for sure it could be done.


Now you understand what the Prototype Design Pattern is about. However, this is not the end of the story.


You would need to search the internet for more articles and tutorials about the Prototype Design Pattern and its usages. This would help you understand it more.


Finally, I hope you found reading this article as interesting as I found writing it.



]]>
<![CDATA[Curse of Recursion in .NET C#]]>https://www.developmentsimplyput.com/post/curse-of-recursion-in-net-c658ad88f088af537a86e4c37Tue, 01 Feb 2022 23:00:00 GMTAhmed TarekWhy and How you should always try to replace Recursion with something else in .NET C#


Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

One of the famous mistakes I come across from time to time while performing code reviews is the excessive uncalled-for usages of Recursion.


I can hear someone asking now:


My answer is:


The main concern about using recursion is that it is too expensive in terms of memory consumption. That’s why you need to be cautious about using it.


You don’t believe me, right? Let me show you an example.




Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

The Nodes Series Example


Let’s assume that we have a series of nodes where each Node refers to the node next to it. Our main goal is to traverse this series of nodes.


So, first we define our Node class as follows:



Then now it is time to implement a method to traverse the tree as follows:



In this method, we are using recursion in such a way that each Node is responsible for traversing the rest of the series starting from it.


Great right? Ok, it would work but let me show you something.


Let’s try to do the same job but now with using loops instead of recursion. So, following this way of thinking, we should end up with something like this:








As you can see, in this method we are using loops to traverse the nodes.


Now, let’s start calling these methods and see if they are going to produce the same result or not.



Here we are just creating a series of 5000 nodes and then calling the two methods; TraverseTreeUsingRecursion and TraverseTreeUsingLoops.


Running the application, we should get something like this:


Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

As you can see, both methods are returning the same result, a list of 5000 node names.


However, can we say that both methods are exactly the same in terms of performance and memory consumption? Let me show you something interesting.


I ran a memory analysis between both methods and the results were as follows:


Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop
Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

Can you notice the huge difference between the memory allocation in both cases? Yes, this is true; Recursion is too expensive.


However, to be totally honest with you, on this example, even with Recursion, we can apply some modifications to enhance the performance and memory allocation to match the loop implementation.


Now I hear you asking:


Let me show you something interesting. Let’s examine how Recursion works.


Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop


This is a simply Recursive function. As you can see, we have some code before the recursion call, the recursion call, and finally the code after the recursion call.


Now, when calling this function, this is what happens in terms of memory allocation.


Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

As you can see, the memory allocation increases while moving through the recursive calls and memory deallocation doesn’t start till the last/deepest recursive call is being resolved.

Additionally, worth to notice here is that the {code before the recursion call} has the biggest contribution in the memory allocation. Therefore, the biggest memory allocation this code needs, the most expensive the whole recursion call would be.


From this we can conclude that if we can minimize the memory allocation needed for the {code before the recursion call}, this would significantly decrease the total memory allocation of the whole recursive method.


Now, back to our example. Trying to minimize the memory allocation of the {code before the recursion call}, we can do the following:



See, instead of creating a new List<string> on each recursion call, we just pass in a reference to a list. Therefore, the same list is used on all levels so no memory allocation is needed on each recursion call.


Now, calling TraverseTreeUsingRecursion should be as follows:



And the memory analysis would be as follows:


Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

See, it is totally different.


Worth to mention here that it is not always easy to achieve the same methodology of enhancement on Recursion methods. Sometimes the call is too complicated. In this case, we have other ways to deal with it.




Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

Findings


As I told you, I used to come across some excessive uncalled-for usages of Recursion while performing code reviews. This has been happening for a while.


So, I decided to study this manner trying to understand what goes in the developer’s mind at that point. Therefore, I decided to stop and ask the developer each time I come across such case.


Most of the answers were about that he didn’t think much about it. Using recursion then was the logical option to him that he didn’t even stop and think about it.


Therefore, it is obvious that sometimes Recursion seems to be more natural and resembling the way our mind works. Simply, when you find yourself repeating some logic in your mind, your brain instantaneously scream Recursion.


So, if you ask me, I will advise you to fight the urge of using Recursion and always try to find an alternative.




Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

Is It Always Possible?


Now, the question that might pop up in your head is:


Not exactly. Sometimes recursion might be the only way of doing it but believe me, in many cases there would be an alternative that you might be missing because you are more focused on the small picture.


What I usually do is that when I find myself trying to use Recursion, I try to visit some concepts and see if they could be alternatives.


Concepts like:

  • Using Loops?

  • Using Stacks and Queues?

  • Using Caching Maps (as in Dynamic Programming)?

  • Using Loops in Bottom Up manner (as in Dynamic Programming)?


If any or some of these help me achieve the same results, I usually do some performance and memory analysis to compare them to Recursion and eventually use the best between them.

In the next section, I will show you one of my favorite ways of replacing Recursion which is Using Loops in Bottom Up manner.







Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

Using Loops in Bottom Up Manner


This concept is originating from Dynamic Programming concepts. Explaining Dynamic Programming is out of scope of this article. So, if you need to know more about it, you can search the internet and you would find tons of resources.


Let me introduce you to the Fibonacci series.


According to Wikipedia:


In other simple words:

  • Fn = Fn-1 + Fn-2

  • F0 = 0

  • F1 = 1


As you can see, the Fibonacci series, by definition, is based on Recursion. Therefore, it is so easy for our mind to formulate it as follows:



Would it work, yes for sure. However, as we proved before, it would be too expensive in terms of memory.


Furthermore, if we try to call FibonacciUsingRecursion passing in 80 as an input, the compiler would not get back at all. Why?


If you try to visualize the series as it is defined, you would end up with this:


Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

Do you see it? do you notice that we have duplicate recursion trees which would be evaluated more than once. The fib(3) subtree would be evaluated 2 times. the fib(2) subtree would be evaluated 3 times, and so on…


Can you now imagine the number of duplicate subtrees for a fib(80) tree? It would be enormous.


Now, you might ask:


One of the ways of dealing with this is to think about the series definition in a different way.


Let’s analyze this:

  1. fib(5) = fib(4) + fib(3)

  2. fib(4) = fib(3) + fib(2)

  3. fib(3) = fib(2) + fib(1)

  4. fib(2) = fib(1) + fib(0) = 1 + 0 = 1


Do you notice that to get fib(5) we need to have fib(2) up to fib(4)? Then why don’t we do it this way?


We first start with fib(2) and keep going up till we reach fib(5). Actually, we can do it as follows:

  1. fib(2) = 1 + 0 = 1

  2. fib(3) = fib(2) + fib(1)

  3. fib(4) = fib(3) + fib(2)

  4. fib(5) = fib(4) + fib(3)


This means that we only need to start with two values; fib(0) = 0 and fib(1) = 1 and then we keep going up by adding the previous two and shift the two values.


So, following this, you can do something like this:



Now, if you run this, you would get the same result as the recursive solution but with much better performance and memory allocation.


Additionally, if we try to call FibonacciUsingLoops passing in 80 as an input, the compiler would be back with the result in no time.


Therefore, what we can learn from this is that replacing Recursion could make the impossible possible.




Why and How you should always try to replace Recursion with something else in DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practice Dynamic Programming Stack Memory Performance Bottom Up Loop

Final Thoughts


As you can see, Recursion is too expensive and sometimes it makes it impossible to execute some logic without hitting a barrier.


Therefore, you should always consider other alternatives before using Recursion.


Finally, I hope you enjoyed reading this article as I enjoyed writing it.



]]>
<![CDATA[Passing Parameters to a .NET C# Method]]>https://www.developmentsimplyput.com/post/passing-parameters-to-a-net-c-method658ad0f317f25f887569864dSun, 30 Jan 2022 23:00:00 GMTAhmed TarekDifferent ways of passing parameters to a .NET C# method.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

This article is mainly about defining the ways of passing a parameter to a .NET C# method while calling it. In simple words, it is about the famous Ref and Val thing.


I know, I know. You might say:


The short answer to your question is: Yes. I know that it seems to be too basic as you said but I have my reasons.


In software, there are a lot of basic knowledge to go through and unfortunately, in the era of fancy frameworks and libraries, young developers tend to skip these basics and jump into learning these fancy frameworks.


Some of them might know about the basic rule, but they don’t know the story or the science behind it. Does it really matter? Yes, most of the times it matters.


Additionally, there is a kind of things that you need to thoroughly observe at least once, then you can live your life knowing that you did it. This topic is one of these.




Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

Key Factors


There are two factors we need to keep in mind when trying to understand how a parameter is sent to a .NET C# method.


These factors are:

  1. Parameter Type

  2. Way of Passing Parameter


Therefore, it is now obvious that we would have 4 combinations:

  1. Value By Value

  2. Value By Reference

  3. Reference By Value

  4. Reference By Reference







Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

How different types stored in memory?


As we said we have 2 types of parameters; Value and Reference. What you need to know is that these two types are not saved in memory in the same way.


In short, we have two types of memory:

▶ Stack

▶ Heap


Note: Explaining every tiny detail of the Stack and Heap is out of scope of this article. That’s why we would just summarize and focus on the small part we need for the main scope of this article.




The Stack


The Stack is where Value types are stored. Additionally, the addresses (Heap memory location) of Reference types (stored in the Heap) are stored in the Stack.


So, if we have:


This would be stored in the Stack as follows.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development




The Heap


The Heap is where the Reference types are stored.


So if we have:


This would be stored in the Stack as follows.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

What does it mean passing a parameter by Value or Reference?


There is a golden rule here to keep in mind. It is simple and effective.



By Value


Means that at runtime, a copy of the original parameter -which is being passed to the method- would be passed to the method.



By Reference


Means that at runtime, the original parameter -which is being passed to the method- would be passed to the method.



Does it make any difference? For sure and that’s what we are going to discuss on the next sections of this article.


Having that said, let’s now analyze the different ways of passing parameters to a .NET C# method.







Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

Value By Value


Let’s say that we have:



As you can see, the ValByVal method:

▶ Is expecting an int as an input parameter which is a Value type

▶ The parameter is expected to be sent by Value (there is no ref before the parameter type)


Therefore, it is guaranteed that the ValByVal method is a candidate for the Value By Value way.


So, back to the code, just after executing line 5, we would have this in the memory.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development


On line 7, when calling the ValByVal method, a copy of the variable x would be implicitly created and passed to the method. Let’s call this copy x’.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development


Therefore, on line 15 where we are incrementing the passed in parameter, we are actually incrementing x’, not x.


This would leave us with this:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development


This means that when we are back to the Main method on line 8, the value of the x would still be 1.


And the result on the console would be as follows:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development







Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

Value By Reference


Let’s say that we have:



As you can see, the ValByRef method:

▶ Is expecting an int as an input parameter which is a Value type

▶ The parameter is expected to be sent by Reference (there is a ref before the parameter type)


Therefore, it is guaranteed that the ValByRef method is a candidate for the Value By Reference way.


So, back to the code, just after executing line 5, we would have this in the memory.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development


On line 7, when calling the ValByRef method, the original variable x would be passed to the method.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development


Therefore, on line 15 where we are incrementing the passed in parameter, we are actually incrementing x.


This would leave us with this:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development


This means that when we are back to the Main method on line 8, the value of the x would be 2.


And the result on the console would be as follows:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development







Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

Reference By Value


Let’s say that we have:



As you can see, the RefByVal method:

▶ Is expecting an Employee as an input parameter which is a Reference type

▶ The parameter is expected to be sent by Value (there is no ref before the parameter type)


Therefore, it is guaranteed that the RefByVal method is a candidate for the Reference By Value way.


So, back to the code, just after executing line 10, we would have this in the memory.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

On line 15, when calling the RefByVal method, a copy of the variable x would be implicitly created and passed to the method. Let’s call this copy x’.


However, what worth to mention here is that what is actually copied, is the value of x stored in the Stack. This value is the address of the memory location in the Heap where the actual Employee object is stored.


Thus, we would end up with this:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

As you can see, x’ would hold the same address of the memory location in the Heap where the actual Employee X is stored. This means that x’ would also refer to the same exact object.


Therefore, on line 25 where we are updating the name of the employee to “Tarek”, we are actually updating the same object Employee ahmed which was originally passed to the RefByVal method.


Thus, this leads to this:


Then, on line 26 we are setting x’ itself to another new Employee. This means that a new Employee object would be created, stored in the Heap, and the address of that Heap memory location would be stored in x’ in the Stack.


Thus, this would leave us with this:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

This means that when we are back to the Main method on line 17, the value of the name of the Employee ahmed would be Tarek.


And the result on the console would be as follows:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development







Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

Reference By Reference


Let’s say that we have:



As you can see, the RefByRef method:

▶ Is expecting an Employee as an input parameter which is a Reference type

▶ The parameter is expected to be sent by Reference (there is a ref before the parameter type)


Therefore, it is guaranteed that the RefByRef method is a candidate for the Reference By Reference way.


So, back to the code, just after executing line 10, we would have this in the memory.


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

On line 15, when calling the RefByRef method, the original variable x would be passed to the method.


Thus, we would end up with this:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

Therefore, on line 25 where we are updating the name of the employee to “Tarek”, we are actually updating the same object Employee ahmed which was originally passed to the RefByRef method.


Thus, this leads to this:


Then, on line 26 we are setting x’ itself to another new Employee. This means that a new Employee object would be created, stored in the Heap, and the address of that Heap memory location would be stored in x’ in the Stack.


But, x’ is actually x. This means that the address of x as well would be updated to the new address.


Thus, this would leave us with this:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

This means that when we are back to the Main method on line 17, the value of the name of the Employee ahmed would be Hasan.


And the result on the console would be as follows:


Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development




Different ways of passing parameters to a DotNet (.NET) CSharp (C#) method. Value Reference Stack Heap Memory Code Coding Programming Software Basics Best Practice Architecture Engineering Development

Final Thoughts


I hope by now the story behind what is happening when calling a .NET C# method while passing in parameters is clear.


If you know someone who is starting his journey as a .NET C# developer, may be you can share with him this article. It would help him visualize what is actually happening.



]]>
<![CDATA[Protecting Public Methods From Illogical Calls In .NET C#]]>https://www.developmentsimplyput.com/post/protecting-public-methods-from-illogical-calls-in-net-c658acaf06a5ccedd14f550d8Wed, 26 Jan 2022 23:00:00 GMTAhmed TarekA full guide with code samples and explanation.


Protecting Public Methods From Illogical Calls In DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practices

On this article I am going to show you a technique to protect your modules public methods from unauthorized calls, or let’s say, illogical calls.


You may say:


I partially agree with you for two reasons:

  1. Sometimes the public methods are on third-party libraries which you are consuming and they are not properly abstracted.

  2. Even if you split your methods into well defined interfaces, never ever underestimate a developer’s ability to make bad decisions.


Still don’t get it, right? Let me show you a quick example.




Protecting Public Methods From Illogical Calls In DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practices

Trip Down a Developer’s Sick Mind


Let’s check the code sample below.



As you can see in the code sample, on line 57 and 62, the developer is casting the IRead to IWrite and the IWrite to IRead and it is going to work because the passed in object is already implementing both interfaces. Yes, this is illogical but it could happen.


I know, I know. We should not design our code to be “this level of ignorance”-proof, but, if we can do something better, then why not?


In the next sections I will show you two ways to make your code more robust against this kind of behavior.







Protecting Public Methods From Illogical Calls In DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practices

The Problem


Now let’s come up with a more clear example of the problem we are going to fix.

Let’s say that we are working on an Online Store Website like Amazon. On this project we have more than one module to work on.


We have the Store module where the end user would be able to see all products and choose the products to add to his shopping cart.


We have the Shopping Cart module where the end user can see the products he added for buying.


We have the Check Out module where the end user can see a summary of his products and the amount to pay.


For our example, we specifically care about the Shopping Cart module and how it could be used by the other two modules; Store and Check Out modules.


Let’s now jump into the code.



As you can notice in the code sample, nothing is too complicated.

However, on line 52 and 68, nothing would stop the developer from doing these castings and using the ShoppingCart in a wrong way by calling methods which should not be called in these contexts.


The dangerous thing is that the code actually would be executed because the object passed in already implements both IStoreShoppingItems and IListShoppingItems interfaces. If this is a banking system or something that critical, this would be a total disaster.


To stop this from happening we have two approaches:

  1. Allow the developer to do the casting but make sure it throws an exception.

  2. Stop the developer from doing the casting in the first place.


These two approaches would be different in terms of design and implementation.




Protecting Public Methods From Illogical Calls In DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practices

Method 1


On this approach we are going to allow the developer to do the casting but make sure it throws an exception.


IStoreShoppingItems, IListShoppingItems, ShoppingCart, Store, and CheckOutManager would all have the same old implementation.


Then, we would add the following:



What we actually did here is that we created two separate wrappers for the ShoppingCart class, one to take care of the Read operations, and the other to take care of the Write operations.


Then we would start using these wrappers instead of the original ShoppingCart class as follows:



This way, if the developer try to do the same illegal/illogical castings, the runtime would throw an exception as now the passed in object is whether ReadShoppingCart or WriteShoppingCart, not ShoppingCart as before.







Protecting Public Methods From Illogical Calls In DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practices

Method 2 - If the Code Is Self Owned


On this approach we are going to stop the developer from doing the casting in the first place.

On this case, we are assuming that the whole code is owned by us which means that we can apply the changes on the whole code.


The main idea of this approach is to protect the calls to the public methods with multiple Secret Keys; a Secret Key for Read operations and another Secret Key for Write operations. These Secret Keys are created at the moment of creating an instance of the ShoppingCart class.


The owner of these Secret Keys is the main module and then the main module is responsible for sharing the right Secret Key to the right module.


Therefore, we are going to apply these changes:



IStoreShoppingItems and IListShoppingItems



What we can notice here:

  1. We added string writingSecretKey as a parameter to the AddShoppingItem method.

  2. This means that whatever the module calling the AddShoppingItem method, it would need to provide a Writing Secret Key that should match the one initially defined and saved into the ShoppingCart object.

  3. Otherwise, an exception should be thrown.

  4. We added string readingSecretKey as a parameter to the GetShoppingItems method.

  5. This means that whatever the module calling the GetShoppingItems method, it would need to provide a Reading Secret Key that should match the one initially defined and saved into the ShoppingCart object.

  6. Otherwise, an exception should be thrown.



ShoppingCart



What we can notice here:

  1. We added private readonly string m_WritingSecretKey; and private readonly string m_ReadingSecretKey;

  2. They would be initialized by the values passed in the constructor. This is so important because we want to delegate initializing them to the owner module.

  3. Also, worth to mention that they should be immutable and hidden from the outside world.

  4. At the beginning of the AddShoppingItem method, we are checking if the passed in writingSecretKey is the same as the m_WritingSecretKey. If not, an UnauthorizedAccessException exception would be thrown.

  5. At the beginning of the GetShoppingItems method, we are checking if the passed in readingSecretKey is the same as the m_ReadingSecretKey. If not, an UnauthorizedAccessException exception would be thrown.

  6. That’s it, as simple as that.



Store



What we can notice here:

  1. We added private readonly string m_WritingSecretKey;

  2. It would be initialized by the value passed in the constructor. This is so important because we want to delegate initializing them to the owner module.

  3. Also, worth to mention that it should be immutable and hidden from the outside world.

  4. When calling the AddShoppingItem of the ShoppingCart, it would pass in the key.

  5. Worth no mention that, on line 26, if the developer tries to do the illegal/illogical casting call the GetShoppingItems method, he would find that he needs to pass in a Reading Secret Key which he doesn’t have.

  6. This would make it sound and clear that he is trying to do something wrong.

  7. Additionally, even if the developer decides to pass in any value for the Reading Secret Key, it would throw an exception.



CheckOutManager



What we can notice here:

  1. We added private readonly string m_ReadingSecretKey;

  2. It would be initialized by the value passed in the constructor. This is so important because we want to delegate initializing them to the owner module.

  3. Also, worth to mention that it should be immutable and hidden from the outside world.

  4. When calling the GetShoppingItems of the ShoppingCart, it would pass in the key.

  5. Worth no mention that, on line 15, if the developer tries to do the illegal/illogical casting call the GetShoppingItems method, he would find that he needs to pass in a Writing Secret Key which he doesn’t have.

  6. This would make it sound and clear that he is trying to do something wrong.

  7. Additionally, even if the developer decides to pass in any value for the Writing Secret Key, it would throw an exception.



Program



What we can notice here:

  1. We are initializing both m_WritingSecretKey and m_ReadingSecretKey.

  2. We are creating an instance of ShoppingCart passing in the keys.

  3. We are sharing the Writing Secret Key with the Store.

  4. We are sharing the Reading Secret Key with the CheckOutManager.

  5. That’s it.


Having these code changes in place would make the whole solution work like charm.







Protecting Public Methods From Illogical Calls In DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practices

Method 2 - If the Code Is Third-Party Owned


On this approach we are going to stop the developer from doing the casting in the first place.

On this case, we are assuming that the whole code is owned by a third party library which means that we can not apply the changes on the main code.


The main idea of this approach is to protect the calls to the public methods with multiple Secret Keys; a Secret Key for Read operations and another Secret Key for Write operations. These Secret Keys are created at the moment of creating an instance of the ShoppingCart class.


The owner of these Secret Keys is the main module and then the main module is responsible for sharing the right Secret Key to the right module.


Therefore, let’s assume that this is the third-party code:



Now what we are going to do is to wrap these into our protected layer as follows.



IProtectedStoreShoppingItems and IProtectedListShoppingItems




ProtectedShoppingCart



The only new thing here is that we are internally using the un-protected ShoppingCart class but wrapping it with our Secret Keys checks.



ProtectedStore



The same concept is applied here, we are internally using the un-protected Store class but wrapping it with our Writing Secret Key check.



ProtectedCheckOutManager



The same concept is applied here, we are internally using the un-protected CheckOutManager class but wrapping it with our Reading Secret Key check.



Program



The only new thing here is that we are creating our protected wrappers passing in the un-protected objects and finally exposing these protected wrappers for the outside world.


Protecting Public Methods From Illogical Calls In DotNet (.NET) CSharp (C#) Code Coding Programming Software Development Engineering Architecture Best Practices

Final Thoughts


Now we have explored more than one way to make our code more robust, however, the question is:


The answer is simply:


Therefore, having that said, hope you found reading this article as interesting as I found writing it.



]]>
<![CDATA[Flagged Enumerations: How To Represent Features Combinations Into One Field]]>https://www.developmentsimplyput.com/post/flagged-enumerations-how-to-represent-features-combinations-into-one-field658abfa3a87baf8fab3513acSun, 23 Jan 2022 23:00:00 GMTAhmed TarekRepresent features like [Read, Write, Modify, …] and their combinations into a single field.


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle


Sometimes when building your Software system and while designing a set of modules, you find that every module of these modules could -or couldn’t- support some features of a predefined list of features. At the end, there should be some field or property which maps each module to its supported features.


For example, let’s say that we are working on a game where every character in the game would -or wouldn’t- be able to:

▶ Walk

▶ Run

▶ Speak

▶ Scream

▶ Fight

▶ …


A character might support the features Walk, Run, and Speak only. Another character might support the features Walk, Scream, and Fight only. And so on,…


Now, let’s say that you want to have only one field or property on the Character class to represent these features so that at any time using the value of this property you can know all the singular features supported by a certain Character instance.


How would you do this? Someone might say:


Yes, this is right, but, do you know the concept that is already used in Flagged Enumerations?


This is what this article is about.




Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Agenda


Flagged Enumerations are supported by almost all -if not all- Object Oriented Programming (OOP) languages. They are used for the cases we described in the Problem Definition section above.


However, if you look closely you would find that Flagged Enumerations is just an implementation of an important concept based on Binary Tables and the Bitwise Operations that could be applied.


That’s why in this article we are going to explore some basics of Binary Tables and the Bitwise Operations.


This is our agenda:

  1. Binary Tables.

  2. Bitwise Operations:

  3. Representing Features With Bits.

  4. Flagged Enumerations.


If you think you already have experience with one or more of these topics, feel free to skip to the next one. You can search the article by the headlines included into the agenda above.







Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Binary Tables


For simplicity, let’s say that Binary is a way of representing numbers into a series of symbols where each symbol could be presented by “0” or “1”. These symbols are given the name Bits. In other words, each Decimal number could be presented into a series of “0” and “1” written in a certain order.


So, if we assume that we want to format a Decimal number using only one Bit knowing that the Bit could be “0” or “1”.


Then we should know that we have these possibilities only:

▶ 0

▶ 1


In this case, we can say that we can represent only two Decimal numbers which are 0 and 1.


But, what if I told you that we would now add another Bit so that the total number of Bits is two instead of one.


Then we should know that we have these possibilities only:

▶ Bit 1 = 0, Bit 2 = 0

▶ Bit 1 = 1, Bit 2 = 0

▶ Bit 1 = 0, Bit 2 = 1

▶ Bit 1 = 1, Bit 2 = 1


In this case, we can say that we can represent only four Decimal numbers which are 0, 1, 2, and 3.


Actually, let’s stop here for a while and try to understand what actually happened.


What we can notice here:

  1. We know that each Bit could be one of two values; “0” or “1”.

  2. And this applies on all Bits including the new one we are going to add.

  3. This means that if we want to know the number of combinations we would get using two Bits, we should multiply { the number of the possible values for the first Bit } and { the number of the possible values for the second Bit }.

  4. Therefore the total number of combinations for two Bits should be

  5. Following the same concept, if we add a third Bit, the total number of combinations for three Bits should be

  6. Then generalizing this idea, we can say that the total number of combinations for n Bits should be

  7. The final thing to note here is that when we say that we represent 8 Decimal numbers, Zero is also included.

  8. Therefore, for three Bits, we can represent the Decimal numbers 0, 1, 2, 3, 4, 5, 6, and 7


Having that said, let’s see how to put this into the famous Binary Table format.




Let’s start with the 1 Bit Binary Table:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle


The main rule here is that we start with “0”, not “1”.


Now, when adding a second Bit to get a 2 Bit Binary Table, we add it as follows:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

As we can see, to add a new Bit, we do the following:

  1. Copy the previous Binary Table.

  2. Extend the rows by copying the already existing ones and pasting them at the bottom (as noted by the red arrow).

  3. Add the new Bit column to the Left.

  4. Fill all the cells corresponding to the rows on the previous table (highlighted in green) with “0”.

  5. Fill the rest of the new column cells with “1”.


Now, you have a 2 Bit Binary Table.


Again, when adding a third Bit to get a 3 Bit Binary Table, we add it as follows:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

As we can see, to add a new Bit, we do the following:

  1. Copy the previous Binary Table.

  2. Extend the rows by copying the already existing ones and pasting them at the bottom (as noted by the red arrow).

  3. Add the new Bit column to the Left.

  4. Fill all the cells corresponding to the rows on the previous table (highlighted in green) with “0”.

  5. Fill the rest of the new column cells with “1”.


Now, you have a 3 Bit Binary Table.




Now you might be asking about the relation between every bits sequence and the Decimal number. Is there a relation?


The answer is yes, there is a relation.


Let’s use the 3 Bit Binary Table as an example.


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

To calculate the Decimal number corresponding to every bits sequence, we calculate the sum of every bit multiplied by (2 raised to the power of the bit zero-order). Not clear, right?


Check this image and you would understand it:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Or even simpler like this:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Now you know how it works.



This is not all. We now know how to convert a Binary number into the corresponding Decimal number. But, what about converting a Decimal number to the corresponding Binary number?


There is a simple way to do it. Let me show you.


Let’s say that you want to convert the Decimal number “7” to its Binary form.


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

This is how we do it:

  1. Start with 7.

  2. Divide it by 2.

  3. We get 3 and a remainder of 1.

  4. Divide 3 by 2.

  5. We get 1 and a remainder of 1.

  6. Divide 1 by 2.

  7. We get 0 and a remainder of 1.

  8. Divide 0 by 2.

  9. We get 0 and a remainder of 0.

  10. This is where we stop.

  11. The answer is 0111.

Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Another example. Let’s say that you want to convert the Decimal number “35” to its Binary form.


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Following the same process, we will end up with this:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Now you might be a little bit confused and not sure where this way of conversion is coming from. Let me prove it for you.


As we explained before, to convert a Binary number (BitN, …Bit2, Bit1) to its Decimal number (X), we do the following:


Now, when we divided 7 by 2, this is what actually happened:


Following the same rule, dividing the Decimal number X by 2 should mean:


Now, comparing these two bold equations, we can see that:

  1. Remainder of first division on 2 should map to Bit1.

  2. Result of first division on 2 should map to the rest of bits.

  3. So, repeating the same operation on the Result of first division on 2, should get Bit2, and so on,…


I hope it is now clear.







Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Bitwise Operations


These are some operations that can be applied on the level of Bits.


According to Wikipedia:


On the next sections, we would explain some of the Bitwise Operators on which Flagged Enumerations depend.


These Bitwise Operators are:

  • AND Bitwise Operator.

  • OR Bitwise Operator.

  • XOR Bitwise Operator.

  • NOT Bitwise Operator.




Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

AND Bitwise Operator


Is true (“1”) only when both bits are “1”. Otherwise, it would return False (“0”).


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle


If you have an input bit, whenever you AND it with “0”, you are sure that the result would be “0”. Also, if you AND it with “1” and the result is “1”, you are now sure that the input was “1”. This is useful when you need to check if a certain bit in a Bit Sequence is “1”.


For example, you are given the sequence 011010 as an input and you want to know if the fourth bit (from the right) is “1”.


This is what you can do:


You AND this input sequence with the masking sequence 001000 where all bits are “0” and only the fourth bit (from the right) is “1”. If the result is identical to the mask sequence, then the fourth bit is “1”. Otherwise, it is “0”.


Using the same example and following the same methodology, let’s say that we want to check if the third bit (from the right) is “1”.



See, the result is not identical to the mask.




Also, if you have an input bit, whenever you AND it with “0”, you are sure that the result would be “0”. Also, if you AND it with “1” and the result is “1”, you are now sure that the input was “1”. This is useful when you need to set a certain bit in a Bit Sequence to “0”.


For example, you are given the sequence 011010 as an input and you want to set the fourth bit (from the right) to “0” without affecting the other bits.


This is what you can do:


You AND this input sequence with the masking sequence 110111 where all bits are “1” and only the fourth bit (from the right) is “0”. Doing this, you end up with the same exact input sequence except that the fourth bit (from the right) is now set to “0”.


Even if the bit was already set to “0”, doing this would not affect the input as follows:


As you can see, the result is exactly identical to the input.







Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

OR Bitwise Operator


Is always true (“1”) except when both bits are “0”. This is why it could be used to check for


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

If you have an input bit, whenever you OR it with “0”, you are sure that the result would be the same as the input. Also, if you OR it with “1”, you are sure that the result would be “1” whatever the input is. This is useful when you need to set a certain bit to “1” without changing the other bits.


For example, you are given the sequence 011010 as an input and you want to set the third bit (from the right) to “1” without changing the other bits.


This is what you can do:


You OR this input sequence with the masking sequence 001000 where all bits are “0” and only the third bit (from the right) is “1”. Doing this, you end up with the same exact input sequence except that the third bit (from the right) is now set to “1”.


Even if the bit was already set to “1”, doing this would not affect the input as follows:


As you can see, the result is exactly identical to the input.




Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

XOR Bitwise Operator


Is true (“1”) when both bits are not the same. Otherwise, it would return False (“0”).


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

If you have an input bit, whenever you XOR it with “1”, you are sure that the result would be the opposite of the input. This is useful when you need to toggle (set if is already unset, unset if is already set) a certain bit without changing the other bits.


For example, you are given the sequence 011010 as an input and you want to toggle the fourth bit (from the right) without changing the other bits.


This is what you can do:

Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

You OR this input sequence with the masking sequence 001000 where all bits are “0” and only the third bit (from the right) is “1”. Doing this, you end up with the same exact input sequence except that the fourth bit (from the right) is now set to “0” instead of “1”.


Following the same way, if you want to toggle the third bit (from the right) without changing the other bits.


This is what you can do:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

You OR this input sequence with the masking sequence 000100 where all bits are “0” and only the third bit (from the right) is “1”. Doing this, you end up with the same exact input sequence except that the third bit (from the right) is now set to “1” instead of “0”.







Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

NOT Bitwise Operator


Inverts the Bit so that if it is “0” the result would be “1” and vice versa.


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle




Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Now What?


Now, you should be able to understand Binary Tables and Bitwise Operations, but still, you might be asking:


I would answer your question in the next sections but I want you to keep in mind the following important notes:

  1. We can use the AND Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to check if a certain bit is “1”.

  2. We can use the AND Bitwise Operator with a mask (mainly all “1” except the bit we are interested into) to set a certain bit to “0”.

  3. We can use the OR Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to set a certain bit to “1” without affecting the other bits.

  4. We can use the XOR Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to toggle (set if is already unset, unset if is already set) a certain bit without affecting the other bits.


Having that said, let’s jump to the next sections.




Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Representing Features With Bits


If you have read the previous sections of this article, you would have noticed that we proved that AND and OR Bitwise Operators are useful for checking and setting bits.


As a quick summary:

  1. We can use the AND Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to check if a certain bit is “1”.

  2. We can use the AND Bitwise Operator with a mask (mainly all “1” except the bit we are interested into) to set a certain bit to “0”.

  3. We can use the OR Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to set a certain bit to “1” without affecting the other bits.

  4. We can use the XOR Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to toggle (set if is already unset, unset if is already set) a certain bit without affecting the other bits.


Now, let’s go back to our original problem. We want to be able to represent the availability or absence of certain features in a single field.




Let’s say that we have an object and this object could support any combination of he following features:

  1. Feature 1

  2. Feature 2

  3. Feature 3


In other words, the object could support Feature 1 only, or Feature 1 and Feature 2, or Feature 1 and Feature 3, or …you get the point.


Does this somehow remind you of something? Could it be like this:


Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle


As you can see, we generated all the possible combinations of the features in the form of a Binary Table. When we put “0” in a cell, this means that the feature is not available. On the other hand, when we put “1” in a cell, this means that the feature is available.


This comes with a huge benefit as now we can represent any combination of features availability with the corresponding Decimal number, in other words, a single field of type integer.







Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Now you might ask:


The answer is simply by using the AND Bitwise Operator. You remember when we said that it could be used to check if a certain bit is “1”? The only thing we need now is to choose the right mask sequence. But, how to get this mask?


As we said before, the mask should be all “0” except for the bit we are interested into.

Therefore, applying the same concept on our example, if we are checking for the Feature 1, then the mask should be the decimal/integer number corresponding to 001 which is equal to 1. So, if the result of {integer value} AND {1} equals 1, then Feature 1 is available, otherwise, it is absent.


The same way, if we are checking for the Feature 2, then the mask should be the decimal/integer number corresponding to 010 which is equal to 2. So, if the result of {integer value} AND {2} equals 2, then Feature 2 is available, otherwise, it is absent.


Furthermore, if we are checking for the Feature 3, then the mask should be the decimal/integer number corresponding to 100 which is equal to 4. So, if the result of {integer value} AND {4} equals 4, then Feature 3 is available, otherwise, it is absent.


Great, so now we know how to check if a certain feature is available or not.


Is this all? certainly No.




Now you might ask:


The answer is simply by using the OR Bitwise Operator. You remember when we said that it could be used to set a certain bit to “1”? The only thing we need now is to choose the right mask sequence. But, how to get this mask?


As we said before, the mask should be all “0” except for the bit we are interested into.

Therefore, applying the same concept on our example, if we want to set the availability of Feature 1 to true without affecting the other features, then the mask should be the decimal/integer number corresponding to 001 which is equal to 1. So, all what we need to do is {integer value} OR {1}.


The same way, if we want to set the availability of Feature 2 to true without affecting the other features, then the mask should be the decimal/integer number corresponding to 010 which is equal to 2. So, all what we need to do is {integer value} OR {2}.


Furthermore, if we want to set the availability of Feature 3 to true without affecting the other features, then the mask should be the decimal/integer number corresponding to 100 which is equal to 4. So, all what we need to do is {integer value} OR {4}.




Now you might ask:


The answer is simply by using the AND Bitwise Operator. You remember when we said that it could be used to set a certain bit to “0”? The only thing we need now is to choose the right mask sequence. But, how to get this mask?


As we said before, the mask should be all “1” except for the bit we are interested into.

Therefore, applying the same concept on our example, if we want to set the availability of Feature 1 to false without affecting the other features, then the mask should be the decimal/integer number corresponding to 110 which is equal to 6. So, all what we need to do is {integer value} AND {6}.


The same way, if we want to set the availability of Feature 2 to false without affecting the other features, then the mask should be the decimal/integer number corresponding to 101 which is equal to 5. So, all what we need to do is {integer value} AND {5}.


Furthermore, if we want to set the availability of Feature 3 to false without affecting the other features, then the mask should be the decimal/integer number corresponding to 011 which is equal to 3. So, all what we need to do is {integer value} AND {3}.




Now you might ask:


The answer is simply by using the XOR Bitwise Operator. You remember when we said that it could be used to toggle a certain bit? The only thing we need now is to choose the right mask sequence. But, how to get this mask?


As we said before, the mask should be all “0” except for the bit we are interested into.

Therefore, applying the same concept on our example, if we want to toggle the availability of Feature 1 without affecting the other features, then the mask should be the decimal/integer number corresponding to 001 which is equal to 1. So, all what we need to do is {integer value} XOR {1}.


The same way, if we want to toggle the availability of Feature 2 without affecting the other features, then the mask should be the decimal/integer number corresponding to 010 which is equal to 2. So, all what we need to do is {integer value} XOR {2}.


Furthermore, if we want to toggle the availability of Feature 3 without affecting the other features, then the mask should be the decimal/integer number corresponding to 100 which is equal to 4. So, all what we need to do is {integer value} XOR {4}.




Now, after having all your questions answered, did you notice anything about the masks we used for all the operations above?


Let me help you visualize it:

Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Is it obvious now?


Let me tell you this, the masks we used are actually the rows corresponding to the decimal/integer values 1, 2, and 4.


You might say:


Yes, but actually those masks could be get by using the NOT Bitwise Operator on the masks highlighted into the image.


This means that, we can save these 3 masks in integer variables then we can use them to do all our check, set, and unset operations. Whenever we need to get the other three masks, we just apply NOT to these saved ones.


If you need to understand more about this, just continue reading to the next sections on this article.







Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Flagged Enumerations


As we said before, almost all -if not all- Object Oriented Programming (OOP) languages support Flagged Enumerations.


Flagged Enumerations are actually using the same concepts we explained on the previous sections of this article to handle all the operations we might need to represent the availability or absence on some features into a single field.


For example, this is how to define a flagged enumeration in .NET C#



As you can see, it is an enum decorated with a Flags attribute. Every entry in this enum represents a mask and that’s why the enumeration entries are assigned values in the format of powers of 2.


Now, using this enumeration, you can do the following:



What we should notice here:

  1. We used the AND (&) operator to check if a certain feature is set.

  2. We used the AND (&) operator in combination with the NOT (~) operator to unset a certain feature.

  3. We used the OR (|) operator to set a certain feature.

  4. We used the XOR (^) operator to toggle (set if is already unset, unset if is already set) a certain feature.


Running this we would get this result:


Worth to mention here is that if in the future a new feature is added, you can easily extend your solution by adding the new feature at the bottom of the Features enumeration entries.

This way you make sure that the already persisted (may be in a database or something similar) values are still valid and not affected by the added feature.




Flagged Enumerations: How To Represent Features Combinations Into One Field. Flagged Enumerations Features Combinations Into One Single Field. DotNet (.NET) CSharp (C#) JavaScript (JS) Java Code Coding Programming Software Development Engineering Architecture Best Practice Binary Tables Bitwise Operations AND OR XOR NOR Toggle

Summary


In this article we explained the following topics:

  • Binary Tables.

  • Bitwise Operations (AND, OR, XOR, and NOT).

  • Representing Features With Bits.

  • Flagged Enumerations.


We also explained that:

  1. We can use the AND Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to check if a certain bit is “1”.

  2. We can use the AND Bitwise Operator with a mask (mainly all “1” except the bit we are interested into) to set a certain bit to “0”.

  3. We can use the OR Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to set a certain bit to “1” without affecting the other bits.

  4. We can use the XOR Bitwise Operator with a mask (mainly all “0” except the bit we are interested into) to toggle (set if is already unset, unset if is already set) a certain bit without affecting the other bits.


Now, you should have enough knowledge to start using Flagged Enumerations in your Object Oriented Programming (OOP) language.


That’s it, hope you found reading this article as interesting as I found writing it.



]]>