Speaking into a microphone

Work

On Tuesday I did something new for the first time. And I feel like I failed miserably. I hosted a webinar. Back in the beginning of the year, I sent out proposals to a bunch of conferences with the goal of giving a talk. A conference by NAGW (National Association of Government Web professionals) accepted my submission. I was supposed to give a talk in Utah in September. Due to calendar issues I had to cancel that appearance. So they asked me whether I was up for giving the talk as a webinar to their audience, which I happily agreed to.

Turns out I need people with faces in front of me! Once the time came to start the webinar I was so excited/anxious that I was barely able to keep my breath down. It almost felt like a small panic attack. I don’t know how it came across to the listeners (it was audio-only) but I felt like I could hardly talk or speak. Which made me speak so unbelievably fast that I went through the whole material in half the time it usually takes me. And I bet I forgot a whole lot of things that I should have said. I do know that I am excited and nervous every time I start a talk in front of a crowd of people. But usually this nervousness fades after 3-5 minutes, once I scanned the room and felt the (positive) reactions of the crowd. After all, your listeners want you to “succeed” and give a great talk. But I had nothing of that during the webinar. I had no reassurance that people actually understood what I was talking about. In any case that felt bad. I learned something from that experience. The first reaction was to never give a webinar again. The second experience was that I need to have a different setup next time. I need to interact with people and for that I will try to use the chat-tool that every webinar software offers. I don’t know how well that works, but I will do what works for me almost always: Be frank and open and tell the audience about my anxiousness and let me help them through their interaction in the chat. It think that’s at least worth a try before abandoning webinars altogether.

August has started and it’s the last month at my current client. This means that I will begin to do a lot more pairing with the permanent developers, and less writing features/code myself. This way knowledge transfer is increased and the company and the people get more out of it. This will be more demanding than the months before, but it’s worth it.

If you’ve been part of this newsletter community for some time, you might remember that I told you about an online course on testing, that I was about to create and release. I still am doing this, but I got stuck. It is the first course that I am creating and will no experience I hit some road blocks that I couldn’t solve on my own. Thus, I entered an online community/course on course building, how meta πŸ˜‰. With this help I am absolutely sure that I can solve the issues and create an interesting pilot course. I will reach out to you again, once I am looking for participants for that.

Personal

I bought yet another bike. 😝 I do love my bikes, and I found a great bargain on eBay with a steel frame, only one year old for half the original price. So I bought it. It’s a fixed-gear bike, which means you cannot coast and have to move the legs at all times. Riding home on it yesterday evening I noticed how incredibly a meditating experience this is. As a beginner with fixed-gear bikes like me, you have to be so 100% aware of what you’re doing at all times. There was no space left in my head to think about anything but moving my legs and riding this bike (“don’t stop pedaling”). Because if you, for one second, stop pedaling, the pedal will still move upwards (rotate) and your leg will move and might catapult you out of the saddle. It’s demanding.

In other news, our older daughter will start with school in about one week. We are incredibly excited and a tiny bit afraid 😬.

Thinking

This is getting long already, so I’ll end this quickly soon. Last time I thought about doing scales in my professional development and how that correlates to doing interval training in sports. But that was wrong. Doing scales is not at all like intervals, but more like easy runs/long runs. You don’t do anything technically demanding but you are doing ground-work, fundamentals, basics β€” whatever you call that. I had a lengthy discussion about this with my mastermind group. They were the ones pointing out this difference to me.

See you next week.

Jouraling

I am writing again. Mostly for myself. As a journal. In the future I’ll try things a bit differently around here: I want to share what I am thinking about, how I work and what I am working on (as far as it makes sense in regard to my clients and NDAs).

Working

I secured a new client for autumn and the first months of 2020. I’ll be joining them as interim tech lead. I am excited. This will let me work a lot with Rails again. The last months were JS/TS only…

Something that I was proud of during the last week was a caching solution I created. Let me describe it briefly:

  • We are in a TypeScript project
  • There are external APIs we are calling to populate our app with data.
  • We display the same value in multiple places on a page or after navigating somewhere else.
  • We do not have a global state management like Redux etc. (Why is a discussion for another time πŸ˜‰)
  • Every display of the value resulted in a fetch to the same API resource.

What I built was a cache-aside solution, where I cache the (pending) Promise for the first request. All subsequent requests receive this Promise as return value, without fetching again. Once the Promise is resolved, the value appears where it’s supposed to appear and every requests happens just once. This is possible and makes sense, because the values change very infrequently and using the “old” value until the site is reloaded works just fine. We don’t yet need things like etags and ModifiedSince. But perhaps this will be added in a future situation. Anyway, this was cool and also challenging to find a proper solution. Caching the Promise itself was an idea that was developed together with my co-worker, Franz.

I am redesigning my website these last months. It always takes longer, because nobody pays me for that πŸ˜‚. It’s progressing nicely, thanks to the help of my designer. She’s great. I am really looking forward to sharing this with you. Also, I need to get back into the rhythm of writing articles. I have a lot of topics planned and see my traffic increase steadily.

I did not renew my subscription to the email marketing service Drip that I used during this last year. They were too expensive anyway. You will receive this mail through Drip, still. But future mails might be sent by something else. I’ll keep you posted and hope to be able to complete the migration without any hassle for you.

Personal

I am in the middle of a training program for my next 10 kilometers race. It’s quite intense, I am running 4-5 times a week. To make the time for that I started to do run-commutes. This means I run to my client in the morning, take a shower there and run home in the evening/afternoon. This is demanding but works out quite nicely. The shortest distance to my current client is about 6km, so it’s fine to run it twice.

I have a height-adjustable desk at my home office now and it is awesome. I love the flexibility. I actually stand most of the time. But after lunch, for example, I tend to sit down more. Ha, just wanted to share. If you are on the fence about getting one, you should!

Thinking / Reading

A quote that still makes me think:

Recently, one of my favorite questions to bug people with has been β€œWhat is it you do to train that is comparable to a pianist practicing scales?” If you don’t know the answer to that one, maybe you are doing something wrong or not doing enough. Or maybe you are (optimally?) not very ambitious?

It’s from this article: https://marginalrevolution.com/marginalrevolution/2019/07/how-i-practice-at-what-i-do.html

My current answer is “my side project” I am working on (nothing to share publicly here, yet). But I do know that I am not stretching doing that project. Compared to my run training, this is like a relaxed long run. Important for basic fitness and healthy, but nothing that increases my ability by much. The caching solution I wrote about certainly stretched me and I learned new things there. But this was work and not practice. And not deliberate but a happy “accident”. I should be able to plan for these training sessions.

So this is something I am thinking about.

Holger

Well this is confusing. I am a web developer and still have trouble getting this sorted. I want to:

  • Publish and create microposts on my wordpress site
  • I want these posts to appear in my micro.blog timeline
  • I want to crosspost my entries to Twitter
  • I do not need a custom domain name for my Micro.blog updates
    I read the help section. I created a category on my wordpress and could post from the IOS app to wordpress. The posts do not appear in my Micro.blog timeline.
    What do I need to do differently @manton?

I just read Paul Jarvisβ€˜ latest email mailchi.mp/pjrvs/own… Now I am (again) motivated to turn away from platforms, switch to Linux and own everything I use. He’s very motivating in how he writes. So where to start?

On my way to Leipzig by train. Once I get there I will head back to Berlin. On my bike. I heard someone call this nonsense 🀣

Using css modules the right way, I got it to work. πŸŽ‰ In the end I had some naming clashes where I already tried to prefix my css class names with the module nameβ€”which is handled by css modules already. Because of this duplication it didn’t work. Now it does. Yay!

I am working on my first React component library for my current client. Doing lots of things for the first time. Running into lots of roadblocks and things don’t really work like I expect them to. This might be simple, but it’s not easy.

This morning I took some detours on my way to my client by bike. I rode through some parks, chose small streets and enjoyed myself on my @8barbikes adventure bike. Iβ€˜m very much in love.

From my friend Ian, I learned the value of putting a clear; in front of your test runs in the terminal. Wasn’t aware of the difference it makes for running your tests many times.

Inspecting changes locally before pushing

If you work on your branch you run into the situation that you would like to push your changes to the remote repository. CI will then pick up your changes and run the linting and code quality checks on it. Afterwards, you will see whether you improved the quality. But perhaps there are some new violations that crept into the code? Happens to all of us!

I usually like to see and check if any new issues might come up on CI. This lets me improve them before I push. The checks I run locally depend on the kind of work that I do. Lately that’s a lot of Ruby on Rails again β€” which is great. I love that framework and the language. To grade my code, I use Rubocop, Reek and Flay. If you run their respective commands on your repository, they will check the whole code base. This might be ok, if you didn’t have any issues before. Since I join teams, these days, that work on legacy projects it is rare that there are no problems with the code. If I run the commands just so, I will get a long list and couldn’t possibly see the issues that I introduced through my changes. Lucikly, there is Git and some “command line foo” that can help us here:

git fetch && git diff-tree -r --no-commit-id --name-only master@\{u\} head | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs rubocop

This command will fetch the current state from the remote and diff your branch/changes to master branch. It then runs rubocop on these changes. In my ~/.aliases.local file I added three lines for all three linters.

# Code Quality
alias rubocop-changes="git fetch && git diff-tree -r --no-commit-id --name-only master@\{u\} head | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs rubocop"
alias reek-changes="git fetch && git diff-tree -r --no-commit-id --name-only master@\{u\} head | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs reek"
alias flay-changes="git fetch && git diff-tree -r --no-commit-id --name-only master@\{u\} head | xargs ls -1 2>/dev/null | grep '\.rb$' | xargs flay"

I am still working on a way to just call one command and have all thee commands run. That doesn’t yet work. Probably because of exit-code reasons, when one linter finds issues.

These simple commands offer a convenient way to find local issues and correct them before pushing to CI.

Avdi Grimm's view on deleting tests

A few weeks ago I wrote about deleting your tests. Yesterday I received the weekly email from Avdi Grimm, where he touches on this subject.

Some premises about my relationship with unit testing:

I like test-driven development. I like driving out individual object design small, isolated (e.g. no database) unit tests. I think of these unit tests as a design aid, full stop. Any help they provide with preventing regressions is gravy. I treat unit tests as disposable. Once they have served their purpose as design aids, I will only keep them around so long as they aren’t getting in the way. These four premises are strongly interconnected. Take away #1 (test first), and tests are no longer a design aid and none of the other points are valid. Take away #2 (isolation) and we get into integration test territory where there’s a much higher possibility of tests having regression-prevention value. Take away #3 (design focus) and the other points lose their justification. Take away #4 (disposability) and I spend all my time updating tests broken code changes.

This makes it easy for me to find myself at cross purposes with others in discussions about unit testing, because often they come into the conversation not sharing my premises. For instance, if your focus in unit testing is on preventing regressions, you might well decide isolated unit tests are more trouble than they are worth. I can’t really argue with that.

A recent conversation on this topic inspired the thought from the driving-design perspective, maybe unit tests are really just a crutch for languages that don’t have a sufficiently strong REPL experience. While I don’t think this is strictly true, I think the perspective shines a useful light on what we’re really trying to accomplish with unit tests. I almost think that what I really want out of unit tests is the ability to fiddle with live objects in a REPL until they do what I want, and then save that REPL session directly to a test for convenience in flagging API changes.

That conversation also spawned the idea of immutable unit tests: unit tests that can only be deleted, never updated. A bit like TCR. I wonder if this would place some helpful incentives on the test-writing process.

You should subscribe to his newsletter, if you haven’t yet.

My submission to Euruko was rejected. ☹ That’s a pity, would have loved to visit Rotterdam. I still have 7 other proposals that might come through. Fingers crossed 🀞

External forces

I am occupied with learning these days. Learning on my own about visualizations of data among other topics. But also learning about learning. For that I read what other people think about learning. There are many things I have to learn about this whole topic. One thought I saw repeatedly, was about external forces, or limiting factors.

Let me elaborate what I mean by that: There are people that can motivate themselves more easily than others can. They reach their goals or at least try very hard. Others give up more easily when they face some resistance. As always, there are people in the middle between these extremes. You know best which group you belong to. πŸ’ͺ

What has this do with software quality? I am getting there… πŸ˜‰

I am wondering how external forces could help improve quality. If you need to reach your goal and you don’t belong to the group of highly self-motivated people there are options like hiring a coach. Athletes do that all the time. I pay for a “virtual” coach that guides my running efforts.

How could you hire a “virtual” coach for your coding efforts, for reaching your targets on your software quality metrics? You could hire me or other “real” coaches, of course. But that doesn’t scale too well and might be too expensive.

Again, for some people it is easy enough to use static analysis or linting β€” a kind of coach in it’s own right β€” and follow their guidelines. Yet, still there are people that ignore the warnings or guidelines imposed upon them by the tools. Reasons may be a hard deadline or too much workload. How could we offer external forces, limiting factors that help them, guide them, towards doing the right thing?

One solution I can think of is to have a robot not accept your code when it is below standard or ignores guidelines. A robot could be anything that measures and grades your code and reports back to your team. Some tools already offer this, for example GitLab. If you want to merge code that decreases the overal quality metrics, you are not allowed to do so. So that would be one.

Another idea: If you try to commit or merge such code, you need to consult with another developer about the code. Once you worked on it together, the other dev has to enter her secret key, to remove the lock on the merge. This forces you to pair on code more often.

When it comes to teaching there is this saying of the “glass has to be empty (enough).” You cannot pour water into it, when it’s already filled. Said ideas πŸ‘†probably won’t work for a team that isn’t aiming for learning and improving.

I will continue to think.

You probably know AC/DC. But have you heard of MC/DC?

If you need to test a complex conditional, you should take some time to learn about this one.

holgerfrohloff.de/newslette…

Today I am working on a new visualization of fragmentation of ownership for Git repositories. The more fragmented a repo is, the more developers work on it together. This leads to no clear ownership and makes it easier for defects to creep into the code.

Complex conditionals

The other day we dealt with code coverage and gnarly conditionals. I promised to offer a way to be able to test them properly.

THERE IS NONE.

Ha, what a bad joke. But the real answer might not be better, depending on your point of view. What you have to do is create a table.

(A || B) && C

This is our conditional.

| m | A | B | C | RESULT |
----------------------
| 0 | T | T | T |    T   |
| 1 | T | F | T |    T   | x
| 2 | F | F | T |    F   | x
| 3 | F | T | T |    T   | x
| 4 | T | T | F |    F   |
| 5 | T | F | F |    F   | x
| 6 | F | T | F |    F   |
| 7 | F | F | F |    F   |

# m is the test case
# A, B, C are the atomic parts of the conditional
# RESULT is the result of the evaluation of the conditional

For three terms in a conditional, you can have 8 different cases (2^3). You don’t need to test every case. You have to find those cases where switching one term (A, B or C) changes the RESULT. You take those cases and write tests for them. You can ignore the rest as they don’t bring you any new information. For our example these could be the test cases 1, 2, 3, 4. I marked them with an x,

The general rule of thumb is that you can solve this with n + 1 test cases where n is the number of terms.

This technique is called Modified Condition/Decision Coverage or short MC/DC. I like this name, it’s easy to remember 🀘.

It gets harder to do, when one term of the conditional is used more than once (coupled). Another thing to take note of is that depending on the decision statement in the code, it may not be possible to vary the value of the coupled term such that it alone causes the decision outcome to change. You can deal with this by only testing uncoupled atomic decisions. Or you analyse every case where coupling occurs one-by-one. Then you know which ones to use.

You’ll have to do this in the aerospace software industry or where you deal with safety-critical systems.

If you read this far: Congratulations. This is one of the more in-depth topics of testing software. You deserve a πŸ‘ for learning about these things!

I am reading the new edition of Refactoring by Martin Fowler these days. I am preparing a new workshop on Software Design and Architecture. I bet there are some ideas in there that will inspire me to create some specific exercises. #refactoring

I am now using Micro.blog for my microposts. I will crosspost my newsletters there. And whatever I think makes sense. I will figure it out by just trying. 😎

Code coverage can be misleading

During the last week, I had two discussions about code coverage. Code coverage is the metric of how many lines of code are covered by your automated test suite. Many test frameworks have built-in ways to measure this. Other times you have to install another tool manually. When you run your tests you then see how many lines are not covered by a test. That means that no test was run where this line of code was evaluated or executed or interpreted.

When you reach 100% code coverage, what then? Are you done? Could you guarantee that there are absolutely no bugs in your code?

If you are tempted to say Yes, or “maybe?” then let me tell you that you are wrong.

Consider this piece of code.

If you write a unit test for this method, the line eval... will be interpreted because of the if emergency at the end. The line is thus covered. But the code is not covered or tested.

Admittedly, this is a very trivial example that I made up. In reality, there are some more profound things to consider.

If you have complex conditionals you might need a logic table where you compare all possible combinations of the atomic parts of the conditional.

You cannot possibly evaluate this in your head and know whether you checked for every possible, sensible combination. Yet when you cover that line you are at 100% coverage and can go home, right?

So what do you do? Let’s look at this tomorrow.

Quick wins, part 4: YAGNI

We refactored some code yesterday, to move knowledge about an implementation of a function back to where it belonged: Into the function’s class and into the function itself.

Today I want to talk about another topic that often comes up when you are refactoring, or plainly “changing code.”

It happened the other day, during a workshop I was doing on software testing. The participant wanted to apply his new knowledge and write tests for a given JavaScript class. He had written the code a few weeks before we did the workshop. During the hands-on part of the workshop, he wanted to add tests, to make sure everything worked and to make sure that he understood what I had been talking about.

We were lucky in as so far that something happened that usually happens next: He noticed that his code was not easily testable. The design of his class made it harder for him than he would have liked. We talked about the problem, and he noticed the source of it. His class had too many responsibilities. He extracted the code in question into a new service and could then mock the new service when testing his original class. This was good. He was ecstatic. He made progress!

Having gained so much momentum, he went overboard: During his test-design, he wanted to be too clever and tried to write an elaborate test setup which was to be reused between different test runs. It was supposed to be a reusable, parameterizable do-it-all function that could setup the tests just right. With no duplication. In short, it was so much code with so much logic that it would’ve warranted its own tests. And the worst thing? It didn’t work and made trouble for writing his tests.

I was a bit thankful because that gave me the opportunity to tell him:

Premature optimization is the root of all evil.

Perhaps you’ve heard that saying already. Donald Knuth coined this phrase. There’s more to it, but that could be discussed in another email.

Back to my tester. After talking about the problems his function gave him and the difficulty in getting it right he settled for the simple solution: Write your tests. Accept duplication. Keep it simple, use copy & paste if it makes you faster and is more convenient. Write the tests you need and keep them green. And after all that, and only then, refactor your tests to remove duplication where applicable. Don’t try to write the perfect code from the start. Let the design evolve with the help of your tests. Don’t be afraid to make baby steps and don’t expect to have perfect code after the first try.

I hope you liked this series. Perhaps you could take something away from it. If you have questions, let me know.

Tomorrow I’ll be off; it’s a holiday where I live, and I’ll use it to spend time with my family. See you on Monday. πŸ‘‹