Incorrect Use Of Partial Classes
Today’s tip deals with a feature of .NET: Partial classes.
Is see partial classes abused from time to time. If you are not aware, .NET allows us to split a class definition across multiple source files. We decorate each of the class fragment definitions with the ‘partial’ keyword. At build time, the compiler takes the various partials and fuses them back into a single class.
Why is this useful?
Generally, this is a framework feature that is handy when we are working with autogenerated code. I’ll get into the details of that next time.
Today I would like to point out a misuse of partial classes.
For example, imagine an enormous AccountController class split across five files:
AccountController.cs
AdminAccountController.cs
UserAccountController.cs
SuperAdminAccountController.cs
OrganisationAccountController.cs
In each of these files, AccountController is defined as a partial class:
public partial class AccountController
With about 2,000 lines per file, AccountController contains approximately 10,000 lines of code. Each of the partials is already bloated, but the whole AccountController class is enormous. Huge classes like this can be a real challenge to work with.
Unfortunately, breaking AccountController up over multiple source code files obscures the actual size of the class. Programming is communication with other developers. We do not want to disguise problems – we want to highlight them, so everyone’s aware of them.
A developer who is aware that a class is already 10,000 lines long may avoid adding more behaviour to it. However, if a class appears to be only 2,000 lines long, they may not be quite so hesitant.
Splitting up a huge class by breaking it up over several files is an anti-pattern. It does not shrink the size of the class – it only appears to reduce it.
A better way is to break a large class into several smaller ones. If necessary, we can use patterns like Aggregation or Composition to reassemble the functionality into a larger whole again.
In our example, the names of the AccountController files already indicate a breakdown by responsibilities. AdminAccountController.cs is probably the place where Admin-related AccountController behaviour resides. Similarly for OrganisationAccountController.cs and the other files.
The fix might be as simple as renaming the AccountController class fragments to align with the file names. In the AdminAccountController.cs file, we change the declaration from
public partial class AccountController
to
public class AdminAccountController
Notice that we have removed the partial keyword. AdminAccountController is no longer a partial class – it’s now a separate class.
Also, breaking down a large class might not always be this simple.
So, when is it appropriate to use partial classes?
There is an excellent reason to use partial classes. We’ll discover that next time.
Today’s takeaway is to avoid using partial classes to spread large classes over several files. It does not reduce class size and complexity but merely obscures it.
Philosophy Friday: On Gratitude
/0 Comments/in Philosophy Friday /by Olaf ThielkePhilosophy Friday: On Gratitude
Photo by Gabrielle Henderson on Unsplash
Why don’t we live in a mansion, have millions of dollars or be as good looking as our acquaintances on social media? We love to compare ourselves to people who have more than us―always thinking about what we don’t have but think we deserve.
That’s human nature. We are descendants of thousands of generations of people who lived in small tribes. Life on the savannah was harsh. Our ancestors were hyperaware as to their relative status within the tribe. Even a slight drop in standing could mean less food and resources and spell disaster for their survival. Our brains are hard-wired into comparative-status thinking.
Today we no longer live in small tribes. Our survival isn’t threatened when we lose social capital. As a trait, comparative thinking is no longer serving us well. In our modern world it’s a cludge; a hindrance. It creates unnecessary anxiety and misery.
The antidote is gratitude. It’s worthwhile reflecting on how lucky we are what we do have. We are fortunate even to be alive. And to live during this marvellous time. Life, in general, is pretty good. Yes, there is a pandemic, and the economy is in trouble, but if we are honest with ourselves, would we want to live in any other period? The most advanced medical treatments, even for emperors, often involved herbs, bloodletting and leeches. Amazingly, anaesthetics were only discovered in the 19th century. For most of history, the excruciating pain during surgical procedures had to be borne by the patient. Let’s be grateful for living in the 21st century!
Let’s be grateful for the people we have in our lives and the experiences we’ve had – even the painful ones. They too, have shaped us into who we are today.
Gratitude leads to happiness.
Fix Downstream Collection Problems
/0 Comments/in Today's Tip /by Olaf ThielkeFix Downstream Collection Problems
Photo by Karen Vardazaryan on Unsplash
Recently I’ve talked about how we should always initialise collection types with an empty collection. Not doing so will cause unnecessary
NullReferenceExceptions. This guidance extends to return values – Never return a null for a collection type.What if we called a method that returned a null collection? The called class comes from a 3rd party library, and we can’t fix the problem at the source. Or the called method is lengthy legacy code lacking unit tests for us to make modifications without introducing new bugs.
If in turn, we are passing through this return collection type to our clients, we may propagate the problematic null collection further. It is our responsibility to ensure clients of our method get sane and expected values even when we receive nonsense. So, how do we ensure our callers don’t get a dorky null collection?
Let’s look at an example:
It seems the purpose of the example method is to construct the search criteria from the parameters and then find matching customers. Unfortunately, Searcher.FindMatchingCustomers() sometimes returns a null collection when there are no matching customers. FindMatchingCustomers() is convoluted legacy code without unit tests which we do not want to modify, if at all possible.
So, how do we ensure our clients always get a collection even when we do not? We perform a null check:
In .NET, a compact and elegant alternative is to use the null-coalescing operator,
??:or even better:
The point isn’t about the specific implementation of converting a received null into an empty collection before we pass it on.
Instead, it’s that as responsible developers, we fix problems and don’t leave our callers hanging.
Ideally, I recommend repairing any collection initialisation problems at the source. However, this is an acceptable way of stopping the propagation of a possible null collection quickly and safely.
What Is Feature Envy?
/0 Comments/in Today's Tip /by Olaf ThielkeWhat Is Feature Envy?
Photo by James Jeremy Beckers on Unsplash
Today’s topic is ‘Feature Envy’, a code smell and an indicator of deeper problems with the software. Feature Envy means that one class is ‘envious’ of, and contains, behaviour that rightly belongs to another. The code is in the wrong place: One type is doing too much and the other, not enough.
In extreme cases, we can end up with God-classes that fail to delegate work and do everything themselves. In my experience, much procedural code, written in object-oriented languages, is plagued by Feature Envy.
By removing instances of Feature Envy, we get better encapsulation, code reuse and balancing of responsibilities between classes.
Let’s look a couple of examples of Feature Envy:
Example 1:
Validate()is doing more than it should. Can you identify the code that we could move to a better home?That’s right; it’s the detailed validation of the
CustomerRegistrationparameter. The code is performing multiple validation checks that would make more sense in theCustomerRegistrationclass. Let’s move the code over into a new publicValidate()method onCustomerRegistration:Now we are in a position to replace the detailed validation in the original
Validate()method with a call toCustomerRegistration.Validate():Much simpler and shorter than before!
Example 2:
A private helper method
IsPublicSchool()is defined as:, and called several times in conditional statements:
if (IsPublicSchool(school))The
Typeproperty is part of theSchoolclass. So why do we determine outside of classSchoolwhether a school is public or not? That does not feel right. Let’s fix this by adding anIsPublicproperty toSchool:public bool IsPublic => Type == 2;The conditional statements simplify to:
if (school.IsPublic)Much better!
How do we identify Feature Envy?
I think a decent indicator is when one class does an extended amount of work with the instance of another class. The registration validation in our first example was like that.
In our second example, we were building behaviour in another class that we could entirely determine inside the School type.
Whenever I remove some Feature Envy, the code feels more natural and balanced. It’s great.
Correct Use Of Partial Classes
/0 Comments/in Today's Tip /by Olaf ThielkeCorrect Use Of Partial Classes
Photo by Ryan Hafey on Unsplash
Yesterday we examined the futility of using .NET partial classes to split up large classes. Stashing a massive class among several files still leaves us with – Drum Roll – an enormous class. It’s not an improvement.
The only thing we had managed to do is sweep the elephant in the room under the carpet. The elephant has not gone away; we’ve only hidden it.
So, what’s a legitimate use for partial classes?
Partial classes are vital when we have autogenerated code that we would like to extend with additional behaviour. Autogenerated? Yes. Code creating code.
Some frameworks and tools will autogenerate code based on the structure of other entities, such as database tables.
For example, here is the definition of a simple
Bookclass that was generated using Entity Framework, a database Object Relational Mapper (ORM):Say, we’ve made a change to the Book table in the underlying database. Maybe we’ve added an Author column. Re-running the autogeneration tool in our .NET project will regenerate class
Bookwith anAuthorproperty. Nice!Unfortunately, we have made a few direct modifications to the
Bookclass too. Running the autogeneration overwrites these! Wiped out; gone. It looks like we should have read the comments at the top warning us about making changes in this file!So does that mean we cannot make modifications to class
Bookwithout them being wiped out every time we want to align the model with the database schema? What if we wanted to add a useful helper method? If we put it in here, it would be lost?Yes, pretty much.
Unless…
Did you notice the
partialkeyword on theBookdefinition?Hey, that means we can create a separate source file and add to the
Bookclass behaviour in there. And any code in that file won’t be overwritten by the autogeneration tool. Pretty clever, right?!Here is an example extension of the
Bookclass:The
Genreenumeration will persist regenerations of the autogenerated partialBookclass.The
partialkeyword is excellent for breaking classes up into two fragments; one that regenerates via a code templating mechanism, and another that is available for manual editing.Incorrect Use Of Partial Classes
/0 Comments/in Today's Tip /by Olaf ThielkeIncorrect Use Of Partial Classes
Photo by Rob Necciai on Unsplash
Today’s tip deals with a feature of .NET: Partial classes.
Is see partial classes abused from time to time. If you are not aware, .NET allows us to split a class definition across multiple source files. We decorate each of the class fragment definitions with the ‘partial’ keyword. At build time, the compiler takes the various partials and fuses them back into a single class.
Why is this useful?
Generally, this is a framework feature that is handy when we are working with autogenerated code. I’ll get into the details of that next time.
Today I would like to point out a misuse of partial classes.
For example, imagine an enormous
AccountControllerclass split across five files:AccountController.cs
AdminAccountController.cs
UserAccountController.cs
SuperAdminAccountController.cs
OrganisationAccountController.cs
In each of these files,
AccountControlleris defined as a partial class:With about 2,000 lines per file,
AccountControllercontains approximately 10,000 lines of code. Each of the partials is already bloated, but the wholeAccountControllerclass is enormous. Huge classes like this can be a real challenge to work with.Unfortunately, breaking
AccountControllerup over multiple source code files obscures the actual size of the class. Programming is communication with other developers. We do not want to disguise problems – we want to highlight them, so everyone’s aware of them.A developer who is aware that a class is already 10,000 lines long may avoid adding more behaviour to it. However, if a class appears to be only 2,000 lines long, they may not be quite so hesitant.
Splitting up a huge class by breaking it up over several files is an anti-pattern. It does not shrink the size of the class – it only appears to reduce it.
A better way is to break a large class into several smaller ones. If necessary, we can use patterns like Aggregation or Composition to reassemble the functionality into a larger whole again.
In our example, the names of the
AccountControllerfiles already indicate a breakdown by responsibilities. AdminAccountController.cs is probably the place where Admin-related AccountController behaviour resides. Similarly for OrganisationAccountController.cs and the other files.The fix might be as simple as renaming the
AccountControllerclass fragments to align with the file names. In the AdminAccountController.cs file, we change the declaration frompublic partial class AccountControllerto
public class AdminAccountControllerNotice that we have removed the partial keyword.
AdminAccountControlleris no longer a partial class – it’s now a separate class.Also, breaking down a large class might not always be this simple.
So, when is it appropriate to use partial classes?
There is an excellent reason to use partial classes. We’ll discover that next time.
Today’s takeaway is to avoid using partial classes to spread large classes over several files. It does not reduce class size and complexity but merely obscures it.
Philosophy Friday: Every Day Is A Bonus
/0 Comments/in Philosophy Friday /by Olaf ThielkePhilosophy Friday: Every Day Is A Bonus
Photo by Federico Respini on Unsplash
You woke up this morning—you’re alive. Many people are not so lucky. Thousands of people died last night while you were sleeping. What would they give to live one more day?
How about this idea: In the morning when you wake up imagine you had died in your sleep. Would you then not be overjoyed to learn you had another day? That today has been gifted to you as a bonus—for you to enjoy as you see fit.
With such a special gift in hand, life’s little obstacles, the ones that usually get us upset, would be no problem. You’d even welcome them as a kind of confirmation that you’re still alive.
Someone cuts you off in traffic? You’d be calm and collected. Maybe you’d even chuckle to yourself knowing how this would have infuriated you before. Is your boss is in one of his sullen moods? Water off a duck’s back. Nowhere near wiping that perpetual grin off your face. Someone wasting your time? Tell them where to go. Today is your special bonus day, and one thing you’re not going to do is spend it on timewasters.
We don’t know on which day we’ll die, so as a policy treating each day as a bonus makes a lot of sense. After all, we could be dead tomorrow.
Today really is special—you won’t ever get this day again. Time is your only non-renewable resource. You can regain lost money and possessions. But not time. Once it’s gone, it’s gone.
Always imagining you’d died last night, but the gods have gifted you a bonus day, will do much to spruce up your remaining days.
How To Write Good Unit Tests
/0 Comments/in Today's Tip /by Olaf ThielkeHow To Write Good Unit Tests
Photo by Christina @ wocintechchat.com on Unsplash
What makes a good unit test?
Meaningful Naming
Are these helpful unit test names?
Test_6Test_SomethingAccounts_TestNo, they are not. These names are devoid of meaning. Readers ought to be able to comprehend the purpose of a unit test immediately;
A technique that I like is using Given/When/Then to name tests. Here are a couple of examples:
Given_No_Matching_UseCase_When_Try_GetUseCase_Then_Throw_UnknownUseCaseGiven_No_AccountGroupName_When_Call_BuildQuery_Then_Throw_ArgumentNullExceptionBut it doesn’t have to be Given/When/Then. For example, in the Bowling Game Kata,
Roll_Guttergameis an excellent contextual unit test name for a rolling all zeros.The reader should immediately get the idea of what a test is all about. There should be no head-scratching.
Easy to Understand
I have seen unit tests that were two pages long. There were many lines of setup and verification all on display. With tests like that, it’s difficult to discern which parts are relevant to a particular test and which are just mechanics.
When we have to brace ourselves before we dig into a unit test to try and understand what is going on, that is not a useful unit test. It should not be like we are trying to decipher the Dead Sea Scrolls.
What happens to tests that are hard to understand and maintain? When they start failing, they will get commented out or deleted.
The body of a unit test should be short and understandable. We must use all our programming prowess to make unit tests intuitive to understand.
Following is an example where I did not fully achieve this:
As the name indicates, the test ensures that the
UpdateBudget()method rounds incoming 4 decimal place budget figures to 2 decimal places.The test has only three lines, which is nice and short. However, when we read the test code, there is at least one aspect that is a little bit off. The test code exposes an unnecessary detail which may cause minor confusion. Do you know what I mean? Maybe reread the test.
The test uses
AccountGroupName. Why is this here? How is it involved in budget rounding? It’s not.AccountGroupNameis needed to initialiseBudgetChange. It’s a detail that is detracting from the meat of the unit test.What should we do? Easy. Hide it:
We have relegated the instantiation of class
BudgetChangeto methodSetupBudgetChange(). We have thus hiddenAccountGroupNamefrom the high-level test code.So, the only moving parts the test is exposing are the ones that we are interested in:
All other detail still exists but has been conveniently hidden away in helper methods.
What Is Not A Unit Test?
/0 Comments/in Today's Tip /by Olaf ThielkeWhat Is Not A Unit Test?
Photo by Adi Goldstein on Unsplash
A few years ago, a programmer colleague nicely illustrated one difference between unit tests other automated tests: He unplugged the network cable from his computer and ran the unit test suite. Many tests that had previously passed now failed – they required network resources.
Those tests were not unit tests. They were integration and system tests.
Unit tests should not depend on Network I/O.
Why is this?
OK, let’s look at what we desire from unit tests:
Unit tests exist to validate the working of our code. We don’t need them to verify that the network is up, or that the database code is working as expected. Unit tests are concerned with our programming.
We want our unit tests to have these properties:
Determinism/Predictability
Unit tests should only fail when either the test code changes or the implementation code changes. That’s it. They should not fall over for spurious and temporary reasons. Unit tests are an extremely reliable measure as to whether our software works or not.
The more we rely on Network I/O and any code that is not ours (database, network, SDKs and libraries, remote services, file systems, configuration files) the further we are moving away from unit tests. Please note, though, that to a degree, we are always dependent on other code, e.g. our computer language and related frameworks.
Speed
Unit tests are meant to be fast. 1000+ unit tests should run in seconds. Accessing resources via a LAN or WAN is slow. System and integration tests run much slower. Depending on the number of tests, a system test run can take minutes to hours.
It is an excellent idea to group our (fast) unit tests separately from the (slow) system tests. We want to be able to run our unit tests all the time to detect broken functionality. On the other hand, integration and system tests that run for hours probably ought to be run once or twice a day.
Finely-Grained
Unit tests are finely-grained. They tend to involve a small group of collaborating classes or functions. On the other hand, system tests verify the working of whole coarse-grained system functions, traversing from the system entry points (UI or API) through the application business logic down to the service layer (database, remote services) and back up again. When a system test is failing, we may not have a good idea as to the cause of the problem: Is it a database problem? Have changes to our business logic caused the test to fail? Or is the failure situated in our presentation layer?
So to recap, other automated tests may require Network I/O but not unit tests.
They should
What Is A Unit Test?
/0 Comments/in Today's Tip /by Olaf ThielkeWhat Is A Unit Test?
Photo by Nina Mercado on Unsplash
In his highly recommended book, ‘The Art Of Unit Testing’, Roy Osherove describes a unit test as ‘an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behaviour of that unit of work.‘
It’s a good explanation. Let’s pick it apart. In places, I will layer my interpretation on top of Roy’s definition.
‘an automated piece of code…‘
It’s Automated; not manual. Manually testing a system is not automatic and therefore never a unit test. A computer runs a suite of unit tests. And Yes, it’s more code for developers to write. It’s up to us to produce the code for the unit tests and the implementation. Unit tests are meant to be meaningful and understandable by the developers who maintain the implementation code. To that end, a unit test should be written in the same computer language as the implementation. Imagine how awkward and difficult it would be to switch languages between unit tests, written in Python, but the system code written in C#.
‘…invokes a unit of work in the system…‘
Real-world systems do many things. They carry out many functions. For a unit test, we want to focus on one such system function and exercise it. For the sake of clarity, this does not mean we are restricted to calling only the highest-level functionality in the system, say, like creating a new customer. Systems perform lower-level, detail-oriented functions, say, hashing a password, and they too are units of work. Anything a system can do is somewhere exposed as a public function. Each unit test focusses on exercising one ‘thing’ a system does, or one unit of work, at a time.
‘…checks a single assumption about the behaviour of that unit of work.‘
Whenever we test a system, whether manually or automatically, in order of it to be a useful test, we must have certain expectations as to how the system should respond. For example, when we try to log in with invalid credentials, then the system will deny us access. A given input for an action will produce an expected result. It’s how predictable systems work. What Roy is saying here is that we should pick one output, one assumption, and check that. For example, a call of a high-level workflow method might perform these steps:
Each of these steps is an assumption and ought to be separately tested via a unit test:
These are independent steps and so deserve at least one unit test each.
I feel that there is a bit more to unit tests which we will examine next time.
Architectural Layers
/0 Comments/in Today's Tip /by Olaf ThielkeArchitectural Layers
Photo by Max van den Oetelaar on Unsplash
Last time we discussed the purpose of software architecture. Readers may recall that a well-designed architecture allows us to
Today, I’d like to outline the various layers that compose such a ‘good’ software architecture.
A lack of clearly designed structure in our programs is evident to all: The code is a convoluted mess; features are hard to implement or change. And when it’s especially awful, developers don’t even want to touch those sections of code. They’ll know that those parts are particularly fragile and confusing in their unnecessary complexity.
On the other hand, well-implemented architecture displays opposing qualities: The code is easy to read; the structure is clear and self-explanatory, automated tests verify the validity of the requirements, and so on.
The following illustration outlines the different layers of a well-designed software architecture:
Let’s explore the layers from the bottom, low-level detail up:
I intend to cover off these layers in detail another time.