I've been developing concurrent
systems for several years now, and I
have a pretty good grasp on the
subject despite my lack of formal
training (i.e. no degree).
Many of best programmers I know didn't finish the University.
As for me I studied Philosophy.
C/C++, C#, Java, etc.). In particular,
it can be near impossible to recreate
conditions that happen readily on one
system in your development
environment.
yes
How do you figure out what can be made concurrent vs. what has to be
sequential?
we usually start with a 1000 miles high metaphor to clarify our architecture to ourselves (firstly) and to others (secondly).
When we faced that problem, we always found a way to limiting the visibility of concurrent objects to non concurrent ones.
Lately I discovered Actors in scala and I saw that my old solutions were a kind of "miniactors", much less powerful than scala ones. So my suggestion is to start from there.
Another suggestion is to skip as many problems as possible: for example we use centralised cache (terracotta) instead of keeping maps in memory, using inner class callbacks instead of synchronised methods, sending messages instead of writing shared memory etc.
With scala it's all much easier anyway.
How do you reproduce error conditions and view what is happening
as the application executes?
No real answer here. We have some unit test for concurrency and we have a load test suite to stress the application as much as we can.
How do you visualize the interactions between the different
concurrent parts of the application?
Again no real answer: we design our Metaphor on the whiteboard and we try to make sure there are no conflicts on the architectural side.
For Arch here I mean the Neal Ford's definition: Sw Architecture is everything that will be very hard to change later.
programming leads me to believe you
need a different mindset than you do
with sequential programming.
Maybe but for me it's simply impossible to think in a parallel way, so better design our software in a way that doesn't require parallel thinking and with clear guardrails to avoid crashes between concurrency lanes.
I generally try and describe Object-Orientated-Programming by using real world examples.
For example, I might say that a class called Vehicle
describes the minimum things that a vehicle is. I'll ask the person to tell me what he or she thinks a vehicle is. Sometimes they say things like "Well, like a car or a truck", and I'll nod and agree with them. Then I'll ask what the differences are between a car and a truck. Sometimes they mention size, sometimes the purpose, and other things.
Then I'll ask them to forget about a car, or a truck and just ask them to continue to describe a vehicle:
"Oh, well it moves"
"It has an operator, or a driver"
etc...
Soon, we know what a Vehicle is and I said that in OOP we would define a vehicle, and for the sake of argument say it can move, and give it a driver of sorts. Then I'll ask, ok, so what does a Car have?
"Doors"
"Windows"
And then a truck....
"Doors"
"windows"
"More Wheels!"
Soon, after lots of discussion, the other person generally has identified:
1) What constitutes a vehicle
2) What constitutes a car
3) What constitutes a truck
4) What constitutes an aeroplane.
All without any technicalities. We've divided up the properties of each in to the right areas. They understand inheritance ("Yeah, a car is a vehicle, a truck is a vehicle, but a car is not a truck, it's SIMPLE, duh!").
They even understand polymorphism, "Sure, they basically do the same, but that might do it slightly different.". We can talk about behavior and where that should live in our tree of objects.
Depending on their education and background, some get it faster than others. But when I compare OOP to real-life objects, most people always get it. In fact, I have found in conversations with non-technical people things I had never thought of. Vehicles don't have to be manned, for example (drones), but would a programmer have thought of the operator of the vehicle as a property of it? I am not saying it is right or wrong to have an operator mentioned, but it causes us to think about what we are modelling and what we are trying to achieve when we develop software.
Now, partial template specialization, on the other hand.... :)
Best Answer
If you can count on any mathematical experience, illustrate how a normal execution flow that is essentially deterministic becomes not just nondeterministic with several threads, but exponentially complex, because you have to make sure every possible interleaving of machine instructions will still do the right thing. A simple example of a lost update or dirty read situation is often an eye-opener.
"Slap a lock on it" is the trivial solution... it solves all your problems if you're not concerned about performance. Try to illustrate how much of a performance hit it would be if, for instance, Amazon had to lock the entire east coast whenever someone in Atlanta orders one book!