2

I come from OOP pradigm and I also know a bit about functional programming and its advantages. Over time I came to like the separation of data and transformations that are applied to it using pure functions. While I like the OOP idea of encapsulating data and the operations you can perform on it using classes I also started to dislike the mess coming from keeping data and functions on one level. However for many reasons I don't feel like switching to functional programming totally (one of them is working in an environment where this would cause massive disruption) and I prefer to take baby steps in selected areas.

So I started to do a middle way, half baked things like creating a props object for keeping the instance properties that really define the state of the object (as in you can serialize or store just the props object and you can recreate the object from that) - sort of the way FB React framework does it in the components. I like the idea that I can store the instanceA props object externally then swap it with a temporary one, use the usual instanceA methods to play with that temporary state and then return to the old props.

There are tons of use cases having to do mostly with reusing the same subsystem 'engine' in all it's current configuration and dependencies to a) manage some temporary state b) simulate some operation without affecting the actual current state c) implementing a material and tool metaphor where you use tool to transform the material in some way, etc.

I started to look for a design pattern describing that strategy, namely having objects with decoupled swappable state to see what are the limitations, some other uses or possible improvements but what I found is this is most often regarded as an anti pattern in OOD (it breaks the 'object should only manipulate it's own data' idea). It is obviously also not really a purely functional approach.

So my question is: given I haven't invented a wheel here is it a recognized pattern or maybe an antipattern for a really good reason or maybe it's a pattern that can become antipattern when used incorrectly like Singleton but it has some well described merits, limits and drawbacks?

(For a bit more of a domain context I work most of the time programming custom, multimedia websites mixing event driven architecture with 60fps updates and lots of non standard UI solutions that often require some improvisation and are subject to late-in-the-process experimentation so the overall architecture needs to be very open to massive changes of requirements in the middle of the projects so I can (and do) live with a bit of punk rock programming patterns).

EDIT To be more specific, I usually need the 'tool' object to have some state, configuration and dependencies of it's own and that's keeping me from having just pure function or static methods.

3 Answers 3

2

Is your question the right question?

Your question is about conformance of your design to patterns and anti-patterns.

But those are only prepackaged answers to known problems. They should not be considered as a dogma nor a cosmic rule for success. You are not obliged to sacrifice your interesting ideas to benefit from a good omen of the software gods.

In the end, the only thing that matters is that you have a performant working software that is fit fir purpose and can be maintained easily for years.

In this regard, you should mainly worry about how much your design fits your needs. And you need to understand what are the current drawbacks that lead you to ask this question in the first place.

The OO answer

What you describe looks somewhat like a flyweight pattern, where your objects would be the extrinsic state, and there would be no shared intrinsic state.

Since the intent of this pattern is to share as much as possible from a state, it seems not a great idea in the first place.

Since all your functions need to access the internals of your object, it is not a good start for a proper encapsulation either, nor for a SOLID design. So at first sight it looks like an anti-pattern.

But is it necessarily wrong ?

On the other hand, your design has a touch of mixins, which are elementary pieces of behaviors that you share between classes in the OOP world.

And also a touch of generic algorithms, which is something that OOP tries to achieve through well defined interfaces.

And last but not the least, the OOP view is not the only truth in this world. Segregation between data and code is something that worked very well before. and it is at the heart of the functional world, which has some success tracks related to reduction of bugs.

Conclusion

I could very well imagine that you are about to create an interesting innovative design, by combining two rather antinomic paradigms.

Progress is made of blending ideas. Nevertheless, be aware that the most important risk is to end up with the worst of both words rather than their combined strength. So be very careful about where you put the balance between encapsulation and functional. If you design your classes as proper minimalistic types, and your function use these types in a clean manner, your design could very well be very promising.

1
  • Thanks a lot for your answer and the pointers. I'm not looking for a mould to fit my design in, but rather some knowledge that would save me from lack of my own foresight and repeating others mistakes. :-) As for the balance I'm well aware that It's a tricky path. Flyweight came to my mind although I'm not sharing state but the machinery. OTOH I was wondering if it's not something common to e.g. physics engines, where you define the world once and modify data objects.
    – konrad
    Commented Mar 11, 2019 at 8:43
1

This looks like it is mix of the "Decorator" and "Builder" patterns. (link below to a list of the patterns and generalized descriptions and class diagrams)

As a summary, the Decorator pattern is geared at wrapping (kind of) around a given entity, class, instance, or whatever you would call the item you are wanting to have some temporary instance. For my "kind of" statement, the concept is similar to having an object in a "dirty" state or a row from a staging table in a database that still needs to be processed to determine if it is valid (row that has the required lookup information, or whatever would define a staged row as valid).

For your case with the Decorator pattern, one instance, instance A or temp instance A, would hold the other, and the needed direction would make more sense with some business defined entity. I typically see that the instance A holds/has a property of Temp instance A, since the reason for the temp data is a modification and certain ID values could be shared.

Since you were looking at temp modifications to test what data changing the data would do, the Builder pattern could be used for the end result. This pattern is geared towards being somewhat of a gateway for the intended entity. For example, instance A has a start/end date of "1/1/2019 - 1/1/2020", and Temp instance A has a start/end date of "5/5/2017 - Null" (we can say null is bad data for the temp instance). A request/function call can be made to the class defined as the Builder for something like GetValidInstance(). At that point, the Builder could return the instance that is in the correct state, depending on the definition of a valid instance.

For this question, the Decorator pattern probably would have covered almost all of the scenario given. I have just found myself keeping that Builder pattern in mind more to help keep certain functionality consolidated.

(https://www.geeksforgeeks.org/software-design-patterns/)

1

I felt good seeing this question. I'm going through a similar situation, and OOP is biting me too. Basically what I'm trying to do is to store plain object (ie dictionary) representations of several instances in my global app state. The reason I don't want to directly store the instances there is that the global app state needs to be serializable as a best practice, which allows for easy persistence and state diffs.

I found myself thinking about ways of dumping the internal state of those instances, and then "reviving" those instances from previously dumped states. It's almost like serialization & deserialization really, but instead of a serialization string, we would get a regular plain object / dict / map.

Exactly like you, I set out to look for a standard approach & terminology to deal with this.

I am sorry to say that your question is the most relevant thing I was able to find until now (!).

The closest thing I was able to find is Python's __dict__ attribute and vars function.

They indeed return the internal state of an instance as a dictionary. But I didn't see a native means to revive an instance from that state dictionary.

Anyway my gut feeling after my research is that there wouldn't be a mainstream pattern to accomplish what we want, because it is essentially incompatible with OOP. I suspect that a proper OOP way of attacking this problem would not involve accessing the instance states directly. But it would probably be complicated.

Because we live in a world of hybrid languages, we regularly find ourselves in situations where we have to work with class instances in an architecture incompatible with OOP, or the other way around.

I think we are alone here as nobody really is an expert in this brave new multi-paradigm world, and this is just one of the reasons modern programming is complicated and hard. Our programming tools are still experimental. I think maybe programmers will make fun of the idea of a "hybrid" programming language 50 years from now.

but what I found is this is most often regarded as an anti pattern in OOD (it breaks the 'object should only manipulate it's own data' idea). It is obviously also not really a purely functional approach

It being an anti-pattern is totally understandable, but what they need to understand is that we are not in an exclusively OO realm anymore. So it's really whatever works now, as long as it isn't totally crazy, sadly.

...

What I did for my needs was to add a toState instance method that dumps the internal state as a plain object (/dictionary), and a fromState factory method that creates a new instance from a dumped state.

I'm still not very comfortable with this, but I wasn't able to find anything more promising on the internet either.

...

OP, if you are reading this, I'd be happy to hear your current thoughts about this matter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.