08-21-2018 03:50 PM
@billko wrote:
@crossrulzI design even the little engineering tools I make with scalability and re-usability in mind
This in my opinion is more important than the tools you use. Using VIPM (or NIPM) doesn't mean you have a good reuse library. Just like check all the boxes, when it comes to what makes a good system. If you aren't actively thinking about reuse, the stuff in your library is likely crap. This is why mining old projects for reuse nuggets usually doesn't pan out. The original developer might not have been thinking about the interactivity between code modules, or the alternate ways their code could be used in the future. Most developers just have a goal in mind and can't spend extra time polishing something that they expect will only ever be used once. It certainly is a balance though. You need to have a good reuse mindset, but also don't spend multiple days on making something reusable, causing the project to get behind.
Unofficial Forum Rules and Guidelines
Get going with G! - LabVIEW Wiki.
17 Part Blog on Automotive CAN bus. - Hooovahh - LabVIEW Overlord
08-23-2018 04:14 AM
classic.
08-23-2018 04:35 AM
@crossrulz wrote:
@LV_COder wrote:
Is using an ancestor class data or method in child class also be an example of reusing code?
It is different in some senses, but this form of reuse is a major reason OOP became popular in any language.
<OOP_Zealot_Mode_On>
Using ancestor data in child abuses encapsulation. Using anything from parent as a child requires this child to "know" the parent, hence creates high coupling between the two. Changing anything in parent might break the child. This becomes major problem if you have multiple childs and they all expect something else from the parent (I have only one so far, but I know this from others as a fact). If you like SOLID terms, you're violating the Dependency Inversion principle by depending on concrete - the parent implementation of the function, rather than abstraction - for example some external component by delegating to it.
So yes, this is a reuse of code, but not necessarily good reuse of code from the object-oriented point of view.
</OOP_Zealot_Mode_Off>
Yeah, I too love the ramblings about the principles! 😄 But in fact I have seen, wrote (and re-wrote, obviously) a lot of code where removing any calls from child to parent vastly improved the code maintability and quality.
08-23-2018 04:45 AM
@PiDi wrote:
@crossrulz wrote:
@LV_COder wrote:
Is using an ancestor class data or method in child class also be an example of reusing code?
It is different in some senses, but this form of reuse is a major reason OOP became popular in any language.
<OOP_Zealot_Mode_On>
Using ancestor data in child abuses encapsulation. Using anything from parent as a child requires this child to "know" the parent, hence creates high coupling between the two. Changing anything in parent might break the child. This becomes major problem if you have multiple childs and they all expect something else from the parent (I have only one so far, but I know this from others as a fact). If you like SOLID terms, you're violating the Dependency Inversion principle by depending on concrete - the parent implementation of the function, rather than abstraction - for example some external component by delegating to it.
So yes, this is a reuse of code, but not necessarily good reuse of code from the object-oriented point of view.
</OOP_Zealot_Mode_Off>
Yeah, I too love the ramblings about the principles! 😄 But in fact I have seen, wrote (and re-wrote, obviously) a lot of code where removing any calls from child to parent vastly improved the code maintability and quality.
Sorry, I disagree.
An accessor for a parent defines a contract regarding what that accessor should do. If the parent changes something, then not only the child needs to be aware of that change, so does every piece of code which uses a parent. This is a change that cannot be encapsulated away. Of course a child needs to "know" the parent, otherwise it can't know what it needs to override and so on. The question is what it should know about the parent.
If a parent simply provides public or protected access to "inner" data which is NOT part of it's behavioural contract (and is thus subject to change due to details of implementation), then the parent has leaky encapsulation. Using the accessor in this moment is not the problem, the existence of the accessor is. The culprit is the parent, not the child.
08-23-2018 06:43 AM
@Intaris wrote:Sorry, I disagree.
An accessor for a parent defines a contract regarding what that accessor should do. If the parent changes something, then not only the child needs to be aware of that change, so does every piece of code which uses a parent. This is a change that cannot be encapsulated away. Of course a child needs to "know" the parent, otherwise it can't know what it needs to override and so on. The question is what it should know about the parent.
If a parent simply provides public or protected access to "inner" data which is NOT part of it's behavioural contract (and is thus subject to change due to details of implementation), then the parent has leaky encapsulation. Using the accessor in this moment is not the problem, the existence of the accessor is. The culprit is the parent, not the child.
You've broken the problem into two aspects:
1. What if the child uses accessor/method that is a part of parent contract?
2. What if the child uses accessor/method that is not a part of conciously designed parent contract, but got there "accidentally" and broke encapsulation?
I think we agree that the latter is bad. It is the culprit of the parent, so we remove this accessor, so the child is now broken and we need to fix it by using some other ways to get to this data/function. And we rewrite the child so it does not have this dependency to the parent, and now we conform to the rules I wrote about. Hence we wouldn't have any problem if we'd not have child-to-parent dependency in the first place.
Now, for the first point: yes, the child may use any method that is a part of parent contract, just as any other object. The question is: if this happens, may it be an indicator that this method should actually belong to other class? See the example below.
A typical example of children using parent I've seen in our LabVIEW world is some kind of HAL where parents ("abstract" hardware, like PowerSupply) hold connection to the hardware and children (specific hardware driver implementations, like ACME9000PowerSupply) keep asking the parent for that connection. This obviously breaks when the connection type required in new child is different (i.e. we have VISA, we need some kind of DLL handler) and can be easily avoided by not introducing this dependency in the first place.
By the way, about the accessors and children using parent data: are you sure you want access to that data? Shouldnt you just tell the parent what to do?
08-23-2018 07:08 AM - edited 08-23-2018 07:09 AM
By the way, about the accessors and children using parent data: are you sure you want access to that data? Shouldnt you just tell the parent what to do?
Using an accessor to access data, you ARE asking the parent to do something, to get the value represented by part of the public (or protected) interface of that class definition. The accessor is a member of the parent class. What the parent does to pass back a value is up to the parent, there is no direct data access across inheritance boundaries possible in LabVIEW. I understand the idea of falling into the assumption that accessors are plain old get and set placeholders for private parent data fields, but that is not automatically the case at all. Accessors can do whatever you want them to. The classic "empty accessor" is not automatic. There are certainly cases where accessors for parents being used in children are perfectly valid (and part of a required intended functionality).
I would not say that in this case the child is abusing encapsulation (which is the phrase I orginally had a problem with). It is simply using encapsulation as the parent has provided it. The parent is not applying the concepts properly. A child cannot differentiate between "use" and "abuse" since encapsulation provides no insight into the intentions of the parent, only the available methods. To paraphrase Yoda: "Use or use not. There is no abuse."
The idea as to whether the classes are correctly organised, I believe that is a separate topic entirely.
08-24-2018 11:19 AM - edited 08-24-2018 11:20 AM
Hooovahh wrote: "Most developers just have a goal in mind and can't spend extra time polishing something that they expect will only ever be used once. It certainly is a balance though. You need to have a good reuse mindset, but also don't spend multiple days on making something reusable, causing the project to get behind."
Whenever I was assigned to maintain a piece of code I didn't write, I felt compelled to go refactor it so that it was up to my standards (mostly for readability). After reading this post my mindset has changed a bit. I still try to be thoughtful when creating new functions, but for a quick fix on a code that has been doing what the customer wants, I just make the fix and don't (i.e. try not to) think about leaving the code "ugly".
08-24-2018 01:01 PM
@Gregory..., but for a quick fix on a code that has been doing what the customer wants, I just make the fix and don't (i.e. try not to) think about leaving the code "ugly".
I have gone as far as putting a decoration around the code I changed with a comment of;
"This is only part I did!"
Ben
08-24-2018 01:16 PM - edited 08-24-2018 01:18 PM
@Ben wrote:
@Gregory..., but for a quick fix on a code that has been doing what the customer wants, I just make the fix and don't (i.e. try not to) think about leaving the code "ugly".I have gone as far as putting a decoration around the code I changed with a comment of;
"This is only part I did!"
Ben
I have code in my reuse with comments attributing it to a forum post with notes about the correction for NaN cases.
Bug me someday and i'll dig it up. You'll recognize the author. (He has more posts than you do)
08-27-2018 08:50 AM
@Gregory wrote:
After reading this post my mindset has changed a bit. I still try to be thoughtful when creating new functions, but for a quick fix on a code that has been doing what the customer wants, I just make the fix and don't (i.e. try not to) think about leaving the code "ugly".
I've read that article a few times and it makes some very good points. The problem for me is starting over and writing from scratch has been so successful to me in the past. There are a few projects where multiple developers work on a project for over a year, then they get promoted, or leave the company. I was then brought in to clean it up. I re-wrote it starting on a Monday and testing was running on the system that Friday logging data and doing everything their system was doing but much better. The software didn't crash, logs were more detailed in a TDMS and PDF rather than a text file, configuration was manageable and wasn't hard coded, test could be adjusted or skipped, manual controls were added, etc. This is something I've done multiple times and while there are usually some nuggets of usefulness in the old stuff, I've usually just asked the engineer what they actually want it to do and make it do that. Maybe this is more of testament about LabVIEW and how quickly it can get something going, or maybe it is a testament about how poor the previous developers were.
Unofficial Forum Rules and Guidelines
Get going with G! - LabVIEW Wiki.
17 Part Blog on Automotive CAN bus. - Hooovahh - LabVIEW Overlord