Having covered recording knowledge in the previous week, and specifically considering the conclusion I arrived at, it was only logical to cover the Breakable Toys pattern next. For those who missed that post, I determined that the best method to keep track of previous knowledge was to use a breakable toy that others could access. This would allow one to both record any information, create a potential feedback loop if others can access this information, and finally just get experience by building and maintaining this toy. But this all begs the question, what exactly is a breakable tool?
These toys can come in a variety of forms that can be decided based on your own interests, but each should be a software project that you will complete on your own. This can range from a wiki or a blog to a calendar or even a video game, but there are some important points to keep in mind about the purpose of these toys. Of course these toys will be helpful in your growth as a software developer, but in order to reach a sufficient level of development on these projects you must maintain your motivation. When choosing a breakable tool to create, ensure that it is something that you know you will enjoy developing further down the line. This may sound obvious, but there are many times where I myself have dropped projects after the initial excitement dies down. Furthermore these toys do not have to be complex, especially at the outset of their development. While it might be tempting to have a vast amount of features to implement in this new project, and it may come from a place of genuine wanting to learn how these work, you should keep in mind that this toy can be developed over a long period of time. Focus first on developing the toy in its most basic form and slowly build on it as your development skill progress, allowing for even further growth.
In summary, these breakable tools should be personal projects in any form that interests you and should be something you return to for further development. This pattern has changed my view from what I said in my previous post, as I was initially going to make a wiki or blog. If I am being honest with myself, making a game appeals to me more than many of the other options for tools that I had listed. I have been playing them for a long time and have always had interest in developing one, especially working on an AI system within the game. Once again I had nothing to disagree with, this was a great read!
As stated in my previous post, I did a group honors project where each member covered a different software testing tool. The primary reason for this was to determine which tools were useful for what purpose, one of which, being Jacoco, I covered in the previous post as well. But, after having heard each group member’s analysis of their tools it begged the question, which tool is best? To properly discuss this I will be examining the pros and cons to each of the tools my group member’s covered in addition to a brief summary of Jacoco.
First there is PIT, which is a mutation testing tool. I was not familiar with these different types of tests, so I will give a quick explanation of what they are. Mutation testing involves the tool essentially making multiple copies of the code which are then given faults, these being the titular mutations. Tests are then run against each mutant with the result being the mutant’s death, meaning the tests failed, or the mutant surviving, meaning the tests passed. The quality of these tests is then determined by the amount of mutants that could be killed. This method of testing is very robust and covers code coverage as well, but this results in these tests being slower than others. PIT is advantageous as it is the fastest of the mutation tests, and has a lot of support from build tools. The other type of testing covered was Programming Mistake Detector, or PMD for short. This tool focuses on finding more expected flaws, like unused variables, useless objects, empty catch blocks, and other such errors we are all familiar with. In addition to this it can also spot any duplicated code with a copy-paste-detector. This is all handled by rules used to test source code, which are grouped into rule sets. Unlike mutation tests, this is much more lightweight and easy to run from a command line, additionally you can run multiple rulesets at once. However this is a less robust testing method, not accounting for any runtime issues or a way to match a ruleset with its generated error easily when running rulesets on a file. So what is the verdict?
Ultimately, there is only really one type of testing that seems sufficient to be used in and of itself, this being mutation testing with PIT. If you are looking for the most condensed testing tool that can do the most in one package, this would be the answer. However you will want to ensure that using mutation testing is necessary, as if you are only really concerned about code coverage Jacoco would be easier and more efficient. Simultaneously, if you want to check the code itself to ensure there are not many errors and do not care about the coverage, you can implement PMD. The answer will ultimately vary from system to system, and if you want to read more about these tools I have provided some resources below. If you want to read about Jacoco be sure to check my previous post!
Yet another post, yet another shockingly related issue addressed by these patterns. The pattern for this week being Record What You Learn, something that is particularly relevant with online learning being the primary method of schooling for most. I have found that, throughout my classes, I have forgotten a significant amount of the minutiae for some of the older projects I have worked on, or even some coding languages I have learned. One way to solve this issue would have been to have a more defined method of documenting what I have learned and worked on, and this pattern has given me some ideas of how to do this.
With a problem as general as this, there are a variety of solutions one can implement. There is the most obvious method of doing this, being to keep a blog about what you learned. The benefits of this are straightforward, as it not only allows you to keep track of any important information, but also allows others to view it. Not only can this help others who are encountering similar problems, it allows others to provide any knowledge they have gained with you. This creates a feedback loop and will undoubtedly aid in remembering this information, as you can also implement changes to any blog posts based on feedback. While this is certainly an effective method, it is not my favorite and keeping a private wiki seems more appealing to me. This, however, has the downside of losing that feedback loop, as it is purely for your own use and maintenance. The option that appealed most to me was to meak a breakable tool that can be used for the record keeping. This allows you to not only record, and potentially share based on the nature of the tool, information learnt but also learn more through the process of utilizing the tool itself.
Everything said in the pattern sounded reasonable to me once again, so nothing to disagree with. If you cannot maintain your knowledge on the subjects you learn, it will slowly decay, so this must be offset. I have realized that, to truly learn this new information, you have to continually engage with it in some manner. Be it through a thoroughly maintained blog or breakable tool, this is the way to retain the learnt knowledge.
For this week’s blog post I chose to focus on a topic that I had to research for an honors project, this being Jacoco. In case you are not familiar with it, Jacoco is a software tool that is used to test code coverage, which in short just involves checking how much of a system’s code is being tested. This may sound redundant if you, like myself, have only really been using tests on small scale projects, but as a program’s complexity increases so does the complexity of the tests required. Additionally you will have to write more and more tests, making it difficult to determine exactly what has been covered. Before anything else however, I am going to break down exactly how code coverage is checked.
Having not known about Jacoco at all, I found this article on Baeldung that was extremely useful in understanding how it worked. As I stated the essential idea is to check code coverage, which consists of line and branch coverage. Line coverage essentially means Jacoco will check how many lines of code are being executed during tests to determine which are actually being tested. Branch coverages is similar to this, but focuses on checking the logical splits in the program, such as conditionals like if statements. The total amount of branches present is then compared to the amount that were covered to give the results. There is one more aspect of a program Jacoco checks for, being cyclomatic complexity. This is essentially a measure of the logical complexity of the program, or how many branches the program has. Now that we know what Jacoco is we can discuss why you might want to use it.
This testing tool certainly has some major benefits for anyone working on a large system. If you are working on writing tests for a system, it may begin as something straightforward, but as the system grows it will become increasingly hard to track exactly what components are being tested. This is where Jacoco comes in, allowing you to see exactly what lines, or just classes, are being tested so you can ensure there is sufficient test coverage. Additionally it can show you the degree of logical complexity present in the system, which could then be adjusted accordingly. One point to keep in mind that is mention in this article is that you should not get tunnel vision when trying to increase code coverage. High code coverage does not necessarily mean the tests being run are adequately testing the system. It is more important to focus on writing a few functional tests for each component rather than just having a plethora of tests that do not really do much of value. This article discusses Jacoco in more detail than I can so if this interests you I would recommend checking it out!
I am once again impressed with the relevance of these patterns, covering many issues that I have been struggling with recently. For this week I chose to focus on the Your First Language pattern. This might sound strange, as I am a senior and at the end of a pretty significant part of my journey as a software engineer, and yet I feel as though I have yet to become an expert on any particular aspect of programming. In terms of programming languages, I have found myself vaguely utilizing many without fully understanding how they work. This is exactly the issue discussed in the pattern.
This pattern focuses on a few different tips for learning a new language well. After choosing a language to focus on this pattern advises you to focus on creating a useful feedback loop with whatever type of work you are doing. This can be through a variety of methods, being finding existing communities of practice online or someone you know who is an expert themselves. As for how to learn the language, there are a few different methods recommended. The overarching method is to have a specific problem to solve rather than just solving small examples present online and in books. I have often ran into this exact situation myself, finding my initial excitement in learning a new language stopped abruptly by some frustrating example problem that has little relevance to what I want to do with the language. Instead, what is recommended is to think of a larger problem you would like to solve with a program. Starting from this very general level try to break it down into smaller components and, after getting to the most basic component to work on, start from there.
Personally I once again had little to disagree with. I have realized that learning new languages seems to be a critical skill for software developers, as there is such a variety available. Each language generally has its own advantages and disadvantages, with some having specific use cases, like html for web design. Thus it is important to know how to go about successfully learning a new one, as it is its own little road on your greater path to becoming a software developer.
It probably goes without saying, but this sprint certainly seemed more effective than the first. This is essentially a given, as a good portion of the first sprint consisted of figuring out how to work within my team in addition to adjusting to the teams shifting around a bit. After this, I feel as though we were able to accomplish everything we set out to, and a little more in some circumstances. Though this sprint certainly was not entirely bereft of some issues, at least with my own contributions to the team. Other than these though, I am satisfied with how this sprint went.
After adjusting to being embedded into the InventorySystem team, the sprint went very smoothly. Initially I had some difficulties being in a community of practice and the team, not really knowing if I should be meeting with others from my COP. We ended up establishing some meeting times and help each other with some parts of Keycloak. We were able to find a method of connecting our mock frontend app to keycloak, in addition to developing a logout function. Additionally, both Keycloak and the mock frontend app were containerized in docker. These were the major issues that I had focused on this sprint and all were effectively completed. Beyond myself, the InventorySystem seemed to accomplish many of the issues, with the exception of maybe one or two, that were posted for this sprint. One part that I felt did not go entirely well was how exactly I could help out the InventorySystem team. It might have just been the nature of the issues I had involving just using Keycloak, but I was concerned that I could have been helping them more in some way. Other than this there were no real issues that I could think of.
Despite the overall success of this sprint, there are a few more thing that I personally feel could change to improve the next sprint. I should clarify that these changes are entirely with myself, the first of which being what I felt was my own lack of participation in the InventoryTeam’s issues. I did not feel like I involved myself enough, this is also the reason why I cannot really speak on how the team can improve. As for changes I can make, I will simply try to involve myself a bit more, if not through taking up some of their issues then just through communicating more. I will try and ask where they are at throughout the sprint so I am more aware of what is happening and, ultimately, when I will be implementing Keycloak into the system. Additionally, I still had some struggles balancing my work for this class with some others, but I have been working on improving this for the next sprint. I have been sticking to the time I have set aside for working on schoolwork and have, at least, kept up. In conclusion, I am very pleased with my current progress going into sprint 3 and am excited to finally finish implementing Keycloak into a system!
Practicing is yet another aspect of software development that I have had issues with in the past. Personally, I find that whenever I bring myself to start some personal project with the goal being to practice programming I find that I simply have too much to do or what I am practicing feels too tailored to this specific practice program. Now that I am coming to the foreseeable end of my time in school, where these practice opportunities are essentially the focus, this issue has been weighing on my mind more and more. Thus, for this post chose to focus on the practice, practice, practice pattern.
Yet again I found myself really enjoying these patterns, as they felt very relatable. This was another insightful read, as I really did not have a set way to effectively practice in mind. I really enjoy the idea of katas that was brought up, which are simpler, but still somewhat challenging, exercises you repeat to try and hone a certain skill. In the case of programming, this can come in the form of working through some older books, as stated in the pattern. The idea of dodjos for programming also sounded enticing, as one issue I found with practicing on my own is a lack of feedback on what I produce. Solo practice is still effective to some extent, but I often find myself wondering if what I am doing is an effective way of solving the problem, or if anyone has devised a better one. This is the exact problem that a dojo addresses and is something I might have to take advantage of in the future!
This pattern has not really changed the way I view software development, at least in terms of practice. This is because I did not have a clear view of how to practice effectively in the first place. I have now been provided this new way of approaching practice that sounds both more engaging and effective than anything I could devise. I now understand that my practice session must involve short, challenging exercises and I must use others as a resource to compare my results and, ultimately, learn. I don’t really have much to disagree with but I did decide that I probably would not use those extremely old books for practice. As exciting as it would be to understand that older knowledge, I have more immediate things to learn.
For this first blog post I chose a pattern that focuses on something I have struggled with on and off almost every semester, this being motivation. I am usually very gung-ho when beginning any sort of programming class, or personal project, but eventually I find that I just get completely buried. This can be for a variety of reasons, being other schoolwork or simply getting lost trying to solve increasingly more complex issues, but it happens consistently enough to be concerning. After reading this however, I do have some ideas for ways to try and cope with this should, or more accurately when, I get stuck in this rut once again.
Personally, I found this pattern to be very helpful, as it resonated quite well with me. I have been getting frustrated with a lot of my recent work, as it is all in relatively new languages I only have a vague grasp on, but I now realize what these are. As stated in the pattern, you have to set aside what you are comfortable with in order to grow, and these states of remaining in your comfort zone are classified as Golden Locks. I just have to understand that a part of the journey to becoming a master in this craft is resisting the urge to remain where I am, in terms of my knowledge. Beyond this, all of the examples used in the pattern felt very relevant and did a sufficient job at helping me relate to what the author was trying to convey.
I would certainly like to say that this pattern will have some effect on the way I think about software engineering. I have realized and acknowledge my issue with my motivation, being that I am simply on the road to mastery and must keep in mind that everything I am struggling through is just a part of that process. I cannot just retreat back into only really caring about Java, I have to continue working with these new languages as I encounter opportunities to learn them, otherwise my career, and most likely my passion, will stagnate. Maybe this is due to a lack of experience, but I did not find myself disagreeing with anything said in this pattern really, it was a good read!
This week’s post is yet again about unit testing, but this time focuses on a much more broad question. After spending the past two posts trying to determine exactly what unit test and the variety of patterns available it is only natural that this next post focuses on how to write the tests well. As someone who personally has not written many, I can acknowledge that there may be some best practices I am not aware. Thus for this week’s post I am going to discuss another blog post, this one by Sergey Kolodiy, that goes into how to write a good unit test.
So how do you write a good unit test? Conveniently enough Sergey has compiled some principles, which are that the tests be easy to write, readable, reliable, fast, and truly unit, not integration. Easy to write and readable are pretty straightforward, and go hand in hand, as both just mean the tests should be easy to implement to cover lots of different cases and the output of the tests should easily identify problems. As for being reliable this means the tests must be giving the correct output, in addition to actually detecting bugs rather than just passing. Sergey also brings up a good reason for keeping the tests fast, being that lazy developers might skip the tests if they take too long. Finally there is the truly unit, not integration principle, which sounds more complex than it is. This simply means that the unit test and system should not access any external data or resources, such as a database or network, which will ensure that the code itself is working. Sergey chooses to focus on another very important part of writing good unit tests after this.
The rest of this blog revolves around discussing writing testable code as a good unit testing principle. He states a plethora of examples to show some bad practices, such as using non-deterministic factors. To clarify, this means some variable in a method that can have different values every time it is run; the example he uses helps put this into perspective more effectively. The original purpose of this post was simply to discuss writing the tests themselves, so I do not want to stray too much. I just wanted to mention this part, as it is interesting! If you want to learn more check out the link below.
Now that we have a good base understanding of unit tests we can dive a little deeper into the subject. When reading through the previous blog I saw mentions of different types of unit tests and my interest was piqued. From past examples I had seen, I assumed all of these tests followed the same format. Thus for this week’s post I wanted to discuss the different types of unit tests, as I only just learned that there were multiple. To aid in this I found a blog post from a programmer named Jonathan Turner who clarifies what each type is.
This blog post identifies three major types of unit tests, these being arrange-act-assert, one act, many assertions and finally test cases. The arrange-act-assert format is the more traditional method of unit testing and the one that most people are probably familiar with. This format involves setting up the conditions for the test, running the code with the test conditions, and subsequently examining the results of the test. As for the one act, many assertions pattern it uses the same basic setup as the previous pattern, but differs in having multiple assertions about the code at the end of the test. Finally there is the test cases patterns, which takes a different approach than the other two by using a collection of many inputs to check their respective outputs. Now that we understand what each of these patterns are we can discuss their advantages.
Each of these tests have their own use cases where they will be most efficient. The arrange-act-assert pattern is the traditional method and, thus, the most straightforward to implement. This pattern should mostly be used for testing specific conditions or situations of a certain system. The one act, many assertions pattern is best used when you have code that has different sections that each act independent of each other. To clarify, use this if testing a method that has multiple blocks of code that do not affect each other, but must each be validated. Finally, the test cases method is very advantageous if you have a program that has a wide span of input output values. This could be one implementing an algorithm that converts values; the blog post gives a very good example. I hope that this post gave you a glimpse into the variety of unit tests available and would recommend checking out the blog post by Jonathan Turner for further information.