This is an introduction to a series of articles in which I attempt to answer the question "How much better would I be as a developer now, if I could have listened to the thought processes of other developers when they were writing applications?"
I remember, as a young developer, being in awe of people who could sit down and code, seemingly without any effort. Systems would seem to flow out of their fingers, effortlessly crafted, elegant, and refined. It felt like I was witnessing Michelangelo in the Sistine Chapel or Mozart sitting down in front of a fresh stave. Of course, with experience, I now know that what I was seeing was developers doing what developers do. Some were doing it well, and really understood the craft of development, while others were producing work that was less elegant and less well written. Over the years, I have been privileged enough to learn from some amazing developers but I keep coming back to the same basic question, time after time, namely…
How much better would I be as a developer now, if I could have listened to the thought processes of other developers when they were writing applications?
In this series of articles, I’m going to take you through what I’m thinking while I develop an application. The code that accompanies the article will be written as a “warts and all” development so you can see how I take something from the initial requirements phase through to something I would be happy for others to use. This means that the articles will show every mistake I make and the shortcuts I take while I’m fleshing ideas out. I’m not going to claim I’m a great developer here, but I am competent and experienced enough that this should help people who are new to the field get over their awe a lot earlier, and gain confidence in themselves.
These articles are aimed at junior developers who want to understand the thought processes when building an application. They are also for more senior developers who just want to have a laugh when someone makes the monumental blunders I will no doubt make over this series.
Right now, I have no code in mind. There are decisions I have not taken. All I have is an initial set of requirements that I will soon be describing in this introductory article. As a solo development, this is not going to follow methodologies such as Agile or Waterfall development; the development I will be doing would more likely aligned with Agile but I don’t have the need to follow the methodologies.
Normally, when I write articles, I tend to write using the third person so I make things more inclusive. I’m not going to do that in this series because the whole point is that you “hear” my thought processes.
I will have to warn you that these articles will have a lot more text than code. I’m going to be explaining why I have made certain decisions and there will probably be a lot of refactoring that means I’ll have to explain why I’m doing what I’m doing. Obviously, I’m not a blank slate so that means that there will be a lot of assumed knowledge; things I’ve done before that I instinctively reach for and I apologise now, but that is going to happen. When I do something like this, I’ll attempt to address that by explaining it or linking off to other sources that explain it well. There may be occasions where I miss this so if you encounter this, please leave me a comment and I’ll attempt to address it.
Right now, the only things I have in mind are my high-level requirements and the language I’m initially going to use in the development. Let’s get those committed to "paper" and start the process rolling.
What We Are Going to Build
I build a lot of RESTful APIs. This means that I spend a lot of time testing them. I use Postman and Swagger an awful lot but these have their limitations. If you’ve not used Swagger, it’s used with REST APIs a lot as a way to test them using a visual interface (okay, Swagger does a lot more, but for the purposes of what we’re going to be building, we’re concentrating on this aspect of it). Similarly, Postman is a third-party tool that allows us to write requests to APIs from an editor, and receive responses. In order to use Swagger, the code has to be embedded in the API. If it’s not embedded, you can’t use it. While I like Postman, I find that, as the day progresses, it has a tendency to slow down, and the interface freezes. So, from this, I have the following requirements and constraints:
- I want an application that will allow me to send requests to APIs.
- Initially, the requests I want to send are
- The requests can have request headers
- The requests can have request bodies and/or parameters
- The application will receive responses from the APIs
- The responses will be decoded
- The language I will be developing the request/response code in is C#
- I will be using .NET 5 as a minimum for the development
While I use Visual Studio and JetBrains Rider for C# development, this could all be accomplished using editors such as Visual Studio Code, so I will show some of the dotnet commands alongside the development. In coming sections, we see how the dotnet commands can be used by people who don’t want to use an IDE such as Rider or Visual Studio, as well as adding files to aid those who do want to use the IDE.
This series consists of the following articles:
It may seem daft, but one of the first decisions I have to take here is what am I going to call this application? Do I need my code solution name to match the ultimate name of the application? At the back of my mind, I have the idea that I want the name to be based on the word Excelsior purely because I have a fondness for the late great Stan Lee and this was the word he adopted as his motto. I’m going to give the word a little bit of “funk” so I’m going to change this to xlcr (phonetically EX EL CEE AR). This project is going to be accessible in Github so I need to check that this is not in use there.
Wow, that sucks. Someone has already claimed xlcr in github so I need to go back and revisit the product name. My next thought moves to the fact that I have occasionally used a “whimsical” name of Goldlight with projects; yes, this was a play on the old Silverlight product and tied back to having added a couple of features to help with Silverlight development a long time back, these Silverlight aids were called Goldlight. I have revisited this name over the years so I’m going to name smash them together (and I’m sure Stan Lee would have approved of Smash!) to create Goldlight.Xlcr.
A quick Google check shows that this name is not in use so it’s time for me to create a dotnet solution with this name. I’m going to start by creating a folder for the solution.
The Testing Dilemma
At this point, I have some decisions to make. Am I going to be writing unit tests to go alongside my code? Am I going to be following Test Driven Development? It may seem daft that I’m having to verbalise these questions but, consciously or not, these affect the way we write code. We will most definitely be writing unit tests, to my mind that’s a no-brainer, but the second question requires more thought.
If you’ve not encountered Test Driven Development before, the idea behind it is a simple one – you don’t write any code without writing tests for it beforehand. This seems to be a counterintuitive idea but it’s actually very simple. You write a test that fails. You write the minimal code to make that test pass. You write another test around that code that further refines it, and makes it fail. You refine the code to make it pass, and so on. The idea here is that you are considering tests as an organic part of your development process so you naturally start to consider what could break your code. The beauty of TDD when it is done well is that it can help to make your life a lot easier when you refactor code. In other words, if you change your code to use an improved algorithm, then your tests should give you that safety net that any changes you make still work without unintended side effects.
As I’m agonizing over whether or not to follow TDD with this development, I’m having to weigh up the fact that following this approach could obscure what I’m trying to teach with the articles. The articles could become a tedious repetition of me writing broken test conditions, fixing the tests, writing more broken tests and so on. I’m aware that this could be difficult for you, reading the article. At the same time, I’ve been doing TDD for so long that it’s a natural part of my way of working so I tend to follow it instinctively. What I have to weigh up, against this is the idea that the practice of TDD could obscure the thought processes I’m trying to get across because I’ll end up focusing on small parts of the code and showing how to write tests for it, without it being apparent how these small components fit into the bigger picture.
Ultimately, I think the best compromise will be for me to start developing this series using TDD. If I find that the narrative of the articles is becoming too difficult to follow because of this focus on the tests then I will switch away from that approach. At least, by that point, you will have seen enough of this in action to understand why I’m working this way and you can choose whether or not you want to make this part of your day-to-day development style.
Now that I’ve made the decision to follow TDD, at least for now, I’m going to add a project to add my tests to. So, inside the solution folder, I’m going to add a subfolder for tests and another folder where the actual source will “live”.
But what am I going to write first? What requirements am I going to be satisfying with my first set of tests and code? How will I lay this out in my projects?
Well, the core of the system is about handling requests and responses so I’m going to start by considering the code to send a GET request to an endpoint. This is one of the simplest API requests to build so it’s a great place to start. As the requests live at the core of the system, I’m going to name the project that holds this functionality
goldlight.xlcr.core. Whenever I test a project, I like to name the test project the same, with
.tests at the end. This helps me to see, at a glance, what tests go with what code, so our tests will live inside
goldlight.xlcr.core.tests. I’m going to add a goldlight.xlcr.core folder inside the src folder, and a goldlight.xlcr.core.tests folder inside the tests folder.
Now, inside the goldlight.xlcr.core folder, I’m going to add a class library to hold the core logic. Adding this is as simple as running the following command:
dotnet new classlib --name goldlight.xlcr.core --output src/goldlight.xlcr.core
When I add the class libraries and unit tests, I am using lower case names because I'm mindful of naming conventions in Linux-based environments. As we're targeting .NET Core, I have the idea that I can deploy the applications on none Window environments as well. As we will see later on in this article, this decision does have an impact on the namespaces generated in the code. I will demonstrate how to revert the namespaces to the more common Pascal naming convention of development later on.
I also want to create a unit test project. Out of the box, the dotnet command comes with support for a number of testing frameworks. I like to use xUnit to run tests, so I’m going to use that with the project. The choice of testing framework is an arbitrarily personal one. Some people like to use nUnit, others like to use Visual Studio tests. For me, the syntax of xUnit appeals to me because it just fits with how I see tests.
dotnet new xunit --name goldlight.xlcr.core.tests --output tests/goldlight.xlcr.core.tests
I’m not shipping test code to anyone, so I need to make sure that the unit test project references the class library. To do this, I am going to have to run the following command:
dotnet add reference ..\..\src\goldlight.xlcr.core\goldlight.xlcr.core.csproj
Finally, I want to add a Visual Studio solution file and add these projects so that I can open the code up in Visual Studio or Rider if I want to.
dotnet new sln --name goldlight.xlcr
dotnet sln add src/goldlight.xlcr.core/goldlight.xlcr.core.csproj
dotnet sln add tests/goldlight.xlcr.core.tests/goldlight.xlcr.core.tests.csproj
You may remember that I said that I wanted to upload this project to git. I’m going to let dotnet add an appropriate gitignore file for me so that I don’t attempt to upload bin and obj files.
dotnet new gitignore
Finally, I’m going to restore any nuget packages that have been added, and build the solution:
I’m done with the command line for a while now, so I’m going to start using Rider or Visual Studio for the next steps.
Now that I have created the project and solution, I am ready to start writing the application itself. In the next part, I will start the process of writing the code itself.
- 12th May, 2021: Initial version