An agile journey and beyond

Kategorie: Coding (Seite 1 von 2)

About Programming

„Real Programmers Do AI in FORTRAN“ — Four Decades Later

Browsing old files last week, I found a quote from 1983 that stopped me for a moment:

“Real Programmers do Artificial Intelligence programs in FORTRAN.”

Forty-three years later, that joke hits differently.

At the time, it was satire. AI meant symbolic systems and Lisp machines. FORTRAN meant numerical computing. Claiming that “real programmers” would write AI in FORTRAN was deliberately absurd — a jab at macho developer culture and language tribalism.

But reading it today, in the age of GPT, Claude, and Gemini, it feels less like a joke about AI and more like a timeless observation about us.


The war never ends — it just rebrands

The original satire nailed something enduring:
developers will always form factions around tools.

Back then it was:

  • Lisp vs. Prolog
  • C vs. Pascal
  • “Structured programming” vs. “real programming”

Today it’s:

  • GPT vs. Claude vs. Gemini
  • Copilot vs. Claude Code
  • Rust vs. Go
  • VS Code vs. JetBrains

The pattern is unchanged:

  1. Pick a tool.
  2. Attach identity.
  3. Defend it with the passion of sports fandom.
  4. Declare everyone else unserious.

It’s comforting. It creates a clean story:
If we choose the right tool, we win.

But that’s rarely where the real advantage lies.


Tool choice is rarely the differentiator

Yes, tools matter. Bad tools slow you down. Good tools accelerate you.

But most performance gaps between teams are not explained by language or model choice. They’re explained by fundamentals:

  • Do you understand the problem?
  • Do you ship in small increments?
  • Do you measure outcomes?
  • Do you integrate feedback?
  • Do you use tools deliberately instead of ideologically?

Last month we evaluated different AI coding assistants for a team. The debate started as, “Which one is smarter?” Within an hour it became clear that the real question wasn’t intelligence — it was integration. Which one fits our compliance constraints? Which one works with our on-prem repositories? Which one aligns with our security model?

The model comparison was interesting.
The workflow implications were decisive.

That’s usually how these debates end — once you stop performing identity and start optimizing for outcomes.


The FORTRAN irony deserves more credit

Here’s the part that makes the original quote even better with hindsight.

The joke is that the author was accidentally right.

Modern AI does run on FORTRAN’s spiritual descendants. Those BLAS libraries and GPU kernels performing matrix multiplications are much closer to FORTRAN’s numerical computing DNA than to Lisp’s symbolic reasoning roots.

The AI revolution wasn’t won by symbolic purity.
It was won by scalable numerical computation.

The “real programmer” flex completely missed the direction history was about to take.


GPT vs. Claude vs. Gemini: the new FORTRAN vs. Lisp

Today’s debates follow the same pattern:

  • “Claude reasons better.”
  • “GPT writes cleaner code.”
  • “Gemini integrates better with our stack.”

Some of that is true in specific contexts. But the winning move isn’t picking a champion. It’s building a system of work.

High-performing teams don’t just “use AI.” They:

  • Define where it reduces cycle time
  • Establish review and validation loops
  • Understand its failure modes
  • Measure impact

Model choice matters.
Workflow design matters more.


Assembly taught me something about this

Here’s what changed my perspective on abstraction layers.

In my early twenties I decided life is too short to program in assembly and switched to Java, C++ and C#. That wasn’t lowering standards. It was choosing leverage. I could build more meaningful systems by operating at a higher level of abstraction.

Assembly still exists — in kernels, embedded systems, performance hotspots. But almost nobody builds complete products in it anymore. Not because we forgot how. Because we learned that leverage scales better than heroics.

Today it feels similar.

Life is too short not to use AI when building software.

Not as a crutch. Not as a substitute for thinking.
But as the next layer of abstraction.

We moved from assembly to high-level languages to gain leverage.
Using AI well is simply the next step in that progression.


So yes, “Real Programmers do AI in FORTRAN.”

And in Lisp.
And in Python.
And with GPT, Claude, Gemini — and whatever comes next.

Because real programmers don’t defend tools as identity.

They use leverage.

Was spricht gegen Exceptions in C++?

Obwohl es Exceptions im C++ Standard schon etliche Jahre gibt, werden diese in größeren Projekten oft nicht eingesetzt. Im folgenden Artikel möchte ich das Für und Wider erörtern und mit gängigen Vorurteilen aufräumen.

try {
    funktion();
   ...
} catch (const std::invalid_argument& e) {
    std::cerr << "Falsches Argument:"  << e.what() << std::endl;
} catch (const std::range_error& e) {
    std::cerr << "Ungültiger Bereich:" << e.what() << std::endl;
} catch (...) {
    std::cerr << "Sonstiger Fehler" << std::endl;
}

Gängige Vorurteile

  1. Die Behandlung von Ausnahmen ist codeintensiver (mehr Schreibarbeit)
    Falsch. Ein sinnvolles try/catch braucht ist sogar weniger Code als ein sinnvolles if/else if/elsefür alle möglichen Fehlercodes. Fehlercodes werden aber oft nicht vollständig überprüft oder gar ganz weggelassen, was der Qualität des Codes nicht gerade zuträglich ist. Exceptions dagegen zwingen zu einer durchdachten Fehlerbehandlung.
  2. Exceptions machen den Code langsam
    Falsch. Wenn Exceptions richtig eingesetzt werden, sollten sie für Ausnahmen im Programmablauf verwendet werden. Die Ausführungsgeschwindigkeit des "Gut"-Pfades (in dem keine Ausnahmen geworfen werden) leidet nicht darunter. Wenn also die Exception die Ausnahme und nicht die Regel ist, hat man nichts zu befürchten. Weiterlesen

Dateiversion auslesen

#pragma comment( lib, "version" )
struct FileVersion
{
	DWORD dwLeftMost;
	DWORD dwSecondLeft;
	DWORD dwSecondRight;
	DWORD dwRightMost;
	bool IsLower( const FileVersion& ver )
	{
		return dwLeftMost < ver.dwLeftMost ? true :
			dwSecondLeft < ver.dwSecondLeft ? true :
			dwSecondRight < ver.dwSecondRight ? true :
			dwRightMost < ver.dwRightMost ? true : false;
	}
};

static void GetFileVersion( const CString& fileNameWithPath, FileVersion& fileVersion )
{
	DWORD dwDummy;
	DWORD dwFVISize = GetFileVersionInfoSize( fileNameWithPath , &dwDummy );
	LPBYTE lpVersionInfo = new BYTE[dwFVISize];
	::GetFileVersionInfo( fileNameWithPath , 0 , dwFVISize , lpVersionInfo );
	UINT uLen;
	VS_FIXEDFILEINFO* lpFfi;
	::VerQueryValue( lpVersionInfo , _T("\\") , (LPVOID *)&lpFfi , &uLen );
	DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
	DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
	delete[] lpVersionInfo;
	fileVersion.dwLeftMost = HIWORD(dwFileVersionMS);
	fileVersion.dwSecondLeft = LOWORD(dwFileVersionMS);
	fileVersion.dwSecondRight = HIWORD(dwFileVersionLS);
	fileVersion.dwRightMost = LOWORD(dwFileVersionLS);
}

C++ Schlüsselwort „explicit“

Mit dem C++ Schlüsselwort „explicit“ kann man dem Compiler implizite Typumwandlungen verbieten. Dies kann manchmal ja auch ungewollt passieren, wie folgendes Beispiel zeigt:

#include 
#include 
struct MyClass
{
    MyClass(const char* name) : m_Name(name) {}
    virtual ~MyClass() {}
    const char* Who() const { return m_Name; }
private:
    const char* m_Name;
};

struct MyExplicitClass
{
    explicit MyExplicitClass(const char* name) : m_Name(name) {}
    virtual ~MyExplicitClass() {}

    const char* Who() const { return m_Name; }
private:
    const char* m_Name;
};


int main()
{
    MyClass A("a");
    MyExplicitClass B("b");
              
    A = "c";  // ok, hier funktioniert das, aber war das auch so gewollt? 
              // Auf den ersten Blick zu durchschauen ist diese Zuweisung jedenfalls nicht.

    B = "d";  // error C2679: Binärer Operator '=': Es konnte kein Operator gefunden werden, 
              // der einen rechtsseitigen Operanden vom Typ 'const char [2]' akzeptiert (oder
              // keine geeignete Konvertierung möglich)

    std::cout << "A: " << A.Who() << std::endl;
    std::cout << "B: " << B.Who() << std::endl;

    return 0;
}

Nützliches im Visual Studio #1

Multi-Zwischenablage

Eher zufällig bin ich beim Coden auf ein nettes Feature im Visual Studio (2008) gestoßen: VS hat eine mehrfache Zwischenablage auf die man mittels Shift+Ctrl+V zugreifen kann. Somit kann man auch auf Sachen zugreifen, die man eigentlich schon überschrieben hat.
vs2008_clipboard

Inkrementelle Datei-Suche

Mittels Ctrl+# gelangt man in das Suchen-Feld. Dort kann man mittels <of + Dateiname Dateien öffnen. Dabei werden alle Dateien der Solution inkrementell auf die Eingabe gematcht und in einer Combobox angeboten.

EIS auf code.google.com

EIS

Easy Installation System


Mein Installations-Tool, das Easy Installation System, ist jetzt auf Google Code verfügbar. EIS ist ein vollständiges Installationssystem, das in MASM32 geschrieben wurde. Es ist in deutsch und englisch verfügbar und für RAR-Dateien ausgelegt. Weitere Details auf der Projektseite: http://code.google.com/p/eis/

Die Entscheidung es OpenSource zu machen fiel, da ich leider nicht mehr genug Zeit habe es zu pflegen. Ich fände es allerdings schade, wenn das Projekt einfach so in der Versenke verschwinden würde.

Ich werde zwar versuchen, das Projekt weiter zu verwalten, aber viel Zeit kann und will ich dafür nicht mehr investieren.

Pure virtual function call

Eine abstrakte Klasse in C++ hat mindestens eine pure virtual Funktion (gekennzeichnet durch virtual ... = 0). Diese Funktionen können per Definition nicht direkt aufgerufen werden, da sie keine Implementierung haben (auch per Definition). Sollte die Methode dennoch aufgerufen werden, wird das Programm (von der Runtime) mit der Fehlermeldung „Pure virtual function call“ abgebrochen. Weiterlesen

« Ältere Beiträge