Leverage configuration.

Some changes don’t require software rewrites.

If your system makes heavy use of configuration, then when people need to make changes due to business needs, it will sometimes be possible to satisfy those needs without having to write new code. Setting parameters on a control panel is much easier than doing a software implementation and deployment. It also delivers the desired change to the customer much more quickly.

This kind of flexibility grows over time. As you receive more and more requests for various new features, modifications can become options. And then, options can become configurable. Eventually, you will be to control some of the behavior of the system through an administration panel.

Because these changes no longer require a software development lifecycle, they can occur much more quickly, resulting in much happier customers.

If you embrace this idea from the beginning, you will acquire more configurable options. You will also add them to the system earlier. Having more configuration options frees up developers to work on more complex issues and makes for faster delivery of the enhanced product to your customers.

Write a story.

Use cases should tell an interesting narrative.

When writing tests that describe a system’s behavior, you should gather them together in a way so that they tell a story.

Individual tests follow the basic rules of storytelling. Starting with a beginning, the author describes the setup of initial variables and conditions. Establish the context of the story. Why is the user here, and what is he trying to accomplish?

In the middle of the tale, the author explains how people will use the software. The story reveals its dramatic points as the main event occurs. The test script exercises the applications in the story.

The end shows the final condition. The script compares the results to expected values. Did the story have a happy ending?

You can describe the three parts of a test in such a way so that they tell a consistent story. Then, you can gather several small stories (individual tests) together to define a larger narrative. Writing tests in this way is not only more interesting, but it also leads to a more descriptive representation of actual business cases.

Avoid the agony of copypasta.

Problems are replicated when code is copied.

Copying and pasting code is a rookie move. The temptation is great, as new developers search the web for solutions to their problems and end up copying some code they saw posted on StackOverflow. Or maybe they simply copy routines to various parts of the application as they need it.

Ultimately this can lead to performance and security problems. As the software gets improved and extended over time, not all copies are likely to be updated because the person making the changes may be unaware that a section of code has been copied multiple times. As a result, each different version of the code section will start to exhibit different behavior. This problem can hide some challenging bugs.

For these and other reasons, one should endeavor to reduce code duplication. Fortunately, there are tools to help identify duplicate code, and you should use them. Even better is to refactor the code and separate out concerns. As you move logic to appropriate helper and utility classes, it becomes more evident that a particular tool can be used in multiple parts of the code, replacing code copies with calls to a single implementation of the class.

My Goals for 2021

It’s that time of year. Time to reflect upon 2020, and more importantly, set goals for 2021.

So. What can I say? 2020 was a crazy year. It certainly didn’t go down the way I expected. On the downside, I lost my job. Still haven’t found a new one, either, after almost three months of searching. It’s really hard to find work when you’re my age and you’re competing with people nationwide. People say I have an impressive resume and background, yet most of the time, I don’t even get an interview.

On the bright side, though, I stayed healthy all year long. Even lost a lot of weight. And being out of work gave me time to work on some of my goals and side projects. Plus, the stock market has been very kind to my portfolio. This is truly amazing since it looked like the end of the world back in March.

Bitcoin rallied last year, setting new all-time highs. It started the year around $7,200 and rose to $29,000 by the end of the year. Yes, that’s 300% – a 4x increase. Ethereum was up even more. The altcoins were garbage in comparison. It seems the smart money (institutional investors) have discovered bitcoin finally, and now it’s on its big march up. I think bitcoin could go over $500k in the long term.

I spent most of the year at home, thanks to Covid-19. This didn’t really bother me much. Working remotely was quite comfortable, and I loved not having a commute. I did miss going on vacation, though, or being able to travel in general.

Last year I set 10 personal goals. Here’s how I did on each of them.

Write 4 short stories. After taking a Udemy course in finding time to write, I finally adopted a system that works for me. Also, being unemployed, I had time to try new things. By the end of the year, I had my four shorts done. Actually, I wrote five.

Write 24 blog posts. There was some demand from former employees to see “Today’s Card.” This was something I would talk about each day, presenting the topic of the day and talking about it during standup. So, during the year, I made blog posts for each and every card I had, over 200 of them. Also, I migrated off of Medium and on to WordPress. Medium was not adding any value to me. WordPress is better, but I find the service to be a bit limiting at times, so it wouldn’t surprise me if I decide to migrate again at some point. So yes, well over 24 posts.

Make new friends. Once again, I found this hard to do. But I did add one, at least.

Complete 4 online courses in new technology. I completed two courses on AWS and achieved my AWS Solutions Architect certification. I also did a course on Alexa and another on blockchain technology.

Catch up on periodicals. Once again, I failed at this. However, by December, I had started a plan to achieve this in 2021. Hopefully, I will wrap it up this year.

Develop some kind of exercise habit and lose more weight. The weight came off automatically this year as I was making lunch at home instead of eating out due to the pandemic. By the end of the year, I had started a new exercise routine. It was also part of my new writing routine.

Gain 15% on my portfolio. Early in the year, I thought this might be an impossible goal. Then the market crashed in March, and I made a few investments. I really wish I had put a lot more money to work in March, but it was a scary time, and I felt like we were entering a new great depression. By the end of the year, however, the market was full into bubble mode.

Read 25 books. Throughout the year, I regularly read books every night. I finished 27 books last year. I really enjoy reading and try to mix it up with a combination of business books and fiction novels.

Sell or donate more old stuff. This didn’t happen. Donations are problematic due to the pandemic, and I didn’t make much headway on clearing the clutter.

Take two vacation trips. The pandemic pretty much killed all travel.

So, I succeeded in six out of ten. Not bad, but not great, either.

For 2021, I’m will have a similar set of goals but maybe adjust them somewhat.

Write 4 longer short stories. This will require sticking with the writing habit throughout the year but should be achievable now that I have a system. Longer-term, I’d like to get going on the first novel.

Complete six short online courses and two longer online courses. I need to continue with my educating myself and improving my skills. Courses may be about development, writing, blockchain… the important thing is to keep learning.

Make new friends. I still don’t have a plan for this. I need to expand my social circle somehow, though.

Catch up on periodicals. This will be the year that I catch up on these things.

Read 25 books. I already know what half of them will be.

Maintain my exercise habit, a healthy diet, and lose more weight. Really, if I just keep doing what I’m doing, this should happen automatically.

Gain 15% on my portfolio. Each year I shoot for 15%. Anything past that is gravy. After succeeding a few years in a row, it may be hard to do it again. Still, I’m going to try.

Sell, donate, or dispose of three shelves’ worth of old stuff. Maybe with a quantity goal, I’ll have a better shot at it? I need to reduce clutter and do away with old stuff I’ll likely never use again.

Take two vacation trips. Maybe I won’t get to go on a cruise or visit my favorite resort. Perhaps it’ll have to be a road trip to see mountains or something completely different.

Achieve gainful employment. Meaning a job where I’m making money, not just volunteering my services.

So those are my 10 personal goals for 2021. It should be an interesting year.

Follow the example.

It pays to write good examples.

As you deal with reviewing software and comparing the results to realistic business scenarios, you will start to collect a series of example situations. These examples address many “what if” questions that come up as people learn how the system should behave under various conditions. A good practice is to document these examples into the tests that cover the code.

When it comes time to refactor the code or add new functionality to the system, it will be quite beneficial to have these examples in place. With the expected behavior modeled in tests, you can be more confident that any change to the software still meets the requirements of all of the examples that have been documented so far.

Although writing tests for each example may be a significant amount of work, the benefits of being confident about the quality of the product are enormous. It’s certainly worth the effort. If you can’t be bothered to write tests, you can’t be trusted to refactor the code.

Be sure to find examples that cover the edge cases. It’s quite common for an incorrect algorithm to appear to function for ordinary data but get the wrong result in certain edge conditions.

Tighten your loops.

For performance and simplicity.

If a calculation does not depend on things inside the loop, you should ensure it happens before the loop. There are two reasons for this: simplicity and performance.

By extracting out concerns that don’t belong inside the loop to the outside, one can more easily identify them as belonging to the initialization or the iteration. Expanding and debugging programs is more straightforward for people unfamiliar with your code if you have made these things as clear as possible.

You can also improve performance by having as little logic inside the loop as possible. Performance generally should only be a concern if the program will run the loop a significant number of times; otherwise, you’ll just end up saving milliseconds that no one will notice.

Also, please move the stuff in the loop to a different method. That method should have minimal dependencies. This change will significantly reduce your method’s size and move the computation inside the loop to a separate concern.

Simplify your iterators. There are techniques where the iterator can be refactored out and take the loop calculation as a block argument. This approach is beneficial when your iterators appear several times in the code.

It’s a UNIX system, I know this.

You should learn the UNIX tools.

The UNIX operating system consists of dozens of small, simple commands. Each of these commands is a program in its own right. Almost all of them can take a stream of data as an input and deliver a stream of data as an output, performing different kinds of data processing transformation.

By chaining together a few of these commands, you can accomplish a lot. Similar to building blocks, you can assemble them in endless ways. The output of one command becomes the input for the next, using the pipe symbol to connect them.

For example, suppose you have a file with a list of names, and you want to find out what the top 3 most common first names are in the file. The string of UNIX commands could look like this:

cat names.txt | cut -f1 -d' '| sort|uniq -c| sort -nr| head -3

Here is the breakdown of these commands:

  • cat names.txt opens the names.txt file and sends it to standard output.
  • cut -f1 -d’ ‘strips out everything but the first field, using a space as the delimiter. The output now has only the first names.
  • sort will rearrange the names in order.
  • uniq -c gives a list of the unique names and their count.
  • sort -nr sorts again, this time using treating the first field as a number, and sorts in reverse (largest number first).
  • head -3 stops the output after 3 rows.

Some of the more obscure UNIX commands can do amazing things. One should explore them and learn their capabilities.

You can extend these ideas to programming as well. Take the objects returned from one class’s methods and use them as inputs to methods in another class.

Beware the singleton pattern.

It’s often misunderstood.

The singleton pattern is a standard programming technique where the program can only instantiate a class once. Typically it is used when an object needs to coordinate actions across a system. State objects, factories, builders, and other types of objects take advantage of the singleton pattern. For example, you only need one factory, and your software uses that factory to generate instances of other objects.

There are times when a singleton is not the best choice, however. Some programmers tend to reach for this tool too often or at the wrong times. Thus, it would be best if you used it with caution.

In some cases, a single-instance requirement may be pure speculation that you will not need additional instances in the future. Unless the requirement (whether from the business or the system designer) explicitly calls out for a single instance, you shouldn’t use the singleton pattern.

The singleton pattern can cause dependencies between conceptually independent units of code. Because everything that interacts with the singleton can change its state, anything dependent on that state could be affected. As a result, you may have two objects that really should have nothing to do with each other suddenly become dependent concerns.

Using a singleton can also be a lazy way to implement global variables. These variables may not need to be global in scope. As the scope of a variable should be as limited as possible, singletons can break this guideline and lead to trouble.

Some people have even gone so far as to label the singleton an “antipattern,” but that is a bit extreme. You simply need to use caution when proceeding with singletons.

Look for the right behavior.

Test for required behavior, not the specific implementation.

When creating tests, make sure you test for the system’s expected behavior and not merely validate a specific implementation. There are many different ways one can get to the correct behavior. Implementation details may change over time, invaliding tests in the future.

For example, sort functions require the comparator to be negative, zero, or positive. Developers frequently implement the function to return -1, 0, and +1. If you set your tests to look for -1, 0, +1, you are testing the implementation, not the required behavior. In this case, the required behavior may be that an array of data objects gets sorted in a certain way.

A later implementation may have the comparator return the difference between two attributes of an object. Although this is valid and would result in the correct behavior, the tests would fail because they are expecting -1, 0, and +1. A better test would have some unsorted sample data, run the sort, and compare the result against the expected sort order.

Code with friends.

Don’t work in isolation.

You can be better if your friends make you better.

When you work alone, you are much less likely to learn new techniques and develop better habits. Often, developers that tackle projects by themselves lack knowledge of best practices. Also, they usually have lower quality standards because they only have to answer to themselves when doing refactoring.

On the other hand, a group of developers from various backgrounds can draw upon a much deeper collective pool of knowledge. If these developers work together and do some rigorous code reviews, there will be much more sharing of good ideas. Best practices from across the industry are more likely to spread when people work together and compare notes.

Solo developers tend to work on simple freelancing projects building basic websites that don’t integrate with other systems very much. Team developers are more likely to collaborate on larger, enterprise-level applications. To work on these larger systems requires a much broader skill set, and developers learn many of these skills by working in a friendly, collaborative environment.