UML Diagram of My General Model Structure

During my recent presentation to the IECFUG, one of the parts we didn't really have time to touch on was a diagram I created of my general model architecture.

The diagram is below, and contains a good number of comments to explain the different pieces. Given the recent discussions going on in the blogosphere and on the lists, I thought this might be interesting to some folks. If anyone has questions, please feel free to ask and I'll do my best to answer. Comments are welcome as well, of course.

Note that this is really just a starting point, and that I tweak this base setup as necessary, depending on the project and the specific problem being addressed. But I've found that, in general, this kind of setup provides me with a lot of flexibility and is actually quite easy to create or even generate. If one chooses to look at ColdSpring and/or Transfer, much of this can be generated automatically and then tweaked as necessary. But even if those frameworks aren't suited to your development approach, each of these pieces is relatively straightforward to create.

A Competition-Based Version of Ray's Lemonade Selling Simulation

Many of you probably saw Ray Camden's Lemonade Stand Contest Results. I had fun creating a function to enter into that contest, but I lost! Congrats to Geoffrey K. Bentz as the winner.

I was curious, though, to see how the functions would perform in a slightly more realistic simulation. Ray's selling simulation basically treated each function in a vacuum, and the main factor was in making the most cups that you could and selling them for the most money, based on the weather and temperature. That may sound obvious, but if a more competitive environment is created, things aren't quite so straightforward. You need to make an appropriate number of cups, and you need to charge as much as you can for them, but you also need to avoid being priced far above your competition.

Well I went ahead and wrote a version of the simulation that tries to take this into account. It's far from perfect, but basically what it does is:

  1. It loops over each day like the original does
  2. It determines the predicted and actual temperature and weather like the original does
  3. It then feeds the prediction temp and weather into each function and gets back its number of cups and its price
  4. It sorts the stands in order by cup price, lowest first
  5. It begins the buying simulation by creating a default pool of customers equal to the number of stands * 100
  6. It sets a default maximum acceptable price of 50 cents per cup
  7. It modifies the number of customers and the acceptable max price based on the weather and temperature. In general, nicer weather and hotter temperature increase the customers and the max price, and bad weather and lower temperature decrease customers and their max price.
  8. It loops over the set of customers and divides them into groups. The group sizes are random, to simulate "waves" of customers coming up to the lemonade stands
  9. As each group is processed, each person has their max acceptable cup price randomized between +/- 12 cents of the base max price, to provide variability
  10. The first person in the group finds the stand with the cheapest price that still has cups available and whose price doesn't exceed the customer's randomized maximum price
  11. When a customer picks their stand, that stand becomes "occupied" and is now not available for other customers in this group. The next customer finds the next best price, etc.
  12. The variable group sizes are run through until the total number of customers is reached
  13. At that point, the number of cups each stand sold, along with their profit and budget, are saved
  14. The day ends and the next day begins

In this way, it's important to sell at a price that makes the stand money, but not so high that its far above what the others are selling for. Even stands selling for cheap prices are out of luck if they don't make enough. Conversely, since the size of the crowds are randomized, as are their price limits, it is easy for a stand to make too many cups and not sell them all.

I ran a 30 day cycle through 30 runs and came up with average rankings for each stand. I also determined the standard deviation for each stand, which is an indicator of consistency. A stand with a large standard deviation was more erratic in its ranking, while a low standard deviation means less variability in its rankings over time.

The level of built-in variation in the simulation causes the results to shift around a bit, but in general Geoffrey Bentz still comes out on top. Usually followed by myself or Mat Evans. Kudos to Stephen Withington, since even though he is not usually the winner, he has a very consistent ranking (low standard deviation) around the 4 or 5 spot. Curt Gratz also does well (I fixed Curt's function to properly deal with cents instead of dollars).

Interestingly, and maybe something of a validation that the more competition-driven simulation actually makes a difference, is that Ray's test "smarterseller" function tended to be in the bottom half of results. Since all that function does is make as many cups as it can, and ignores weather to ramp up the price based on temperature, perhaps that should be expected? This function probably ended many days with a lot of unsold cups.

Anyway, some example results are below. If you are interested, you can see and run the modified simulation code. Thanks again to Ray for running this! Writing the little simulation version was an interesting exercise. Maybe someone else will try an alternate approach or try some of the other ideas that were thrown out (like actually reading historical weather data, or applying a weather pattern algorithm).

Sales Results Across 30 Runs of 30 Days Each

Stand Average Ranking ± Std. Deviation
BENTZ 3.87 ± 3.88
MATEVANS 4.70 ± 5.41
BRIANKOTEK 5.37 ± 3.23
CURTGRATZ 6.03 ± 2.88
PADDYROHR 6.10 ± 4.70
STEPHENWITHINGTON 6.37 ± 2.69
CFSILENCE 6.77 ± 3.65
JOHNERIC 8.00 ± 2.48
MATTOSBUN 9.63 ± 4.53
JOELSTOBART 9.80 ± 2.84
SMARTERSELLER10.83 ± 5.96
GENTRYD 10.83 ± 2.37
MATTJONES 11.03 ± 2.59
BRADWOOD 11.27 ± 3.07
TUTTLE 12.40 ± 3.59
CISKE13.93 ± 2.26
COYNE 16.07 ± 1.15

Remember:
  • Look not only at the average ranking, but at the standard deviation.
  • A lower standard deviation means that stand was more consistent in its ranking.
  • A higher standard deviation means that stand had a wide variability in its rankings.
  • So in the end, consistent performance and a good ranking really make the best stands.

Ask Brian: How to Handle Object Validation?

Jason asks:

Brian,

I'd like to ask a question about Beans and Validation. Feel free to use it is a blog post.

So a lot of people have been telling me that Beans could/should have a validate() method to validate their own data.

My issue with this is, how can a bean validate it's own data if it is throwing errors in get() methods because you are trying to insert invalid data.

Since I cannot insert "Jason" into a date var or a numeric var, what good is my bean's validate() method gonna do me.

It seems to me that I have two choices.

1. I can do pre-validation validation. And validate the data before I insert it into the bean for validation

2. I can do all of my validation in the service layer or handler/listener(if no service layer) and THEN populate my bean with valid data.

I like option 2.

Am I making sense?

FYI, I am an OO n00b.

Hi Jason, don't worry, you're making sense. I actually don't do either of these. Before I do anything like a save() of an object, I create a Result object. My Result is a generic object with methods like isSuccess(), hasErrors(), getErrors(), etc. I use this to handle my validation.

Basically, I call user.populate(data, result). The populate function attempts to populate the object by calling setters that correspond to the data that was passed. (For customization, an object can override it's inherited populate() method if the generic behavior isn't sufficient.) If there are any failures, an error is caught and added to the Result object.

Once that is done, attempt to save the object even if there are errors, so that I can get additional validation error messages (i.e. end date must be after start date). Saving is done the same way: user.save(result). The save() call triggers a validation, and any validation errors not based on type are added to the Result as well. If the Result contains no errors after validation, I proceed with the save. If there are errors, the save does not continue.

Once that is done, I have a Result object that either has errors or it doesn't. These may be population errors cause by type mismatches, or they may be validation errors handled by my validation rules. Regardless, I now have a nicely packaged Result object that I can return to the calling code. This can be returned to something like Flex, or it can be returned to an HTML Controller such as Model-Glue, but either way, that code can now decide how to proceed.

This is just the way I do things but I've found it to be very flexible and useful. I hope that helps!

INDUS is Hiring a Junior CF Developer at the National Toxicology Program

My old company INDUS is hiring at the National Toxicology Program in Research Triangle Park, North Carolina.

INDUS is a very good company, and the folks at the NTP are also very nice and easy to work with. They use CF8, Oracle, Fusebox, Farcry, and a number of other technologies. Processes and testing are also very important elements of the work there. Anyone who is interested, please check out the job listing. The INDUS site wants you to create a profile to apply online, so if you don't feel like doing that just contact Matt Darby directly at:

mdarby [at email symbol] induscorp [dot] com.

(Sorry for the cryptic email format, you know how the spammers are.)

Web Developer I
http://jobs-induscorp.icims.com/induscorp_jobs/jobs/candidate/job.jsp?jobid=1339&mode=view
This is an onsite position, no telecommuters or recruiting agencies. If cf skills are not strong we will consider programing skill in other languages as a means to transfer skills into CF.

My IECFUG Presentation Recording and Files

Last Friday I gave a presentation to the Inland Empire ColdFusion User Group. It covered a range of topics: MXUnit, ColdMock, and elements of my RIAForge FormUtilities and ColdSpring Bean Utilities projects.

The presentation went well, I think. There are a few technical issues towards the end when they were trying to set up a microphone to get a Q&A going, but they are minor. I've linked to the files and the recording below in case anyone is interested in having a look. Thanks again to Sami, Luis, and the IECFUG for allowing me to present!

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner