I’m currently reading Brian P. Hogan‘s book ‘Write Better with Vale‘, about Vale (a command line tool to ease follwing style guides in prose text). While intended for prose text (as far as I know), Vale can also process any text file, including code.
When I tried to copy & paste commands from the epub version of the book, into my shell, I got an error message:
> vale .
E100 [NewE201] Runtime error
The path ‘…/vale_example_project/../styles’ does not exist.
Execution stopped with code 1.
After some exploration, I figured that some zero-width-space characters were in the INI file I copied into my example project (and reported it over at the books feedback site).
Then I realised that I could create my own Vale rule to detect these invisible characters in text files.
Now, Vale is configured using an INI file. There you declare where it can find the styles and which rules should be applied for which files (see https://vale.sh/docs/vale-ini for more details). I set up a new rule in a file …/styles/Custom/NoZeroWidthSpaces.yml:
# Styles/Custom/NoZeroWidthSpace.yml
extends: existence
message: "Avoid using zero-width or invisible characters (%s)."
level: error
scope: raw
raw:
- '[\u200B\u200C\u200D\u2060\uFEFF]'
I set up Vale to use this new Custom rule in .vale.ini like this:
StylesPath = styles
[*.md]
BasedOnStyles = Custom
With that, I get a nice message when running vale against a file riddled with those characters::
> vale .
example.md
1:111 error Avoid using zero-width or Custom.NoZeroWidthSpaces
invisible characters ().
Admittedly, the empty looking parentheses aren’t very instructive, since they contain invisible characters. At least it’s possible to copy-&-paste them to find out what they are in other tools.
-dialog, the request is aborted. Both of these options are powered by (Turbo)[https://turbo.hotwired.dev/]
+dialog, the request is aborted. Both of these options are powered by [Turbo](https://turbo.hotwired.dev/)
Both contributions were in the documentation, rather than the project’s code.
I find it easier to contribute to documentation rather than code. I don’t need to worry about setting up a working test environment for the whole project. Generating the documentation on my machine and then checking the resulting HTML usually suffices.
In any case, don’t worry that a change is too small to be accepted
I will admit that one aspect of very small contributions is overhead. In most open-source projects, contributions follow several steps:
Fork the project (i.e. create your own Git repository with the projects code).
Create a branch in your fork, and make the change in that branch.
Create a ‘Pull Request‘ (sometimes also called a ‘Merge Request‘) summarising the change. Participate in the discussion (if there is any) and incorporate further changes as needed.
Get the pull/merge request accepted & merged into the projects main branch.
I recommend one more step after 4: Celebrate 🎉 at least a little bit.
For detailed information about contributing to open-source projects, I recommend the Open Source Guides.
This is another blog entry in the #ReminderToSelf category.
I got a new MacBook an wanted to change its hast name since I find “Stephan’s Mac” not terribly inspiring.
Since joining the Oceanography department at the University of Bremen (years, nearly two decades ago), I find ocean names are the way to go. — Even more so since I started open water swimming not that long ago.
Here’s what I tried first:
Set the name in the Mac’s system setting under “General” ➙ About:
Set it in the “Sharing” part as well:
Interestingly, that didn’t seem to be enough, the command line prompt still showed the computer’s default name.
However, there’s a command line tool that allows setting these kinds of information `scutil’:
In most cases, these dates are identical. Still, they can be different, as the author and committer can be different people (for details about the commit details, see the extensive Git documentation for commits). One interesting detail about the dates: The author date can be set with the command line option --date , while the committer date can only be set using an environment variable.
How to set the dates
I chose to set the author date using the command line option and the environment variable GIT_COMMITTER_DATE for the committer date.
When there is a change in the Git index (or staging area), here’s how to commit it with the given date and time info:
All is good: I created a file with some content, added it to the staging area, and committed it.
Varying the dates
Let’s be more daring with the commit dates and go a few years into the future and past. Add some more text to the file ‘wahoodie’ I used before, add the change to the Git index and commit:
> echo "another line" >> wahoodie
> git add .
> GIT_COMMITTER_DATE="Wed 11 Oct 1634 22:47:38 +0000" git commit -m "Updates file" --date "Tue Jan 19 2038 03:14:08 UTC"
fatal: invalid date format: Wed 11 Oct 1634 22:47:38 +0000
Huh? Is something wrong with the (committer) date? It looks OK, but it could be the weekday that’s causing trouble. Let’s try to commit a change using the wrong weekdays:
After experimenting with the date & talking to folks on the Git Discord, I figured the epoch is the (lower) boundary for dates in Git. Let’s use the following shell script (‘demo-date-format-issue.sh’):
git init tmp
cd tmp
echo "Some content" > non-empty-file.txt
git add .
GIT_COMMITTER_DATE="31 Dec 1969 23:59:60 +0000" git commit -m "Commit 1" --date "12 Dec 1969 23:59:60 +0000"
GIT_COMMITTER_DATE="01 Jan 1970 00:00:00 +0000" git commit -m "Commit 1" --date "01 Jan 1970 00:00:00 +0000"
Running it gives the following output:
> ./demo-date-format-issue.sh
Initialized empty Git repository in /Users/stephan/dev/garble-git-repo/tmp/.git/
fatal: invalid date format: 31 Dec 1969 23:59:60 +0000
[main (root-commit) 9c0b65a] Commit 1
Date: Thu Jan 1 00:00:00 1970 +0000
1 file changed, 1 insertion(+)
create mode 100644 non-empty-file.txt
Aha! The first commit attempt fails and gives a misleading error message: The date format is perfectly valid. Apparently, Git can’t process a date before 1 January 1970 00:00:00 UTC.
Remarkably, the next date that might cause trouble, ‘2038-01-19T03:14:08+00:00’, doesn’t. Instead, the last future date & time at which a commit is possible is ‘2099-12-31T23:59:59+00:00’, as the following example code shows:
echo "More content" > non-empty-file.txt
git add .
GIT_COMMITTER_DATE="01 Jan 2100 00:00:00 +0000" git commit -m "Commit 2" --date "01 Jan 2100 00:00:00 +0000"
GIT_COMMITTER_DATE="31 Dec 2099 23:59:60 +0000" git commit -m "Commit 2" --date "31 Dec 2099 23:59:60 +0000"
The output of this is:
fatal: invalid date format: 01 Jan 2100 00:00:00 +0000
I don’t understand why the year change from 2099 to 2100 is the upper boundary for the dates Git will process. To me, this seems a bit limiting since it’s ‘just’ ≈75½ years until then. (If you know why this limit has been chosen, please share.)
In any case, printing an error message that claims a date format is invalid when it’s not is a bug. I said ‘obscure bug’ in the title. 😃
I reported the issue in the Git mailing list, but am not sure about how thigs develop from here. Someone proposed a better error message and I very much appreciate it.
Note: I denote this as day zero since the conference starts counting the conference days, with ‘day one’ being the first day after the tutorial day.
As every year, the Agile Testing Days start with a tutorial day. I chose ‘Breaking into AI and Machine Learning’ by Tariq King. The tutorial followed a top-down approach. We did not have to (re-) learn linear algebra and the like before getting started. Instead, after a brief introduction to the topic, we could work on an example task: Classifying irises. A CSV file containing typical attributes of various flower species was used to create a model that could classify a flower as one of the species the model was trained on. Tariq introduced this as the ‘Hello world of AI’.
We saw how overfitting a model can cause issues when a model is used with new data it wasn’t trained on. This happens when the model matches the test data (nearly) perfectly, which usually causes larger misclassifications when new data is put into the model.
We also learned how models can be trained on images to classify them. This is the next step since it requires processing much more data.
Then ChatGPT was introduced. While I am still a bit sceptical about some of its output since it’s known to (for example) ‘hallucinate’ citations for scientific papers. Yet, I am impressed with what can be achieved when it’s provided with enough data and prompts tuned to its needs.
In the first keynote, Maaike Brinkhof wrapped the experiences in her software testing career in the story of a role-playing game. In this setting, she met increasingly hard-to-conquer ‘bosses’. Inspiring, entertaining – and providing input for the following keynotes. In other words, It opened my mind for the conference to come.
Day 1 – No Overnight Sucess & Sociocracy
In the day’s first keynote, Kristel Kruustuk presented her thoughts about ‘10x Software Testing‘. My takeaway was this: You don’t become a ’10× tester’ overnight. Instead, it requires persistence and regular training. This matched nicely with my personal experience and is linked to one of my sessions this year.
The next session I attended was CraigRisi’s ‘Becoming an Open Sourcerer‘. He explained what teams should consider when they use open-source software. He also discussed the advantages and potential disadvantages of using open-source software. Finally, we learned about contributing to open-source projects. While contributing code changes is likely the most common way to contribute, providing documentation is another essential aspect, as are providing and improving bug reports and even (automated) tests.
Consent means “Good enough for now, safe enough to try”
John Buck, Agile Testing Days 2023
As a tester, I’m unsure how to use this to debug management, and I will admit that I haven’t tried it yet.
Day 2 – Workshop & Infotainment
I missed the first keynote of the day since the next scheduled time slot included my workshop ‘Fun with U̡̟ͩ̊̏ͬͯni͑c͐̀͢od̲̎ͅḕ̶̩͙͆‘. Much to my pleasure, it was well attended, and folks were surprised at how bad some software is with processing Unicode. As Maaike tweeted:
Biggest lesson so far at the Unicode workshop: good luck in life with computers if your name contains diacritics #agileTD
After collecting my workshop material and winding down, I attended the keynote ‘Everyone is a Leader‘ by Zuzi Šochová. I liked how easy it was to follow along and the message that everyone can be a leader – at some time, for some topic. Leadership doesn’t have to be assigned but can be assumed temporarily when it makes sense.
The following two keynotes were mindblowing! Dr. Rochelle Carr requested the audience to ‘MOVE THAT WALL‘. This talk was loud and inspiring and made me think about which walls I have that I may want to move – or tear down entirely.
‘Don’t go breaking my code‘, by Lena Nyström & Samuel Nitsche, was a keynote in a musical or rock opera format: Loud, entertaining, and fun. It also explained where and why testers and developers have different points of view. Not only that, they also demonstrated ways to get along with each other better.
I ended the day by spending time at the Agile Testing Days Book Fair, organised by Tobias Geyer and Maik Nogens. Thankfully, I got the books I was looking for: Zuzi Šochvá’s ’The Agile Leader’ and John Buck’s ‘We The People’. They were even kind enough to sign the books for me. Thank you!
Day 3 – Conflict Resolution, Micropowers & Judgment Day
In the morning keynote ‘A Fighting Chance – Learning the Art of Conflict Resolution‘, Alex Schladebeck presented pitfalls to avoid when dealing with conflict and good ways to deal with them. Planned as a pair keynote, the second speaker, Sophie Küster, couldn’t be at the conference. Sophie, you were missed, and we all hope you’re back next year! My key takeaway: Noticing that someone perceives a conflict goes a long way to mitigating it. – Especially if the affected parties know about the pitfalls, such as saying, ‘You always/never do XY’.
After this, Eveline Moolenaars and I prepared our talk ‘Micropowers: Learn to Speak Up and Be Heard‘. This was about our shared experience of recovering from cancer and its treatment and how that helped us to start asking for help – and helping others. We found the term ‘superpower’ intimidating and came up with the term ‘micropower’. We defined this as an ability one can trust that helps to act when we see things that should be changed.
In the morning keynote, ’A Fighting Chance – Learning the Art of Conflict Resolution’, Alex Schladebeck presented pitfalls to avoid when facing conflicts and good ways to deal with them. Planned as a pair keynote, the second speaker, Sophie Küster, couldn’t be at the conference. Sophie, you were missed, and we all hope you’re back next year! My takeaway: Noticing that someone perceives a conflict goes a long way to mitigating it. – Especially if the affected parties know about the pitfalls, such as saying, ‘You always/never do XYZ’.
After this, Eveline Moolenaars and I prepared our talk ‘Micropowers: Learn to Speak Up and Be Heard’. This was about our shared experience of recovering from cancer and its treatment and how that helped us to start asking for help – and helping others. We found the term ‘superpowers’ intimidating and came up with the word ‘micropower’. We defined this as an ability one can trust that helps to act when we see things that should be changed.
The keynote ‘Wait! That’s Not Tested’ by Heather Reid introduced the idea that not all things need to be tested. We need to consider time, cost and risk when testing software. And since there is never enough time to test everything anyway, we must make bets. This connects nicely to John Buck’s definition of consent: ‘Good enough for now, safe enough to try’.
The keynote, ‘The Rise of Generative AI: Judgment Day’ by Tariq King, was the perfect ending to the official program since it nicely connected to my tutorial day. He presented content (paintings and music) in pairs: One an original from a human artis, the other one created by AI is the style of that artist. The audience was tasked to tell which one was the original and which one the ‘copy’. – I found it shocking that we, the audience, did not perform particularly well.
My overall impression of the Agile Testing Days: It was a very well-planned conference, with sessions that connected ideas and concepts. I am already looking forward to Agile Testing Days 2024 – and have many ideas for proposals already.
Thank you to everyone I have met and talked with this year. I hope to see you again in 2024.
My translation to English: ‘The question ‘Why’ often blocks accepting a situation.’
I immediately reacted to this.
I thought back to the day a doctor diagnosed me with cancer. He saw a question I was about to ask and before I started to speak, he told me to not ask ‘Why’. He advised me to instead concentrate on how I wanted to deal with the situation.
That really changed my thinking. To help me with this, he asked whether I had any plans for the near to mid-term future, something that I wanted to achieve. This changed my thinking from intense worrying extremely to something I I could focus on.
I still worried about the treatment! But I also thought about any plans that I had. And indeed, there was one big plan that I did have: To give a keynote at Agile Testing Days 2018! I WANTED to do it. Badly.
I later realised, another good news that was hidden in the question about my plans for the future: Apparently the doctor thought I had a future, at least the chance to have it.
As it turned out, I was not able to give the planned keynote, since the therapy massively compromised my immune system and that meant I had to avoid larger crowds of people. During the traditional flu season, I was strongly advised to not meet more than 3-4 people at a time. And to avoid even that whenever possible.
Eventually, in 2019, I could give the keynote, and it was received well. Very well, indeed.
Now, having read that quote from above, I started to think about asking ‘Why’ – or even asking ‘Why’ five (!) times to dig into the cause of whatever one is investigating. There may be better questions or approaches. Is asking ‘How do we want to deal with this?’ a better way?
I can imagine that especially when trying to understand a situation that went bad, avoiding ‘Why’ may be a good idea. At least in German ‘Warum’ (of the similar terms ‘Weshalb’ or ‘Wieso’) already carries with it a tiny bit of shaming or (suspecting) guilt. This is something that one very likely wants to avoid, if the plan is to actually get to the root causes of a situation.
Given the learnings from my illness, I think the following question is an improvement on asking ‘Why?’:
How do we want to deal with this situation?
In my experience, asking ‘Why?’ often also involves ‘you’ as in ‘Why did you do X?’. This adds to the potential of shaming or assuming guilt: Now, there is also some separation between the one asking and the person being asked.
I had good experiences using ‘we’, when figuring out problems. Using ‘we’ signals that, in fact, we have a problem.
Using ‘We’ puts us on the same side of a task: we are facing the problem together. Therefore neither of us ‘is’ the problem (or maybe we all are), but… the problem is the problem.
Having made clear that this problem is our problem, we can collaborate to find a good solution. Even better, we might find three (or more) solutions and then select the best one for the given context, at that moment in time, and implement it.
This is related to Jerry Weinberg’s observation about understanding problems:
If you can’t think of at least three things that might be wrong with your understanding of the problem, you don’t understand the problem.”
Disclaimer: I am not suggesting to change the Ruby style guide.
At a workshop I was giving a few years ago, someone not used to writing Ruby code found an interesting way, that you can write Ruby code.
First let’s assume a class Thingy, that doesn’t do anything useful. It’s just needed to demonstrate the way to write Ruby.
Assume this is in file ‘thingy.rb’:
# frozen_string_literal: true
# Thingy is only used to demonstrate
# a way of writing Ruby code
class Thingy
def initialize(*args)
@args = args
end
def this(other)
@args << other
self
end
def that(*other)
@args << other
self
end
def content
@args
end
end
Now, let’s use this class in another script, that’s showing the alternative way to write Ruby code (in file use_thingy.rb):
Notice that rather LISP-like way to parenthesise, in line 7 in particular. I still am surprised that this is possible in Ruby and actually behaves the way I’d expect.
It’s also entertaining that Rubocop does not complain about this code:
> ls
thingy.rb use_thingy.rb
> rubocop .
Inspecting 2 files
..
2 files inspected, no offenses detected
This is one of the reasons I like programming in Ruby so much: One can discover new ways (even if probably not very useful ones, sometimes) even after years of using it.