Hype be gone! #Delphi

Originally shared by Lennart Aasenden

Hype be gone!

12 thoughts on “Hype be gone! #Delphi


  1. Stefan Glienke yep, except that my code is very rarely willing to accept orange juice when it asks for water. “give me an IRemotePrinter” … “here, I got you an IFilesystem”.


    Which is the core problem with DI: compile time errors become runtime ones. SOA is even worse “what’s in this file?”… “printer offline”… oh, obviously “data corruption reading from network socket”. Sure, let me just add a bunch of error detection and retry code to my program.


  2. Moz Le That’s nonsense. You are acting as if you lose type safety with DI. You still cannot pass an IRemotePrinter to an IFileSystem (except these interfaces inherit from each other or you cast them).


    DI requires discipline that many people lack because they are used to cowboy programming. And then they come with excuses like “its hard to debug, i guess runtime errors, blabla”. Yeah, sure, have fun with debug sessions through your entire code base without having proper unit tests because everything is clumped together… ok, sorry, I got carried away 🙂


    I agree that with few experience in software architecture (especially certain principles like SOLID – hello Arnaud…) you can easily fall into a trap.


    It’s funny. Bridges, ships, houses, cars, spaceshuttles… (I could go on..) can be built in a modular way and most of the time all these pieces fit and work together properly. But when talking about applying that model to software people refuse it. 🙂


  3. Stefan Glienke so the example doesn’t work, then. “DI for 5 year olds” apparently doesn’t work for adults. Programs can’t just say “you asked for orange juice so you want a drink, here’s water”… “you asked for IFileSystem so you want an IInterface, here’s an IPrinter”. In real life it’d be more like “here’s an IFilesystem2” and when you call .OpenFile() you get ENetworkDelayPleaseRetry or a read-only file because the underlying model has changed and now you need to pass the optional fmReadWrite flag that was recently introduced. That’s the great thing about interfaces, and also the biggest pitfall. You might test with a local hard disk, but then someone opens a file on a remote DVD-ROM and suddenly your iCrap can’t spread its little turds over the filesystem so it sulks for a few minutes.


    And you’re saying that you unit test at the application level? Saying “this code works with mocked dependencies” is totally not the same as “this code works in production”. You need integration testing and UAT for that.


    As soon as the dependency isn’t in the monolithic executable you have exactly DLL hell, except that with SOA you get RPC problems as well. Since you didn’t ask, yes, these are exactly the problems I have in my day job – we sell embedded systems and I have to support every device we have shipped (serial #5 still sends data, we produced #995000-ish this week). I have shims that take 1200 baud dial-up reports and forward them to an IP-only server in the cloud. And people get quite grumpy with me when things don’t work. I follow the state of the art, and I emphasise follow – if it works reliably for you in maintenance, I’ll consider it. IUf you can’t point to apps in maintenance mode that use it… I’m going to take that as proof that it’s at best untried.


  4. Building physical things with modular elements is completely not like software. A closer parallel is architecture or design. 


    Saying “4130 50mm x 1.2 tube TIG welded with internal braces at every butt joint” is fairly similar to “iterate the collection and pass each element to this method”. But saying “use HT grade 14 M12x55 bolts” is much more like “requires 1GB of RAM” than anything you’re ever going to see in a software spec. You just won’t ever buy need to build 4 million identical units of a bit of software – you design one then say to the framework or OS “give me 4 million of these”. Bolts, even windows and HVAC plants are very much “give me X quantity to spec Y”, like “MyObject = new TSomething()”.


    But architecture… same problem space as software, and many similar solutions. At the high level it’s software design (“we want a house. On this block. Three stories. No, four. And a garage. 3 bedrooms. No, 2 bedrooms. Oh, now the design is finished we want to add a study”… yep, that sounds like software. But at the low end it’s writing code… “power point F27 is 680mm above the floor, 1.38m from the corner of the room”.


    And just BTW, watch what happens when that basic infrastructure fails and see how many programmers never think about it, in a way that could reasonably lead to a prison term for an architect or engineer. “abnormal exit with EOutOfMemory” is quite like “building collapse blamed on bad design, architect sentenced to 12 months”. But somehow you don’t see “professional” software developers is prison because they screwed up. But look at Christchurch, NZ and watch the people who designed the CTV tower fighting in court to stay out of jail.


  5. Moz Le If you don’t get the expected behavior because the implementation changed you did not follow the LSP, period. It’s there for exactly this reason: so you can change the underlying implementation without changing the outcome for a consumer.


  6. But what when the model or expectations differ in ways that either aren’t documented, or can’t be documented? “filesystem” is perhaps useful here, because to Linux “everything is a file” so if you have a Windows programmer (using Delphi, say) it might not be obvious that to (say) change the UDP buffer size on a socket you edit a file. Or to put it another way, editing a file can change the behaviour of the networking system. At the trivial level, it greatly expands the set of error conditions you need to consider unless your error “handling” model is to crash.


    I’m not convinced that the LSP is a particularly useful rule for production code. It’s great as a design principle, but once you go into maintenance mode it’s a recipe for a nightmare of very similar but subtly different things that have been introduced over time as parts change in small ways. So you get IFileSystem, IReadonlyFileSystem, INetworkFilesystem, IForwardIterationOfDirectoriesFilesystem and so on, all of whom sharing the most recent common ancestor IInterface. Good luck working out which one you should use for your new “display the software license” code.


    The alternative, of completely redesigning your hierarchy every time something changes, is what your manager will call “throw it out and start again” if they’re in a particularly polite mood when you suggest it.


    So you end up with versioning in either the name or the interface: IFileSystem2 or TheGlobalVariableThatHideasAllTheGlobalVariables.GetMeAnInterface(IFileSystem, 2)


  7. I don’t understand why you keep hammering on that IFileSystem example – probably just to make your point. Most software does not abstract away file system access with an interface because of exactly that problem of the file system being too tightly coupled with almost everything. But you might abstract away on a higher level like ISoftwareLicenseProvider.


  8. You started with “it’s like giving a five year old a drink they don’t want” and you complain that my example is unreal? It’s the random thing I started with, nothing more than that.


    If you like I could start with something more real, like the performance hit I can’t afford when a thread needs to request a new concrete instance of a class that it doesn’t currently have from the global dependency manager. But then we’d talking about (say) IDecryptAES128Bug1 which is an instance of IDecrypt but is not an instance of IDecryptAES128, although it probably should be. But I don’t have time to refactor all the places it’s used, or work out exactly why the fallback code works through IDecryptor instances in the way that it does. Some of those concrete classes use libraries that are not threadsafe so you need one instance per thread, but others are safe so I can usually get away with one global copy (except that “threadsafe” and “multithreaded” and not necessarily the same thing). Just as one example of a consideration I need to think about when managing dependencies.


    But from there saying “DI would be useful except that it’s a server so I need to be absolutely sure at startup that every single implementation is present and correct” would be a needlessly roundabout way of getting to “turning compile time errors into runtime ones is bad”.


  9. Moz Le You should not put words into my mouth that I did not say (write). I just posted a link to an – imo – good and simple enough (and humorous) explanation about what DI is.


    Implementations of DI are a combination of well established patterns (like decorators and abstract factories). However as always you can make up exceptional cases where DI might not work ideal (especially when doing it wrong) and state that’s why DI is not good.


    Also just saying DI containers know well enough how to handle singleton vs transient vs singleton per thread vs per session vs custom lifetime management.


  10. The IDecrypt example is not made up. The rest… you seem to love DI unconditionally, I think it might be useful in some situations.

Leave a Reply