Autor: denkmalpflege

  • Agile Anti-Pattern: No clue about change.

    Pattern Description

    Your company follows a very rigid long-running stage-gate process, which takes around two years between first ideation and go-live.

    You have three to four releases per year.

    You cannot change anything which already passed a gate.

    Issue, Problem, Risk

    The 1%-requirements creep rule is ignored, thus after 24 months more then a quarter of your project’s results will be wrong.

    Root Cause

    If you are held responsible for the software design you will insist on getting a frozen requirements specification document.

    If you know your failure will be recognized by your peers down the line and reported through the hierarchies – to finally land on your desk again, you become a cautious and fearful person.

    Thus, maybe the biggest reason for the absence of a culture for change is silo thinking in combination with well established blaming mechanisms.

    Mitigation, Remedy, How to avoid

    Reduce fear by establishing a culture for failure and a culture for change.

    Establish a culture for change by establishing a change process for all projects. 

    Agile embraces change. It is one of the four values of the Agile Manifesto: ‚responding to change‘ and one of its principles is ‚welcome changing requirements, even late in development.‘

    Agile thinking requires the working implementation of a concept called ‚feedback loops‘. 

    Thus whenever we do something, there should be some kind of planning before we do it (Cf. ‚I guess I’m just a fool, who never looks before he jumps.‘ in ‚Everything happens to me‘ as sung by Chet Baker, in https://youtu.be/MaGl6zd3rHg). 

    And after we did something, there should some kind of check, and some kind of a reaction of what we found out. Other forms of feedback loops:

    • OODA (Observe, Orientate, Decide, Act)
    • PDCA (Plan, Do, Check, Act/Adjust)
    • PDSA (Plan, Do, Study, Act)
    • Build, Measure, Learn (Lean Startup)

    See e.g. http://prince2.wiki/Change.

  • Agile Anti-Pattern: No vision.

    Pattern Description

    You have lot’s of stories converted from an old fashioned requirements specification. You have enough to do for the next years. Your customer is raising the bar and starts to put pressure on your deliveries.

    Issue, Problem, Risk

    A rat race is a rat race is a rat race.

    Nobody knows why he/she works so hard? That’s bad and quite the opposite of ‚transparency‘ (pillar #1 of Scrum). Your eco-system should cater for openness and transparency.

    Does every member of your scrum team – your Product Owner in particular – have a clear understanding of each of your sprint’s ‚Sprint Goal‘? If not, you have uncertainty on what a successful sprint is and when to kill the sprint because you will miss the sprint goal.

    A missing or bad sprint goal will pull your DevTeam into the ‚finish stories‘ anti-pattern. This is quite different from maximizing product/customer value/benefit through a ‚potentially shippable increment‘.

    Root Cause

    It is just wrong to throw top-down overboard and believe you could deliver „the next big thing“ bottom-up.

    You thought Scrum (as defined in here https://www.scrumguides.org/scrum-guide.html) is enough to get the cash cow to the customer? Bad luck. It is not.

    Mitigation, Remedy, How to avoid

    Let’s start with the easy ones.

    The SAFe Requirements Model

    If you look at your very own product backlog, you may see not much more than a flat list of quite simple ‚requirements‘: 

    Product Backlog items have the attributes of a description, order, estimate, and value. Product Backlog items often include test descriptions that will prove its completeness when „Done“.

    The Scrum Guide.

    That’s about it. And this is why a ton of methodologists had to invent something ‚above‘ this.

    PRINCE2 Agile has thought about the matching of standard PRINCE2 artifacts to agile terms, and came up with four possible levels (and I selected one possibility by underlining it…):

    • Vision
    • Epic, feature, theme, scope
    • Epic, feature, function, coarse-grained user story
    • User story, fine-grained user story

    SAFe is very specific about their requirements hierarchy. Please have deeper look into https://www.scaledagileframework.com/safe-requirements-model/.

    • Epic, is realized by
    • Capability, is realized by
    • Feature, is realized by
    • Story

    But be warned: A high level story (feature, epic, whatever) is not just a BIGGER story. At least within SAFe it has quite different attributes for very good reasons.

    In essential SAFe (https://www.scaledagileframework.com/) there are two levels of stories: features and stories. But features are not written with a story stencil in mind:

    As <who> <when> <where>, I <want> because <why>.

    https://en.wikipedia.org/wiki/User_story

    No. As an author of a SAFe feature you should stick to this:

    Features are defined using a Features and Benefits (FAB) Matrix: Feature – A short phrase giving a name and context Benefit hypothesis – The proposed measurable benefit to the end user or business

    © Scaled Agile, Inc. https://www.scaledagileframework.com/features-and-capabilities

    Features are driving the product increments (a set of sprints) as stories drive the sprints (iterations in SAFe terms).

    And features are combined to product roadmaps. See below…

    Now with this at hand, we are getting much closer to the basic intent of Agile: Optimizing the value delivered to the customer.

    The Sprint Goal

    The current scrum guide mentions ‚Sprint goals‘ 27 times for a good reason.

    In Scrum (https://www.scrumguides.org/scrum-guide.html#artifacts-sprintbacklog) the sprint backlog consists of three items:

    • A set of product backlog items which shall be implemented within this sprint.
    • A sprint goal.
    • A sprint plan on how to implement the product increment and how to realize the sprint goal.

    Please have a look at https://www.scrum.org/resources/blog/getting-done-creating-good-sprint-goals to get some ideas about good sprint goals.

    If you want to challenge your sprint goal, take some ideas from Fabio Panzavolta I found here: https://www.scrum.org/resources/blog/five-questions-sprint-goal

    Would you please keep in mind that although the sprint goal is mandatory and very important when it comes to meaningfulness. But it is by no means sufficient to really vanquish your team’s worm’s-eye perspective.

    BTW: Nexus (https://www.scrum.org/resources/online-nexus-guide) structures sprint goals by adding a higher level nexus sprint goal, which will be fulfilled by each team’s individual sprint goal. This is symmetrical to the concept of Nexus sprint planning versus team’s sprint planning.

    Product Roadmaps

    So, plan we must.

    © Scaled Agile, Inc. https://www.scaledagileframework.com/roadmap/

    Roman Pichler has got some good advice on product roadmaps (https://www.romanpichler.com/blog/10-tips-creating-agile-product-roadmap/)

    SAFe has got a different approach: https://www.scaledagileframework.com/roadmap/. And I quite like it. 

    If you think about a ’standard‘ implementation, a product increment (PI) takes one quarter because it is consisting of six two-weeks sprints (iterations). Features (turned into PI objectives, for a deeper look into the differences spend some time on how to Differentiate between Features and PI Objectives in https://www.scaledagileframework.com/pi-objectives/) drive the PI. And as a product manager you should have a clear idea about this next quarterly PI. Thus the set of features (to be precise: the set of PI objectives) in the next PI is committed.

    The PI roadmap now combines this committed PI with the forthcoming PIs which contain not so clear and sure features. These forthcoming PIs are forecasts and not committed, because you have learned your lesson from

    Responding to change over following a plan

    This is #4 of the four values of the Agile Manifesto (https://agilemanifesto.org)

    If you now commit to the next three to four PIs (or: quarters), you committed suicide, because your ability to respond to change is down to zero.

    Over-commitment is committing Agile suicide.

    me.

    The Vision.

    Scrum does not have a clear idea about the product vision. Although you may find some ideas in this blog useful:

    https://www.scrum.org/resources/blog/10-tips-product-owners-product-vision

    Sadly, Robbin suggest to use a story-like stencil, which is not quite the right way to communicate successfully with top-tier management, product marketing, non-developers or anyone who is not a Scrum-disciple.

    The statement of a desired future state.

    PRINCE2 Agile

    SAFe agrees to this:

    The Vision is a description of the future state of the Solution under development.

    SAFe https://www.scaledagileframework.com/vision/

    But SAFe says much more about your vision: Your vision should be present on all layers of your organization: 

    • Starting at the C-level you should have your strategic themes at hand.
    • On portfolio level you should have a clear birds-eye view on the long-term endeavors.
    • On the solution level (covering multiple product and/or systems) and again on the product level (then it’s called product vision….) you should ask yourself

    What will this new solution do? 

    What problems will it solve? 

    What features and benefits will it provide? 

    For whom will it provide them? 

    What Nonfunctional Requirements will it deliver?

    © Scaled Agile, Inc. https://www.scaledagileframework.com/vision/

    BTW: The product roadmap „is part of the vision“.

  • Agile Anti-Pattern: Sub-contractor stick & carrot approach.

    Pattern Description

    Your IT department is doing pretty good in using Agil, but somebody from the C-level forgot to ‚agilize‘ your purchasing department and/or sub-contractor management.

    Thus the contracts with your vendors did not change since 1980 and may be summarized as:

    • Fixed price contracts,
    • Contractually binding requirements specification,
    • Contractual penalties based on
      • Quality gates
      • Error levels
      • Reaction times (typically: analysis only, not resolution)
    • Project plan including milestones.

    Issue, Problem, Risk

    If your company is going Agile and your suppliers don’t, you are in trouble.

    Root Cause

    You startet an isolated bottom-up implementation of Agile.

    Mitigation, Remedy, How to avoid

    Agile has to start on the C-level and should be iteratively implemented with E2E in mind.

    If contractors are involved in your E2E processes (or value streams in SAFe lingo), then you either have to exclude these artifacts explicitly from your Agile universe or your should consider a different contracting approach. Think about PRINCE2 Agiles view on Agile Contracting.

  • Arduino IR sensor to trigger onboard LED

    Use this sketch to detect an object very close to the IR sensor. This could be useful for model railroading where a train should be detected to trigger a warning light at a level-crossing.

    // hardware: Arduino UNO, IR sensor from funduinoshop.de
    // https://funduino.de/arduino-infrarot-abstandssensor
    
    // port connected to analog read of IR sensor module
    const int ANALOG_IN = A0;  
     
    // onboard LED
    const int LED = 13;   
    
    // threshold, to be set to values which work in your situation
    const int THRESHOLD = 300;
    
    // value in ms, delay between measurements
    const int DELAY = 100;      
    
    void setup() {
      pinMode(LED, OUTPUT);     
    }
    
    void loop() {
      digitalWrite(
        LED,
        (analogRead(ANALOG_IN) < THRESHOLD) ? HIGH : LOW
      );     
      delay(DELAY);
    }
  • Does your Google search make a difference on your carbon footprint?

    The „problem“…

    Some people (https://www.welt.de/kmpkt/article196360705/Weltretter-Anleitung-6-Wege-wie-du-in-deinem-Alltag-ganz-leicht-CO2-sparst.html) think that it is best to not use Google, because „they are evil“ or whatnot. And then they come up with the CO2 thing and think that something like https://www.ecosia.org will save their souls. Sounds too good to be true, doesn’t it? Well. It is.

    To get a deeper insight into this, we need numbers. Here they are:

    The numbers…

    [table id=8 /]

    The conclusion…

    You could compensate for all of your annual Google searches by spending less than ten seconds less under the shower. Per year. Which translates to around 10 milliseconds a day, which I was happy to factor in this morning. I am feeling so much better now…

  • A reply on Michael Küster’s agile anti-patterns

    https://failfastmoveon.blogspot.com/2019/07/how-agilists-betray-very-nature-of.html

    While I agree upon the „badness“ of Michael’s anti-patterns, I would like to add some remarks on my reasons, why he is right.

    On Agile projects

    Anti-Pattern

    There’s no such thing as Agile Projects! You must do Product Development!“ – can you even smell how dogmatic and close-minded this is? You’re not inviting a discussion, you’re ending it!

    https://failfastmoveon.blogspot.com/2019/07/how-agilists-betray-very-nature-of.html

    Remark

    Since Scrum is Agile and Jeff Sutherland’s wife Arline is using Scrum for projects in church (cf. https://www.pmi.org/learning/library/agile-project-management-scrum-6269) I don’t care, if some people get angry about “agile projects”.

    For the sad few for whom this is not enough, I would like to add that the PRINCE2 Agile world distinguishes between projects and business as usual (or BAU). While BAU is for ongoing activities with steady teams and more predictable outcome (and PRINCE2 Agile is not applicable), PRINCE2 Agile deals with projects, which in turn deal with uncertainty, complexity, and time boxes.

    On Fixed scope

    Anti-Pattern

    We’re Agile! That’s Big Upfront Design, Waterfall!“ Proposing to make the scope known upfront is met with arrogance and disdain. You wouldn’t even bother to ask,  „what do you mean by fixed scope„, because fixed scope indicates that this person just doesn’t get it.

    https://failfastmoveon.blogspot.com/2019/07/how-agilists-betray-very-nature-of.html

    Remark

    PRINCE2 Agile uses the “fix and flex” concept on six dimensions, and scope is one of them. For scope prioritization it uses the MoSCow technique (Must, Should, Could, Won’t have), meaning that you may flex the should haves and could haves, but should not flex = fix the must haves).

    https://publications.axelos.com/prince2agile2015/content.aspx?page=cros_37&showNav=true&expandNav=true

    A car without an engine is not a car, a car without a sat-nav maybe is not up-to-date (should? could?) but still marketable.

    See also https://cms.vp-consulting.de/prince2-agile/#whattofixandflex

    On Milestone dates & product roadmap

    Anti-Pattern

    We can’t know what or when!“ – calling the request unreasonable and insisting on a free pass for the team. 

    Our stakeholders want to know our product roadmap – what they can expect in the next year or two. A roadmap instills confidence that you know what you’re doing and aren’t getting tossed about by every wind.
     „That’s not Agile„, I hear you scream!

    https://failfastmoveon.blogspot.com/2019/07/how-agilists-betray-very-nature-of.html

    Remark

    Exhibitions typically are fixed and planned events, aligned with different streams and external parties, e.g. presenting at IFA Berlin or CES is very resource intensive, expensive and will affect share prices if you don’t deliver, so deliver the best you can. 

    Which means, keep your core product requirements fixed and flex on the should/could haves.

    In SAFe lingo: continuously re-prioritize your product backlog, having your product roadmap towards the exhibition in mind.

    Progress report

    Anti-Pattern

    We have Reviews, and thus, progress reports are a waste„. The mere suggestion of a progress report obviously means that the individual doesn’t understand agility and the organization wants to preserve status quo.

    https://failfastmoveon.blogspot.com/2019/07/how-agilists-betray-very-nature-of.html

    Remark

    cf. https://scrumguides.org/scrum-guide.html#artifacts-productbacklog and look for “managing progress toward goal”.

    This gives a quite nice hint on what to do: First you have to have a goal. Second: “Various projective practices upon trending have been used to forecast progress, like burn-downs, burn-ups, or cumulative flows.”

    As Tom DeMarco once said: “Bad metrics are better than no metrics”.

  • How to control effects via MIDI with a Teensy 3.6/LC

    Introduction

    A friend of mine, a keen professional guitar player, wanted a small box to control settings of a looper (a box with which can be used to store audio fragments, loop and stack these fragments).

    MVP

    • MIDI out (DIN)
    • at least three (configurable) push buttons which send a MIDI control change message
    • a configurable MIDI channel

    This system is realized with a Teensy 3.6, but a much cheaper Teens LC will work as good.

    Step 1: Get the MIDI out going

    If you use a Teensy LC or 3.x this is a very easy exercise:

    A MIDI out for the Teensy 3.6 (or LC) using serial send port 1 (TX1). Cf. https://www.pjrc.com/teensy/td_libs_MIDI.html

    Be aware that Arduino is based on 5V and then the resistors have to be different (220 Ω). Too low resistors will cause too high currents on the instrument’s side. So it is not my fault, if you have to send in your Dave Smith…

    This quite simple setup can be used by our (quite simple…) first sketch. In step one we want to play a halftone scale from C1 to C2, each note will be played for a 10th of a second and then stopped. The loop should do nothing. 

    #include <MIDI.h> 
    
    // connect the MIDI library to serial port TX1
    MIDI_CREATE_DEFAULT_INSTANCE();
    
    void setup() {
      MIDI.begin();
      for (int note=60; note <= 72; note++) {
          MIDI.sendNoteOn(note, 100, 1);
          delay(100);
          MIDI.sendNoteOff(note, 100, 1);
      }
    }
    
    void loop() {
    }

    You will have to connect some MIDI instrument via the old fashioned MIDI cable, and have to listen on MIDI channel 1. If you don’t hear anything, you may switch on your amp, move the MIDI plug to your instrument’s MIDI in, or swap MIDI pin 4 and 5 (a wrong connection won’t do any harm). 

    Step 2: ‚Press the sustain pedal‘ if a push button is pressed

    We will use the code from above, but will check the status in the loop() function. To avoid multiple sends we have to capture the send status, thus we only send the control message ’sostenuto pedal = ON‘ if the button is pressed AND the message hasn’t been sent already.

    Here comes the fritzing board:

    Same as above, but now we have to react to the push button…

    Step 2 a): Send a C when you press the button (sketch is the same)

    #include <MIDI.h>
    
     // connect the MIDI library to serial port TX1
     MIDI_CREATE_DEFAULT_INSTANCE();
    
     const unsigned int PUSH_BUTTON_PIN = 2;
     const byte INTRO_NOTE = 108;
     const byte BUTTON_NOTE = 60;
     const byte CHANNEL = 1;
     const byte VELOCITY = 100;
    
     bool sent;
    
     void setup() {
       sent = false;
       MIDI.begin();
       pinMode(PUSH_BUTTON_PIN, INPUT_PULLUP); 
       MIDI.sendNoteOn(INTRO_NOTE, 100, 1);
       delay(500);
       MIDI.sendNoteOff(INTRO_NOTE, 100, 1);
     }
     void loop() {
       unsigned int buttonState = digitalRead(PUSH_BUTTON_PIN);
       // if button pressed and not  sent
         // send note on
       if (LOW == buttonState && !sent) {
         MIDI.sendNoteOn(BUTTON_NOTE, VELOCITY, CHANNEL);
         sent = true;      
       }
       // if button not pressed and sent
         // send note off
       if (HIGH == buttonState && sent) {
         MIDI.sendNoteOff(BUTTON_NOTE, VELOCITY, CHANNEL);
         sent = false;  
       }
       delay(10);
     }

    Step 2 b): Send the Control Change when you press the button

    #include <MIDI.h>
    
    MIDI_CREATE_DEFAULT_INSTANCE();
    
    const unsigned int PUSH_BUTTON_PIN = 2;
    
    const unsigned int SUSTAIN_PEDAL = 64;
    const unsigned int SOSTENUTO_PEDAL = 66;
    
    const byte INTRO_NOTE = 108;
    const byte BUTTON_NOTE = 60;
    const byte CHANNEL = 1;
    const byte VELOCITY = 100;
    const byte CC_OFF = 0;
    const byte CC_ON = 127;
    
    bool sent;
    void setup() {
      sent = false;
      MIDI.begin();
      pinMode(PUSH_BUTTON_PIN, INPUT_PULLUP); 
      MIDI.sendNoteOn(INTRO_NOTE, 100, 1);
      delay(500);
      MIDI.sendNoteOff(INTRO_NOTE, 100, 1);
    }
    
      void loop() {
        unsigned int buttonState = digitalRead(PUSH_BUTTON_PIN);
        if (LOW == buttonState && !sent) {
          MIDI.sendControlChange(SUSTAIN_PEDAL, CC_ON, CHANNEL);
          sent = true;
        }
        if (HIGH == buttonState && sent) {
          MIDI.sendControlChange(SUSTAIN_PEDAL, CC_OFF, CHANNEL);
          sent = false;
        }
        delay(10);
      }

    Step 3: Add DIP switches for the controller number and the MIDI channel

    There are 16 MIDI channels (1..16) which could be defined by a four way DIP-switch connected to ground and four input channels. And if we understand how to read these four ( 4 bit) switches, we easily could extend our code to define the control change number (0..127, thus 7 bit).

    At the moment we can take this route but we already have in mind that this approach consumes a hefty 11 Teensy input channels.

    The code to read the MIDI channel DIP switch is pretty straight forward. Obviously this has to be placed in the setup() function. Since we placed this routine in the setup() function, it will only be read once – during startup.

    To be consistent we read from left to right, thus the control channel bit 0 is the left DIP switch labeled with ‚1‘, etc. (BTW: In the original setting I used a 4 way DIP switch instead of two two way ones…)

    #include <MIDI.h> 
    
     MIDI_CREATE_DEFAULT_INSTANCE();
    
     const unsigned int PUSH_BUTTON_PIN = 2;
    
     const unsigned int SUSTAIN_PEDAL = 64;
     const unsigned int SOSTENUTO_PEDAL = 66;
     
     const byte INTRO_NOTE = 108;
     const byte BUTTON_NOTE = 60;
     const byte VELOCITY = 100;
     
     const byte CC_OFF = 0;
     const byte CC_ON = 127;
    
     bool sent;
     unsigned int channel;
    
     void setup() {
      
       sent = false;
       MIDI.begin();
    
       pinMode(PUSH_BUTTON_PIN, INPUT_PULLUP); // button
    
       pinMode(3, INPUT_PULLUP);
       pinMode(4, INPUT_PULLUP);
       pinMode(5, INPUT_PULLUP);
       pinMode(6, INPUT_PULLUP);
       
       channel = digitalRead(6) << 3;
       channel |= digitalRead(5) << 2;
       channel |= digitalRead(4) << 1;
       channel |= digitalRead(3); 
       channel++; // 1..16!
       
     }
     
     void loop() {
       unsigned int buttonState = digitalRead(PUSH_BUTTON_PIN);
       if (LOW == buttonState && !sent) {
         MIDI.sendControlChange(SUSTAIN_PEDAL, CC_ON, channel);
         sent = true;
       }
       if (HIGH == buttonState && sent) {
         MIDI.sendControlChange(SUSTAIN_PEDAL, CC_OFF, channell);
         sent = false;  
       }
       delay(10);
     }

    The control change DIP switch will be set up accordingly. But as you can imagine, we are running out of pins pretty quickly. Since we want three push buttons in our sketch, we would need 3×8+4 = 28 ports just for the three buttons.

    Future improvements

    • Step 4: Add an input shift register to reduce the number of Teensy ports. 
    • Step 5: Cater for different types of control change messages
    • Step 6: Add rotary input controls
    • Step 7: Add status save buttons for the rotary controls
  • Arduino state machines with function pointers

    Rudysmodelrailway implements a railway crossing with blinking lights by introducing a state rdudiagram, which he then in turn implements by switch statements. Here is my take on the state diagram of a (one way) railway crossing with sensor S1 detecting an incoming train and sensor S2 detecting if the train has passed the crossing:

    This looks a bit too messy (but maybe I thought a bit too complicated), so let’s split the problem in two parts: In the first part we just have the blinking lights in the second, we add the gates.

    Now let’s have a look at the blinking-only version: Let’s assume the sensors are less then one train lengths apart and installed on both sides of the railway crossing. The following pictures give us an impression on what to show when.

    In state 0 the crossing is idle. In state 1 the first sensor sees the train, this the blinking should start.
    In state 2 both sensor see the train, blinking is ON. In state 3 only the left sensor sees the train, the blink continues. 

    So, the bottom line is: „Blink if at least one sensor is detecting something, otherwise be quiet“. To describe this behavior we use a thing called a ’state transition table‘ (https://en.wikipedia.org/wiki/Finite-state_machine) :[table id=8 /]

    This state transition table can be realized as so:

    // teensy 3.6
    
     const unsigned int S1_PORT = 1;
     const unsigned int S2_PORT = 2;
     const unsigned int LED1_PORT = 3;
     const unsigned int LED2_PORT = 4;
     unsigned int blinkingLightsDuration = 300;
     unsigned int blinkingLightsLeft;
     unsigned int blinkingLightsRight;
     unsigned long oldSensorTimer;
    
     void setup() {
       oldSensorTimer = millis();  
       pinMode(LED1_PORT, OUTPUT);
       pinMode(LED2_PORT, OUTPUT);
       pinMode(S1_PORT, INPUT_PULLUP);
       pinMode(S2_PORT, INPUT_PULLUP);
     }
    
     void loop() {
       unsigned int sensorValue = detectSensor();
       switch (sensorValue) {
         case HIGH:
           blinkingLightsOn();
           break;
         case LOW:
           blinkingLightsOff();
           break;
       }
       blinkingLightsSend();
       delay(123);
     }
    
     unsigned int detectSensor(void) {
       // if one or both of the buttons are pressed, return 1
       return 
        (!digitalRead(S1_PORT) || !digitalRead(S2_PORT)) ? 1 : 0;
     }
     void blinkingLightsOn() {
       unsigned long timer = millis();
       if (timer - oldSensorTimer > blinkingLightsDuration) {
         blinkingLightsLeft = 
              (blinkingLightsLeft == LOW) ? HIGH : LOW;
         blinkingLightsRight = !blinkingLightsLeft;
         oldSensorTimer = timer;
       }
     }
     void blinkingLightsOff() {
       blinkingLightsLeft = LOW;
       blinkingLightsRight = LOW;
     }
     void blinkingLightsSend() {
       digitalWrite(LED1_PORT, blinkingLightsLeft);
       digitalWrite(LED2_PORT, blinkingLightsRight);
     }

    The loop function looks already a bit messy, but bear in mind we haven’t even introduced the gates yet.

    This is one of the standard ways to implement finite state automatons: write down the state transition table and implement it as cascading switch clauses.[table id=9 /]

    Here we have a slightly improved version of the state transition table. Instead of text we use a function style syntax. How would this better implemented in C?

    To answer this we need a bit of knowledge about function pointers, so have a look at this: http://www.newty.de/fpt/index.html

    If you want to understand function pointers a bit better, have a look at http://johnsantic.com/comp/state.html. The way he implements the FSA is quite straight forward, but not at all easy to understand. 

    Let’s try to implement the transition table in a way similar to John’s way.

    // teensy 3.6
    
    // cf. http://johnsantic.com/comp/state.html
    
     const unsigned int S1_PORT = 1;
     const unsigned int S2_PORT = 2;
    
     const unsigned int LED1_PORT = 3;
     const unsigned int LED2_PORT = 4;
    
     unsigned int blinkingLightsDuration = 300;
     unsigned int blinkingLightsLeft;
     unsigned int blinkingLightsRight;
     unsigned long oldSensorTimer;
    
     void blinkingLightsOn();
     void blinkingLightsOff();
     void doNothing();
    
     enum States {IS_OFF, IS_ON, MAX_STATES} states;
     enum Events 
        {BUTTON_NOT_PRESSED, 
           AT_LEAST_ONE_BUTTON_PRESSED, MAX_EVENTS} events;
    
     // { action_s1_e1, action_s1_e2, action_s1_e3, action_s1_e4 },
     // { action_s2_e1, action_s2_e2, action_s2_e3, action_s2_e4 }
    
     void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {
       { doNothing, blinkingLightsOn },
       { blinkingLightsOff, blinkingLightsOn }
     };
    
     States state = IS_OFF;
    
     void setup() {
       oldSensorTimer = millis();  
       pinMode(LED1_PORT, OUTPUT);
       pinMode(LED2_PORT, OUTPUT);
       pinMode(S1_PORT, INPUT_PULLUP);
       pinMode(S2_PORT, INPUT_PULLUP);
     }
    
     void loop() {
       Events event = detectSensor();
       state_table[state][event]();
       delay(123); 
     }
    
     Events detectSensor(void) {
       Events e;
       if (
         LOW == digitalRead(S1_PORT) || 
         LOW == digitalRead(S2_PORT)
       )
         e = AT_LEAST_ONE_BUTTON_PRESSED;
       else
         e = BUTTON_NOT_PRESSED;
       return e;
     }
    
     void doNothing() {};
    
     void blinkingLightsOn() {
       unsigned long timer = millis();
       if (timer - oldSensorTimer > blinkingLightsDuration) {
         blinkingLightsLeft = 
            (blinkingLightsLeft == LOW) ? HIGH : LOW;
         blinkingLightsRight = !blinkingLightsLeft;
         oldSensorTimer = timer;
       }
       blinkingLightsSend();
       state = IS_ON;
     }
    
     void blinkingLightsOff() {
       blinkingLightsLeft = LOW;
       blinkingLightsRight = LOW;
       blinkingLightsSend();
       state = IS_OFF;
     }
    
     void blinkingLightsSend() {
       digitalWrite(LED1_PORT, blinkingLightsLeft);
       digitalWrite(LED2_PORT, blinkingLightsRight);
     }

    You find the tricky bits in the loop() function. 

    It is tricky, because the switch statement has magically disappeared. Instead of the switch statement, you just call (!) an array element, which turns out to be a function, indexed by state and event. 

    To implement it you have to do this:

    • You define an enum for the states of the finite state machine, for your convenience add a MAX_STATES to it. This field is helpful in loops.
    • You define an enum for the events of the finite state machine, for your convenience add a MAX_EVENTS to it. 
    • You define all functions before referring to them.
    • You create a two dimensional table with MAX_STATES rows and MAX_EVENTS columns containing pointers to the functions which process the given combination. In case of doNothing() at an empty function…

    Example: When the FSM is in state „IS_OFF“ and receives an event „AT_LEAST_ONE_BUTTON_PRESSED“ then the function pointer table is referring to the function blinkingLightsOn(). Thus this function will be called. Within this function the state will be set accordingly (new state: „IS_ON“, leading to a new route, when the next events is read.

    How to extend to the final version with railway gates and IR sensors

    How IR sensors can replace the simple micro buttons can be learned here:https://cms.vp-consulting.de/arduino-ir-sensor-to-trigger-onboard-led/

    If you now want to extend this solution then to the version with gates, it seems to be very easy:

    • Add the servo to the sketch.
    • Add two function, one for raising the bars, one for lowering them.
    • Add these two functions to the functions which now trigger the blinkingLightsSend() function.

    If you see the risk the bars are not lowered before the train passes the crossing, place the detectors further apart and add a detector in the middle. 

    The logic with three sensors seems to be 100% identical.

  • A reply to Michael Küster’s article on „When will the Agile Project be done?“

    https://failfastmoveon.blogspot.com/2019/07/when-will-agile-project-be-done.html

    Dear Michael, this post should serve as a reply to some of the points you made in the post found above.

    I’ve got some questions…

    Q: Is „it“ a project?

    A: A project is a time-boxed endeavor to deliver a specific ‚product‘ with a limited resources. All these three conditions have to be fulfilled. Thus, if you don’t know what you want to deliver after the time box has ended, it’s not a project.

    Remarks from the PRINCE2 Agile perspective

    PRINCE2 is driven by themes, one of their themes is the business case. This business case will be initially developed in the ‚Starting up the project‘ process and will be finalized in the ‚Initiating the project‘.

    The business case contains three scenarios (best case, average case, worst case), which are based upon a combination of expected outcome (defined by high level requirements, AKA epics), risks, quality expectations and a defined timeline.

    PRINCE2 Agile thinks about what to flex and what to fix. Scope could be fix or flex. If we consider MoSCoW as a heuristic for evaluating importance/relevance of requirements, fix means „must have“ and sometimes „should have“, flex means „could have“.

    Q: What is your definition of the project’s „Definition of ‚done’“?

    A:  If you don’t have a ruler, you cannot measure distances. If you don’t have an idea of ‚done‘-ness of your project and its required product features, you can neither define the product your project shall deliver, nor can you judge if or when the product has been delivered successfully.

  • Weighted Shortest Job First (WSJF) and Climate Change.

    Based upon a total distance of 200,000 km, an eGolf driven by electrical energy as of today’s German production situation will produce 142 g/km CO2, a Diesel Golf will product 140 g/km CO2. If an eGolf is „fueled“ by wind energy only, it produces 59 g/km CO2. 

    https://www.welt.de/wirtschaft/article192405223/Klimabilanz-Erst-nach-100-000-Kilometern-ist-der-E-Golf-wirklich-gruen.html

    This is a complete disaster, because no smart person would invest 50 k€ to basically deteriorate his/her carbon footprint. And the 59 g/km are just based on hope, since green energy will just not be available in amounts needed to significantly transform western economy.

    What would a SAFe consultant do? My guess is: a SAFe consultant (I am one…) would apply the WSJF principle: 

    https://www.scaledagileframework.com/wsjf/

    In SAFe the weight is calculated by dividing the Cost of Delay (CoD) by the Duration:

    Weight = CoD / Duration

    The CoD is the sum of user-business value, time-criticality and risk reduction and/or opportunity enablement:

    CoD = user-business value + time-criticality + risk reduction

    where each parameter has a value of 1, 2, 3, 5, 8, 13, or 20.

    WSJF Applied to the eGolf and Possible Alternatives 

    Now, how would a carpool with two people who currently both own a Diesel Golf (solution 1, leading to weight 1) compare to the acquisition of two eGolfs (solution 2)?

    I actually do not know the CoD, but CoD1 should be roughly twice the value of CoD2, since CO2 production of the cars is quite identical and thus are halved in case 1.

    What is not identical is the time to market: The carpool can go live tomorrow, the eGolf has to be ordered and produced in let’s say three month, thus w2/w1 = 90.

    Now, my question is: Why on earth don’t we focus our efforts on carpools instead of electrical cars?!