BreakPoint

cancel
Showing results for 
Search instead for 
Did you mean: 

OOP Privatize Data As a Benefit

I thought about posting this in the LabVIEW sub-forum but I thought this might stir up more un-restricted conversations.  I am one of those advanced LabVIEW programmers who rarely use OO and classes <pause for gasps>.  There are literally dozens of us I know.  I'm not against OO and I am making an effort to learn more and apply it when it makes sense.

 

But one thing I've noticed, is that the privatization of data is touted as a benefit of OO and generally is listed as one of the main benefits of OO.  Obviously there are other goodies that come with OO like dynamic dispatch and inheritance, but lets talk about this first.

 

A class can define what level of restriction is put on the data allowing or prohibiting a method from accessing, or modifying the data.  Now if I am NI I see this as a benefit of OO.  And if I am making toolkits that I want locked, I see this as a benefit of OO.  But if I am just Joe developer why would I want to restrict access to data?  As Joe developer I find times when I can't get access to data that I know is there and it is frustrating.

 

Have you ever wondered what mysteries are behind the DAQmx task wire?  It behaves like a string but what if I could use an unbundle and pull out all kinds of cool information from that class.  Wouldn't that be nice?  Sure it could be dangerous especially if I were allowed to bundle data back into that class, but that is on the developer using the toolkit.

 

I can really only think of one reason why I would want to privatize data.  If an update was made to a class, and in that update the data type used behind the scenes were updated.  If I had this be an unrestricted cluster, then when that class is updated a data type may get renamed, or removed.  When I have VIs (or property nodes) exposing the data, then I don't need to worry about if a user of the library used an unbundle and pulled out some data that wasn't intended for them.  If this weren't a class then the majority of the time it would break their code and they would have to fix it.

 

With this one minor benefit, I now am forcing developers to edit the class, add accessing VIs, and then call those acessing VIs when they want to read some private data.  But if it were just a cluster a developer just uses the unbundle and bundle.  So am I missing something?  Is there other reasons you would want to privatize a classes data where a typed cluster wouldn't do the same thing but easier?

 

BTW lets keep this civil I'm not trying to bash OO I am trying to weigh the pros and cons to help decide when it is appropriate to use it.

0 Kudos
Message 1 of 11
(8,189 Views)

@Hooovahh wrote:

I am one of those advanced LabVIEW programmers who rarely use OO and classes <pause for gasps>.  There are literally dozens of us I know.


I find myself using objects a little more in the last year, and I really think they have helped, mostly due to the Dynamic Dispatch.  Where I find the "hiding data" really comes in handy is where you want to hide some implementation from the users of the library/class.  For instance, I had an application where I was trying to communicate with a web site.  I did not want to ever give a change that somebody could change some of those handles and implementation details outside of that API.

 

Other than that one project, I have only used objects for Dynamic Dispatch. Though, I had another project used Composition with a lot of success, but that's a whole other story.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 2 of 11
(8,176 Views)

This presentation might be useful to you.  It's intended to address casual OOP users who create classes but don't put very much thought into the scope of the accessor methods they create.

 

The primary benefit of encapsulation, IMO, is that you have control over WHERE your data is accessed, and therefore you are free to make changes to your data structure and business logic associated with that data (enforcing data rules + error checking) without concern of what callers that might impact.  If all of your data is passed via clustersaraus, anybody can read or write any data they want into that cluster.  Very convenient true, but very difficult to then make changes in the future.  It's a form of coupling, that each consumer of your data becomes brittle-ly bound to one typedef.  You should be able to change your data structure and not wonder, "who did I just break?"

 

By making all of your data private within a class, and then providing an interface to that data via its methods, you are free to modify the data structure and its business rules without breaking callers, as long as you don't break the API.  That is why my presentation harps against public Write Accessors.  Public Write Accessor methods poke holes in your encapsulation force shield.  You can still plug the holes by adding some code to your accessor methods, but then I feel that's hurting the readability of the code to your development team because typically a write accessor is a straight pass thru.  What looks like a property node write could actually be mutating the data, and that feels misleading to me.  Therefore I minimize the use of Public Write Accessors (prefer protected or private), and if I think I might want to add code to the method later, I don't call it Write <XYZ>, I call it Set <XYZ> and change the icon, so that people who read my code don't assume its a straight pass-thru.  Anyway, that's a bit of a tangent, but helpful to understand my presentation I think.

 

BTW, encapsulation can be acheived by disciplined coding guidelines without OOP, but OOP allows you to codify those rules.  .lvlibs could be used instead of .lvclass to help codify it, but then you lose data inheritence and dynamic dispatch.

Nate Moehring

SDG
Message 3 of 11
(8,126 Views)

@Hooovahh wrote:

 

With this one minor benefit,...


With reuse code, or anything used in a large number of places, that is a MAJOR benefit.  Other places it might be minor, but making accessor VIs is a reasonably minor task.  And the tedium of making an accessor will hopefully prompt consideration of why one is making an accessor, as it's an extra thing the User of a class must understand.  A good class is a simplifying abstraction.  Again, this is more important with reuse code.

Message 4 of 11
(8,048 Views)

@drjdpowell wrote:

With reuse code, or anything used in a large number of places, that is a MAJOR benefit.


I can see this now, thank you.  I have used classes for driver level APIs in the past and can see their benefit.  I was sorta trying to mention this with this line.

 


"And if I am making toolkits that I want locked, I see this as a benefit of OO."


 

 

What I should have probably said to make it clearer is "If I am making reusable modules".  

 

After taking some other OO training I can see when this feature can be beneficial.  It seems to help enforce users to follow rules.  Now if those rules were part of a software process, and the developers followed those rules, then this feature of OO seems unnecessary.  But processes aren't always in place, and devlopers (internal or external) might now follow them.  So forcing them to follow the rules is a good practice.

0 Kudos
Message 5 of 11
(8,003 Views)

@Hooovahh wrote:
...Now if those rules were part of a software process, and the developers followed those rules, then this feature of OO seems unnecessary.  But processes aren't always in place, and devlopers (internal or external) might now follow them.  So forcing them to follow the rules is a good practice.

 

This is actually one of the fundamental concepts differentiatinag Object-Oriented Design from Object-Oriented Programming.  Object-Oriented Design is the design practice and orientation around objects in your thought patterns.  Object-Oriented Programming is features of a programming language that enforce certain rules of OOD.

 

In fact, as I recall, NI's OO in LV training module makes a point of explaining this difference.

 

 

I had a colleague who was absolutely convinced that he did not understand anything about object-oriented programming and that it must be some abstract concept that would bring revolutionary change to how he did things when he learned it ... turns out he had been practicing object-oriented design all along and OOP was just new syntax that expedited commons actions and enforced others.



0 Kudos
Message 6 of 11
(7,968 Views)

@drjdpowell wrote:
With reuse code, or anything used in a large number of places, that is a MAJOR benefit.  Other places it might be minor, but making accessor VIs is a reasonably minor task.  And the tedium of making an accessor will hopefully prompt consideration of why one is making an accessor, as it's an extra thing the User of a class must understand.  A good class is a simplifying abstraction.  Again, this is more important with reuse code.

Tedious is also the creation of "wrapper" VIs where you want to expose the functionality of a contained class (a Class as a data member of another class).  If you simply provide access to the sub-object, encapsulation is lost, if you don't provide access to the sub-object, you need to create a boatload of "wrapper" VIs which simply pass on the arguments to the contained class.  I really wish this aspect could be improved.

Message 7 of 11
(7,955 Views)

Intaris wrote:

Tedious is also the creation of "wrapper" VIs where you want to expose the functionality of a contained class (a Class as a data member of another class).  If you simply provide access to the sub-object, encapsulation is lost, if you don't provide access to the sub-object, you need to create a boatload of "wrapper" VIs which simply pass on the arguments to the contained class.  I really wish this aspect could be improved.


Indeed this is a real pain point. I love tucking things away in objects and have a nice composition structure. This is especially true of a "Manager" type class that stores multiple instances of other classes. Accessing the properties of these "inner" objects  without exposing the actual class to the outside world seems like quite a bit of work sometimes. 

0 Kudos
Message 8 of 11
(7,944 Views)

@Hooovahh wrote:

 It seems to help enforce users to follow rules.  Now if those rules were part of a software process, and the developers followed those rules, then this feature of OO seems unnecessary.  But processes aren't always in place, and devlopers (internal or external) might now follow them.  So forcing them to follow the rules is a good practice.


It's more than that; an enforced rule is one I'm SURE isn't broken.  If something is private to the class then I know it isn't being used elsewhere.  I don't have to go and inspect other code to see how it is used.  That reduces the burden on me, as there is a limited amount of code I have to focus on, and I can be (relatively) sure of not introducing bugs in other code modules.  

0 Kudos
Message 9 of 11
(7,922 Views)

Here's one article that adds good example to the general opinion here that making class data public can lead to more bugs than profits: https://lostechies.com/jimmybogard/2010/03/10/strengthening-your-domain-encapsulated-collections/ 

You can easily replace the Order/Customer with the DAQmx wire example from the first post:


Hooovahh wrote:

Have you ever wondered what mysteries are behind the DAQmx task wire?  It behaves like a string but what if I could use an unbundle and pull out all kinds of cool information from that class.  Wouldn't that be nice?  Sure it could be dangerous especially if I were allowed to bundle data back into that class, but that is on the developer using the toolkit.


And then think of any number of scenarios in which the developer of client code (or "toolkit user" as you name him) can break everything.

 

The last, bolded part, is the core of the problem here. It's never the client responsibility to make sure the toolkit supplier code* works. The supplier should make sure that the client knows how to use his code without problems. Without this, the client developer is sentenced to lenghty reverse-engineering to understand what went wrong. Of course, there are many ways to give the client the requested knowledge - documentation, drawings, conversations, presentations, etc. But ultimate way to archive this is simply not allowing the unsupported scenarios. No additional documentation, no explaining, no warnings and swearing - simply don't let anyone break anything. It doesn't matter, if in any particular case you're both supplier and client. It's usually profitable if you fully switch to the client mode when using your own code, just to criticise it and make it better.

 


@Neil.Pate wrote:

Intaris wrote:

Tedious is also the creation of "wrapper" VIs where you want to expose the functionality of a contained class (a Class as a data member of another class).  If you simply provide access to the sub-object, encapsulation is lost, if you don't provide access to the sub-object, you need to create a boatload of "wrapper" VIs which simply pass on the arguments to the contained class.  I really wish this aspect could be improved.


Indeed this is a real pain point. I love tucking things away in objects and have a nice composition structure. This is especially true of a "Manager" type class that stores multiple instances of other classes. Accessing the properties of these "inner" objects  without exposing the actual class to the outside world seems like quite a bit of work sometimes. 


 

Ok, I have to be careful here, as the topic is delicate, but I believe what you say is not about object-oriented, but purely structural programming. You have a data structure which you have to decompose in client code to add any actual value to it.  The "Manager" class sounds much like Facade (or Proxy?), which should expose the behaviour of the sub-system to the client. (in Domain-Driven Developement we'd probably simply call it Aggregate, or broader - Module) Behaviour, not data. If you have to deconstruct the object to take the inner objects out, then make some operations on them, and then put them back in the initial object, then your project is suffering form Anemic Domain Model, where your objects have all the data they need but they have no idea what to do with it. This easily lead to high coupling and low cohesion of the code, as the logic is spread throughout many layers of the code. This is especially noticeable if you have a user interface which have to deal with multiple different objects to properly use single code module (i.e. DataAcquisition). The simplest test for this is the question: "how many classes you need to know do do_something?" or "how many objects you need to use to do_somenthing?". Ideally, there should be one standalone class that represent one module, so you don't need to understand the underlying structure of it. In many cases this class should probably be an interface**, which helps to look at the same object from different contexts without too many distracting details.

 

(Disclaimer: all of the above applies to many pieces of my own code as well. If you, dear Reader, feel offended with such strong words as "structural", keep in mind that I'm actually also offending myself 😉 My goal is same as Hooovahhs and most of the others - to learn and understand something through discussion).

 

 

 

* I think "supplier code" is better fitted to the discussion here. The "toolkit" is very specific entity where someone during developement had to weight reliability and capabilities - and sometimes the latter would win. And then you hear: "oh, we didn't though you would want to do this that way and that why we didn't test if it would work" or "sorry, it is possible the way you did it, but not supported" 😉

**And this is what I think we really miss now in LVOOP - interfaces (and at the same time I'm afraid that introduction of them would lead to many purely technical problems, but thats completely other discussion).

0 Kudos
Message 10 of 11
(7,864 Views)