Highlighted

Thinking About Object Oriented (OOP) ColdFusion and Updating Entities from a Simple Web Site Form

Participant ,
Feb 12, 2018

Copy link to clipboard

Copied

I've been reading a lot about object oriented programming (OOP) and domain driven design (DDD) over the past few months.  I've also been trying to wrap my head around how I can implement OOP coding styles into my daily CFML application development. 

Most of the time you'll see OOP/DDD applied towards solving rather complex problems, which makes sense in terms of using it for production purposes.  However, when trying to learn a concept sometimes it makes sense to take something simple and make it a little more complicated in order to learn.  In other words, I need to learn how to walk before I can run.

What I've done is set up a simple model for a user registration system that will be used on a web site.  I'm sure we've all built tons of these things - a user visits a web site where they are asked to enter their name, email address, password, etc...  My goal was to take what I've learned about OOP so far and apply it to a scenario like this.

In my reading about OOP I came across a concept called an "anemic domain model" which some people consider to be an anti-pattern. An anemic domain model, as I understand it, is basically using your entity objects (the "user" object in this case) as dumb "bags of getters and setters".  Essentially this means your objects don't contain any business logic and aren't all that different different than a standard CFML struct.  Many people argue that entities should contain behavior.  The difficult part for me is understanding which behavior belongs in an entity, and which belongs in a service.    If you add too much behavior in an entity, you could wind up with a massive object that is trying to do too many things at once (a "no-no" if you're following SOLID principals).  Walking that thin-line has been a challenge for me.

Another thing I came across (special thanks to Hal Helms and Sean Corfield) that really struck a cord with me was that an entity object should never be allowed to exist in an invalid state.  I really liked that idea and felt that if I could ensure my entities were never invalid, I could write better code with fewer potential for bugs.  My takeaway from this concept is that from the time you create an entity object to the time it evaporates at the end of a request, it should never ever exist in an invalid state. For example, if you had a business rule stating that all users must have an email address.  You would need to design your User entity so that emailAddress could never be anything other than a valid email address.

So how does all this apply when you're talking about a user registration form?  Here's a diagram I made of my model:https://i.imgur.com/NoxX0Eh.png

NoxX0Eh.png

Components:

  • UserService
    The user service is a singleton object which assists with the getting and saving user data. An important thing to note about a singleton object like this is that it does not manage state!  What this means is that this service should be accessible and used by other people using the application. Typically I like to store singletons in the application scope or in a factory which lives in the application scope.

  • UserDAO
    The user DAO (data access object) is what actually communicates with the database.  This object is responsible for running the SQL required for getting, adding, saving, records from the database. This object is injected into the UserService as a dependency. By injecting the object and making it private ensures that only the UserService can make calls to it. 

  • User
    The user object represents an individual user record in the database.  This object is also known as an "entity" and contains a specific instance of a user's data. For example, first name, last name, etc.  Note: In an attempt to move away from an anemic domain model, you can place business logic in your entity objects.  For example, if you wanted to have a requirement for password strength or some other business logic you could include it here.  You might also have some logic insuring that the emailAddress field contains a valid looking email address.  The "business logic" I've included ensures that the user entity object can never exist in an invalid state.  Some people call entities like this "rich domain models" or "rich entities".

  • RegistrationForm
    The registration form object is also an entity. This object will contain the data for the actual form fields (input boxes, etc...) as well as validation logic to ensure that the data is valid and safe to be inserted into the User entity object.   Think of the registration form object as a "proxy" that lives in between the user's input and the actual object they are trying to add or update. 

You might be asking yourself right about now, "Why do we even need a separate object to hold the form data? Couldn't we just add the data directly to the user entity object?"   The reason we use the RegistrationForm object is because a registration form can exist with no data, partial data, or even drastically invalid data.  Think about it... when you first visit a registration form all of the text boxes are empty.  Is the form in an invalid state?  No.   You can type anything you want into the name fields, or you could leave them blank.  You could type gibberish into the email address field, or make a password with only 1 character.  The form, still exists without throwing an exception error. In other words, a form is simply something that accepts user input.

If you tried to add a gibberish email address into the User entity object the User entity object would exist in an invalid state. That would be very bad.  To prevent invalid states from occurring gracefully, the RegistrationForm entity has some business logic thrown into it, the validate() method.  The validate() method checks to see if the data contained within itself is suitable to be placed within a User entity object.   If the validation passes, the User entity is updated.  If validation doesn't pass, the form shows itself to the user again so they can correct their inputs. 

Here's a diagram showing how that process works:

49rsv1I.png

So there's my attempt at taking something as simple as a user registration form and applying my understanding of OOP principals.  I'd love to hear your thoughts on my approach, how you'd handle things differently, and if you have any suggestions for me moving forward.


One thing that I'm still wrestling with is the idea of the "anemic domain model" and how much (and what kind) of behavior to include in my entities. I can think of some examples where an object might have a bunch of behavior or business logic and it would make sense to break that out into several different services otherwise your entity object code would be massive and unmanageable.  

Thanks for reading and I look forward to hearing your thoughts and criticisms.

Views

720

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more

Thinking About Object Oriented (OOP) ColdFusion and Updating Entities from a Simple Web Site Form

Participant ,
Feb 12, 2018

Copy link to clipboard

Copied

I've been reading a lot about object oriented programming (OOP) and domain driven design (DDD) over the past few months.  I've also been trying to wrap my head around how I can implement OOP coding styles into my daily CFML application development. 

Most of the time you'll see OOP/DDD applied towards solving rather complex problems, which makes sense in terms of using it for production purposes.  However, when trying to learn a concept sometimes it makes sense to take something simple and make it a little more complicated in order to learn.  In other words, I need to learn how to walk before I can run.

What I've done is set up a simple model for a user registration system that will be used on a web site.  I'm sure we've all built tons of these things - a user visits a web site where they are asked to enter their name, email address, password, etc...  My goal was to take what I've learned about OOP so far and apply it to a scenario like this.

In my reading about OOP I came across a concept called an "anemic domain model" which some people consider to be an anti-pattern. An anemic domain model, as I understand it, is basically using your entity objects (the "user" object in this case) as dumb "bags of getters and setters".  Essentially this means your objects don't contain any business logic and aren't all that different different than a standard CFML struct.  Many people argue that entities should contain behavior.  The difficult part for me is understanding which behavior belongs in an entity, and which belongs in a service.    If you add too much behavior in an entity, you could wind up with a massive object that is trying to do too many things at once (a "no-no" if you're following SOLID principals).  Walking that thin-line has been a challenge for me.

Another thing I came across (special thanks to Hal Helms and Sean Corfield) that really struck a cord with me was that an entity object should never be allowed to exist in an invalid state.  I really liked that idea and felt that if I could ensure my entities were never invalid, I could write better code with fewer potential for bugs.  My takeaway from this concept is that from the time you create an entity object to the time it evaporates at the end of a request, it should never ever exist in an invalid state. For example, if you had a business rule stating that all users must have an email address.  You would need to design your User entity so that emailAddress could never be anything other than a valid email address.

So how does all this apply when you're talking about a user registration form?  Here's a diagram I made of my model:https://i.imgur.com/NoxX0Eh.png

NoxX0Eh.png

Components:

  • UserService
    The user service is a singleton object which assists with the getting and saving user data. An important thing to note about a singleton object like this is that it does not manage state!  What this means is that this service should be accessible and used by other people using the application. Typically I like to store singletons in the application scope or in a factory which lives in the application scope.

  • UserDAO
    The user DAO (data access object) is what actually communicates with the database.  This object is responsible for running the SQL required for getting, adding, saving, records from the database. This object is injected into the UserService as a dependency. By injecting the object and making it private ensures that only the UserService can make calls to it. 

  • User
    The user object represents an individual user record in the database.  This object is also known as an "entity" and contains a specific instance of a user's data. For example, first name, last name, etc.  Note: In an attempt to move away from an anemic domain model, you can place business logic in your entity objects.  For example, if you wanted to have a requirement for password strength or some other business logic you could include it here.  You might also have some logic insuring that the emailAddress field contains a valid looking email address.  The "business logic" I've included ensures that the user entity object can never exist in an invalid state.  Some people call entities like this "rich domain models" or "rich entities".

  • RegistrationForm
    The registration form object is also an entity. This object will contain the data for the actual form fields (input boxes, etc...) as well as validation logic to ensure that the data is valid and safe to be inserted into the User entity object.   Think of the registration form object as a "proxy" that lives in between the user's input and the actual object they are trying to add or update. 

You might be asking yourself right about now, "Why do we even need a separate object to hold the form data? Couldn't we just add the data directly to the user entity object?"   The reason we use the RegistrationForm object is because a registration form can exist with no data, partial data, or even drastically invalid data.  Think about it... when you first visit a registration form all of the text boxes are empty.  Is the form in an invalid state?  No.   You can type anything you want into the name fields, or you could leave them blank.  You could type gibberish into the email address field, or make a password with only 1 character.  The form, still exists without throwing an exception error. In other words, a form is simply something that accepts user input.

If you tried to add a gibberish email address into the User entity object the User entity object would exist in an invalid state. That would be very bad.  To prevent invalid states from occurring gracefully, the RegistrationForm entity has some business logic thrown into it, the validate() method.  The validate() method checks to see if the data contained within itself is suitable to be placed within a User entity object.   If the validation passes, the User entity is updated.  If validation doesn't pass, the form shows itself to the user again so they can correct their inputs. 

Here's a diagram showing how that process works:

49rsv1I.png

So there's my attempt at taking something as simple as a user registration form and applying my understanding of OOP principals.  I'd love to hear your thoughts on my approach, how you'd handle things differently, and if you have any suggestions for me moving forward.


One thing that I'm still wrestling with is the idea of the "anemic domain model" and how much (and what kind) of behavior to include in my entities. I can think of some examples where an object might have a bunch of behavior or business logic and it would make sense to break that out into several different services otherwise your entity object code would be massive and unmanageable.  

Thanks for reading and I look forward to hearing your thoughts and criticisms.

Views

721

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Feb 12, 2018 0
Adobe Community Professional ,
Feb 12, 2018

Copy link to clipboard

Copied

As you seek and explore more on this, I’ll point out that there’s an entire book on the topic, “Object-Oriented Programming in ColdFusion” by Matt Gifford. While written in 2010, most concepts should not have changed much since then:

https://www.amazon.com/Object-Oriented-Programming-ColdFusion-Matt-Gifford/dp/1847196322/ref=as_sl_pc_tf_til?tag=carehart-20&linkCode=w00&linkId=34b20c6b363661773c988153d348e4e9&creativeASIN=1847196322

That should be one long line. If it’s appearing broken into two.

I can’t comment myself beyond that, regarding all that you shared. OO/COD/SOD is just not my bag. I focus solely on CF server troubleshooting, not having done professional CFML development for about 15 years. I just wanted to point you to the book in case perhaps you find that no one else replies with more.

Hope it’s helpful.

/charlie

/Charlie (server troubleshooter, carehart.org)

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Feb 12, 2018 0
Participant ,
Feb 13, 2018

Copy link to clipboard

Copied

Thanks for the reply, Charlie.  It's funny you mention the Matt Gifford book as that is the first ColdFusion OOP book I read.  The Amazon link didn't work for me but you can also find it on PacktPub here.  I then followed up with reading the Adobe ColdFusion Anthology by Michael and Judith Dinowitz which covers many topics including some OOP patterns however I didn't feel that book went into as much detail as I would have liked on the subject of OOP.

I then decided to read a book about OOP in JavaScript (also on PacktPub ) to get a different perspective on the subject.  I found that book to be extremely helpful in teaching me terminology and new concepts even though Javascript is very different than CFML.  

I haven't found many modern resources or sample code for OOP/DDD development with CFML these days so I've turned to looking at examples for other languages like Python or Java.  

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Feb 13, 2018 0
Adobe Community Professional ,
Feb 15, 2018

Copy link to clipboard

Copied

A laudable undertaking. I don't want to split hairs, just to make an additional remark or two.

What you've presented (domain objects, entities, behaviour, responsibilities, S.O.L.I.D. principles, etc) is OOAD, Object-Oriented Analysis and Design. This is different from OOP, Object-Oriented Programming, which comes later (encapsulation, polymorphism, inheritance, abstraction, packages, etc).

I wouldn't worry about dogma. I would just make sure my design has the minimum set of classes necessary to fully model my domain. Each such class would have a specific responsibility. It would contain just the properties (fields) and behaviour (methods) it needs to carry out its responsibility.

Its properties should be private by default. Any client who wishes to know the state of an object, or to change it, has to do so by means of a public interface. That is where the getters and setters come in. But they are by no means obligatory.

Now, if you were to switch databases from SQL Server to MySQL or Oracle, would it mean changing huge portions of your design or code? If so, then your domain and data layer are strongly coupled. You should use Data Access Objects to mitigate such coupling. They would do so by enabling your application to seamlessly switch database brands, without any significant change in design or code.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Feb 15, 2018 0
Participant ,
May 10, 2018

Copy link to clipboard

Copied

Sorry for the delayed reply BKBK.  Thank you for sharing your thoughts on the subject and I think you're right.  It's very easy when learning about OOP (or OOAD) to get overwhelmed with terminology and best-practices which are often misused on Stack Overflow and various programming blogs.  There definitely is a lot of programming Dogma out there, and I find myself struggling with which ideals to put into practice, and which I should leave out.

It has definitely been challenging to find more advanced resources on OOP/OOAD in CFML development so I often find myself reading books and articles on problem solving in other languages like JavaScript, Python, Java, and C#.   I do wish Adobe would offer more resources for modern CFML development with a more OOP/OOAD mindset.  For example, it would be great if they would put together write-ups on popular design patterns and how they could be implemented in a CFML application.

One thing I've started using in my apps since I initially wrote my first message is the repository pattern.  Even though adding a repository has added additional complexity to my project, I like the idea of adding an abstraction layer between my business logic and the database access objects.  I believe that utilizing the repository also does address the concern you brought up about coupling data access with the rest of the application.  

I actually designed a chart that I keep nearby that I use for reference when planning out an app.   The chart is designed to identify the different "layers" of an application and where each type of object should live and who it should communicate with.

Here's the chart I've been using in case anyone is curious or has feedback:
[caption width="999" align="alignnone"] Application layer reference chart[/caption]


Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
May 10, 2018 0