Thursday, November 11, 2021

Bugs in Complex Software

In the picture: history's first bug.

Complex software will be guaranteed to have bugs in it. And most of the bugs are caused by state changes.

The human mind has limited capacity of keeping track of state (data, variables.) Hence, there is a discrepancy between what the state looks like in the programmer's mind, and what it actually looks like.

How does state change?

Where in the code does the state change?

When does the state change?

In what order does the state change?

And even... why doest the state change?

The mental picture of those, formed by the programmer, is very poor.

So.. bugs!

There is of course a paradigm where state-change plays a zero roll: functional programming. But despite decades of trying, we have not been able to practically use that in complex software. Mainly because the real world deals with state. Try making a video game that carries no state!

John Carmack once did an impromptu talk on functional programming and video games, and made in interesting observation that you could write an AI/sim that takes the entire world as function input, and produces the entire world as its output.

About John's example of a one-person hallway... I think the solution is simple. Input for hall-entering needs more than the current entity. It needs a list of all other entities that want to enter. Then use a heuristic to choose which one can actually enter. Done.

So yeah... complex state changes. As long as we have not harnessed the complexity of state, I find it pretty futile to crusade against C's unsafe memory referencing, e.g. A bug caused by following a dangling pointer is so shallow, compared to a bug caused by asynchronous state changes racing to completion. Throw in multiple threads, multi-player, and it will be too hard to reason about.

Sunday, November 7, 2021

Switching

I've been learning a lot about transistors, lately. This is because I found myself having to switch a load that would be too large for an IO pin. Here I summerize my newly gathered knowledge on them.

A BJT transistor is switched ON/OFF using current at the base. This current is then multiplied at Collector/Emitter.

To tune the current flowing through the base, we need a bias resistor. This makes PCB design bulkier, but you can get pre-biased transistors. I find I need to get them with a low Ohm bias, else my transistor will not switch fully on.

BJT comes in two variants, NPN and PNP. The schematic symbol differs in which way the arrow points. Mnemonic: NPN has the arrow "Not Pointing iN."

PNP transistors can be used to switch a load at its high-side: You cut the load's connection to V+ ON/OFF.

NPN transistors can be used to switch a load at its low-side: You cut the load's connection to GND ON/OFF.

MOSFET transistors are often a better choice, unlike of BJT's current based switching, the switch based on voltage at the gate.

MOSFET comes in two variants, P-CHANNEL and N-CHANNEL.

P-CHANNEL transistors can be used to switch a load at its high-side: You cut the load's connection to V+ ON/OFF. A 0V at the gate will switch on the transistor. Source is connected to V+ and Drain is connected to the load.

N-CHANNEL transistors can be used to switch a load at its low-side: You cut the load's connection to GND ON/OFF. A V+ at the gate will switch on the transistor. Source is connected to GROUND and Drain is connected to the load.

To simplify a PCB design, you can get two transistors that share its housing in an "Array."