You can download the full code samples
I used in my Rapid OO talk that I gave most recently at cf.Objective(ANZ)
, and previously at cf.Objective()
Before people ask, I don't tend to post slides, as they are generally only pictures, and tend to have no context without me talking next to them.
That being said, I'll have a chat with the CFMeetup crew, and see if they would like me to give the presentation there, so there is a recording for posterities sake, and for those who couldn't make those conferences.
While I am recovering from the Australian WebDU
conference, a few days before that started I got off a plane after the end of the wonderful cf.Objective()
I have to say, this year's cfObjective() was the best organised out of all the years I have been to. As per usual, the content was stellar, the hotel was lovely, and it was an absolute pleasure to catch up with everyone at the conference. I have to give a big 'congratulations' to Jared, Steven, Jim and the rest of the cf.Objective() crew for putting together such a smooth and professional conference.
I had the pleasure of doing two sessions, Rapid OO Development with ColdFusion Frameworks
, which covered a variety of techniques on how to increase your development speed when building OO models, and I was very happy to see that it seemed to have been very well received. I had one attendee let me know that 'Now I know why
I'm using ColdSpring! I was using it before, but now I know why
', which is an amazing thing to hear as a presenter, that you've managed to create an 'Aha!' moment for someone.
I also did my Introduction to Building Applications with Transfer ORM
, which was a repeat of the session that I did last year. Unfortunately Ray Camden
couldn't make it to do his Transfer
session, so I was called in at the last minute to take his place.
The big news that we announced at cf.Objective(), is that I will now be the lead developer on the ColdSpring
project. Since Chris Scott's major focus these days is the Swiz Flex framework, he decided it was time to pass on the reigns, and since I tend to talk to him regularly about Cold/Spring, have contributed code to ColdSpring , and know about running an Open Source project, he seemed to think I would be a good fit. I'm pretty excited about the opportunity, and have discussed some great ideas with theColdSpring development group, of which Chris is going to stay on as lead architect. I expect we will start off by building the infrastructure around the project, e.g. a centralised wiki, ticket tracker etc, and then move on to some more interesting items.
The obvious question there is, of course, what does this mean for Transfer? (I think I need to start writing down how many times I've been asked if it's 'Dead'. Does anyone actually expect a 'yes' for an answer?), and quite frankly, I don't see this impacting on Transfer much at all, simply because this is going to be code that I would have probably ended up writing on ColdSpring anyway, but it is now a more formalised relationship. When I run into a feature or a bug on an Open Source project, that I want to be implemented, my first natural reaction is to start looking into the code, and writing the feature. This was first exemplified by my contribution toColdSpring of annotation based pointcuts
. There are several aspects of ColdSpring I wanted to improve on, so it was just a natural reaction for me to end up writing code for it.
As stated, the content at cf.Objective() was brilliant as per usual, with my own personal highlights being, Advanced ColdFusion Server Administration (Adam Lehman), Advanced ColdFusion 9 ORM (Terry Ryan) and ColdFusion Portlets (Adam Haskell).
Thinking about the content, I have a little confession to make, that I realised on the way back from cf.Objective() this year. I have a tendency to go to the wrong sessions when at a conference. This may sound like a weird thing, but I realised the last few years I tend to go to sessions that I already know a lot about, just to see if they say something a little bit extra that I can add to my knowledge base. Quite often I end up walking out feeling like I haven't added much to my repertoire. Really what I should be doing is going (mostly) to sessions in which I know absolutely nothing about
, which means I actually get the best return on the my investment in the conference. While it may not be specifically applicable to what I'm currently doing, at the very least it will inspire me to do some interesting new things, and may give me some knowledge that I can then apply at some point in the future. This is a philosophy I plan on applying to all future conferences that I attend.
Finally, I also had the opportunity to be part of a CFConversations round-table
on the second night of the conference. Brian Meloche
, Andy Powell
, Andy Matthews
and I had a really good chat about the conference in general, our thoughts on some of Adobe's upcoming products, various other topics relating to ColdFusion. It was lots of fun to do, and you can download and/or read more about it here.
Again, thanks to all the cf.Objective() crew, and look forward to seeing many of you again at cf.Objective(ANZ).
As per usual, I'm late with my announcement that I will speaking at
cf.Objective() again this year. It is actually really interesting to
see the schedule contain so many sessions that cover OO concepts, and specifically, how to use common tools and development practices to make OO development in a web application context so much easier, better and faster.
This is obviously a real trend in the ColdFusion thoughtscape, with sessions like:
- Introduction to OO Modeling and Design - Brian Kotek
- Taking Code Reuse to a Higher Level - Jeff Chastian
- Building an Object Oriented Model - Bob Silverberg
- RAD OO in Code - Peter Bell
- Atomic Reactor - Mark Drew
- Leveraging Basic Object Oriented Concepts and Design Patterns in ColdFusion - Phill Nacelli
- What to do When OO Fails you in ColdFusion - Brian Meloche
- The Best of Both Worlds: Java Backends with CFML Frontends - Matt Woodward
- Object Relational Mapping with ColdFusion - Jason Delmore
- An Object Oriented Approach to Validations - Bob Silverberg
- Leveraging Enterprise Open-Source Java in ColdFusion - Joe Rinehart
..and of course, my very own Rapid OO Development with ColdFusion Frameworks
If you are looking to do, or already are doing Object Oriented development in ColdFusion, this is quite obviously the place to be!
In my Rapid OO talk, we are going to take a completely manually written OO
model, including persistence to the database, and slowly strip parts of
the code away, replacing them with a combination of ColdFusion
Frameworks and custom generic code, to give you some new tools in your 'OO Development tool-belt', that you can then go away and play with, and hopefully include in your day to day development practices.
Look forward to seeing you all there!
I'm feeling pretty excited, because my first article for Adobe DevNet has finally been published.
An introduction to ColdFusion frameworks
It covers the differences between Model-View-Controller, Dependency Injection, and Persistence frameworks, and also gives a general overview of some of the most popular offerings that are available in ColdFusion right now.
There was a bit of a rush towards the end, and some pieces of it are not as perfect as I would have liked, but I hope that it serves as a way for people to enter into the ColdFusion framework world, gives them enough information so that they understand the differences between framework types, and also allow them to make an informed decision on which one to use based on their personal preferences and needs.
Jared just did a blog post over at Alagad on a feature request for named transactions
. I have to chime in here and say that I really, really, really, want this feature!
The current restriction of having transactions only within a <cftransaction></cftransaction> block is incredibly limiting from a OO perspective.
Something that I had on the radar for Transfer
was to be able to control the Transactions at a database level with
your code, as well as automatically clearing from cache the relevant
objects if something went wrong.
Essentially it would go something like this:
transaction = getTransfer().getTransaction();
employee = getTransfer().get("employee", 1);
manager = getTransfer().get("employee", 4);
this code, if we got to the 'transaction.rollback()', not only would it
roll the DB data back, but it would also intelligently discard the
'employee' and the 'manager' objects from cache - thus ensuring that
there was no dirty data.
Currently, with ColdFusion transactions
structured the way they are, it's actually impossible for me to do
this, as there is no <cftransaction> block, and I have no hook to pick up when something goes wrong.
With a named Transaction block, I could internally handle how transactions where managed inside my Transaction.cfc, and and I could pick up the rollback() or commit() call as appropriate.
This would be an incredibly handy thing, so count me on a big +1
for this feature!
Last week we had Robin Hilliard of Rocketboots
into the office to help us get the biggest bang for our buck performance wise with the Transfer
application, and I have to say it was a great session all around.
Apart from imparting upon us a great many ideas for aspects of our
application we could cache, and various other pearls of wisdom, we
turned on Report Execution Times, and managed to find several key
places in Transfer that were sometimes called over 500 times in one
request (we do a fair amount of data movement per request).
For one thing, in all honesty, I had completely forgotten about Report
Execution Times. I had turned it off when it was making my CFC heavy
applications go into a slow paced crawl, and had quite literally left
it for dust.
However, after turning it on, and just running it over just a few
requests, the key areas of Transfer that would provide significant
performance increases became very apparent very quickly.
This is where all those small, finicky, performance 'tricks' come to the fore very quick -
- using else/if statements rather than case statements
- replacing the use of iterators with for() loops that use a counting numeric index
- playing with different Java Collections for different operations - i.e. ArrayList vs LinkedList
- Assigning method results to variables before large looping operations, rather than evaluating them every time.
- ..and other such things
It should be worth noting, that by doing some of these things, the code
ended up looking rather ugly, but with testing, performs faster than
before. So this is not to say that I went through the entire Transfer
codebase and switched out everything I could find to being the most
efficient I could possibly, in fact that couldn't be further from the
truth. There are many places in Transfer that use case statements,
even knowing that else/if statements are faster - simply because I find
case statements are more readable, and they are not in places of the
system that are called in numerous succession. By the same token, I
make extensive use of Java iterators to loop over my collections in
Transfer, as they provide a high degree of abstraction away from what
sort of Collection is being used behind the scenes, but those places
are now limited. However, by specifically pin pointing aspects of the
system that are critical to the performance of the framework, the
necessary tweaks to the framework could be discovered and acted upon.
So say thanks for Robin for the new performance improvements for Transfer that can now be found in SVN.
just finished up
a great tutorial on how to handle Object Composition, going from
creating CFCs from scratch, through to modelling the entire thing with ColdSpring
He goes into some great detail on how to use his Illudium PU-36 code generator
to generate the Transfer templates to make life a lot easier for the outset.
Definitely an interesting read.
I've had several conversations with people on various mailing lists about what is the best way to structure your CFCs so that they:
- can be typed via 'return' attributes of cffuncion of 'type' attributes of cfargument
- can be set in 'extends' attributes of cfcomponent
- are very portable - i.e. it is easy to use com.io.FileReader in one project, and you can pick it up and move it to another without having to do a global find and replace to change com.io to com.domain.io.
- are able to be used in different applications across a domain - i.e. if you have one application at /myapp1/ and another at /myapp2/ they can both have a com.myCFC that can be named the same, but do differnet things, and they won't intefere with one another.
- are easy to maintain.
Unfortunately, I don't believe that there is currently a BEST option out there to cater to all of these things, but I'm going to go through all the options I have found, and describe the pros and cons of each, and you can make your own decisions (For those of you who are on CFCDev, I'll be taking a lot of stuff out of what I wrote there).
Use a CF Mapping
In a lot of cases this can end up being the best option. It solves all your issues with typing (1, 2), however it does not make the code very portable, in that you may not ever have access to the cfadmin to create the mapping, and/or if the mapping needs to change, you have to edit your code to work with that, so you cannot simply just drag and drop.
To work around that problem, you could either (a) use the ServiceFactory to check if the mapping already exists, and if not create it in the appropriate place and/or (b) create a mapping that looks like "/com/mynamespace/mystuff/" that will nicely translate into a path like 'com.mynamespace.mystuff'. The advantages of (a) is that you can make a entry point to your CFC lib (most likely a Factory) setup the mapping as necessary, and therefore you don't need to go to the cfadmin, however, obviously it is a undocumented feature. The advantages of (b) is that you are almost totally guaranteed that someone hasn't already used that namespace (much like packaged in Java).
The cons of cfmapping (and the ServiceFactory workaround above) have to do with code portability and using the same CFCs across a domain (3,4). Since a mapping is server wide, if the applications have differing code, it's going to get very messy. You will end up having to set a unique mapping for that application, and therefore break all your return, extends and type attributes in your CFCs.
This would work very well for application specific code, but not code that you wanted to port from one place to another, such as a product or framework (I shudder at the thought of having different versions of framework on the same server that used a mapping...).
Put all your CFCs in one directory
Placing all your CFCs under a single directory solves most of the above problems, particularly the one with applications spread across a domain (4) and since all the CFCs can see each other typing is not a concern. The major issues here (I feel it's major) has to do with what happens when you start looking at systems with large amounts of CFCs. Having anywhere above 20 CFCs in one directory is going to start to get very hard to work with, and could cause some maintenance frustrations in the long run.
One of the nice things about packages is that they can be relatively self documenting, assuming they are named well, and can help break down an application into manageable 'chunks'.
This would be useful if you have a small amount of CFCs and/or having multiple CFCs across domains with the same name, but different functionality (4) is of utmost importance.
Use relative '/' rather than '.'
I can remember when I first found out about this technique - I thought it was going to be the absolute best thing ever. However, like all the rest it has its drawbacks. It handles issues of typing quite well (1,2), but does mean that you can end up with some very odd package design, and more often than not, most of your main CFCs in the same directory anyway. It is very portable (3), but only within a given OS, as '/' must be used on *nix, and '\' must be used on Windows, which pretty much defeats the purpose of portability. Otherwise you have no problems with multiple apps across a domain (4) as all the mappings are relative.
This would be most useful when you know you aren't going to change OS, and being able to use code across a domain is very important. This couldn't be used for product development simply because of the OS issue (and it's an undocumented feature).
Don't use typing
This essentially boils down to not using inheritance (because you have to hard code it), and all type and return values are either 'any' or 'web-inf.cftags.component'. One could argue that since CF won't check things until runtime anyway, this won't make any in terms of how errors are fired on the system.
To help bring back some sort of typing (1,2) you could do some sort of testing to ensure that a CFC is the CFC you require (via getMetaData), or that it has the given method you wish to call. This can cause further overhead, especially considering that getMetaData is known to be pretty expensive. It will also take a little bit longer to develop as you have to write the extra code.
However - this code is very portable (3), and can be used across domains easily (4), but you do lose a lot of the self documentation that typing gives you, and could leave you wondering which CFC you were meant to pass in as an argument.
If you were writing a product to be used it a variety of places, this may be an appropriate place to use this method, but for application specific code, it is probably overkill.
Store them in a directory in the root of your domain
This seems to be the most 'rounded' of solutions for placing your CFCs. If you notice, Mach-ii, model-glue, Tartan etc all require you to include their install files in a directory in the root of your domain, and since we figure the people who wrote this stuff are a *little* bit clever ;o) so we can assume that there is a reason for this.
This solves issues with typing and portability (1,2,3) and is obviously easy to maintain (4). The issue comes from where you have multiple applications running across a domain (quite possibly a relatively low percentage of apps?) with different versions of CFCs required on them.
If application /app1/ is running v0.8 of their framework, and /app2/ is using v0.9 and they BOTH have to have their CFCs in the root of the domain - you are either going to run into a mess, or you will need to test app1 all over again to make sure nothing breaks with the new version.
This seems to be the best option for when you are developing a product (particularly frameworks) as it is the most portable version, and it is very unlikely you will not have access to the root of the domain. If you use this for application specific code is probably dependent on what is being developed on that server.
Of course there is nothing to stop you from chopping and changing different aspects of these approaches into whatever happens to work for you.
I think I managed to cover all the approaches that are possible - but if you have some other way, please let me (us?) know.
Just found a nice article on JavaBoutique that talks about coupling and cohesion, along with explaining how to calculate metrics to determine if your code needs less coupling, or more coehsion.
Is a good read.
A while ago, I posted an example of creating CFC definitions on the fly using a function I wrote called StructToBean().
It essentially used the concepts of Prototype Based programming to implement the getter and setter methods on a blank CFC, so that the data of the Struct was encapsulated in an object without having to actually write the object itself.
I put that post on here while I was writing a library that was an attempt to cut down on the amount of time I spent writing simple Beans for use as Business Objects.
The basics of the library was such that I had a XML config file that defined each of the Beans that I wanted to be able to use in the system, like so (cut down version):
<property name="number" type="numeric" />
<property name="name" type="string" />
The library would then create a .cfm file on the fly, which would contain all the UDFs required to add the required getters and setters to the blank CFC.
When the specified Bean was called for, the library would create a blank CFC, and insert each of the methods onto the blank CFC at runtime, so it was ready to use.
As personal projects tend to do, this idea fell by the wayside for a while, and now I've been rebuilding compoundtheory, it's come back to me, and I've started to question whether or not it's really something I want to get behind in terms of how I build my CF applications. I'm still pretty much sitting on the fence as to whether or not I'm actually going to rewrite the code (it needs a good refactor), and utilise it in the new version of CT.
While CFCs aren't exactly prototype based, the basic flexibility of being able to utilise slots in the CFC to add and remove methods remains the same, but the question that I am wondering at the moment, is should it be used.
On one side there are alot of interesting things you can do with method injection and removal:
- Adding Object functionality on the fly
- Create Interfaces on the fly
- Faking Base class functionality
- Changing protection on methods due on the fly (i.e. remove a init() constructor once it has been called once)
- Fix bugs on the fly
But obviously there are cons as well:
- Adds a whole level of complexity to an application that is harder to document
- Breaks some core OO concepts (which may not be a bad thing, but you have to be happy about it)
- Can lead to some awefully spagettied code if not managed correctly
Now, obviously, whether or not you leverage this capability is very dependent on applicaiton requirements, your own personal views on OO Analysis and Design etc, but the usage of this functionality does exist, yet seems to be a topic that is not talked about much in the CF community.
So I ask you guys, as an information gathering excercise:
- Have you considered taking a Prototype based approach before?
- If you had, did you do it?
- If you did, what was it, and why did you do it? (I would love to hear of some places it was used!)
- If you didn't, why not?
- Would/wouldn't you consider using this approach for something in the future?
That being said, in the next few weeks (as I continue to develop the next version of CT), I'll do a follow up post on whether or not I decided to utilise the prototype based approach to developing the Business Objects for this site, and why I decided to do it, and hopefully this will get some interesting discussion going!
Some more reading on Prototype Based Programming
Well, I didn't get much response out of CFCDev, so I figured I would move the discussion over to my blog.
(So applogies to all this sounds really familiar to)
I always wonder what the best way is to get the results from a database when dealing with composite Business Objects.
Reading Matt Woordards blog post on DAOs and Composition,
He talks about composition, and to quote:
We're using composition in our beans, so why not use composition of
sorts (this isn't strictly composition, but bear with me ...) in our
DAO as well? When we instantiate the Person DAO, why not just
instantiate an Address DAO inside the Person DAO so we can call things
Now, in my mind - there are two options for getting the PersonBO information and the AddressBO information.
1) Seperate SQL queries for both BO's - The Address DAO gets the results for a Address, and the PersonDAO gets the results for the
Person BO - there are 2 query hits on the db.
Pros: It's clean, consise and really reusable
Cons: For complex objects, that's alot of database hits - is that a good idea?
2) JOIN between tables - a Gateway object (maybe?) gets a joined result by getting the relevent data form both the Person Table and the
Address Table, and the DAO's intelligently create the BO's that they need from that single query's results
Pros: It's alot more efficient than the above
Cons: It doesn't exactly promote code reuses
It also can get tircky as JOIN can cause duplicate data to display, and you have to avoid creating the same BO twice or more (unless you want to join up data usion UNION or something similar).
Personally I've been running with option (2) for a while, simply from a database performance perspective - but it does leave me with alot of pretty ugly code. Which makes me lean more these days towards options (1)
But sometimes I write BO's that can be composite of greater than 20 objects (and yes, all are required), so querying the database will 20 small hits I think would take a longer time.
So, which way around do you do it? and why?
Frameworks have been a hot topic of discussion around my peers at work of late, and I was wondering what sort of frameworks the wider community was using.
Personally I tend to utilise a custom/personal framework that I have slowly developed over the past few years. I've tended to shy away from using something standard such as Fusebox or Mach II, not because they are bad products (I've honestly never looked at them properly to give a good evaluation) but simply because (a) I like knowing how the internals of my system work and (b) I find framework development really interesting (and often the most interesting part of application development).
That being said, if I'm doing Java development, I'll tend to use something like Struts or the like, simply because I find I need something like that to get work done in J2EE (being it is rather low level). That may also just be because I've not had a huge chance to get my hands deep down into the bowels of what really makes J2EE tick, and therefore haven't had the time to make up something of my own.
So, do you use a custom framework? if so, why so? or have you started developing with something like Fusebox or Mach II, and if so, why so?
I found these two really nice articles on Business Objects on Java Boutique yesterday, and thought I would share them, considering my previous post on using OO with ColdFusion.
- The Mysteries of Business Object - Part 1
- The Mysteries of Business Object - Part 2
Business Objects tend to find their way into almost every type of application development that utilises an OO approach, so understanding the concept (and you may already be doing it without knowing it) is a pretty good idea.
The second article goes through a example application, and goes through alot of the considerations to be made when utilising business objects in an application.
Obviously the articles are Java related, but due to the general nature of Business Objects, as well as the myriad of frameworks that support BO's under Java, it tends to stick to pretty vendor non-specific details, so is a good read for ColdFusion developers as well.
I hear alot of arguments (particularly of late on the CFAUSSIE mailing list) about ColdFusion and Object Oriented Programming.
It seems that almost even the most tangential conversation that could possibly relate to OOP, degenerates into pointless bickering about how OOP is good, bad or ugly when combined with CF. It's verging on rediculous.
The facts remain as such - Object Oriented programming has been THE software development paradigm for more years than I have been alive. There is a REASON why we don't code in procedural code anymore, and a REASON why Object Oriented programming has come into almost every aspect of software development.
Looking solely at Macromedia related products. CF was procedural, and then came along CFC's. Flash was... well, Flash... and now you can define classes in Actionscript. Blackstone will further enhance CFC's with Event gateways and the like.
The truth of matter is - the Future for Coldfusion IS OO. You can like it, you can hate it, but quite frankly, if you develop with CF, Object Oriented programming is here to stay, and there is nothing you or anyone else can do about it. All it's every going to do is infiltrate more and more of the CF development community, as the years go by, and the support for it in future ColdFusion versions grows.
Yet again, I implore you - if you want to develop your software development abilities with ColdFusion go and drop into a Java course. Not only will it give you the theory you need to stay with the time in ColdFusion, but it also provides you with the ability to combine CF with it's sister language, and give you capabilities with this language you never had before.
Can that really be a bad thing?
This is something that tends to get my goat a little in some instances, so I apologise if I get a tad ranty.
We had a recent discussion on cfaussie about the this scope in CFCs, and whether or not it was an appropriate place to store data. Regardless of what the outcome of that conversation (and we all have varying opinions on the topic), there was one thing that became very prevelent to me:
There seems to be a bunch of people out there trying to write OOP code, without a full understanding of OOP concepts.
Unfortunatley I think that this is one of the pitfalls of CF - because it is so easy to write code, people can often think that they can just 'work it out on the fly' and they will be just fine.
Sometimes this is true - and sometimes it isn't. I know quite a few proficient coders that have come to many of OO's basic concepts through trial and error, but I don't think it is the most efficient way of doing things.
The simple fact of the matter is - OO concepts have been around for many years, so why would you try and guess them when you can find them out by studying a OOP language?
If you want to do OOP Programming with ColdFusion, go and study an OOP Language, and bring the theory of it back to ColdFusion.
I cannot possibly encourage this enough. Doesn't matter if it's Java, C++, Eiffel, SmallTalk, whatever. What you are looking for is the concepts and theories.
Basic software design concepts and terms such as:
I feel should be understood before really useful OOP Coldfusion code can be developed.
By undertaking some Object Oriented training of some kind, I can assure you that many pieces of software design will make so much more sense to you, and will become a far greater ColdFusion coder because of it.
I just want to make clear here as well - I am NOT saying that if you don't understand these terms or concepts, you are a bad coder, or that you write bad software. Far from it. People have different backgrounds, and different skills and come at things in different ways. So I apologise if I have offended anyone.
I just want to make sure that all of us that talk about software (and web development is software development) use the language, terms and vocabulary that have been around for many years.