And if you think I'm on crack for saying such things, see this PDF file. Modula/Oberon programmers agree with my philosophies, it seems.
This is not just a problem in Delphi however I'm really getting scared about Delphi developers and the habits they have got into. Whenever I download a Delphi project to try, I see the same problem over and over again:
- huge monolithic project
- no runtime project components, just compile time components
The idea of Delphi was that you could create components and slap them into your project. The problem I see is that all Delphi applications are not properly componentized. The forms before compile time are componentized - but the actual exe and source code is one monolithic, tied-together on a string, huge, hard-to-debug beast.
Instead of making one huge monolithic compile time project with hundreds of components that can easily break, a project should modularize development into different areas. A file manager should have separate exe's or Dll's that do different things. In some cases, even when a search is invoked, a search executable may need to be invoked externally (so that if the search algorithms crash, only the search exe crashes, not the entire program). Instead we have people using bloated TSearch JEDI components slapped onto the form1 with drag and drop. Sometimes it is wise to start a new project, or a new DLL/BPL instead of slapping a TSearch component onto the Form1.
Then we have someone slap a TCvsViewer and a TXmlViewer component on form one. The application gets bigger, and bigger, and bigger, with more TThisThat components slapped on form1, form2, form3.
Plus, why should a search algorithms and and a sockets system like Synpase be slapped onto Form1? Delphi is based around forms.. but there is no "application form". The components get lost and piled up on form1.. when some of the components should instead be thrown onto Application container or Application form. But there is no application container or application form to put components on.. there is only form1, form2, form3. I'm not talking about the main form of the application, I'm talking about a separate dedicated application form, for stuff related to the application to be thrown on. Shouldn't it be slapped onto the Application if it isn't part of just form1, but actually part of the application? Oh but there is no application form or application placeholder, there is only form1, form2, formMain etc.
(there is TDataModule for component containers which delphi developers rarely use)
Of course, one can always make separate units not being tied to forms - but many delphi developers abuse Form1 or FormNNN and drop things on those forms that should really be in the application core, not on the form. But where is the application core? In unit1? Or in a separate unit? Or in several separate units? It seems to be on form1 in many delphi projects, which is sad, with many algorithms shoved into the form units directly (rather than algorithms being DECOUPLED from the GUI event handlers so they can be reused later... i.e. functions stored in separate modules).
Large Delphi projects I've downloaded are such huge monolithic beasts that you can't debug them or extend them easily. One thing breaks another. Change one component and the whole exe might be dead. Can't remove many algorithms that are welded into the objects since they rely on GUI stuff that they shouldn't. (i.e. hard coded ShowMessage() calls instead of a universal function that can point to writeln or showmessage).
Hard Coding vs Plugging In
Instead of all this hardcoded component stuff in Delphi, some dependencies should be designed as run time modules or external programs that one can load. A program shouldn't be one huge monolithic compiled application - this leads to developer frustration when he wants to extend, change, or modify a project. I'm not talking about just going into the options dialog and checkmarking "use packages". That just hides all the problems. A proper application API needs to be created on larger applications.
For one-off quickie applications there is no need to modularize the application, I'll admit. It's still good to put algorithms in separate units instead of shoving them into unit 1 even on small applications though.
If Delphi developers would modularize the executable into separate programs/dll's/bpl's then we could pinpoint which dll/exe is causing a particular problem, we could extend the executable much easier, and we could change the programs much easier. Big huge monolithic Delphi exe's are like write once perl programs; only the first person who wrote it, can really modify the application without breaking it. Yes, in many cases it is really this bad.
Solution for Medium or Big Projects
If an application API is created that is robust, then the plug-ins can contain the bugs and we can blame the bug on the plugin, by simply unloading the plugin and seeing if the application is no longer broken. Instead of trying to debug the entire huge 1,000,000 line monolithic source base tied together on a shoe string of 500 delphi components, we debug modules!
Modula and Oberon have modules... and the creators of Modula/Oberon systems and compilers understand that NOT EVERYTHING IS AN ABSTRACTED CLASS. Some programming can still be done via modules instead of everything being a class that abstracts from another class.
Even web pages are components - if one web page fails, most likely most of the website is still working - just that one page is broken and a few that it affects. If a Delphi exe breaks, the whole compilation of thousands and thousands of lines of source code breaks - and the application can't run, and the developer is frustrated, and he hopes to hell that the debugger takes him to the right line, if he has a debugger that even works precisely enough.
I am against monolithic applications, as you can see. The only monolithic application that should be built is something like an embedded MP3 player written in assembly code.. or a very small editor like notepad, or a compiler. Huge GUI applications should be modularized though. Most large delphi projects are bigger GUI applications, and this is where I see the problem.
Creating run time plug-ins also allows one to use Delphi 3 code with Delphi 6 code, whereas you'd be pretty much laughed at if you tried to get a Delphi 3 compile time component working in a Delphi 6 application (not to mention ugly IFDEF's scattered all over the place making the code spaghetti and meat balls).
Delphi developers are getting into very bad habits. Although, I've seen the same problem in many C++/Visual Basic projects too - so it isn't just Delphi developers. I just thought that at least Delphi developers would understand the idea of a component more. Unfortunately it seems most Delphi developers only understand IDE components as they have been brainwashed by them. They don't understand program run time components and the advantages they offer.
One Real Component Example
I've rarely seen anyone use a great program component system, aside from Total Commander (which still needs some improvement, but it is really good).
Gone Too Far
Monolithic compiled object orientation and abstraction has gone way too far. How is a 10-60MB exe reusable when it is one huge monolithic beast that may or may not compile depending on what version of compile time component I have installed in my IDE?
Certain parts of a program should be modularized out into other programs or libraries and loaded at run time. I'm so sick and tired of compile time monolithic components that cause me to sit behind my keyboard for 60 hours repairing components that don't compile with other components.
All medium, large and even smaller executables should be modularized. Stop slapping all those damn components onto form1 and form2. Start slapping some components into library1, exe1, and exe2. I can guarantee you that the future will not consist of monolithic "1,000,000 lines of source code in one exe" projects with so called "components" that Delphi offers at compile time. The web has even proved this, in the simplest way - if one web page breaks the whole website does not come crashing down - only a couple pages that rely on that one web page do.
So N. Wirth invented Modula which offers compile time modules. And borland invented the compile time components, and the "units". However, the future consists of run time modules that get loaded - so that if some developer creates a bad module, you just unload it and blame it on him. If you compile his component in, he could break your entire software program. That's why websites are not one big compiled program.
N. Wirth has caught on to the idea of run time components with his Oberon. ComponentPascal also has caught on to the idea.
Bad Old Habits
We aren't using Standard Pascal any more folks. We aren't compiling a single toy project at once. We are also not compiling large 1 million line programs in one big stream of text.
We should be compiling 1,000 line mini-projects that work together with each other at run time, and maybe a few 10,000 line projects. No, not 100,000 or 1,000,000 line projects. I'm talking about compiled modules that interact with each other - but can be separated from each other and reused in other places.
Looking Down at Them
Developing web applications and plug-in systems for executables has taught me a lot about why the typical Delphi developer (and his 320 cool compile time component widgets slapped on his form) is wrong. It has taught me that a typical Delphi developer shoots himself in the foot when he develops his huge monolithic project with so called "components". They are components at compile time, but they aren't modular at run time (problem time).
Using Delphi alone will not create a bad programmer - the programmer must learn to use his tool the best way. I'm not against widgets and visual development - you can still use visual development and widgets in each program and library you create - the idea is that each widget should not be a compile time component in one huge monolithic program. That is all I'm getting at.
Modularize your development, and you modularize your bugs. Bugs can be tracked much easier if component1 is causing a bug and is unloaded at run time, than if component1 is embedded into the monolithic exe.
You can even disable a certain module if it is causing a problem, and continue on working until that component is fixed. Whereas if your component is embedded to your monolithic exe then your program may even crash and stop working until you delete code and recompile the entire exe. It's just like web pages ! how would you like to have your entire website broken if there was one error in one web page? People need to learn about reusability and why reusability has sometimes nothing to do with object orientation - but a lot to do with modularization at run time. Compile time modularization is great, but so is run time modularization.