Posted by Sam on Apr 09, 2008 at 07:34 AM UTC - 5 hrs
Something's been bothering me lately. It's nothing, really. ?, ?, null, nil, or whatever you want to call it. I think we've got it backwards in many cases. Many languages like to throw errors when you try to use nothing as if it were something else - even if it's nothing fancy.
I think a better default behavior would be to do nothing - at most log an error somewhere, or allow us a setting - just stop acting as if the world came to an end because I *gasp* tried to use null as if it were a normal value.
In fact, just because it's nothing, doesn't mean it can't be something. It is something - a concept at the minimum. And there's nothing stopping us from having an object that represents the concept of nothing.
More...
Exceptions should be thrown when something exceptional happens. Maybe encountering a null value was at some time, exceptional. But in today's world of databases, form fields, and integrated disparate systems, you don't know where your data is at or where it's coming from - and encountering null is the rule, not the exception.
Expecting me to write paranoid code and add a check for null to avoid every branch of code where it might occur is ludicrous. There's no reason some sensible default behavior can't be chosen for null, and if I really need something exceptional to happen, I can check for it.
Really, aren't you sick of writing code like this:
string default = "";
if(form["field"] != null and boolFromDBSaysSetIt != null
and boolFromDBSaysSetIt)
default = form["field"];
when you could be writing code like this:
if(boolFromDBSaysSetIt)
default = form["field"];
I think this is especially horrid for conditional checks. When I write if(someCase) it's really just shorthand for if(someCase eq true). So why, when
someCase is null or not a boolean should it cause an error? It's not
true, so move on - don't throw an error.
Someone tell me I'm wrong. It feels like I should be wrong. But it feels worse to have the default path always be the one of most resistance.
What do you think?
Hey! Why don't you make your life easier and subscribe to the full post
or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate
wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!
Last modified on Apr 09, 2008 at 07:39 AM UTC - 5 hrs
Posted by Sam on Mar 26, 2008 at 06:26 AM UTC - 5 hrs
When I try out a product, I like it to work. Sometimes, I like to tinker with things to gain a better understanding of how they work. Occasionally, I can manipulate them with skill. At other
times, I'm tinkering in the true sense of the word.
I'm going to point out a few problems I've had with some products I've been using. I won't name names, but some of you who also use these
products (or similar ones with the same problems) might understand what I'm talking about.
Hopefully, you all can draw a good conclusion from it.
I'm not a mechanic, but sometimes I might want to look into my radiator. Is there a reason
I need to disassemble the front of my car to unscrew the radiator cap?
More...
Likewise, diagnosing a problem with, and subsequently changing a starter or alternator isn't a task that only automobile doctors should perform. These are relatively high-failure parts that shouldn't require taking
apart the exhaust system to replace. That's the tinkerer in me talking.
Image courtesy Daimler-Chrysler via How Stuff Works
I am a software developer, but sometimes I don't want to act like one when I work
with software written by someone else. Don't make me build your product from source. I'm not asking you to build it for me, and then email it to me. I'm just asking if it's possible for you to set up an automated build on all of the platforms where you intend your software to work.
I enjoy the ability to tinker with
open source software, not the requirement to do so.
The situation is even worse for proprietary programs. If you're lucky, there might be a way to mess with the settings that satisfies the tinkerer in you. But if you're not lucky,
you could do things like upgrade your operating system and have it break something in 3rd party code. Then you'll be at the mercy of that vendor
to make their software run properly with your upgrade. In the mean time, you're stuck
manually starting the software, or writing your own scripts to do it.
In the first release of an accounting package, I might expect to edit a text file to set my tax rate. But I better not have to do that in the ninth version. Moreover, if your software makes
certain assumptions about its running environment and those assumptions are parts that are
likely to fail, you better make sure I can change them in your program without tearing it
apart.
In the end, I understand that for early versions of products, you might not have worked out all the kinks or even found its purpose or audience. I expect that as an early adopter, and when I take that plunge, I enjoy it.
But once you're several years old and multiple versions in, I don't think it's too much to
have certain expectations. At that point, your software should just work and make it easy to make small adjustments.
Last modified on Mar 26, 2008 at 06:28 AM UTC - 5 hrs
Posted by Sam on Jan 14, 2008 at 06:42 AM UTC - 5 hrs
This is a story about my journey as a programmer, the major highs and lows I've had along the way, and
how this post came to be. It's not about how ecstasy made me a better programmer, so I apologize if that's why you came.
In any case, we'll start at the end, jump to
the beginning, and move along back to today. It's long, but I hope the read is as rewarding as the write.
A while back,
Reg Braithwaite
challenged programing bloggers with three posts he'd love to read (and one that he wouldn't). I loved
the idea so much that I've been thinking about all my experiences as a programmer off and on for the
last several months, trying to find the links between what I learned from certain languages that made
me a better programmer in others, and how they made me better overall. That's how this post came to be.
More...
The experiences discussed herein were valuable in their own right, but the challenge itself is rewarding
as well. How often do we pause to reflect on what we've learned, and more importantly, how it has changed
us? Because of that, I recommend you perform the exercise as well.
I freely admit that some of this isn't necessarily caused by my experiences with the language alone - but
instead shaped by the languages and my experiences surrounding the times.
One last bit of administrata: Some of these memories are over a decade old, and therefore may bleed together
and/or be unfactual. Please forgive the minor errors due to memory loss.
How QBASIC Made Me A Programmer
As I've said before, from the time I was very young, I had an interest in making games.
I was enamored with my Atari 2600, and then later the NES.
I also enjoyed a playground game with Donald Duck
and Spelunker.
Before I was 10, I had a notepad with designs for my as-yet-unreleased blockbuster of a side-scrolling game that would run on
my very own Super Sanola game console (I had the shell designed, not the electronics).
It was that intense interest in how to make a game that led me to inspect some of the source code Microsoft
provided with QBASIC. After learning PRINT, INPUT,
IF..THEN, and GOTO (and of course SomeLabel: to go to)
I was ready to take a shot at my first text-based adventure game.
The game wasn't all that big - consisting of a few rooms, the NEWS
directions, swinging of a sword against a few monsters, and keeping track of treasure and stats for everything -
but it was a complete mess.
The experience with QBASIC taught me that, for any given program of sufficient complexity, you really only
need three to four language constructs:
- Input
- Output
- Conditional statements
- Control structures
Even the control structures may not be necessary there. Why? Suppose you know a set of operations will
be performed an unknown but arbitrary amount of times. Suppose also that it will
be performed less than X number of times, where X is a known quantity smaller than infinity. Then you
can simply write out X number of conditionals to cover all the cases. Not efficient, but not a requirement
either.
Unfortunately, that experience and its lesson stuck with me for a while. (Hence, the title of this weblog.)
Side Note: The number of language constructs I mentioned that are necessary is not from a scientific
source - just from the top of my head at the time I wrote it. If I'm wrong on the amount (be it too high or too low), I always appreciate corrections in the comments.
What ANSI Art taught me about programming
When I started making ANSI art, I was unaware
of TheDraw. Instead, I opened up those .ans files I
enjoyed looking at so much in MS-DOS Editor to
see how it was done. A bunch of escape codes and blocks
came together to produce a thing of visual beauty.
Since all I knew about were the escape codes and the blocks (alt-177, 178, 219-223 mostly), naturally
I used the MS-DOS Editor to create my own art. The limitations of the medium were
strangling, but that was what made it fun.
And I'm sure you can imagine the pain - worse than programming in an assembly language (at least for relatively
small programs).
Nevertheless, the experience taught me some valuable lessons:
- Even though we value people over tools, don't underestimate
the value of a good tool. In fact, when attempting anything new to you, see if there's a tool that can
help you. Back then, I was on local BBSs, and not
the 1337 ones when I first started out. Now, the Internet is ubiquitous. We don't have an excuse anymore.
-
I can now navigate through really bad code (and code that is limited by the language)
a bit easier than I might otherwise have been able to do. I might have to do some experimenting to see what the symbols mean,
but I imagine everyone would.
And to be fair, I'm sure years of personally producing such crapcode also has
something to do with my navigation abilities.
-
Perhaps most importantly, it taught me the value of working in small chunks and
taking baby steps.
When you can't see the result of what you're doing, you've got to constantly check the results
of the latest change, and most software systems are like that. Moreover, when you encounter
something unexpected, an effective approach is to isolate the problem by isolating the
code. In doing so, you can reproduce the problem and problem area, making the fix much
easier.
The Middle Years (included for completeness' sake)
The middle years included exposure to Turbo Pascal,
MASM, C, and C++, and some small experiences in other places as well. Although I learned many lessons,
there are far too many to list here, and most are so small as to not be significant on their own.
Therefore, they are uninteresting for the purposes of this post.
However, there were two lessons I learned from this time (but not during) that are significant:
-
Learn to compile your own $&*@%# programs
(or, learn to fish instead of asking for them).
-
Stop being an arrogant know-it-all prick and admit you know nothing.
As you can tell, I was quite the cowboy coding young buck. I've tried to change that in recent years.
How ColdFusion made me a better programmer when I use Java
Although I've written a ton of bad code in ColdFusion, I've also written a couple of good lines
here and there. I came into ColdFusion with the experiences I've related above this, and my early times
with it definitely illustrate that fact. I cared nothing for small files, knew nothing of abstraction,
and horrendous god-files were created as a result.
If you're a fan of Italian food, looking through my code would make your mouth water.
DRY principle?
Forget about it. I still thought code reuse meant copy and paste.
Still, ColdFusion taught me one important aspect that got me started on the path to
Object Oriented Enlightenment:
Database access shouldn't require several lines of boilerplate code to execute one line of SQL.
Because of my experience with ColdFusion, I wrote my first reusable class in Java that took the boilerplating away, let me instantiate a single object,
and use it for queries.
How Java taught me to write better programs in Ruby, C#, CF and others
It was around the time I started using Java quite a bit that I discovered Uncle Bob's Principles of OOD,
so much of the improvement here is only indirectly related to Java.
Sure, I had heard about object oriented programming, but either I shrugged it off ("who needs that?") or
didn't "get" it (or more likely, a combination of both).
Whatever it was, it took a couple of years of revisiting my own crapcode in ColdFusion and Java as a "professional"
to tip me over the edge. I had to find a better way: Grad school here I come!
The better way was to find a new career. I was going to enter as a Political Scientist
and drop programming altogether. I had seemingly lost all passion for the subject.
Fortunately for me now, the political science department wasn't accepting Spring entrance, so I decide to
at least get started in computer science. Even more luckily, that first semester
Venkat introduced me to the solution to many my problems,
and got me excited about programming again.
I was using Java fairly heavily during all this time, so learning the principles behind OO in depth and
in Java allowed me to extrapolate that for use in other languages.
I focused on principles, not recipes.
On top of it all, Java taught me about unit testing with
JUnit. Now, the first thing I look for when evaluating a language
is a unit testing framework.
What Ruby taught me that the others didn't
My experience with Ruby over the last year or so has been invaluable. In particular, there are four
lessons I've taken (or am in the process of taking):
-
The importance of code as data, or higher-order functions, or first-order functions, or blocks or
closures: After learning how to appropriately use
yield, I really miss it when I'm
using a language where it's lacking.
-
There is value in viewing programming as the construction of lanugages, and DSLs are useful
tools to have in your toolbox.
-
Metaprogramming is OK. Before Ruby, I used metaprogramming very sparingly. Part of that is because
I didn't understand it, and the other part is I didn't take the time to understand it because I
had heard how slow it can make your programs.
Needless to say, after seeing it in action in Ruby, I started using those features more extensively
everywhere else. After seeing Rails, I very rarely write queries in ColdFusion - instead, I've
got a component that takes care of it for me.
-
Because of my interests in Java and Ruby, I've recently started browsing JRuby's source code
and issue tracker.
I'm not yet able to put into words what I'm learning, but that time will come with
some more experience. In any case, I can't imagine that I'll learn nothing from the likes of
Charlie Nutter, Ola Bini,
Thomas Enebo, and others. Can you?
What's next?
Missing from my experience has been a functional language. Sure, I had a tiny bit of Lisp in college, but
not enough to say I got anything out of it. So this year, I'm going to do something useful and not useful
in Erlang. Perhaps next I'll go for Lisp. We'll see where time takes me after that.
That's been my journey. What's yours been like?
Now that I've written that post, I have a request for a post I'd like to see:
What have you learned from a non-programming-related discipline that's made you a better programmer?
Last modified on Jan 16, 2008 at 07:09 AM UTC - 5 hrs
Posted by Sam on Nov 22, 2007 at 12:04 PM UTC - 5 hrs
Since the gift buying season is officially upon us, I thought I'd pitch in to the rampant consumerism and list some of the toys I've had a chance to play with this year that would mean fun and learning for the programmer in your life. Plus, the thought of it sounded fun.
Here they are, in no particular order other than the one in which I thought of them this morning:
More...
- JetBrains' IntelliJ IDEA: An awesome IDE for Java. So great, I don't mind spending the $249 (US) and using it over the free Eclipse. The Ruby plugin is not too shabby either, the license for your copy is good for your OSX and Windows installations, and you can try it free for 30 days. Martin Fowler thinks IntelliJ changed the IDE landscape. If you work in .NET, they also have ReSharper, which I plan to purchase very soon. Now if only we could get a ColdFusion plugin for IntelliJ, I'd love it even more.
- Programming Ruby, Second Edition: What many in the Ruby community consider to be Ruby's Bible. You can lower the barrier of entry for your favorite programmer to using Ruby, certainly one of the funner languages a lot of people are loving to program in lately. Sometimes, I sit and think about things to program just so I can do it in Ruby.
If they've already got that, I always like books as gifts. Some of my
favorites from this year have been: Code Complete 2, Agile Software Development: Principles, Patterns, and Practices which has a great section on object oriented design principles, and of course,
My Job Went to India.
I have a slew of books I've yet to read this year that I got from last Christmas (and birthday), so I'll have to
list those next year.
-
Xbox 360 and a subscription to
XNA Creator's Club (through Xbox Live Marketplace - $99 anually) so they can deploy their games to their new Xbox. This is without a
doubt the thing I'd want most, since I got into this whole programming thing because I was interested
in making games. You can point them to the
getting started page, and they could
make games for the PC for free, using XNA (they'll need that page to get started anyway, even if you
get them the 360 and Creator's Club membership to deploy to the Xbox).
-
MacBook Pro and pay for the extra pixels. I love mine - so much so,
that I intend to marry it. (Ok, not that much, but I have
been enjoying it.)
The extra pixels make the screen almost as wide as two, and if you can get them an extra monitor I'd do
that too. I've moved over to using this as my sole computer for development, and don't bother with
the desktops at work or home anymore, except on rare occasions. You can run Windows on it, and the
virtual machines are getting really good so that you ought not have to even reboot to use either
operating system.
Even if you don't want to get them the MacBook, a second or third monitor should be met with enthusiasm.
-
A Vacation: Programmers are notoriously working long hours
and suffering burnout, so we often need to take a little break from the computer screen. I like
SkyAuction because all the vacations are package deals, there's often a good variety to choose from (many
different countries), most of the time you can find a very good price, and usually the dates are flexible
within a certain time frame, so you don't have to commit right away to a certain date.
Happy Thanksgiving to those celebrating it, and thanks to all you who read and comment and set me straight when I'm wrong - not just here but in the community at large. I do appreciate it.
Do you have any ideas you'd like to share (or ones you'd like to strike from this list)?
Last modified on Nov 22, 2007 at 12:04 PM UTC - 5 hrs
Posted by Sam on Oct 31, 2007 at 04:26 PM UTC - 5 hrs
When looping over collections, you might find yourself needing elements that match only a certain
parameter, rather than all of the elements in the collection. How often do you see something like this?
foreach(x in a)
if(x < 10)
doSomething;
Of course, it can get worse, turning
into arrow code.
More...
What we really need here is a way to filter the collection while looping over it. Move that extra
complexity and indentation out of our code, and have the collection handle it.
In Ruby we have each
as a way to loop over collections. In C# we have foreach, Java's got
for(ElemType elem : theCollection), and Coldfusion has <cfloop collection="#theCollection#">
and the equivalent over arrays. But wouldn't it be nice to have an each_where(condition) { block; } or
foreach(ElemType elem in Collection.where(condition))?
I thought for sure someone would have implemented it in Ruby, so I was surprised at first to see this in my
search results:
However, after a little thought, I realized it's not all that surprising: it is already incredibily easy to filter
a collection in Ruby using the select method.
But what about the other languages? I must confess - I didn't think long and hard about it for Java or C#.
We could implement our own collections such that they have a where method that returns the subset we are
looking for, but to be truly useful we'd need the languages' collections to implement where
as well.
Of these four languages, ColdFusion provides both the need and opportunity, so I gave it a shot.
First, I set up a collection we can use to exercise the code:
<cfset beer = arrayNew(1)>
<cfset beer[1] = structNew()>
<cfset beer[1].name = "Guiness">
<cfset beer[1].flavor = "full">
<cfset beer[2] = structNew()>
<cfset beer[2].name = "Bud Light">
<cfset beer[2].flavor = "water">
<cfset beer[3] = structNew()>
<cfset beer[3].name = "Bass">
<cfset beer[3].flavor = "medium">
<cfset beer[4] = structNew()>
<cfset beer[4].name = "Newcastle">
<cfset beer[4].flavor = "full">
<cfset beer[5] = structNew()>
<cfset beer[5].name = "Natural Light">
<cfset beer[5].flavor = "water">
<cfset beer[6] = structNew()>
<cfset beer[6].name = "Boddington's">
<cfset beer[6].flavor = "medium">
Then, I exercised it:
<cfset daytypes = ["hot", "cold", "mild"]>
<cfset daytype = daytypes[randrange(1,3)]>
<cfif daytype is "hot">
<cfset weWantFlavor = "water">
<cfelseif daytype is "cold">
<cfset weWantFlavor = "full">
<cfelse>
<cfset weWantFlavor = "medium">
</cfif>
<cfoutput>
Flavor we want: #weWantFlavor#<br/><br/>
Beers with that flavor: <br/>
<cf_loop collection="#beer#" item="aBeer" where="flavor=#weWantFlavor#">
#aBeer.name#<br/>
</cf_loop>
</cfoutput>
Obviously, that breaks because don't have a cf_loop tag. So, let's create one:
<!--- loop.cfm --->
<cfparam name="attributes.collection">
<cfparam name="attributes.where" default = "">
<cfparam name="attributes.item">
<cfif thistag.ExecutionMode is "start">
<cfparam name="isDone" default="false">
<cfparam name="index" default="1">
<cffunction name="_getNextMatch">
<cfargument name="arr">
<cfloop from="#index#" to="#arrayLen(arr)#" index="i">
<cfset keyValue = attributes.where.split("=")>
<cfset index=i>
<cfif arr[i][keyValue[1]] is keyValue[2]>
<cfreturn arr[i]>
</cfif>
</cfloop>
<cfset index = arrayLen(arr) + 1>
<cfexit method="exittag">
</cffunction>
<cfset "caller.#attributes.item#" = _getNextMatch(attributes.collection,index)>
</cfif>
<cfif thistag.ExecutionMode is "end">
<cfset index=index+1>
<cfset "caller.#attributes.item#" = _getNextMatch(attributes.collection,index)>
<cfif index gt arrayLen(attributes.collection)>
<cfset isDone=true>
</cfif>
<cfif not isDone>
<cfexit method="loop">
<cfelse>
<cfexit method="exittag">
</cfif>
</cfif>
It works fine for me, but you might want to implement it differently. The particular area of improvement I
see right away would be to utilize the item name in the where attribute. That way,
you can use this on simple arrays and not just assume arrays of structs.
Thoughts anybody?
Last modified on Oct 31, 2007 at 04:29 PM UTC - 5 hrs
Posted by Sam on Sep 25, 2007 at 06:39 AM UTC - 5 hrs
The last bit of advice from Chad Fowler's 52 ways to save your job was to be a generalist, so this week's version is the obvious opposite: to be a specialist.
The intersection point between the two seemingly disparate pieces of advice is that you shouldn't use your lack of experience in multiple technologies to call yourself a specialist in another. Just because you
develop in Java to the exclusion of .NET (or anything else) doesn't make you a Java specialist. To call yourself that,
you need to be "the authority" on all things Java.
More...
Chad mentions a measure he used to assess a job candidate's depth of knowledge in Java: a question of how to make the JVM crash.
I'm definitely lacking in this regard. I've got a pretty good handle on Java, Ruby, and ColdFusion. I've done a small amount of work in .NET and have been adding to that recently. I can certainly write a program that will crash - but can I write one to crash the virtual
machine (or CLR)?
I can relunctantly write small programs in C/C++, but I'm unlikely to have the patience to trace through a large program for fun. I might even still be able to figure out some assembly language if you gave me enough time. Certainly in these lower level items it's not hard to find a way to crash. It's
probably harder to avoid it, in fact.
In ColdFusion, I've crashed the CF Server by simply writing recursive templates (those that cfinclude themselves). (However, I don't know if that still works.) In Java and .NET, I wouldn't know where to start. What about crashing a browser with JavaScript?
So Chad mentions that you should know the internals of JVM and CLR. I should know how JavaScript works in the browser and not just how to getElementById(). With that in mind, these things are going on the to-learn list - the goal being to find a way to crash each of them.
Ideas?
Last modified on Sep 25, 2007 at 06:41 AM UTC - 5 hrs
Posted by Sam on Sep 12, 2007 at 07:11 AM UTC - 5 hrs
This morning ColdFusion got another mention on InfoQ, the news source for all things new and hip (or at least not normally dead and dying). The first time I saw it there was back in the summer.
I wonder if, with the new missing method handler allowing you to write even more dynamic code, and its ability to inter-operate so well with both Java and .NET, we might see a resurgence into more mainstream waters. I'd still like to see better cfscripting options available though (more than can be provided with scriptaGulous).
Posted by Sam on Aug 23, 2007 at 09:16 PM UTC - 5 hrs
The next few days in Houston are busy for programming technophiles. A couple of quick reminders:
BarCampHouston 2 is this Saturday, August 25, 2007 beginning at 9:00 AM at Houston Technology Center.
Update: I had the map wrong since it was wrong on the BarCampHouston wiki page. I hope no one went to the wrong place. Here is the correct one: HTC.
I also decided to take the day off and chill out instead of heading up there.
My apologies to anyone who had planned to say hello!
HouCFUG is hosting a ColdFusion 8 release party on Tuesday, August 28 from noon to 1:00 PM at Ziggy's Healthy Grill where they'll be giving away a licensed copy of CF 8.
Finally, Agile Houston is hosting a session with Robert Martin, object mentor on Tuesday as well. It's at 6:30 PM in PGH 563 on the University of Houston Campus.
I should be at both BarCamp and at Robert's presentation, but I'll be in class during HouCFUG's meeting.
Last modified on Aug 25, 2007 at 09:28 AM UTC - 5 hrs
Posted by Sam on Jul 19, 2007 at 10:26 AM UTC - 5 hrs
In the past you used to give and receive advice that keeping form state in a session was a valid way to approach the problem of forms that span several pages. It's no longer sound advice, and it hasn't been for a while.
Even before tabs became popular, a few of us were right-clicking links and opening-in-new-windows. It's a nice way to get more things done quicker: loading another page while waiting for the first one to load so that you are doing something all the time, rather than spending a significant amount of time waiting. It even works well in web applications - not just general surfing.
More...
But back then, and even until relatively recently when tabs were confined to the realm outside of Internet Explorer, the amount of people who used the approach in web applications was small. So small, in fact, we felt we could be lazy and hold what should have been repeated as hidden form fields within sessions instead.
Now Internet Explorer has tabs, and people are starting to use them. That changes things as people start to internalize the concept and use the productivity-boosting feature in ways that break our applications. Now, instead of presenting a list of customers and expecting our user to click one and edit the associated records until he's complete; our users are opening three or four customers (customerA through customerD) at a time in separate tabs. If you had stored form state in the session, when they think they are editing customerA, they will in fact be changing the record for customerD with a form that is pre-filled with values from customerA. Oops.
Luckily, the fix is relatively easy: just start storing the state in the form instead of the session. Of course, that's only "easy" if the path through your forms is linear. What about the case where many different forms can be traversed in just about any order, sometimes they appear based on what other forms said, and some are required while others can be skipped?
It's still easy if you've got automated tests that cover the possible scenarios. Just strip out the session and add the data to the forms until the tests pass. If you don't have tests, and you are not familiar enough with the different paths to create 100% coverage (or its been so long you forgot the paths), it's not looking good for you. Chances are, you don't have tests. This is a relic from the days before tabbed browsing, and who was doing automated testing then?
But, there is still one way out for you: inject the needed fields into your form after it's been crested but before it has been sent to the browser. I've not yet come across a situation in Rails or Javaland where I needed to do this, so I haven't investigated how to do it there (and Rails is new in the first place, so its unlikely it would be a problem in any application if you've thought to avoid the practice now that tabbed browsing is popular). But in ColdFusion, it is easy. Since Application.cfm is run before the request, you can check what page is being requested from there and intercept it if the page is one on which you need to do this processing. Wrap a cfinclude of that page in cfsavecontent tags, and now you have a string of what will be sent to the browser. Just find the spot you need to insert your data, insert it, and output the resultant string to the browser.
In my case it was especially easy because fortunately, we were only storing the id of the record in the session and I could be sure it needed to be in every form on the page. Thus, my code looked like this (in Application.cfm):
<cfif cgi.script_name is inMyListOfScriptsToIntercept>
<cfsavecontent variable = "toBeOutput">
<cfinclude template = "#cgi.script_name#">
</cfsavecontent>
<cfset toBeOutput = replaceNoCase(toBeOutput,"</form>","<input type="hidden" name="id" value="#form.id#" ></form>","all")>
</cfif>
If you can get at the data before it is output to the browser, this strategy works well. However, I don't like the magic nature of it when you'll be editing the individual files later and wondering why in the world it works. It's only a hack, so expect to learn the application well enough to test it and put the right fix in later. But, this works well as a temporary solution as you can be more sure it works than you can be sure about the flow of the application when it gets quite complex.
Posted by Sam on Jul 13, 2007 at 09:22 AM UTC - 5 hrs
Software Developer has an article, Ghosts in the Machine: 12 Coding Languages that Never Took Off that spotlights twelve of many thousands of languages that never made it big. Some had potential, others were doomed to begin with.
ColdFusion makes the list. So do Haskell, Delphi, and PowerBuilder.
I don't know that I disagree with the assessment based on the thought that "the vast majority of us all use the same dozen or so."
What do you think of the list? I was surprised to see those four languages included with some of the others, but at the same time you still have to ask, have they made it? And if they did make it, are they still there?
(via Venkat)
Posted by Sam on Jul 01, 2007 at 09:25 PM UTC - 5 hrs
Let me start out by saying the NFJS conference was incredible!
I went in with the intention of blogging as the sessions and days went on, but I was incredibly busy, and felt like my notes didn't do justice to the presentations. So I'm going to review the slides and flesh out my comments, and hopefully do a good job at letting you know what went down.
More...
For this post, I just wanted to give an overview of the symposium in general. As soon as I walked in and found my name badge, I knew these guys were a seriously professional conference, and they would pay attention to the small details to make our experience great.
Why? The badge was inside a nice, hard plastic (think something you might store a baseball card in, but bigger) and worn around a neck clip - the kind you used to see people wearing to hold their keys around their necks. But that wasn't the impressive part - the most impressive was that they put the schedule inside too, upside down on the back side, so all you had to do was flip over the badge and you could read the schedule and room assignments easily.
We also got a nice laptop backpack, a leather notebook where we could store pre-printed slides and code samples from the sessions we attended, as well as a CD with all the presentation material from every session.
Now, that's all useful for going back and having something to reference, but it's also great to have so you can flip through and see a good overview of sessions before you attend, so you know if it will be valuable for you.
The rooms were outstanding. We stayed in the Marriott Austin Airport South. I got the feeling the hotel staff greatly appreciated us being there - I got even better service from them than I normally expect from Marriott. Now, I'm not sure of the weekend rates there, but Thursday they wanted 200 dollars (US), and Sunday they wanted $189 (if I recall correctly). But NFJS was able to negotiate $99 rooms for us for Friday and Saturday. It was certainly nice to get such great service at such a bargain. Of course, it would have been even nicer if the hotel provided free wireless Internet access. NFJS provided it in the conference rooms, but that didn't reach all the way up to our rooms. I'm getting free wireless next door in another Marriott-owned hotel for over 100 dollars less than I would be paying at Marriott proper tonight!
The food was amazing as well. Just good all-around, and even included options for vegetarians that didn't include side-dishes only. I was fairly impressed by that. Also, I think the hotel bar is the cheapest bar in Austin. =)
Everything went extremely smooth from what I could tell. Jay Zimmerman and any other staff (including the hotel) did an excellent job of ensuring that. Oh yeah (read: "most importantly"), the speakers were awesome. They really knew how to entertain and be informative. But, for being a Java-based conference, it was interesting (exciting?) to see how many bashes Java got - and not just from the speakers. I'll probably blog some funny quotes later.
The first night most of the speakers made themselves available (aside from in-between sessions) at the hotel bar. I had dinner with a friend of mine (who I didn't know was going to be there) and Scott Davis, who is an amazingly charismatic guy. The second night a lot of people went to Bruce Tate's house. Someone later told me the group I was hanging out with in the dynamic languages BOF had been invited, but by that time we didn't feel like going to crash the party (not to mention a second-hand invite of "I heard" isn't that strong a thing to go on in the first place).
Also, one of the presenters had Sean Corfield's blog on his bookmarks toolbar, so that was exciting to see (I'll have to go through my notes to remember who).
In any case, I've got tons of sessions to blog about, some of which may contain useful information for you. I'm staying another night in Austin so I won't start tonight (other than this one), but keep a look out for more detailed posts about the actual content of the conference in the coming days.
PS: I'm also looking forward to catching up with all the other blogs and seeing how CFUnited went. But if I see one more post about the iPhone I'm going to have to duct-tape my head like a mummy gets wrapped to avoid exploding.
Last modified on Jul 01, 2007 at 09:30 PM UTC - 5 hrs
Posted by Sam on Jun 26, 2007 at 09:09 AM UTC - 5 hrs
I ran into a couple of stumbling blocks today using a particular company's XML request API, and it made me wonder about the restrictions we put in our software that have no apparent reason.
My plan was simple: create a struct/hash/associative array that matches the structure of the XML document, run it through a 10-line or so function that translates that to XML, and send the data to the service provider. Simple enough - my code doesn't even need to know the structure - the programmer using it would provide that, and the service provider doubles as the validator! My code was almost the perfect code. It did almost nothing, and certainly nothing more than it was meant or needed to do.
But alas, it was not meant to be. Instead, the service provider has a couple of restrictions:
More...
The first was regarding case (as in upper/lower). The XML elements needed to have the same case as described in the documentation (which contained at least one element that wasn't in the real specification anyway). That's fine - I can live with that. But it annoyed me a little that they saw fit to use camelCase. (this is only a machine, after all. I don't think it cares if it can easily read the differentWordsAllBunchedUpTogether.)
At least if they had chosen all upper or all lower I can easily switch the case of my own, but requiring camelCase made my code quite a bit nastier than it needed to be. Now, I have to provide a lookup mechanism for each element in the XML. Of course, if the language I was using was case sensitive, this wouldn't be a big deal at all. However, even though it is not sensitive to case, this is still not that bad of an issue.
But then restriction number two comes along: all elements must be sent in the order they appear in the specification. We're just passing data around here. The XML describes the data in the first place, so what use is ordering it? I understand that parent/child relationships must remain intact, but I cannot see how there could possibly be a good reason that the "firstName" element should come before the "lastName" element. (Can you? I'd love to know!) Why don't we just go to a flat file and forget about the angled brackets altogether?
I might as well have just hard-coded the XML and had a variable for every element/attribute!
Posted by Sam on Jun 21, 2007 at 02:55 PM UTC - 5 hrs
Today I was writing this simple function to recursively create XML based on a struct, and ran into
a minor gotcha:
More...
<cfcomponent>
<cfscript>
function structToXML(struct)
{
var result = "";
for (item in struct)
{
if(not isStruct(struct[item]))
result = result & "<#item#>#struct[item]#</#item#>";
else
result = result & "<#item#>" & structToXML(struct[item]) & "</#item#>";
}
return result;
}
</cfscript>
</cfcomponent>
Can you spot the problem? Its easy to miss: I forgot to var my loop variable, item. I normally remember to put most variables in the var scope, but I often forget to do so when variables are being defined in or by a tag, or in a loop. Things like item, index, and query names. So I spent some time trying to figure out why ColdFusion's stack didn't seem to be working properly: instead of closing the tag with the correct element name, it was closing it with the last used one on recursive calls.
I was about to ask if anyone could help me spot the flaw in my logic when it hit me - the var scope!
Posted by Sam on Jun 21, 2007 at 12:19 PM UTC - 5 hrs
I thought I had read this somewhere, about not being able to use " cf" as a prefix to a function, but when I defined all those functions in scriptaGulous with that prefix, and it let me, I thought maybe I made the whole thing up.
But then today I was having a look through the docs for cfscript, and I found this:
Caution: ... You cannot put a user-defined function whose name begins with any of these strings within this tag:
-
cf
-
cf_
-
_cf
-
coldfusion
-
coldfusion_
-
_coldfusion
However, so far it has let me with no problems. What shall be done?
Posted by Sam on Jun 21, 2007 at 09:11 AM UTC - 5 hrs
Bruce Eckel posted an article on how to use Flex with a Python back end over at Artima.
He said its possible to do the same thing "with any language that has support for creating an XML-RPC server."
In any case, I'm going to look into this in the future (I still haven't hopped onto the bandwagon). Anyone else played with it? What has been your experience?
Posted by Sam on Jun 18, 2007 at 02:50 PM UTC - 5 hrs
This one refers to the 40+ minute presentation by Obie Fernandez on Agile DSL Development in Ruby. (Is InfoQ not one of the greatest resources ever?)
You should really view the video for better details, but I'll give a little rundown of the talk here.
Obie starts out talking about how you should design the language first with the domain expert, constantly refining it until it is good - and only then should you worry about implementing it (this is about the same procedure you'd follow if you were building an expert system as well). That's where most of the Agility comes into play.
More...
Later, he moves on to describe four different types of design for your DSL. This was something I hadn't really thought about before, therefore it was the most interesting for me. Here are the four types:
- Instantiation: The DSL consists simply of methods on an object. This is not much different from normal programming. He says it is "DSLish," perhaps the way Blaine Buxton looks at it.
- Class Macros: DSL as methods on some ancestor class, and subclasses can then use those methods to tweak the behavior of themselves and their subclasses. This follows a declarative style of programming, and is the type of DSL followed by Ruby on Rails (and cfrails) if I understand him correctly.
- Top-level methods: Your application defines the DSL as a set of top-level methods, and then invokes
load with the path to your DSL script. When those methods are called in the configuration file, they modify some central (typically global) data, which your application uses to determine how it should execute. This is like scripting, and (again) if I understood correctly, this is the style my (almost working correctly) Partial Order Planner uses.
- Sandboxing (aka Contexts): Similar to the Instantiation style, but with more magic. Your DSL is defined as methods of some object, but that object is really just a "sandbox." Interaction with the object's methods modifies some state in the sandbox, which is then queried by the application. This is useful for processing user-maintained scripts kept in a database, and you can vary the behavior by changing the execution context.
Note: These are "almost" quotes from the slides/talk (with a couple of comments by myself), but I didn't want to keep rewinding and such, so they aren't exact. Therefore, I'm giving him credit for the good stuff, but I stake a claim on any mistakes made.
The talk uses Ruby as the implementation language for the example internal DSLs, but I think the four types mentioned above can be generalized. At the least, they are possible in ColdFusion - but with Java, I'm not so sure. In particular, I think you'd need mixin ability for the Top-level methods style of DSL.
Next, Obie catalogs some of the features of Ruby you see used quite often in crafting DSLs: Symbols (because they have less noise than strings), Blocks (for delayed evaluation of code), Modules (for cleaner separation of code), Splats (for parameter arrays), the different types of eval (for dynamic evaluation), and define_method and alias_method.
Finally, he winds up the presentation with a bit about BNL. I liked this part because I found Jay Fields' blog and his series of articles about BNL.
As always, comments, questions, and thoughts are appreciated. Flames - not so much.
Posted by Sam on Jun 15, 2007 at 09:18 PM UTC - 5 hrs
Sean Corfield responded in some depth to " Is Rails easy?", and explained what I wish I could have when I said (awkwardly, rereading it now) "I think my cat probably couldn't [code a Rails app]."
Sean makes it quite clear (as did Venkat's original post) that it isn't that using a framework, technology, or tool in general is easy or hard (although, you can certainly do things to make it easier or harder to use). In many cases, what it does for you is easy to begin with - in the case of Rails, it is stuff you do all the time that amounts to time-wasting, repetitive, boring busy-work. Rather, the right way to look at them is that they are tools that make you more productive, and it takes a while to learn to use them.
If you go into them thinking they are easy, you're likely to be disappointed and drop a tool that can really save you time before you learn to use it. And that could be tragic, if you value your time.
Posted by Sam on Jun 15, 2007 at 01:43 PM UTC - 5 hrs
I never thought to do this before today, but all of the sudden I had this idea that it would be nice to have a variety of utility methods for every object. I'm talking about things like respondsTo(methodName), to see if a component has a certain method public, or inspect() as an object oriented way to do getMetaData(object), and just things in general that all objects should be able to do to or for themselves.
Rather than creating a class which would be the equivalent of BaseClassToBeExtendedManuallyByAllOtherClasses, I decided I'd like to just replace component.cfc in the CF7 install. As it happened, the component.cfc that was there (CFusionMX7/wwwroot/WEB-INF/cftags) was a 0 byte file. I just added my code for respondsTo(methodName):
More...
<cfcomponent>
<cffunction name="respondsTo" access="public">
<cfargument name="methodName">
<cfset var result = false>
<cfif structKeyExists(this, methodName) and isCustomFunction(this[methodName])>
<cfset result = true>
</cfif>
<cfreturn result>
</cffunction>
</cfcomponent>
And it worked. No fuss or anything.
Is anyone else doing this? What sorts of object methods have you added? What would you find useful if you had the stomach to do this?
Posted by Sam on Jun 12, 2007 at 04:43 PM UTC - 5 hrs
It's been a couple of months, but cfrails has been "officially" updated (as in, I released a new zip, not just put new code into the repository).
We're a lot closer to 1.0 than one quarter of the way, so soon you should be seeing higher version number jumps. Anyway, here's what's been updated with this release:
More...
-
Added the automatic include of views/layouts/application_header.cfm and views/layouts/application_footer.cfm even when using view CFC (formerly, this only happened if you instructed it to and using .cfm templates for views). Also added auto-include of controller-specific templates simply by placing controllerName_header.cfm and controllerName_footer.cfm in views/layouts.
-
Brought the existing unit tests up to date (amazingly, with all the neglect there was only a couple of very minor problems, mostly due to changing paths).
-
Migrated request processing out of individual applications and into Dispatcher.cfc. This is a major improvement in the DRY arena, and allows me to make changes to the ways requests are processed without having to make them to every application that uses cfrails (Thanks to Dan Lancelot for prodding me to do this a couple of months back).
-
Added some minor Spry integration for form validation - this only works with required text fields at the moment.
-
Added the ability to use primary keys that aren't named "id" (although, still no composite PK support)
-
Changed behavior of a particular file to not catch errors (it was getting hard to debug)
-
Added an onchange attribute for form elements (can edit onchange per column without writing out the entire form)
-
cfrails now automatically creates blank controller, model, and view cfcs if you request one where it doesn't exist. This just makes it easier to develop, and may end up being a setting you turn on and off.
-
Added validations where you can specify a function to call and a message to display upon failure for validating forms (as opposed to simply using the built-in autovalidation based on DBMS metadata).
-
Added support for bigint, tinyint, and smalldatetime data types.
-
Added the ability to call a function when outputting a column in a list (though complete closures are not yet fully integrated)
So, there was a lot done as you can tell. And, MySQL support is coming soon, I promise!
Update: Oh yeah, I forgot what might be the most important part: New, more complete docs on cfrails are available (thanks to cfcdoc).
Last modified on Jun 12, 2007 at 04:47 PM UTC - 5 hrs
Posted by Sam on Jun 07, 2007 at 12:20 PM UTC - 5 hrs
Timothy Farrar brought up an issue about scriptaGulous that I thought was a good one (and one I've worried a bit about).
Should people start using the scriptaGulous library and Adobe decides to start naming functions after tags (i.e., cfQuery()), then a lot of code will break unless they start honoring your functions over theirs instead of throwing errors, as is currently the case.
He suggested using an underscore convention ( _cfQuery(), and Andrew Powell proposed a tagFunctionName() style convention.
But what are the odds Adobe would start naming functions cfTagName()? Any idea from the guys over there would be appreciated, as well as anyone else with any input. Would tagFunctionName() as opposed to cfFunctionName() (or tagQuery() over cfQuery()) work better? I'm partial to the underscore method if it is needed, but obviously I prefer just simple tagName() the most.
What are your thoughts?
Posted by Sam on Jun 04, 2007 at 09:23 AM UTC - 5 hrs
First I wanted to thank Andrew Powell for his gracious offer to help on this project.
Then, the update:
The ScriptaGulous RIAForge page (as does the SVN repository) has a zip with a file that actually compiles now, so you can start using it in your projects.
There are a couple of tags that were removed, such as cfloop and cfoutput, where it doesn't make sense to have them (unless we decide to use closures). Some tags, such as cfmail and cfhttp include extra parameters for their respective "params." The general guideline followed is that it is an array of structs - each struct is full of name/value pairs that represent the param tag's attributes and values you want to give those attributes. Please have a look at the hints, and if they aren't clear, feel free to ask us (or tell us what doesn't work) at the issue tracker at RIAForge or the scriptaGulous Google group.
More...
There has been some suggestion about packaging this into CFCs (and I like that idea). That will happen down the line (when someone has time to sort through and categorize the tags), but I see it as being an option to use instead of simply including the entire file. So basically, I'm thinking related functions/tags will be in separate libraries, and then the respective CFCs will include them, and a monster CFC might aggregate all the individual ones (not sure about the monster CFC, but I think a monster file would be good for include purposes if you choose that route).
I want to stress that I only checked that it compiles. I've got some non-CF work to do over the next couple of days, so if anyone has CF work to do and wants to use it, we'd appreciate any comments on what works, what doesn't, and what works but not how you might expect. Again, feel free to tell us these things using the issue tracker at RIAForge or the scriptaGulous Google group. I'll commit to responding and fixing things relatively quickly (most likely within the same day).
Posted by Sam on Jun 03, 2007 at 12:12 PM UTC - 5 hrs
Last night Thomas Enebo announced on Ruby Talk that JRuby 1.0 RC 3 has been released, and that it "will likely be our final release candidate before our 1.0 release."
I'm interested to deploy a web app trying Ruby on Rails with JRuby (or JRuby on Rails, perhaps), and also in experimenting with Sean Corfield's Scripting for CF 8 to run Ruby within ColdFusion.
Anyone else planning to do good things with JRuby?
Posted by Sam on May 30, 2007 at 01:55 PM UTC - 5 hrs
Today I put some code into the scriptaGulous repository at RIAForge. (scriptaGulous is a function library that intends to duplicate all the ColdFusion tags (where it makes sense) to make them usable in cfscript blocks).
Basically, I wrote a generator to read the taglib.cftld and generate some code for us to start with. I was going to generate some unit tests too, but I've got to move on to doing some other work.
Anyway, I'm sure plenty of the tags/functions actually do work, but when you cfinclude scriptagulous.cfm, you'll get attribute validation errors in some of the tags.
So now on to the next stage of development: making all the tags work. For that, we need your help! (if you want to use this sooner rather than later)
If you'd like to commit to contributing a tag or two (or more!), please join the scriptaGulous Google Group and record which tags you're working on so we don't duplicate our efforts.
Posted by Sam on May 29, 2007 at 01:46 PM UTC - 5 hrs
That's ScriptaGulous with a big-G (not C). The name is kind of cheesy but there's been a lot of talk lately about being able to have all the tags available for scripting in CF. This is something I've wanted personally for a while as well, and it has been on my to-do list for quite some time (ever since 11/22/2006 after a conversation with Ron Jeffries about how "agile" a tag-based language could be on the XP Yahoo! Group). It's been there for so long with no action on my part, I thought starting a project page at RIAForge would get me moving. It's certainly not going to be a particularly hard project to do, as most of it is repetitive busy-work, but I think it will be very useful.
More...
There are no files yet, but here's how I'd like to see it go:
- The code for the CF8 version will be easy since all tags can accept attributeCollection, we just send named parameters to the function and send arguments through attributeCollection
- I'm tentatively thinking all methods should be prefixed with "cf." Thus,
<cfabort> becomes cfabort(), and so on. This has two potential benefits: It makes memorization easy, since we already think in those terms for tags, and any potential naming conflicts with actual CF functions are gone (as far as I can think from the top of my head).
- It's going to take a while to do every tag. I don't want this to be "Sam's project" (though will eventually complete it even if no one contributes), but more of a community project. So if you've got time to do a tag with all the possible combination of attributes (so this will work in previous versions), I'm sure everyone would appreciate the effort. I'll try to commit to doing a tag every other day or so.
- I'm thinking it might be nice to put these into packages of related functions (based on the CF documentation), but I don't know how useful that would be.
- If you already know of something like this, please let me know and I'll gladly drop this one (or if you want to call it ScriptaGulous and host it on RIAForge perhaps we can get them to transfer project ownership).
So, what do you think? Your input and/or participation is/are most welcome!
Posted by Sam on May 29, 2007 at 07:14 AM UTC - 5 hrs
Often when we make a change to some code, if it is not properly designed, the result is that cascading changes need to be done throughout the application because bugs will ripple through the system. That's one of the ideas behind why we want to have low coupling between classes. We also have unit testing to combat the effects of this, but let's just suppose we haven't written any, and haven't used JUnit Factory to create regression tests.
Given that there is a lot of code out there that isn't quite perfect, wouldn't it be nice to have a tool that could analyze changes and where they would affect other code? I can imagine how such a tool might work, but I haven't heard of one before now (that I recall, anyway).
So the point of it all: I heard something about BMC and IBM teaming up on such a tool (my understanding is that BMC started it, and IBM later joined the project). I'm assuming it'd be in Java, but does anyone have information on this? Can anyone confirm or deny the story I heard?
Last modified on May 29, 2007 at 07:15 AM UTC - 5 hrs
Posted by Sam on May 28, 2007 at 04:41 PM UTC - 5 hrs
Ok, this is a well known issue (and I feel like a moron for it taking me so long to figure out), but I couldn't figure it out for the life of me (I was looking in the wrong spot the whole time - who would think CF Studio had anything to do with it?).
For the longest time, my FTP was not working, and today we finally narrowed it down to Allaire FTP & RDS. The only problem is, I couldn't set up an FTP site on it, and I couldn't uninstall it (in fact, it looked about half-uninstalled, as it remained under "My Computer" but the icon was dead and you couldn't do anything with it.
More...
We were looking at 3 different computers and trying to figure out why one used to work, one stopped working long ago, and one worked just fine. We were lucky enough to be doing a fresh install of Windows on one of the computers, and on the clean install FTP worked fine. After installing CF Studio 4.5 (he's old school) the FTP stopped working. Problem found.
To fix it, we just needed this technote from Adobe (which was hard to find because the searches were yielding links to House of Fusion --> Allaire.com --> Macromedia.com --> Page no longer exists on Adobe.com). Anyway, that's what you'll likely need to do to get your FTP working again if you're a CF developer and it stopped working.
Posted by Sam on May 20, 2007 at 08:04 AM UTC - 5 hrs
What if we had functions compile(String sourceCode) and runCompiled(BinaryData compiledCode)? What could you do with it? Could it act as a closure, and bring really dynamic coding to traditionally static languages, perhaps allowing dynamically named variables and functions to languages without them (and much more!)? Could we store our code in a database and mix and match chunks, building programs based on a SQL query?
What do you think? Useful or useless?
Posted by Sam on May 19, 2007 at 01:25 PM UTC - 5 hrs
Peter Bell's presentation on LightWire
generated some comments I found very interesting and thought provoking.
(Perhaps Peter is not simply into application generation, but comment generation as well.)
The one I find most interesting is brought up by several people whose opinions I value -
Joe Rinehart, Sean Corfield,
Jared Rypka-Hauer, and others during and after the presentation.
That is: what is the distinction between code and data, and specifically, is XML code or data
(assuming there is a difference)?
More...
The first item where I see a distinction that needs to be made is on, "what do we mean when we are talking about
XML?" I see two types - XML the paradigm where you use tags to describe data, and the XML you write - as in,
the concrete tags you put into a file (like, "see that XML?"). We're talking about XML you've written, not
the abstract notion of XML.
The second idea: what is code? What is data? Sean Corfield offers what I would consider to be a concice,
and mostly correct definition: "Code executes, non-code (data) does not execute." To make it correct (rather
than partially so), he adds that (especially in Lisp) code can be data, but data is not code. You see this
code-as-data any time you are using closures or passing code around as data. But taking it a bit further -
your source code is always just data to be passed to a compiler or interpreter, which figures out what the
code means, and does what it has been told to do.
So is XML code? Certainly we see it can be: ColdFusion, MXML, and others are languages where your
source code is written (largely) in XML. But what about the broader issue of having a programmatic
configuration file versus a "data-only" config file?
Is the data in the config file executable? It depends on the purpose behind the data. In the case of data
like
<person>
<name>
Bill
</name>
<height>
4'2"
</height>
</person>
I think (assuming there is nothing strange going on) that it is clearly data. Without knowing anything about the
back end, it seems like we're just creating a data structure. But In the case of
DI (and many others uses for config files),
I see it as giving a command to the DI framework to configure a new bean. In essence, as Peter notes,
we've just substituted one concrete syntax for another.
In the case of XML, we're writing (or using)
a parser to send data to an intepreter we've written that figures out what "real" commands to run based on
what the programmer wrote in the configuration file. We've just created a higher level language than we had before
- it is doing the same thing any other non-machine code language does (and you might even argue
about the machine code comment). In the configuration case,
often it is a DSL (in the DI case specifically, used to describe which objects depend on which other
objects and load them for us).
While we don't often have control structures, there is nothing stopping us from implementing them,
and as Peter also notes, just because a language is not
Turing complete), doesn't mean it is not
a programming language. In the end, I see it as code.
Both approaches are known to have their benefits and drawbacks, and choosing one over the other is largely a matter
of personal taste, size and scope of problem, and problem/solution domain. For me, in the worlds of
JIT compiling and interpreted langages, the programmatic way
of doing things tends to win out - especially with large configurations because I prefer to have
the power of control structures to help me do my job (without having to implement them myself).
On the other hand, going the hard-coded XML route is especially popular in the compiled world, if not
for any other reason than you can change configurations without recompiling your application.
I don't make a distinction between the two on terms of XML is data, while programming (or using an in-language DSL)
in your general-purpose language is code. To me, they are both code, and if either is done incorrectly it will
blow-up your program.
Finally, I'm not sure what value we gain from seeing that code is data (and in many cases config data is code),
other than perhaps a new way of looking at problems which might lead us to find better solutions.
But that isn't provided by the distinction itself, just the fact that we saw it.
Comments, thoughts, questions, and requests for clarifications are welcome and appreciated.
Posted by Sam on May 16, 2007 at 07:41 AM UTC - 5 hrs
I've been thinking about it lately, and I cant't seem to think of any (in my admittedly small set of knowledge) other language that allows you to be dynamic by leaving out language constructs (such as the type and returntype attributes of parameters and functions), but that, when you do decide to use them, the language acts statically (and is CF even acting statically when it checks the arguments, or is it acting strongly?).
For all you supermultilingual coders out there: do you know of any other language which is dynamic, but allows you to instruct it to become static like CF does? If there are others, is CF the first?
More...
Is it good to be such a hybrid? I would think it keeps the staticians and dynamos both happy, but I'm not sure if it can (or even should) be quantified as good/bad. Do we want it to continue down the path that leads to having complete static options available (for instance, you can type your variables if you want to, and it will provide benefits of static languages, but leaving them off keeps it dynamic)?
What if you could write Java code as: name = "Johnny"; name=3; (and switch back to having it statically typed in the same class)? What would it look like to do operations on a dyanmically declared variable when a static one is expected? I suppose this has more to do with strong vs. weak typing, really, but would the mere existence of allowing dynamic typing mean the compiler can no longer check any method call for correct argument types? Would the fact that you can declare variables without a type make statiphiles cringe (because they may intend to use the typing and leave it off, and then the compiler won't tell them)?
Does allowing any typing to be done dynamically mean all checks must be performed at runtime? If so, what is the point to adding static features into CF (to make it throw an error perhaps 2 lines prior to where it would have thrown it - at the beginning of the method rather than where the argument is used)?
Does it even make sense to classify a language as a static/dynamic hybrid? (And can I ask any more questions?)
Last modified on May 16, 2007 at 07:42 AM UTC - 5 hrs
Posted by Sam on May 15, 2007 at 01:07 PM UTC - 5 hrs
It might be petty, but those two three-letter words really get to me. They clutter my code almost as much as semicolons, Object obj = new Object() // assign a new object to the object called "obj" which is is of type Object, and angle brackets. I'm want to do something like newCodebase=rereplace(entireCodebase,"[gs]et","","all").
What if we had a new idiom where calling the method without arguments would cause it to return a value (the get), while calling it with an argument would run the setter? Its easy enough to do. What do you think, am I off my head?
Posted by Sam on May 07, 2007 at 09:20 AM UTC - 5 hrs
As I'm getting into little details about the generation cfrails is doing, I had a couple of questions I thought the community could provide some insight on better than my own experiences regarding lists.
One of the great things about generating this stuff is that you can have for free all the bells and whistles that used to take a long time to do. In particular, you can have sorting on columns automatically generated, as well as pagination.
So question 1 is: given that you can have sorting for free, would you rather automatically sort on every column, and specify any columns you did not want to sort on, or would you prefer to not have sorting placed automatically, but just specify which columns to sort on?
And question 2: Given that more and more people are on broadband, is it time to up the 10-record limit on results? I find it annoying to have to reload all the time, and if given the option, I normally up the results/page to 50 or 100. What do you think, would you make the default number of results/page higher (and how high would you take it?), or would you cater to the lowest common denominator?
Posted by Sam on May 02, 2007 at 07:24 AM UTC - 5 hrs
As expected, Ben was a great speaker and gave a good presentation. He said we were quiet, and someone said its because we've read all the blogs about it before he came. He was running a little late, due to some fiasco in Austin where the city commandeered the meeting room and they had to change the venue at the last minute.
Unfortunately, Dave's post about the presentation did act as sort of a spoiler, and Ben didn't give us any scoops (that I noticed). Anyway, that's why I don't have much to add. =)
One important thing though: so far, they have yet to get an error on CF8 running old CF6/7 code (some public facing parts of adobe.com are running on CF8 now, he said). Of course, this is what you would expect, but I remember the nightmare we had moving from 5 to 6 - it wasn't pretty.
Seeing the presentation live did give some perspective to Dave's notes, and it's worth going even without learning anything new. I also wanted to thank the HouCFUG guys for putting all of that together- you guys did a great job (and it was good to meet you!). Finally, congrats to the winners of the raffle prizes. I guess I'm going to have to break out the wallet when 8 comes out. I think I'd buy it just for the inline arrays and structs.
Posted by Sam on May 01, 2007 at 09:51 AM UTC - 5 hrs
Thanks to Dave Shuck's post about Ben Forta's presentation at Dallas/Fort Worth CFUG, I now know a lot more about CF8 than I did before. He has a long list of new features, but the two I'm most excited about are inline arrays and structs! Dave showed a couple of examples:
<cfset MyArray = ["CFIMAGE","CFWINDOW","CFPOD","CFMENU"] />
<cfset MyStruct = {Name="Dave",FavoriteLanguage="CFML",Cool=true} />
Now, if we could just get closures ... =)
Last modified on May 01, 2007 at 09:52 AM UTC - 5 hrs
Posted by Sam on May 01, 2007 at 09:36 AM UTC - 5 hrs
There are a couple of drawbacks (or some incompleteness) to scaffolding being truly useful. The one that seems to be most often cited is that normally (at least in Ruby on Rails, which seems to have popularized it) it looks like crap (it is only scaffolding though). Of course, most who make that complaint also recognize that it is only a starting point from which you should build.
Django has been generating (what I feel is) production-quality "admin" scaffolding since I first heard about it. It looks clean and professional. Compare that to the bare-bones you get by default in Rails, and you're left wondering, "why didn't they do that?" Well, as it happens, it has been done. In particular, there are at least 4 such products for use with Rails: Rails AutoAdmin (which professes to be "heavily inspired by the Django administration system"), ActiveScaffold (which is just entering RC2 status), Hobo, and Streamlined (whose site is down for me at the moment).
More...
My interest lies in the second complaint though - that writing it to a live file (rather than dynamically figuring it out - which I've been calling "synthesis," as opposed to generation) means you can't get the benefits of upgrades to the scaffolding engine (and, it is not following DRY!). But, if you just use the default scaffolding, what happens if it doesn't come out just right (assuming you've even passed the notUgly test in the first place)? Well, thats a big part of what I'm trying to solve with cfrails, by using a DSL that provides tweakability to the scaffolding, without requiring you to write to a file (though, if the tweaks won't work, you are always welcome to go to a file with HTML and the like). The interesting part for me about the RoR plugins above, therefore, is that it appears (I haven't checked them out yet) that at least Hobo contains a DSL, called DRYML, to help along those lines.
I'll be having a closer look at those when free time becomes a bit less scarce. What do you think? Is it the holy grail, or can there be very useful
"scaffolding"?
|