UtterAccess.com
X   Site Message
(Message will auto close in 2 seconds)

Welcome to UtterAccess! Please ( Login   or   Register )

Custom Search
 
   Reply to this topicStart new topic
> Best Practices To Do Object Oriented Programming And Orm In Access VBA?, Access 2016    
 
   
javert
post Dec 19 2017, 12:55 PM
Post#1



Posts: 59
Joined: 18-January 16



Hi. I've hit a block regarding a task involving generation and maintenance of control charts. My usual way of procedural programming has got too complicated for the task and the whole problem seems to be better approached by creating a bunch of class modules and doing the object oriented way (among other challenges, some processes require a big number of parameters whose coherency also needs to be checked).

Since I've got no experience doing OO programming regarding Access data (is this Object-Relational Mapping?, sounds like it) I want to get informed of the best practices to do so in order to avoid reinventing the wheel, or creating something unnecessarily convoluted. For example, how do you associate the group of records or entities in the child table within the object that represents the parent record? Is it better to create an array of objects of the child class and resize it at convenience or is the customary way to create a Collection and append or delete items as needed?

This is the kind of questions that I want to have clear before starting to churn out code. Is there a specific guide or document you can link to in order to start learning?
Go to the top of the page
 
Jaiket
post Dec 20 2017, 03:42 AM
Post#2



Posts: 125
Joined: 3-May 17
From: France


Hi Javert,
I am in the same boat - where the *&'£% do I start with this stuff.
This might help you get answers here at UA - "Ask one question at a time".
Maybe if you post "Anyone got a source for learning OOP" and another " task involving generation and maintenance of control charts." you could get some expert help, which I cannot give.

I agree wholeheartedly with the idea of looking for "best practices", but maybe OOP being a global idea, not specific to any one language, you might find more information if you look for "principles of OOP". Try searching for "SOLID OOP". SOLID is a way of remembering the basic principles of OOP.

I am only just getting to grips with the difference between class and standard modules. Sometimes I think I understand, and then it fades... I think I am right in saying that "this is becoming complicated" is not a valid reason to use a class module. In my experience, when it gets complicated, I try to split big sections of code into separate procedures. I read somewhere that if you get to 8 indents it's time to "encapsulate" some of your code - split it up into smaller reusable coherent parts. I think this is part of OOP. I also find it useful to spend time choosing meaningful names for my procedures. For example, I just changed a procedure from "Scan" to "StringIsFitForUse". Depending on what "fit for use" means to the calling procedure, it checks for nulls, empty or zero-length, invalid characters, spaces etc. OOP can involve (I think..) reusing code in wildly different circumstances from those it was originally created in. This procedure is an attempt at "defensive programming" which (I think..) can help guarantee the code will always function.
I am fairly convinced that the secret to discerning between class and standard modules is in understanding exactly what "class modules represent objects" actually means.

If you do find that elusive tutorial , please post it..
Good luck.




--------------------
UA = Unsurpassable Assistance. Couldn't do it without you.
Go to the top of the page
 
jleach
post Dec 20 2017, 04:06 PM
Post#3


UtterAccess Editor
Posts: 9,852
Joined: 7-December 09
From: Staten Island, NY, USA


Oh boy - do NOT try to do OOP in VBA (and ORM is something else entirely different that doesn't have any sort of place in VBA at all - best bet is to forget that one altogether).

I've been through all this... VBA has some very (very) basic OOP stuff, which basically amounts to class modules (there's interfaces as well, but probably less than 1% of people I know use them in VBA). When you say OOP (and when you search for OOP), you're using terminology that rest of the world associates with "real" OOP, and really doesn't have a place in Access.

Thus, if you want to do OOP in Access, forget OOP as the term and search on Class Modules instead, and that's as far as you can go. You'll save yourself a ton of confusion (OOP is confusing enough to come to grips with on it's own, let alone trying to apply all that BS you'll read about to Access).


With that said, a quick note on ORMs. An ORM (Object-Relational Mapper) is a tool that is used by "real" OOP (NOT Access classes) to automatically take database data and turn it into class tree data (there's what they call an impedance mismatch between the two, which basically means that the natural format of data in a relational database doesn't really match the natural format of data in an OOP language, so the ORM is an OOP-specific tool that does its best to cross the bridge between the two so you don't have to do it all manually, because that's a LOT boring tedious code to write by hand). ORMs have absolutely no place in Access by any stretch of the imagination.

If you are going to do this in Access, using Class Modules (which I'm not sure I can recommend - VBA is only really good for very light classwork compared to actual OOP), then you'd want some sort of public standard-module function to say "given this ID, load these set of classes" and work through it all (which is basically your maybesortakindaORM procedure).

If you think you're going to have to go to actual first-class OOP for this, I'd highly recomend you pick up an actual OOP framework/language instead of Access (we - being the collective MVP group (and myself) have seen many people from OOP backgrounds attempt to do this with Access/VBA and the result is always a horrific mess).

Anyway, with that said, if I haven't been able to dissuade you smile.gif ask any further questions and I'll answer as I can.

Cheers,

--------------------
Go to the top of the page
 
javert
post Dec 20 2017, 04:52 PM
Post#4



Posts: 59
Joined: 18-January 16



Thanks for the response man.

Yeah, the whole OOP package looks daunting and wasn't even sure if that was what I was looking for. I guess I'll write a little about what I want: without delving too much on the specific details, I have a table for control points, other for chart limits, other for limit evaluations, etc. When I want to add a new control point to the table I need to evaluate possible new control limits, calculate them, draw the charts for visualization, analyze them for tendencies, etc. Right now the code encompasses some procedures many screens long, some of them tied to form modules, others to standard modules and since all of it is mostly procedural it is hard to track where some code is located for X task even for me once many days pass after mantaining it.

I believe using class modules that represent intuitive objects like Process, ControlChart or ControlPoint I could assign the tasks to the class that better suits them (for example, adding a control point to the ControlPoint class, or calculating limits to the ControlChart class, etc) and at the same time I could simplify the tasks by creating Properties instead of the procedural way where methods could require 8-10 parameters and where I would need to devote like 80 initial lines of code just to check the validity of the parameter values. I know I would need to check them anyway in a class module but having the code distributed among Property Get and Property Let statements will make it easier to read and debug. I started reading this to get an idea. Seems useful, although I don't know if not having C++ features a VBA is actually bad or a blessing instead grinhalo.gif because I've heard and read about C++ being the stuff of nightmares to debug.

Doesn't matter that much if this isn't the domain of real world OOP yet; in fact it would be a relief, since then I wouldn't have to study, delve into and learn casts, inheritances, polymorphisms, constructors and the rest of scary OOP stuff. I just want to get a job done in a way that doesn't take me entire days to modify or debug if the need arises.



Go to the top of the page
 
Jaiket
post Dec 20 2017, 04:55 PM
Post#5



Posts: 125
Joined: 3-May 17
From: France


This is true, but won't actually help with OOP.
I had never heard of OOP. I was struggling with almost every aspect of Access. One thing I could handle was "Language" as in English, and that naming things clearly would help me understand myself later. I actually have a module called "Oops" which contains procedures like "StringIsEmpty" and such, a kind of error-trapping module before I could be bothered to put error-handling in every procedure.
CODE
Oops.StringIsEmpty

--------------------
UA = Unsurpassable Assistance. Couldn't do it without you.
Go to the top of the page
 
Jaiket
post Dec 20 2017, 05:12 PM
Post#6



Posts: 125
Joined: 3-May 17
From: France


There is a discussion about whether or not VBA is an OOP language here. There are suggested workarounds to try and make it an OOP.

--------------------
UA = Unsurpassable Assistance. Couldn't do it without you.
Go to the top of the page
 
jleach
post Dec 20 2017, 07:27 PM
Post#7


UtterAccess Editor
Posts: 9,852
Joined: 7-December 09
From: Staten Island, NY, USA


I don't think OOP is the right answer for you. OOP is a mess: it's very easy to tangle yourself in a knot with it, and that's after you know it well and know what to be careful of. It has a much higher learning curve than "regular" VBA.

You can write any code procedurally and have it as well structured as OOP code (in fact, some might argue that procedural languages are easier to keep straight than OOP, and I would probably be in that group myself despite the fact that I work in C# for 90% of my code these days).

It sounds like what you need is a good clean structure to your procedural code, rather than OOP. It's worth noting that this is as much (or more of) a requirement for OOP, and if you're familiar with procedural stuff but aren't quite there yet then trying to adopt OOP - it's not going to be pretty.

It sounds like a good heavy refactoring with some standard best practices can do you a lot of good. Once you have code that's highly readable and easy to follow, then you're in much, much more maintainable shape.

Here's some general rules:

- No procedure should be longer than what can fit in a code window at a single time (shouldn't have to scroll)

- A procedure should do one thing and one thing only

- A procedure should not have any external dependencies: feed all required information to it, don't make it go get it things (except calling other procedures - for example, don't tell something in a
public module to get information from a form: feed that information to the public procedure instead)

- A procedure should not care where it's data comes from, nor should it care what the end result of that data is. It should only care about itself.

- A workflow process can be many (many) procedures deep: this is fine

- You can have a procedure who's single job is to call a bunch of other procedures. This is fine (but that procedure should still stick it it's one and only job)

- Pay close attention to scope and naming conventions: tight scope control (never more than strictly required) and good naming conventions have subtle but highly important impacts on code integrity.


This of course doesn't take into considerations things such as event procedures or an AfterUpdate event (for example) where it may be required to read the value of the control before sending it along to some sort of "core logic", but said "core logic" should not be fetching that information itself. It has one job and must be provided the tools it needs for the job.

Think of things in terms of "main layers" of your application (3-tier architecture, but not quite). There's a "presentation" layer, which is your forms and reports, and you have code that is specific to managing the presentation and behavior of those forms and reports. Then you have a completely separate layer where your "business logic" (aka, domain, aka application logic, aka any number of a thousand names it's been given...) which is where the "real thinking" is: the stuff that is churning around your serious calculations (update whatever data when X happens with Y whatever type of stuff) without caring what happen to make it have to do so, only that it has to do so. So, you have Presentation and you have Logic. Try to keep your form code only for form management, and keep your "real" code inside standard modules. (most 3-tier architectures have a Data layer as well, but Access doesn't do a good job separating these: in fact the opposite, so it's easier in Access to make the mental distinction between presentation code and core code and leave the rest alone).


OOP is not better than procedural languages: it's just two different ways to do things. It's very good for some things, very bad at others, same as anything else. I'd say to leave thoughts of OOP for the time being, focus on improving the cleanliness of your existing code, then after a while when you can sit back and say "yea, this actually looks pretty good" - then you can delve into OOP a bit.

(also, please try to avoid "forcing" VBA to be OOP as per the last link in Jaiket's reply: this is like taking something that's bad at something and yelling at it to get better: "you better climb that tree, you fish, or I'm going to throw you up there and fix all of our problems!") (no offense Jaiket - but...)

Hope it helps...

--------------------
Go to the top of the page
 
jleach
post Dec 20 2017, 07:41 PM
Post#8


UtterAccess Editor
Posts: 9,852
Joined: 7-December 09
From: Staten Island, NY, USA


I might also recommend a copy of Steve McConnell's Code Complete. It's quite possibly the best book on writing code in existence and is very much on topic. ISBN-13: 978-0-7356-1967-8

(Clean Code by Robert Martin aka "Uncle Bob" is another highly popular one, but it's written for OOP and tends to read like a "for dummies" book and sometimes misleads for the purpose of not trying to overwhelm, whereas Code Complete by McConnell is highly raw and unbuffered, so to speak).

--------------------
Go to the top of the page
 
Jaiket
post Dec 20 2017, 09:06 PM
Post#9



Posts: 125
Joined: 3-May 17
From: France


No offence taken, Jleach, quite the opposite. I'm kind of hanging out here hoping for someone to set things out in a way which I can understand. Which you did on many points, so thanks. I am that fish, and try as I might, I couldn't throw myself up that tree. I have no regrets whatsoever in ceasing to fail to understand OOP.

Would you be so kind as to explain briefly what an Interface does? You speak in a way I can understand, which is wonderful.

Thanks for the general rules. One rule I've adopted is thorough testing every time I change a bit of code, it was a life-changer for me. It eliminates a lot of errors while the code is fresh in your mind.
This post has been edited by Jaiket: Dec 20 2017, 09:07 PM

--------------------
UA = Unsurpassable Assistance. Couldn't do it without you.
Go to the top of the page
 
jleach
post Dec 21 2017, 04:02 AM
Post#10


UtterAccess Editor
Posts: 9,852
Joined: 7-December 09
From: Staten Island, NY, USA


An interface, in a very general sense, is the publicly exposed methods and properties of some piece of code (that's for all programming, not just OOP). For example, you have a standard module with 5 procedures, two of which are public. Those two public procedures could be called the module's Interface.

Think of a bunch of bubbles in a space with a bunch of connecting lines between them. Inside the bubbles are your "core" code (the implementation: how it's actually doing the work) - where the lines connect to the bubble represent the interfaces (inter: between two or more things, faces: on the surface). In a way, interfaces are like a descriptor of what the code needs to get it's job done.

This is actually very important to all programming...

The above is not just for OOP, but ALL PROGRAMMING!

There's a saying in OOP (mostly in OOP, but it applies everywhere): Program to an interface, not to an implementation. Now, a great many OOP amateurs have taken this to mean they must always use the OOP-specific structure of an interface (see below), but that's not the case: there's a far far more important bigger picture. Its true power is much more general: it means when you're programming, and you have code like this:

CODE
Public Function OutputReport(ReportName As String, OutputType As OutputType)
   If OutputType = OutputTypes.PDF Then OutputPDF(ReportName)
   If OutputType = OutputTypes.Word Then OutputWord(ReportName)
   If OutputType = OutputTypes.Excel Then OutputExcel(ReportName)
End Function


... it means that you shouldn't, at this particular moment, care at all about how OutputPDF actually outputs a PDF file, only that it does. You don't care how OutputWord creates a Word document, only that it does. The OutputReport method doesn't care nor know about how OutputPDF/Word/Excel works. OutputPDF/Word/Excel should not know that it was OutputReport that called it. Whatever called OutputReport should not know nor care if OutputReport has to call a specific function to get a PDF version, it just knows it can specify what type of report it wants and it'll be done.

You don't care about the implementation of those methods (the code within), you care about the interface of those calls (it's called OutputPDF and requires a report name... and presumably it'll create a PDF for me... ok!)

This is very much like a typical chain of command in an organization. The boss says to his underling: "I need X done: take this and this and go do it" and (s)he expects that it will be done, or (s)he'll know the reason why (the underling comes back and all is normal, or comes back with... dare I say it... an Error!). Point is, the boss isn't particularly concerned about how the underling does it, only that they do.

This is a method of thinking, but an extremely powerful method of thinking. It's what allows your mind to manage large, complex problems, and thinking and programming like this tends to force a person's code to become more structured. In fact, this is all very relevant to what I was explaining about clean code practices in my prior reply. Very relevant indeed. It is the foundation of nicely defined code.



(warning, OOP specifics follow...)

For OOP specifically, an interface is a formal structure that defines the... well, an interface. Let's say we have an IBook interface. That interface itself might state that an object of IBook must expose a Pages collection and a NextPage() method. Then you create an object called Book and say it implements interface IBook, and the compiler will throw an error if the Book doesn't have a Pages collection and a NextPage method. The interface is the contract defining (at least part of) what the object can do (but again, doesn't care at all how it does it, just that it does).

You could have an object with more than one interface. Let's say we have an IBook interface that requires Pages and NextPage(), then we have a IBurnable interface that requires a Burn() method. Then you have a class called Book which implements both IBook and IBurnable:

CODE
public interface IBook {
    List<Page> Pages {get;set;}  // must have a Pages property
    void NextPage();             // must have a NextPage method
}
public interface IBurnable {
    void Burn();                 // must have a Burn method
}

public class Book : IBook, IBurnable {

   public List<Page> Pages {get;set;}   // satisifies IBook.Pages
  
   public void NextPage() {             // satisifies IBook.NextPage
       currentPage.GotoNext();
   }
  
   public void Burn() {                 // satisfies IBurnable.Burn
  
      // let's implement a timeline action of the book's pages peeling and
      // slowly turning to charcoal and emit events on the book's burning
      // process so the presentation can read it and update the screen
      // accordingly.  Sounds fun!!
      
   }
}


What's neat then is you can have some completely different code elsewhere that says "I'm an incinerator, you can give me stuff that burns but only stuff that burns". Instead of saying "give me a variable of Integer type", you say "give me a variable of IBurnable type":

CODE
public class Incinerator {
  public void BurnItem(IBurnable burnableItem) {
    burnableItem.Burn();
  }
}


The "burnableItem" could be any object which implements IBurnable. Could be a book, a car, a goat, whatever, as long as it implements IBurnable. That piece of code (the "burnableItem.Burn();" line) works because due to the interface, it knows it must have a Burn() method.

Or maybe you have an angry mob that wants to burn a bunch of stuff:

CODE
public class AngryMob {
  public List<IBurnable> PileOfStuffToBurn {get;set;}
  public void BurnItAll() {
    foreach (var thing in PileOfStuffToBurn) {
      thing.Burn();
    }
    HootAndHoller();
  }
}




Let's further say we have a few different kinds of books. Maybe we have classes for Book, AntiqueBook and RareBook. Each of these three classes implements the IBook interface. Then we have an object called Bookshelf, which can take a bunch of books:

CODE
public class Bookshelf {
    public List<IBook> Books {get;set;}
}
.. elsewhere

Debug.WriteLine (myBookshelf.Books[5].Pages.Count)


The list of Books on the shelf are of type IBook, and thus this bookshelf could contain any of those three types of books, and a person could grab one, see it has Pages, and goto the NextPage() in any of them. (this is somewhat of a poor example as Book, AntiqueBook and RareBook should be set up a bit differently per some other OOP requirements, but it gets the point across).

And finally, if you want - here's an article I wrote a while back about Classes in VBA, using the Books example as well: http://www.UtterAccess.com/wiki/Classes

And - you can actually do this in VBA as well. Do a search for "VBA Implements" and you'll find some info (but... I don't really recommend it: I've twisted VBA as a language inside and out and have only ever used this twice, and both times was not because I needed to, but because I wanted to, and in both cases I know I shouldn't have because someone who comes along behind me is not apt to figure out what I was up to).



Interfaces are the foundation on which separation of concerns are built, and SoC is part of the foundation on which a good codebase is built. It's actually a very good question: if you know how to "think in interfaces" you can squeak your way through most anything. For all of the various programming concepts, interfaces are among the most fundamentally important (maybe along with the concepts of coupling and cohesion (those two don't have direct representation in OOP: rather Dependency Injection and Inversion of Control (IOC containers) take care of that, but good luck figuring out what those mean!)).


Cheers,

--------------------
Go to the top of the page
 
jleach
post Dec 21 2017, 04:38 AM
Post#11


UtterAccess Editor
Posts: 9,852
Joined: 7-December 09
From: Staten Island, NY, USA


Also maybe relevant to OP: https://dymeng.com/when-to-use-class-modules-in-VBA/

--------------------
Go to the top of the page
 


Custom Search
RSSSearch   Top   Lo-Fi    21st January 2018 - 03:43 PM