Live data from Hacker News

Premature Abstraction

arendjr.nl

41–50 of 116 posts

Re: Premature Abstraction

#41

My general take (and w/ the caveat that every system is different) is as follows: - procedural code to enter into the system (and perhaps that's all you need) - object oriented code for domain modeling - functional code for data structure transformations & some light custom control flow implementation (but not too much) I like the imperative shell, functional core pattern quite a bit, and focusing on data structures…

When you write a procedure that has to maintain an internal state between calls, changing it into a class makes sense. As for the name, you change the verb (write) into a noun (writer), and you now have a name for the class.

C# will silently create hidden closure classes for you when you use lambdas or yield.

Re: Premature Abstraction

#42
post #17

I like to start with a fairly unambitious bit of procedural code and gradually introduce abstractions when it starts to get complicated or repetitious. Straight code becomes functions, occasionally a group of functions cry out to become a class. In C++ this is a huge effort to do - change hurts more there. In python it's much less painful and I end up with a program that is some imperfect composite of object oriented…

I find that JS/TS also lends itself towards this in terms of Node/Deno/Bun usage for apps. You can have a file/module that simply exports a function, a collection of functions, a class, etc. It's easy to keep it simple and then combine with a mix of procedural, functional and oo concepts as best fits the use case.

Re: Premature Abstraction

#43
post #5

> Post-Architecture is a method of defining architecture incrementally, rather than designing it upfront For anyone else wondering what it means. I'm going to be honest, almost all architecture I've seen out in the wild has followed a more incremental approach. But then again everywhere I've worked hasn't separated the architecture/coding roles.

If you work with C# or Java in a lot of places, such as Banking in particular, you'll definitely see a lot of up-front architecture and excess abstractions early on.

Re: Premature Abstraction

#44
post #41

My general take (and w/ the caveat that every system is different) is as follows: - procedural code to enter into the system (and perhaps that's all you need) - object oriented code for domain modeling - functional code for data structure transformations & some light custom control flow implementation (but not too much) I like the imperative shell, functional core pattern quite a bit, and focusing on data structures…

When you write a procedure that has to maintain an internal state between calls, changing it into a class makes sense. As for the name, you change the verb (write) into a noun (writer), and you now have a name for the class. C# will silently create hidden closure classes for you when you use lambdas or yield.

Just know that if you do this, you’re injecting statefulness in the center of wherever it was this procedure was being used. If your entire system already has statefulness everywhere, nobody will bet an eye. But if you want to have any chance at creating a functional core or island, it’s the opposite of what you should be doing.

Re: Premature Abstraction

#45
post #33
post #25

Earlier quoted context omitted.

If you think OOP is particularly well-suited to domain modelling, you should try the FP approach to domain modelling. You will never be able to unsee the complexity inherent to OOP.

Do you happen to have a link to an example or explanation?

The keyword to search for is algebraic data types, which are common in functional languages, but for instance Rust also has them.

Here is an example comparing C# with F#, where the latter also algebraic data types: https://blog.ploeh.dk/2016/11/28/easy-domain-modelling-with-...

Re: Premature Abstraction

#47
post #17

I like to start with a fairly unambitious bit of procedural code and gradually introduce abstractions when it starts to get complicated or repetitious. Straight code becomes functions, occasionally a group of functions cry out to become a class. In C++ this is a huge effort to do - change hurts more there. In python it's much less painful and I end up with a program that is some imperfect composite of object oriented…

Yes, I'm doing that a lot, too. I'm often astounded how hostile some languages are to later changes - e.g. java always feels resistant to change, while dotnet and especially python are more amenable. I.e. I totally transformed a program from function to oo in python without much sweat - would have been a total pain in dotnet or java

Re: Premature Abstraction

#48
post #45
post #33

Earlier quoted context omitted.

Do you happen to have a link to an example or explanation?

The keyword to search for is algebraic data types, which are common in functional languages, but for instance Rust also has them. Here is an example comparing C# with F#, where the latter also algebraic data types: https://blog.ploeh.dk/2016/11/28/easy-domain-modelling-with-...

The syntax has improved quite substantially since 2016 for pattern matching at C#'s end, and it's very easy to model ADTs with records (and the experience of using them even before that was decent with methods accepting lambdas).

Today, you write it in a similar way you would write a match in Rust.

Re: Premature Abstraction

#49
post #41

My general take (and w/ the caveat that every system is different) is as follows: - procedural code to enter into the system (and perhaps that's all you need) - object oriented code for domain modeling - functional code for data structure transformations & some light custom control flow implementation (but not too much) I like the imperative shell, functional core pattern quite a bit, and focusing on data structures…

When you write a procedure that has to maintain an internal state between calls, changing it into a class makes sense. As for the name, you change the verb (write) into a noun (writer), and you now have a name for the class. C# will silently create hidden closure classes for you when you use lambdas or yield.

When you write a procedure that has to maintain an internal state between calls, stopping what you're doing and switching to functional programming makes sense.

Re: Premature Abstraction

#50
post #15

Earlier quoted context omitted.

This is a strong argument against inheritance, but that isn't everything about OOP. Just one well supported advanced abstraction (That I would also argue should be rarely used.) I would argue that just having strong type system and bundling methods with data gets you the vast majority of the usefulness of OOP. Liskov, Open/Closed, Message Passing, and other theoretical abstractions be damned. EDIT - Where are the goo…

> One is when you are trying to create a system that inverts dependencies by allowing a plugin system or follows some sort of nuanced workflow that others might want to "hook into". I’m fairly certain that’s the use case of inheritance - at least in the Simula tradition. Classes as a means of lifetime management, moving parts that have well defined steps of operation (methods), and interchangeable parts (subtypes) wh…

> Classes as a means of lifetime management

Wrt plugin systems: at least as the class level, are classes really a means of lifetime management in practice?

IIRC, audio plugin APIs follow the shell command pattern of memory management for loading new classes-- the user dynamically loads a library into a running instance of an application, and there it stays until the application exits.

And even if plugin systems as implemented are actually unloading classes, the user is almost always just restarting the app to make sure it took. :)

Edit: clarification

Post reply on HN