Showing posts with label inverted. Show all posts
Showing posts with label inverted. Show all posts

7 July 2025

Only Exceptions for Control Flow

Where It Started
At technical unconferences I like to start (and conclude) the day with some fun coding. After all, writing code is (still, in June 2025,) at the heart of software development. During SoCraTes Linz 2024 I proposed the first session to be a "Coding Fun session: Only use exceptions for control flow." I explained that it would be impractical but fun ;-) Using exceptions like that was an anti pattern but I wanted to see what would be possible.

Coding Fun: Only Exceptions for Control Flow
I start the session with a few slides: Control flow is is the order in which individual statements, instructions or function calls of an imperative program are executed or evaluated. And the idea of the session is to only use exceptions for changing the control flow. This is a constraint, an artificial addition to a coding exercise, to make it more focused or challenging. To force us to use exceptions for control flow I need to take away all other options:
  • Not using if, while or for, the ternary operator or similar language constructs. (This is the same as the constraint Cyclomatic Complexity One.)
  • Not using any array or (Java) stream operations like map, filter, etc. (These functions are a way to deal with Cyclomatic Complexity One.)
  • Not using lookup arrays of functions. For example a map with the keys true and false and functions as values is an if-else statement. (These lookups are another way to deal with Cyclomatic Complexity One.)
  • Not using modulo, signum, minimum and maximum Math functions as well as various String translate and replace functions. (These are unrelated to Cyclomatic Complexity One, but offer ways to work around in the specified task further down.)
control room in former refinery (licensed CC BY-NC-ND by Michal Jancek)Word of Warning
This is an exercise, even more it is an "inverted" exercise because it wants us to do things we usually avoid doing. And for good reason, using exceptions this way is an anti pattern. It is basically a goto statement, not a structured break or continue style go to, but a real nasty one where we can jump across multiple stack frames. It makes code hard to understand. Often performance is bad due to the cost of creating exceptions. Don't do this in your project. Keep in mind that we are just playing...

Assignment
As a task let us create a ROT-13 "Encryption", also known as Caesar-Chiffre. Our requirements are:
  1. Write a function encode to encode a message using ROT-13.
  2. Each letter is replaced with one 13 added in the alphabet.
  3. At the end of the alphabet, it continues at the beginning.
  4. Characters other than letters are not encoded.
  5. Lowercase letters are first changed to uppercase letters.
  6. Umlauts are letter combinations for encoding, e.g. "Ä" becomes "AE" before encoding and so on.
  7. Bonus: Make rotation configurable. Now it is 13.
These are plenty of requirements. In a usual session we manage to finish item 4) which shows all the relevant parts. If we have more time we can of course do more.

Try it Yourself
Below I will show Java code of the most common solution. After you see it, you will not be able to un-see it. If you want to explore the constraint and the exercise on your own, then stop reading now! I encourage you to do that. Best way is to work with difficult constraints is to code a little bit and then step back and verify if all rules still apply.

Hands On!
I run this session as "interactive demo", which means I let participants decide what to do next, or at least I let them propose what to do next and I wait until a proposition is aligned with my plan. I make sure we stay focused on the main goal of the exercise. The whole coding takes 30 to 40 minutes. Further more I (demand to) use TDD and try to make the code readable (as possible). How do I start? I start with a (simple) failing test of course:
public class Rot13Test {

  @Test
  public void empty() {
    assertEquals("", encode(""));
  }

}
To keep things simple I add the production code (that is the function encode) at the top of the test class:
public class Rot13Test {

  public String encode(String message) {
    return "";
  }
The first test established the method with the required signature, see requirement #1. Now I am able to replace letters with one 13 added in the alphabet. A suitable test case is "A" becomes "N", i.e. assertEquals("N", encode("A")). The first challenge is how to check if there are characters in the message? I cannot loop or map them. How about:
public class Rot13Test {

  public String encode(String message) {
    try {
      message.charAt(0);
      return "N";
    } catch (StringIndexOutOfBoundsException empty) {
      return "";
    }
  }
Ok. Next I choose to go for more letters. I could also do that at the end, it depends what people say during the workshop... A suitable test case is "AA" becomes "NN".
public class Rot13Test {

  public String encode(String message) {
    try {
      char first = message.charAt(0);
      String remaining = message.substring(1);
      return encodeChar(first) + encode(remaining);
    } catch (StringIndexOutOfBoundsException empty) {
      return "";
    }
  }

  private String encodeChar(char c) {
    return "N";
  }
The recursion ends when the message is empty. Back to requirement #2. My next test case is "B" becomes "M" and I only need to modify the method encodeChar():
public class Rot13Test {
  ...

  private String encodeChar(char c) {
    int encoded = c + 13;
    return Character.toString((char) encoded);
  }
This works for the letters "A" to "M" (which becomes "Z"). Nice. Requirement #3 deals with letters "N" to "Z", so
public class Rot13Test {
  ...

  private String encodeChar(char c) {
    int encoded = c + 13;
    try {
      // if encoded <= 'Z' then jump
      int tmp = 1 / (encoded / ('Z' + 1));
      encoded -= 26;
    } catch (ArithmeticException smaller) {
      // leave encoded alone
    }
    return Character.toString((char) encoded);
  }
I will explain how that works: If encoded is less or equal to "Z" the logic is already correct. How can I create an exception if a number is less than 'Z' + 1? If encoded is smaller than this limit, the integer division will be zero which will result in a division by zero, which in Java causes an ArithmeticException. If encoded is larger than "Z", the result of the division will be 1, so dividing by it is allowed and the code continues. Now the algorithm works for all letters.

The Sluice Gate (licensed CC BY-NC-ND by Ib Aarmo)Requirement #4 tells us to leave special characters alone. Which are these? A quick look at the 7 bit ASCII table,
 !"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
shows the special characters. There are three ranges which I need to handle. (At the moment there are only two ranges, and I know that lowercase letters will be handled later.) I add a test for several special characters below, i.e. assertEquals("!/?@", encode("!/?@")) and later one above i.e. assertEquals("[_`{~", encode("[_`{~")), always using the first and last character of each range.
public class Rot13Test {
  ...

  private String encodeChar(char c) {
    int encoded = c;
    try {
      skipIfBelow(encoded, 'A');
      skipIfBelow('Z', encoded);
      encoded += 13;

      skipIfBelow(encoded, 'Z' + 1);
      encoded -= 26;
    } catch (ArithmeticException smaller) {
      // leave encoded alone
    }
    return Character.toString((char) encoded);
  }

  private void skipIfBelow(int codePoint, int limit) {
    int tmp = 1 / (codePoint / limit);
  }
By extracting a helper method skipIfBelow() I can check against the limits of the two ranges: Below and above. The basic algorithm is complete. Requirement #5 is more of the same, adding a toUppercase:
public class Rot13Test {
  ...

  private int toUppercase(int codePoint) {
    try {
      skipIfBelow(codePoint, 'a');
      skipIfBelow('z', codePoint);

      return codePoint - 'a' + 'A';

    } catch (ArithmeticException skipped) {
      // leave char alone
      return codePoint;
    }
  }
Control Flow "Library"
I said I try to make the code more readable. This can be done with custom exceptions and extracting the flow control logic into separate "library" functions like skipIfBelow(). During a different run of the session I ended up with
public class Rot13Test {
  ...

  static class SmallerThan extends Exception {
    public SmallerThan(Throwable cause) {
      super(cause);
    }
  }

  private void testIfSmaller(int codePoint, int limit)
               throws SmallerThan {
    try {
      int tmp = 1 / (codePoint / limit);
    } catch (ArithmeticException e) {
      throw new SmallerThan(e);
    }
  }

  static class LargerThan extends Exception {
    public LargerThan(Throwable cause) {
      super(cause);
    }
  }

  private void testIfLarger(int codePoint, int limit)
               throws LargerThan {
    try {
      testIfSmaller(limit, codePoint);
    } catch (SmallerThan e) {
      throw new LargerThan(e);
    }
  }

  static class ReplacedUmlaut extends Exception {
    public final String replacement;

    public ReplacedUmlaut(String replacement) {
      this.replacement = replacement;
    }
  }

  private void replaceUmlaut(int codePoint, int umlaut,
                             String replacement)
               throws ReplacedUmlaut {
    try {
      testIfSmallerThan(codePoint, umlaut);
      testIfLargerThan(codePoint, umlaut);
      throw new ReplacedUmlaut(replacement);
    } catch (SmallerThan | LargerThan notUmlaut) {
    }
  }
This allows me to distinguish different cases in the catch clause, which becomes a switch statement.

Closing Circle
This code is not like the code you see every day and it was definitely not the code you should write, but all participants agreed that they had a lot of fun. Several people said that I had screwed their mind and my long time peer Bernhard Woditschka said that he liked how it forced him to think outside of the box. This is probably because I am exploring negative aspects, i.e. concepts we usually try to avoid. Samuel Ytterbrink agreed saying "I think this session was like balm for the soul, nothing so freeing as being ordered to do something you are not supposed to do."

Using only exceptions for control flow, like naming all identifiers randomly, focuses on unwanted qualities of code, sharpens our awareness and (hopefully) raises our dislike of them. Ant it is a fun exercise, too. Stay tuned for my next Coding Fun session: No Composition Only Inheritance ;-)

17 February 2021

Dice Namer Constraint

A constraint is an artificial challenge during an exercise to make the exercise more interesting, challenging or fun. I like constraints and wrote about some of them. The Dice Namer is such a constraint: Everything but the names of test methods is named using random dices. The French company Arolla created some really nice dices using random, enterprise-y useless names like Processor, Dummy or Factory. I managed to get several sets and to use them in my coding exercises after discussing naming in code. Now with the remote work due to Covid, I had to come up with something new. And here it is, the

Arolla Dice Namer Application

Press the buttons and see the random dices for your name, together with some dices-like sound (if you allow your browser to play it). This is a real fun and it will help you create amazing code like this one using viciously named functions...
What does this code do?

20 July 2015

Write the worst code you can

Global Day of Coderetreat 2014
Last Code Retreat I was lucky to co-facilitate the event together with Alexandru Bolboaca from Romania. He wrote a summary of the event in Vienna in his blog, so I will not describe it myself. I rather describe one constraint he introduced. A constraint, also known as an activity, is a challenge during a kata, coding dojo or code retreat designed to help participants think about writing code differently than they would otherwise. I have written about other constraints before, e.g. No naked primitives.

The Fun Session
The last session of a Code Retreat is usual a free session that is supposed to close a great day and it should be fun. Alex liked to gives participants many options and he came up with a list of different things they could do:Alex Bolboaca Fun SessionWhile I was familiar with all the pairing games, e.g. Silent Evil Pairing, which is also called Mute with Find the Loophole, I had never tried inverting a constraint.

Write the worst code you can
Alex explained that there were many ways to write bad code. All methods could be static, only mutable global state, bad names, too big or too small units (methods, classes), only primitives, only Strings, to just name a few. Some of these bad things are available as their own (inverted) constraints, e.g. all data structures must be hash tables. (PHP I am looking at you ;-) Bad code like this can get out of hand easily, imagine writing the whole Game of Life in a single, huge method.

But how could this teach us anything? A regular constraint is an exaggeration of a fundamental rule of clean code or object oriented design. People have to figure out the rule and work hard to meet the constraint. The inverted constraint is similar. People have to think about what they would do, and then do the opposite, exaggerating as much as possible. As a bonus, most of them get stung by the crap they just created a few minutes ago. And most developers really enjoy themselves working like that. Maybe they have too much fun, but I will come back to that later.

Armament... or maybe not
I used the constraint in several in-house Coding Dojos when the teams asked for fun sessions. Here is what I learned: The constraint is not hard. Some people get creative but in general it is too easy to write bad code. Most "worst" code I saw had inconsistent naming, a lot of duplication, primitives all over the place and bad tests. In general it looked almost like the day to day code these teams deliver. I particularly loved a dialogue I overheard, when one developer wrote some code and proclaimed it as ugly while his pair denied its ugliness.

One participant complained that he wanted to learn how to write clean code and that he saw this worst case code everyday anyway. He was really frustrated. (That is why I said not all people like this constraint.) And this is also pointing out a potential problem of inverted constraints in general - practising doing it wrong might not be a good idea after all.

Conclusion
I am unable to decide if this constraint is worth using or not. I like the idea of inverted constraints and this one is definitely fun and probably good to use once in a while. But I believe the constraint is lacking focus and is therefore too easy to meet. People should not deliver code during a practise session that just looks like their production code. I want them to work harder ;-) I will try more focused, inverted constraints next. Allowing only static methods might be a good start. On the other hand, code created when following the constraint to only use Strings as data structures is too close to the regular (bad) code I see every day. Therefore a good inverted constraint would be one that takes a single, bad coding style to the extreme. Allowing only one character for names comes to my mind, which is an exaggeration of bad naming - or even a missing tool constraint, because it renders naming non-existing.

Have you worked with inverted constraints? If so, please share your constraints and opinions about them in the comments below.