|
LATEST POSTS
Sunday, July 16, 2006
I've been following the Igloo Coder's series on Code Naming Conventions. Think I'm past the point where I can change my naming conventions (or at least to do so consistently) but the articles have a good layout with a summary of the main schools of thought followed by the Inuit's intuitions.
The series fits in with the idea of Conscientious Coding I mentioned in an earlier article so I'll throw in some of my own comments. My own naming conventions are moot but for the record, I'm not a fan of Hungarian notation. Part of my philosophy is that the code has to “look” good and throwing str's and int's at the beginning of variable names takes away from the aesthetics. Not very scientific, I know, but it's in keeping with the Conscientious Coding mantra: Be nice to the next person looking at your code. You could argue that giving clues to your variable's intent is being nice but I would argue that a decent developer will have no issues deciphering what type of variable it is from the code itself. Hard to misinterpret errorMessage = “An error occurred: ” + exception.Message; and where there is ambiguity, maybe some comments.
Having said that, the Visual Studio IDE tends to use Hungarian Notation for the controls you drop on a page in the designer but one of the corollaries of Conscientious Coding is: if extra work doesn't add any value, don't do it. And prefixing the control names with their type is a nice way of differentiating controls from your own variables. (On a side note: I'm making these rules up as I go but really, doesn't everybody?)
Also, the Igloo Coder doesn't mention this but I use a combination of the two methods he mentions for module variable naming. That is, I prefix them with m_. The reason is that I don't like using just m because it looks hideous when you use camelCasing (which I usually use) as the Iceman mentions. But, and again this has more to do with aesthetics, I don't like looking at words that begin with an underscore. There's something unnatural about it. Maybe it's my grammatically anal nature (remind me to rant someday on why I'm forced to use the American spelling of “color“ in my CSS). But I recognize the value of differentiating module level variables.
Regardless, I don't feel strongly enough about any naming convention to defend it to the death so if you don't agree with me, I will lose no sleep trying to come up with ways to convince you. As it is, I'll switch from camelCasing to PascalCasing depending on the lunar cycle. Not within a project, mind you, but every time I start my own little side project, I'll think about it and justify one or the other and start using. Halfway through, I'll wonder why which might explain why none of my side projects are finished.
But something is often overlooked in discussions about naming conventions: you rarely go to a place that is starting from scratch. Especially as a consultant. Chances are, the company you're with has a bunch of applications already. If you're lucky, they have naming conventions already and if you're really lucky, they're being followed. More often, the standards are at the whim of whatever developer worked on it. And if more than one developer was involved, you can usually tell which sections were worked on by different ones (and I don't mean because they've left comments with their names attached).
In this case, the conscientious coder will follow the standards already in place in the organization. If there are, it doesn't matter in the least what your preference is. As a consultant, your goal is to create an application that some other poor sap at the organization is going to have to maintain so you'd better make it look like every other application in that organization. They use Hungarian Notation for their properties, you use Hungarian Notation for your properties. They name their functions based on characters in Charles Dickens' books, you'd better get a copy of Great Expectations and start highlighting. (Of course, you are well within your rights to make suggestions for changing the standards. In my experience, Stephen King's books are usually a more appropriate source for function names. There's a sense of freedom when you “Cujo“ an object.)
If there are no formal ones, this is tough because you have a decision to make. There may be some loose standards emerging if you've somehow managed to retain the same group of people for more than six months. Your goal should always be to make the application maintainable by the existing developer base so if there are some obvious standards being followed, try to stick with them. If they are unreasonably restrictive, you may be justified in following a different one but do so very carefully. You can never underestimate the power of consistency.
If the standards are all over the place from application to application, then you have even more latitude but even here, I think it's best to try not to introduce new standards unless you are making a formal recommendation for naming standards throughout the organization. Again, the goal is to make the application look like it was written within the organization. (By that I mean the naming standards, not the logic, so stop rolling your eyes and saying, “Yeah right”.) If you can do so while still making the application clean and easy to read, and more importantly, if you can justify it, well, you're a better consultant than I am.
Sunday, July 16, 2006
I've been reading, listening to, and watching articles, podcasts, and webcasts on Test-Driven Development as well as talking to colleagues who are in the same boat as I am in that we are kind of excited about it but are still learning. I'm going to waffle a bit on my ultimate opinion.
At the moment, I don't buy it. At least not the whole thing. There are bits and pieces I like. Unit tests, for example. And continuous integration (which may or may not be part of the methodology; haven't quite worked that out yet). But on the whole, I don't see the benefits of writing tests first. Or rather, I don't think there are enough benefits to TDD to outweigh the cost of the extra code you have to write. And make no mistake, you have to write a lot of code.
Part of my disillusionment, I think, has to do with the examples I've seen which range from rudimentary to impractically simple. I watched both episodes of Jean-Paul Boodhoo's dnrTV episode on the subject. Two hours of presentation to bind a combobox to to a list of customers from the Northwind database. And if I recall correctly, he added a total of six projects to his already-populated solution to get it to work. This is code I can “write” in about seven minutes in Visual Studio 2005. I say “write“ in quotes because these days, you don't even need to write code to do this.
There's an argument that the code I write won't be testable. My counter to that is: so what? I'm binding a dropdown to a datasource. It's not rocket science. And once it's working, in what universe is this code ever going to break? This is basic functionality practically built-in to the framework. Why am I even writing code to bind this combobox, let alone code to test it?
To be fair, I'm railing against the example, rather than the methodology. And I will admit that I probably don't understand the benefits as well as I could. For some more complicated piece of logic, I can see how someone would justify writing the tests first. But even then, as a wise man pointed out, you're losing some features offered by the IDE. Like Intellisense. I don't program well without Intellisense.
And I should point out that there is lots to like about Boodhoo's dnrTV episode. The Model-View-Presenter pattern, for instance (which I'm hoping to see more of in his follow up episode). The way he lays out projects made a lot of sense to me. And the overall architecture of the project looked interesting enough that I wish his code was made available. The man clearly knows his stuff.
I've also heard the argument that TDD forces you to write unit tests which are oh-so-often dropped due to time constraints. That's very true. But let's assume we are given three months to do a project that we know will take four with the unit tests.... I'm trying to dance around how to word the fact that I would rather hand in fully functional but untested code rather than fully tested but not fully functional code because it would be too easy for that argument to be attacked. But sometimes there are certain time restrictions that just can't be avoided. Yes, you should try to convince the client of the benefits and yes, you should always unit test and yes, you should always brush your teeth three times a day. Well, the sky is blue in my world and sometimes my boyish good-looks and easy charm aren't enough to convince the client that I'm going to need another month to get all the features done.
Again, I'm not against unit tests. In fact, I'm all for them. They should be written often, they should be run often. And right now, I don't believe they need to be written for absolutely every piece of code that you write. There are certain places where you just have to trust the fact that a certain function has run properly for the last ten years and will probably continue to do so for the next ten. In the end, I think TDD was borne of some good ideas but maybe got sidetracked because it got thrust into a formal methodology.
So despite my early enthusiasm, I'm going to keep TDD in the back of my mind for now. At this point, I think I know enough that if I tried it on my own, I would get frustrated very easily. And let me make my ignorance clear: I'm going solely on what I've read and seen, not on actual practice. I don't want to shortchange the idea without giving it a decent runthrough. So until I'm on a real business project with someone who knows and loves it, consider me firmly on the fence.
Until then, I've become an advocate of a new practice proposed by the aforementioned wise man: Conscientious Coding. In this methodology, there is no strict, religious adherence to any one programming dogma. There is only one basic tenet: someone else is going to have to look at your s**t. Be nice to them.
Sunday, July 09, 2006
Deep breaths....deeeeeeep breaths....
That's my mantra these days while trying out this extender thing. You can probably tell from the title but I've decided to postpone/abandon my extender for now so that I can get back to the actual application I want to build.
An initial draft of it is up and running. The basics are there but don't expect anything from the advanced search.
Atlasers will notice that it is entirely ASP.NET driven (except for some of the sample extenders). I decided to add an UpdatePanel to the top GridView (the search results one) and make it dependent on the click event for the search button. The results came back fine and without a postback, as expected. Then I clicked on a column header to sort the list:

You're probably thinking the same thing I did: Line 257646674?!?!?
Let's put some commas in there: 257,646,674. That's right. There is a javascript error somewhere around the two hundred and fifty-seven THOUSAND line mark in some javascript. When I clicked yes, I got a nice debug version of my ASPX page but not the javascript itself. Which is just as well. I wouldn't know what to do even if I could find the offending line.
Not sure why Atlas has decided to punish me in so odd a fashion. UpdatePanels I thought were fairly innocuous. You wrap some text around a GridView and everything just magically works. It's identical to how I did it in my demo but I guess something is different somewhere. I don't want to get disillusioned with Atlas but this whole ordeal has been very humbling for one who considered himself at least an above average developer. Guess I'll have to settle for best hooch at last year's Hillbilly Wine Festy-val.
Anyway, I upgraded to the June CTP but wasn't expecting much. I did work in a help desk after all and know the benefits of telling someone to upgrade and call you back right before you go to lunch. It helped a bit. Now the error is in line 94,576,125.
In the meantime, my blog hasn't been very informative or entertaining lately so to remedy that, I give you this little number that's fun in a geeky kind of way. Created by someone in my top three list of people whom I wish had a technical blog (not that I don't enjoy your other shenanigans, big guy).
Friday, July 07, 2006
The attached application is designed to demonstrate AJAX and Atlas techniques. It's an annotated version of the one I presented at the Calgary Code Camp. It includes a sample ASP.NET application, a non-Atlasized AJAX version of the same application, and an Atlas version that uses UpdatePanels. It also includes a half-finished version that demonstrates declarative scripting and another one that shows how you can call web services from Javascript as well as how you can use the sample extender providers that come with the Atlas Control Toolkit.
So download the code and start wading through if you like. It's heavily commented but contact me if you have questions.
MusicPlayer.zip (1.2Mb)
Monday, July 03, 2006
Changing the title of the series slightly so as not to confuse Googlers who think that I might actually get a working extender out of this. So to clarify, I'm trying to build an extender and reporting back on my trials and tribulations.
So on the advice of Ted Glaza, I tried creating my own Sys.UI.Control within my code. I added the following line to the initialize call for my extender:
_collapsePanel = new Sys.UI.Control( _collapsePanelID );
Re-compile because even though this is javascript, you need to do this with Atlas. Probably something to do with registering it with ScriptManager but I'm not one to dwell on reasons for implementation details, just on implementation details themselves. Load the page and voila!

Again this highlights some issues that still remain when working with Atlas. If I choose to debug, I get a page that's too much trouble to screen capture at a decent size and include here. It's a line somewhere in the Atlas javascript that calls the initialize function on my extender. It's clearly the new line causing the error but the debugger doesn't delve deep enough for me to see where.
There's more. When I try to leave the page, I also get the following:

No idea what to make of that. As you probably suspect, there is no mention of displayMode in any of my code. So how do I track this down? And if I do track this down and it's in Atlas code where I think it is, what do I do about it?
To be clear, I know the bug is in my code, not in the Atlas code. What I mean by that last question is: If I can even find which line is causing the error, what do I do to fix it?
Stay tuned, kiddies!
Saturday, July 01, 2006
June CTP of Atlas is out as of yesterday. Biggest change everyone is talking about is the ability to add UpdatePanels dynamically, something Nikhil Kothari explains a lot better than I ever could. Not sure I've wrapped my head around the whole “control must be in the same naming container as the UpdatePanel” concept for ControlEventTriggers. Will have to try it out.
I have mixed feelings about this update. I'm glad their improving but I'm having a hard time keeping up with the current Atlas implementation and I fear I'm going to fall even further behind people like Garbin. *$%^& hard trying to stay on the cutting edge.
Thursday, June 29, 2006
Another post saying that I haven't done anything useful recently. Have brought in a paycheque, yes, but all the interesting stuff happens extracurricularly in my life (unless you really want to know the inner workings of Open Text Livelink) and there hasn't been much extracurricular time. Plenty of excuses: just moved back home after six-months away, recent trip to London, my daughter has been doing her impression of Keith Moon's death the last two days while I'm being a single dad for the week.
So I've been trying to get organized again which at the moment means my workspace is wallpapered with sticky notes. Really need to try out some life hacks. In the meantime, thought I'd outline, for posterity, some of the major and semi-major projects that I've been neglecting:
- Full version of the app I demoed at Calgary Code Camp. Gonna be sweet. I have about 2500 songs to search through.
- Update the app I whipped up one weekend six years ago for my brothers' land surveying company. Interestingly enough, it uses some of the AJAX techniques I mentioned in my demo. Not so interestingly, they've become somewhat demanding for an update with new features.
- Build a small accounting system to manage a friend's financial statements. The current accounting systems all suffer from one basic flaw, they handle at most two currencies. My friend has accounts in six and Excel just isn't cutting it anymore.
- Build a user group in the Bahamas. And sweet Jesus, the Igloo Coder's series on just that could NOT have come at a better time. I have to make some minor adjustments to allow for a caribbean mentality but that series is pure gold baby.
- Finish the articles on search applications I start so many moons ago. I'm so bad at following through.
- Move my blog to something other than .Text (probably dasBlog 'cause I want to be Scott Hanselman).
These are the major unpaid items. Doesn't include my current full-time job. Or the side contract I have. Or my new consulting business I need to start developing. Or catching up on JP Boodhoo's blog. (Seriously, I know how many kids he has. Where does the guy find the time.) Or other little things like why the IIS service keeps throwing errors and restarting on my server since I installed .NET 2.0.
Anyway, I know I'm not alone in having a list of neglected side projects. So fess up. What's your list?
Wednesday, June 28, 2006
I love demonstrating the UpdatePanel to people on a paged, sortable GridView. Especially people who have tried to do the same thing manually. It's a very cool demo.
But I want to say a little something on the problem Atlas doesn't solve for this demo. Let's say you have a page that loads a grid on startup. Then you move ahead a couple of pages and sort the grid on a different field. It's pretty easy to configure the GridView for this so that it shows the proper results. That is, it will sort the results first, then render the third page.
Now let's say the user refreshes the page. If it's a normal ASP.NET page, you'll get the normal warning saying you are about to repost the data you submitted. It sucks that users have had to get used to this little quirk since in reality, what have you really submitted? But c'est la web and until some kid gets fed up enough to actually build Web 2.0 in his basement, we'll have to live with this.
Take the same example with an UpdatePanel. Page ahead two and resort. Again the results are displayed correctly and we have the benefit of not having to regenerate the entire page. But press refresh in this case and the page returns to its original state. I.E. Unsorted on page one. (You can see the effects of this in the sample app I did for Calgary Code Camp; it doesn't page but it sorts.)
In some respects, this is better in that you don't see the annoying popup (or the Page Expired message if you click Cancel). For the most part, though, it's more confusing for general users who would certainly wonder what happened to their results.
The reason this is a problem is familiar to anyone who has done AJAX work. On the one hand, you don't reload the entire page but on the other hand, but as a consequence, the browser hasn't registered that any page change has taken place while you've been merrily clicking away. When you reload a page in the browser, it will load the page as it was first rendered.
Incidentally, this also applies if you do any sort of DHTML work, too. For example, if you add rows to a table on the client, this will get lost when you refresh.
And at its core, Atlas is still AJAX. It doesn't solve any of the architectural problems that go along with AJAX, just some of the developmental ones (while introducing a couple of new ones). If you were to build this same page five years ago using AJAX, you would have the same problem. It's the nature of HTTP.
Note that you can get around this refresh problem with AJAX/Atlas through inventive/bastardized use of cookies. You store data about the grid's current state in a cookie and in the onload event for the body, do some mucking around with DHTML. I imagine this is pretty tough with AJAX because you'll need to know very intimately what the HTML looks like generated by ASP.NET.
But here's another question: what if the user wants to bookmark that exact page number and sort? A cookie won't work in this case. Or rather it might work if the user only ever wants to bookmark one page. Try to bookmark page four as well as page three and you're out of luck. With both AJAX and ASP.NET.
If you do need to support bookmarkable pages (or similarly, the ability to e-mail a page to a friend), the ultimate solution is pretty low tech: use an HTTP GET. Remember HTTP GETs? From the old ASP days? It seems so long, long ago in a galaxy far, far away.
Stick with QueryString parameters to figure out what page you're on and how you're sorting and in what direction. Google does it. Yahoo does it. MSN does it. All search engines do it. They have to. C'est la web. I know, I know. It's not as fun building apps like this in ASP.NET because you pretty much circumvent the entire event architecture they so desperately want you to use. And Request.QueryString seems so twentieth century.
But such is the sacrifice we make for our beloved users.
Wednesday, June 28, 2006
Blogged this entry from the airport recently so I could pretend I was too cool to waste precious minutes waiting for my flight to leave. My facade is dampened somewhat by the fact that I was in the Miami airport whose main culinary highlight is the fact that the Skittles in the kiosks have the new Limited Edition strawberry ice cream flavour. Donde es los wireless, MIA? Perhaps the bird's nest in the loft of the A terminal where I awaited my flight interfered with the signal somehow. Poor little fella. All he did was stare out the window wondering, "I know I got myself into this mess. How the &$*% am I going to get out of it?" The parallels to my own career are a little frightening.
A small update on my extender which is not forgotten but not progressing thanks to my recent trip to London (and if you're ever going to London, I'd suggest doing so during the World Cup). Got a couple of good suggestions from Ted Glaza on the Atlas forums. First was that my internal control should derive from Sys.UI.Control which is good to know.
The second is that a similar control is already in the works in the new toolkit. It's an accordion control and it's still in their prototype project. I didn't quite get it to work completely but enough to see how it was going to do it. I just glanced at the implementation briefly and I think I'll continue on the path I'm on. I think it does what I want but what I didn't like was that each panel had to be implemented within the accordion control itself. What I'd rather do is specify my panels in the HTML, then elsewhere, define an extender that references. This is how the other controls work and this is how I expect an extender to work. That's why it's called an extender.
Which is not to slight the accordion control, which is more robust in that it allows more than one panel to be defined instead of hardwiring it to two like I'm doing.
Anyway, haven't done any actual coding (hillbilly or otherwise) since I last pontificated. Stay tuned.
Wednesday, June 14, 2006
Phew! This Atlas Extender thing isn't as easy as I thought it would be. Have spent a good part of the day trying to build my dream toggle-able panels and am no further than I was yesterday. Gained a bit of knowledge though and yes, it is in fact a dangerous thing.
In my original attempt, I essentially duplicated the existing CollapsiblePanel extender so I'd have something to start from. My next task was to remove properties I didn't plan to implement: ExpandControlID, ExpandDirection, AutoCollapse and AutoExpand. ExpandControlID because I'm forcing the control to be a toggle. AutoCollapse and AutoExpand because they don't really make sense in this context. ExpandDirection because, frankly, I have enough to worry about.
Removing these properties from both the Properties.cs file and the Behavior.js file was pretty painless. I even got a little cocky and changed the animation parameters to make it a little smoother.
Then came the part when I tried to implement the second panel.
Every extender automatically implements a TargetControlID property because, well, we're extending an existing control so we should know which one it is. I decided to use this property to represent the panel that is initially visible and I added a second property, CollapsePanelID, to represent the sister panel that is collapsed on startup.
The actual javascript for the CollapsiblePanel that does the main work is fairly simple. When initialised, it creates an animation object that is tied to the target control:
_animation = new AtlasControlToolkit.NumberAnimination(); _animation.set_property("TargetHeight"); _animation.set_duration(.25); _animation.set_fps(10); _animation.set_target(this); _animation.ended.add(Function.createDelegate(this, this._onAnimateComplete));
In the click event for the control that collapses the panel, it sets the start value for the animation to the panel's current size and sets the end value to its collapsed size (which is usually zero but doesn't have to be). Then it plays the animation.
_animation.stop(); _animation.set_startValue(this._getTargetSize()); _animation.set_endValue(this._getCollapsedSize()); _animation.play();
The click event for the control that expands the panel is almost identical but sets the end value to the panel's expanded size.
My problem comes in the _animation.set_target line. What I'd really like to do is set up an animation for the second panel and execute it at the same time as the first one. This, to me, would be the easiest implementation because the Atlas framework does all the work and it's consistent with the rest of the implementation.
But it looks like set_target takes an object and I don't know what kind of object to pass in. I don't want to create a whole separate instance of my object to pass in because then I'll have to manage potential stack issues (since ToggledPanel objects will keep creating more ToggledPanel objects). But I'm also not familiar enough with the object model to know what else I could pass in. I tried Sys.UI.Panel but there is no such object as far as I know. And the documentation for animation is non-existent except for the actual code itself.
As I type this, an idea is forming, though. I'm wondering if I can create a second version of the ToggledPanel object. One that will still expand and collapse but that is designed to be controlled by another object. Stay tuned...
P.S. One thing I'm having trouble getting used to. When you modify the .js file for your extender, you need to recompile in order for the changes to be reflected. Been developin' these har web pages a long time and I ain't ne'er hadun ta compile ma javascript befur. And iffun I hafta compil'em, I reckon there should be some sorta benufit to it, see. Like compile time checkin'.
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent
my employer's view in any way.
Copyright © 2010 Kyle Baley. All rights reserved.
|
|
|
CATEGORIES
|
|
LATEST POSTS
POPULAR POSTS
|
|
ARCHIVE
| March, 2010 (1) |
| February, 2010 (8) |
| January, 2010 (2) |
| December, 2009 (3) |
| November, 2009 (2) |
| September, 2009 (5) |
| August, 2009 (4) |
| July, 2009 (2) |
| June, 2009 (5) |
| May, 2009 (6) |
| April, 2009 (5) |
| March, 2009 (6) |
| February, 2009 (2) |
| January, 2009 (6) |
| December, 2008 (5) |
| November, 2008 (2) |
| October, 2008 (5) |
| September, 2008 (9) |
| August, 2008 (5) |
| July, 2008 (7) |
| June, 2008 (6) |
| May, 2008 (11) |
| April, 2008 (13) |
| March, 2008 (13) |
| February, 2008 (12) |
| January, 2008 (19) |
| December, 2007 (16) |
| November, 2007 (8) |
| October, 2007 (23) |
| September, 2007 (15) |
| August, 2007 (8) |
| July, 2007 (6) |
| June, 2007 (11) |
| May, 2007 (19) |
| April, 2007 (14) |
| March, 2007 (3) |
| February, 2007 (4) |
| January, 2007 (7) |
| December, 2006 (5) |
| November, 2006 (9) |
| October, 2006 (11) |
| September, 2006 (14) |
| August, 2006 (11) |
| July, 2006 (15) |
| June, 2006 (8) |
| May, 2006 (10) |
| April, 2006 (12) |
| March, 2006 (3) |
| February, 2006 (7) |
|
|
|