Almost any young programmer’s first programs look the same. 1. 2. This is all well and good in the beginning, however, non-descriptive variable names pose an issue as time goes on. When your programs get more complex and you work in teams, naming conventions become incredibly important. A lack of naming conventions decreases code clarity […]
Students often focus on code with a singular program as the goal. However, there are many different software architectures to consider based on the scope and specifications of a software. The article linked below gave a detailed comparison of two major architectures types: monolithic and microservices. A monolithic architecture is like the all-in-one software solution. […]
Understanding Versioning: SemVer vs. CalVer Most software, libraries, games, etc… will come with a version number attached. Often times, it is easy to just gloss over this and not pay much attention, however that number can reveal important information. The article linked below compares 2 types of versioning you may encounter. Semantic Versioning (SemVer) – […]
This semester, we spent plenty of time learning about and discussing Agile and Scrum. We learned about the framework and how it can be implemented in teams, as well as the performance advantages of teams that use it. However, just as not every tool is right for every job, it is just as important to […]
One of the incredibly positive aspects of the software development community is the general spirit of collaboration. This is particularly true within the open source software community. Paired with the fact that anyone can maintain a project/portfolio on GitHub, there is a lot of code out there. I would argue that this is a good […]
I will admit, learning Git is…unpleasant? A headache? Baffling? Rage-inducing? I, for one, do not enjoy trying to untangle the mess when Git goes off the rails. In fact, I have on a few different occasions decided that it would be more worth my time to redo all my work for a project/assignment than spending […]
In software development, code smells are subtle yet significant indicators of potential problems within a codebase. Much like how an unpleasant odor hints at deeper issues, code smells signal areas in the code that might lead to bigger challenges if left unaddressed. The article linked below is exploration of this concept, highlighting the importance of […]
YAGNI – You aren’t going to need it. In the simplest terms, the principle (initially created by Ron Jefferies) means don’t overengineer before it is necessary. It means to find the solution that works for what is needed today without engineering for POTENTIAL future scenarios. Outside of software engineering, this principle is applicable to everyday […]
Test Driven Development….it admittedly feels a bit tedious to properly execute. …painful might be a more accurate descriptor.
I am a big picture thinker. I am very good at looking at the end goal and seeing the broad-strokes path to get there. This means that I am most comfortable solving problems in (what I thought were normally-sized) chunks of logic. However, TDD is the opposite of how I am most comfortable approaching problems. TDD requires building a solution in the smallest chunks possible from the ground up. To properly execute it, sometimes you return a fixed value to get a green test rather than do the math. All I can keep thinking is how on earth is typing [return 1] better than [return a+b] when I am going to have to fix it in 3 minutes anyway??
However, despite the pains of execution, I do see that it can be an effective development model when applied in the correct situations.
According to NCrunch, those situations are as follows:
Pure Logic functions
A clearly defined set of inputs/outputs
When defining layers within an application
Likewise, you should AVOID using TDD if….
Your existing code doesn’t have any tests implemented already
It is already working
I would also like to add to the list that coding in an exploratory context is not a suitable scenario for TDD. As a student, I often use coding as a medium to work through problems, test different solutions to problems and just explore topics (for example, writing code to draw fractals and messing with it to get a better grasp of how they work). In these types of scenarios, it would be largely a waste of time to take a TDD approach.
Seeing the appropriate times to implement TDD spelled out alleviated a lot of my frustration at the process, as it changed my impression of what TDD was. It was my impression that TDD must be used throughout the entire development process. Although there are some very passionate developers who would live and die by it, I now see it as a tool that can be used when it is needed.
Additionally, I loved the suggestion to look for places to use TDD. Due to my aforementioned gripes with the process, I don’t see myself jumping to implement it on all my projects. However, I do think I would like to integrate it as part of my development process. (i.e. I see a lot of value in implementing TDD to create a particular method that does a complex calculation or that modifies a string.) The guidelines above will serve as an effective starting point in assessing when implementing TDD would be the best path forward.
Mocking is a technique used in software testing where you create a simulated version (a mock) of an object or component to mimic its behavior. This aids in test isolation, faster tests and allows tests to focus in on the targeted part of the system.
In my limited experience with mocking, I have not yet used it to reference anything external to the program I was building. My initial thoughts on it were that mocking seemed like it would be a viable tool to use to circumvent some of the complexity of dealing with external references. After reading the blog post, it became clear exactly why that was wrong.
In the simplest terms “Don’t mock what you don’t own” means what it sounds like: when you are writing tests, don’t mock anything that you don’t have complete ownership of. This applies to third party libraries and external systems.
Why, you may ask?
You don’t own the code, so there is no guarantee about how it will behave in the future. Therefore, mocking it leads to test fragility.
Code clarity. When you mock external references it forces you to handle the behavior of it, when your focus should be on the behavior of the application you are working on.
Tight coupling. The tests become tightly bound to external code and the system becomes harder to maintain over time.
What should you do instead? Create a wrapper around the third-party code, then mock the wrapper
I found the proposed solution of wrapping the external “thing” and then mocking the wrapper to be a rather elegant solution. This avoids a lot of the coding gymnastics that would be necessary to maintain the “external” mocks. The author of the blog post made a good point, mocking external object creates faster tests, but fast isn’t enough to justify test fragility and poor tests. This sparked the line of thinking “What is the goal of this tool (mocking) and how does using it in this way align with that?” This was a new thought process for me. Up until this point in my education, most things I have learned took the form of “Here’s a new thing you can do, now do it”. This new thought process adds to that the important layer of discernment over my toolbox of skills. Afterall, you can (in theory) hammer a nail with a screwdriver if you hit it enough times, but you will get some funny looks, and your life would be much easier if you had just chosen a hammer. In my work, I will be certain to keep this in the forefront of my mind.
TLDR: Only mock code that you own and choose your tool wisely.