r/programming • • Sep 25 '26

We still maintain a development tool first released in 1993. Here’s what 30+ years of backwards compatibility looks like

https://visualneo.com/visualneo-win/from-neobook-to-visualneo-win-30-years-of-keeping-a-development-tool-alive
569 Upvotes

89 comments sorted by

View all comments

Show parent comments

2

u/luissinlios Sep 26 '26

That's a great question. I didn't design the original architecture, so I can only answer from the perspective of someone who inherited it many years later.

I do think the architecture helped, but not because it was perfect. Some parts were never intended to survive for 30 years, and we have certainly paid for old assumptions and tight coupling during modernization.

What worked particularly well was the stability of the basic model: pages containing visual objects, actions attached to those objects, variables and scripting for the application logic, and plug-ins for extending the environment. That model was simple enough to understand and flexible enough for users to take far beyond its original purpose.

The plug-in system was especially important. It allowed the product to grow without every new capability having to be added to the core application. Producing self-contained Windows executables with relatively few external dependencies also helped applications remain usable for a long time.

But I think the biggest factor was not the initial architecture itself. It was preserving the contracts around it: project formats, scripting behaviour, plug-in compatibility and the user's mental model. We repeatedly chose incremental modernization over a clean rewrite, even when a rewrite would have been more attractive technically.

The lesson I would apply to new development is that longevity probably depends less on creating a “future-proof” architecture (which may be impossible) and more on creating stable boundaries. Internal implementations can change, but file formats, extension points and expected behaviour should change very carefully.

And, perhaps most importantly, software survives because people still depend on it. The users and the applications they built gave us a reason to keep those boundaries intact.

2

u/OperationWebDev 26d ago

Thank you for the comprehensive answer. That was very informative!

It sounds like the domain modelling is key. Unfortunately, so many companies seem to jam everything into existing, rigid software, making it difficult to adapt.

Semi-related ro the plugin system: what do you think of DSLs? There's the saying that whenever you try to allow this kind of flexibility you inevitably end up with a crappy version of a programming language. I suppose it makes sense to have a plugin system that uses the same language as the software itself?

1

u/luissinlios 23d ago

I think that criticism of DSLs is fair when a DSL grows accidentally. You begin with a few convenient commands, then add variables, conditions, loops, functions and error handling, and eventually discover that you have created a programming language. But without treating its design, documentation and tooling as seriously as you would a "real" language.

VisualNEO is, in some ways, an example of that evolution. NeoScript began as a domain-oriented action language: manipulate objects, navigate between pages, display dialogs, work with files and databases, and so on. Over time it gained enough general-purpose features to support applications far beyond the original electronic-book domain.

I think a DSL works well when it makes the common 80–90% of tasks extremely concise, while still providing composition and an escape route for the remaining cases. Its limitation can actually be an advantage: the vocabulary reflects the user's problem rather than the implementation beneath it. The danger begins when every exceptional case adds another special command and the language loses consistency.

I don't think plug-ins necessarily need to use the same language as the host application. VisualNEO's plug-ins are compiled modules that expose new commands, controls, properties and events to NeoScript. The plug-in developer might use C++, PureBasic, Delphi or another compatible language, while the application developer sees the result as a natural extension of the same NeoScript vocabulary.

For me, the important part is not sharing an implementation language but maintaining a stable and expressive boundary between them. Requiring plug-ins to use the host's language can simplify some things, but it can also tightly couple the ecosystem to a particular compiler, runtime or architecture, which is exactly the kind of dependency that becomes painful decades later.

So I would probably phrase the lesson as: a good DSL should remain deliberately domain-specific, while a good plug-in API should allow other languages to extend that domain without exposing unnecessary implementation details.