The Future of Software: Code Generation - The Analysis

The Future of Software: Code Generation - The Analysis

Finally on to what I've been promising since the beginning of the series.  Here is a quick recap of how we got here:

In the first post of the series, I made the bold statement that we really haven't seen a game changing software advance in the last 15 years.  I've been trying to prove that assertion starting with what I think is by far the most important software technology of all, programming languages.  I have other proof points as well I intend to discuss after this thread is concluded, but my approach to anything technology related is typically in priority order, and I believe programming languages is by far the most critical technology we deal with as software professionals.  After all, everything we do is ultimately expressed in a programming language of some sort.  Even machine code is a programming language.

Next we discussed programming language evolution.  I did my best to make this as quick and painless as possible, omitting many details to just focus on what I think were the most prevalent and ground-breaking evolutions.  I apologize to all those who worked on other languages and evolutionary paths, they are just as significant in their own right.  But nonetheless, here is the small but critical subset of what we went through.

In evolutionary step 1 we discussed moving from machine code to assembly language.  The productivity improvement going from machine code to assembly language is quite impressive, but what is more impressive is that it was done without a notable side effect.  I've been working quite a few years now and I can tell you that is a very special feat.  Almost every massive improvement I can think of also introduced non-trivial side effects.  The measure of a good technology in my opinion is the ratio of productivity improvement to side effect.  If that ratio is big, or practically infinite in the case of assembly language, then you have something very special on your hands.

In evolutionary step 2 we learned about the advancement from assembly language to compiled languages.  Another massive productivity increase where you no longer have to know all the intimate details of the CPU in order to program software.  Unfortunately compiled languages introduced significant side effects, most of which was addressed through improvements to CPUs and through the use of interactive development environments and debuggers.  Speed is still an issue today, but when you take into account the overall ratio of the massive productivity boost compared to the very small remaining side effects, assembly language is seldom used today.

In evolutionary step 3 we discussed object-oriented programs running inside of virtual machines.  This productivity enhancement added a level of abstraction to organize software for much higher levels of reuse.  Virtual machine runtimes added the ability under most circumstances to do automated garbage collection, freeing programmers to focus on the problem instead of the technology solving the problem.  Unfortunately along with the massive productivity increases also came non-trivial side effects.  I believe we are still struggling with the side effects today.  But here again the ratio of productivity improvement to side effect is so large, most people are writing object-oriented code inside of virtual machine runtimes. If you simply can't tolerate the performance issues and uncontrollable garbage collection pauses, then you go back to using compiled languages.

So now we come back to that bold statement I made.  Smalltalk was invented in the 70's and came quite popular for a time in the early 90's.  Java was created in the early 90's as well.  That was more than 15 years ago, no disputing that.  However I'm sure many of you will dispute the statement we haven't made a significant advancement since then.  So let's briefly discuss a few interesting evolutionary paths that haven't become mainstream to prove my point.

4th Generation Languages

Early in my career, I had to choose between pursing jobs using object-oriented languages verses pursuing jobs using 4th Generation Languages (4GLs).  At the time it was basically Smalltalk verses PowerBuilder.  Many of my friends took the PowerBuilder route and indeed made a good deal of money, almost certainly more than I did.  But I would contend I still made the correct choice with SmallTalk and then Java.  The problem with 4GLs is that pesky ratio of productivity improvement to side effect.  4th Generation Languages indeed have productivity improvements well beyond compiled languages and object-oriented languages.  The premise of a 4GL is to speed up the development of an entire application.  You develop the user interface for the application and the business logic behind the user interface.  The 4GL then automatically generates the code to execute the user interface, tie the user interface to the business logic, and persist the information entered into the user interface in a database.  Object-oriented programming languages won't do that for you, you have to hook all of that up in detailed code on your own. You map all of the information in the user interface screens to the business logic, then map the business logic to the database, and you have to properly handle the multitude of errors that can happen each step of the way.  In a large application, that amounts to millions of lines of complex and error-prone code, most of which is just automatically generated for you by the 4GL.

That all sounds really good, then why haven't 4GLs caught on?  Some would debate that statement.  Ruby on Rails and its derivatives are essentially 4GLs in nature.  They have the same core premise as PowerBuilder, they allow you to prototype the user interface and automatically generate code to link that user interface all the way through to databases.  Unfortunately Ruby on Rails has limitations like all the other 4GLs I'm aware of.  To fulfill the massive amount of code generation required to provide a workable solution, these languages need to greatly limit what they support.  PowerBuilder at the time I worked with it only supported Microsoft Windows thick clients.  No Mac or Linux desktop support, no web user interfaces, no native applications on iOS or Android.  Ruby on Rails supports web user interfaces only, no native applications for Windows/Mac/Linux/iOS/Android.  Most of the 4GLs support relational databases only. And since the relational databases aren't identical in their implementation of SQL, stored procedures, indexing, search, record locking, partitioning, encryption, and other features critical to a large-scale complex application, the 4GLs have limited support for vendors and versions.

User interface support is definitely an issue, but it isn't the fundamental issue.  Java doesn't support all the user interface technologies we listed above either.  The fundamental issue as I see it is the code generation is so pervasive and complex that it always creates serious limitations in designing and implementing your application.  The code generation is "too good."  When the system generates code you don't like, code that doesn't match your application requirements, you then are confronted with a serious problem.  You can try to:

  1. Figure out a way to change the generated code after the system generates it but before it is packaged into an application.  Almost always a bad idea, as the next time you change your application, you lose the tweaks to the generated code and have to do that work all over again. We briefly discussed the notion of round trip engineering in a previous post, tweaking generated code in this fashion breaks the principle of round trip engineering.
  2. Integrate custom code into the 4GL generated code.  Basically this means for a portion of your application, you have to turn off code generation.  You write the code manually, using the same technology as the code the 4GL generates, and follow detailed instructions created by the organization that crafted the 4GL, to integrate it properly with the rest of your generated application.  All good 4GLs have a way to do this as the problem above is a problem for every complex application.  This works very well the first time you do it, you claim victory, and move on.  Unfortunately this is a very bad long term strategy.  The next release of the 4GL changes the way the 4GL works, which changes the way your integration works, which then breaks your integration.  You may need to completely recode your integration, or you are stuck running old and subsequently unsupported versions of the 4GL.  I have seen this happen countless times in my career.
  3. Tell your stakeholders that your technology doesn't support their requirements and you can't do it at reasonable cost.  They must change their requirements.  That never goes over well, good luck with that!

Here is where we get back to that ratio, the productivity increase of a 4GL is tremendous, at least as significant as any of the other evolutions we previously discussed.  We have a big number on that side of the ratio.  But let's look at the side effects.  Limited support for the user interfaces the end users want to use.  Limitations in what you can code in your application and no good way I am aware of to exceed those limitations.  The number on that side of the ratio is equally large.  Overall I would claim a 4GL approach just isn't attractive as the side effects are equally as large as the productivity increases.

Functional Programming

I've had a few comments in prior posts that functional programming languages are a significant recent advancement. I would debate that in 2 ways. First of all I don't think it is recent, the principles of functional programming go all the way back to Lisp in the late 1950s. Second, I don't think it is a mainstream programming language. The most useful functional programming concepts are being adopted into recent releases of mainstream programming languages (Java Lambda expressions) and the languages themselves just don't provide that massive productivity boost. I think the best functional programming languages these days are actually object-oriented in nature with the addition of functional concepts. I'm sure the folks that came up with Scala wouldn't be happy with that characterization, but that is how I see it.

Evaluating New Languages

Lastly, let's take a look at the newest programming languages out there according to the Wikipedia list, by date of invention:

Clojure is a next generation Lisp (functional programming) language, which we addressed above. Go and Rust are next generation C/C++ languages with object-oriented and concurrent programming features added into the mix. They are compiled and have limited runtimes to address garbage collection pauses and runtime performance issues. Dart is a next generation Javascript language. Swift is Apple's equivalent of Java with again limited runtime features to minimize performance issues.

So that brings us to languages like Julia and MATLAB. They are programming languages specifically designed to specify and solve math problems. And guess what, FORTRAN was invented in the 1950s for that exact reason. However, I do think these languages need to get a lot more recognition these days. Some of the most difficult and most interesting problems out there for software developers today are laced with artificial intelligence which is incredibly math intensive. Self-driving cars, image recognition, voice recognition, virtual and augmented reality, robotics, social media networks, and massive multi-player games all require concurrent processing of real-time data with intensive math algorithms. But FORTRAN started down this path a long time ago.

Conclusion

I'm hoping I have convinced everyone by now that there have been no significant advancements in programming languages in the last 15 years. The last significant advancement in my opinion is the evolution from compiled languages to object-oriented languages with virtual machine runtimes. Newer programming languages almost universally look to optimize older compiled or object-oriented languages. Functional programming languages and mathematical languages are not revolutionary, they have existed for quite some time and the newer languages are just optimizations of older implementations.

So where is that next evolution going to come from? I don't believe it came from 4th generation programming languages. They have been around for 20 years now and are not mainstream because of the issues we discussed above. There is some talk of 5th generation programming languages and 6th generation programming languages, but nothing of substance has impacted mainstream software development. Thus ends the analysis, my firm conclusion is that we are stuck in the mud as a software development industry. Instead of spending our time developing truly revolutionary programming languages we are content to use our 15 year old technologies to write the latest/greatest applications. That is a huge departure from how we thought about software development when I started my career, and it makes me very sad.

This is my wake up call to the software development industry. We need a radically improved approach to programming languages. I have several thoughts on how to do this, which I'll detail in my next post. But in the mean time, I am hoping to hear your thoughts.

Happy Holidays!

Todd Lauinger

Albert Pinto

AI Leader|Agentic AI|Multi modal search|RAG|Generative AI| Neural Networks|Transformers

2 年

Todd, This is a great article about the software development history and what it is currently today. Appreciate you sharing it!

回复

要查看或添加评论,请登录

Todd Lauinger的更多文章

社区洞察

其他会员也浏览了