CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Brendan Tompkins [MVP]

Blog First. Ask Questions Later.

March 2005 - Posts

  • Digging (into) the Community Server Source...

    I've been playing around a bit with the source code of Community Server.  I hinted last week that I really like the way the application was built... Well, today was the second time that I've gone digging in the source code to try to do something, and it was simple to do.

    I added the comment count to our main feed page, so you can see the number of comments, and link directly to the comments on the given blogs.  This took me all of 10 minutes to do, mainly because what I needed to do was anticipated in some respects by the Community Server team.  They built me a good domain object model that I could easlily reuse. For me to be able to pull the comment count out of the "post" object, was as simple as inspecting the object, and grabbing it.  It was just there.  I then needed some of the blog's settings (to determine if commenting was enabled).  Guess where that was - "post.Weblog.EnableComments" - right were it should have been.  No guesswork on my part.  No modifying a SQL sproc.  No fiddling around with a DataSet hoping I don't screw something up.  It was just there for the plucking.

    This is the kind of stuff that makes me happy as a developer, and I can say that my source code experience so far with CS has been this way.

    -Brendan


  • Off-Topic : MS Walk

    Next month I'm walking with my father and sister in the MS walk here at the beach.  My mom has MS, and we're Team Tompkins this year.

    If you'd like, you could help a great cause and sponsor me.  I'm trying to raise $250... Hey it's easy as pie.  Just click here.

    :)  Thanks! 

    Brendan
  • Applying Behavior Analysis Theory to the Software Industry

    Citing Bob Reselman’s “Coding Slave” Darrell gives his take on how to fix the software development industry

    In addition to paying great programmers more, we need to pay crappy, or maybe "less sophisticated", programmers much less.

    On one hand, he’s absolutely right : great programmers should be rewarded. On the other hand, I don’t normally see overpaid software developers.  And the “fat” that I do see that should be cut, can never be because of politics, policy, etc.  I do, however, run into lots and lots of under-paid, overworked developers – this the is part of the problem that the guild idea from Coding Slave is meant to address. But the interesting thing about this thread, however is Bob Reselman’s comment to Darrell’s post:

    You bring up some interesting thoughts on the nature of human motivation. I am very interested to know your thinking on this question: What do you suppose motivates (motivated) an artist such as Van Gogh, Jackson Pollock or Charles Ives? Pollock made some money for his art, but Van Gogh and Ives made not a cent from an endeavor to which they devoted their lives. I wonder, is there something intrinsically motivating in the act of creation?

    In my previous life as a student of behavioral psychology, one of the things we were taught was to be very careful about guessing what may be motivating for someone.  We called this Putative thinking.  What is motivating to one person may not be for another – there aren’t really any generally accepted motivators. 

    Say you take Darrell’s assumption that money is motivating and you give your good developers raises.  You may find that you wind up reinforcing some adjunct behavior - behavior that has nothing to do with your target behavior.  Wearing ties, showing up early, speaking up in meetings, gossiping, whatever.. The point is, you have no idea if your money has had any real affect on the target behavior writing better code, until you see the better code being written.

    Okay, now take Bob’s idea that the act of creating is motivating.  Well, he could be on to something here, and it certainly costs a lot less than Darrell’s idea, but I have a feeling that this may only be motivating for some. Again, the idea is Putative.  You may end up affecting your target behavior, you also may reinforce some other strange behavior that you didn’t intend to reinforce.  You may even end up with some avoidance behavior.

    So what you do to increase the target behavior of writing better code?  Well, my point is, you won’t know until you try something, and see what happens.  Now, this idea isn’t any great help if you’re an IT manager, but a behavior analyst would change the environment until there was an increase in the target behavior. When they see an increase, they know that the change they made had an effect. They've then isolated the variables that affect their behavior, and they can begin to make real changes.

    What I do like about Darrell and Bob’s ideas are that they focus on the environment.  This is in stark contrast to what I’ve been noticing lately – a lot of what I call “individual differences thinking.” In this type of thinking people say “some developers are good, others aren’t, that’s just the way it is.”  This kind of thinking focuses on identifying and weeding out the superstar developers, not on creating the conditions that foster coding better. 

    Since I’ll always be a behavior analyst at heart, I believe this type of indiviual differences thinking is flawed, and is a bad trend in our industry.   I think we all can learn to code better, superstar or not.

    -Brendan

  • I'm Rapidly Becoming One of Those Open Source Hippies

    This is a topic I think I'm going to be writing a lot more about in the near future.  With every small side project I do, I'm more and more convinced that open source is a good thing, no an essential thing, and I find myself turning into one of those open source hippies.  Now, I'd never recommend open source for my big clients who can pay for software, and I'm not talking about OSes and databases here (I'd never use anything but SQL Server)... But when I need to get something done in my non-corporate consulting work, I turn to open source for the solution. Why?  

    For one, it ensures that I don't leave too much alien code behind for someone else to have to maintain. 
    I don't want to be tied to a client forever, and if I solve their problem using DotNetNuke, or Community Server, I can bet that others will know how to maintain it when I've moved on to other things.

    B. I can quickly get source code that I can customize to get the job done. 
    Whether it's getting the latest DNN source, or an FTP client like FileZilla, I can get what I need with an Internet connection, on any computer, wherever I happen to be.

    #3 It's going to protect my career as a consultant.
    If you read A church switches to open source and teaches us a lesson, it looks like we MSfties are going to be loosing work to PHP/Linux jobs.  Now I'm not worried about this happening inside large corporations anytime soon, but certainly for smaller shops, it's happening.  I like doing these smaller jobs, and the idea of all this PHP code proliferating out there is, well, horrifying!

    So, look for more open source sympathizing from me.  I'm going to go turn on the Grateful Dead and spin around in circles now.

    -Brendan

  • Resharper Dissed by asp.netPro Readers Choice Awards

    Was Resharper dissed By asp.netPRO Readers Choice Awards?

    Each year, asp.netPRO recognizes outstanding products and vendors in the ASP.NET add-on market. Please take a moment to select your favorite ASP.NET tools. This is your chance to voice your opinions regarding the tools and products you use in your everyday development efforts.

    In the Add-in category, they list CodeSmart, and CodeRush, but no Resharper? 

    First let me say that I have no affiliation with the folks at JetBrains. I’ve never even once exchanged an email with them.  But, I’m very curuious about the amount of chatter they’ve received.  It almost seems like they’re being snubbed in some circles.  I’ve purchased and used all three of these products, and I just think Resharper hands down is the best tool.  Why do I care?  Because we need to code better, and we need tools like this to help us...   

    Strange.

    -Brendan

     

  • Welcome John Papa

    I'd like to welcome our newest CodeBetter.Com blogger, John Papa.

    John Papa .NET architect and a baseball fanatic who spends most of his
    summer nights rooting for the Yankees with his two little girls, wife,
    and faithful dog, Kadi. He has authored several books on ADO, XML, and
    SQL Server and can often be found speaking at industry conferences such
    as VSLive.

    Now, that sentence about "rooting for the Yankees" may need some updating ;)  but ADO, SQL and XML still rock, and I can definitely speak for all of us to say that we're all very excited to be blogging with him.

    Welcome John!

    -Brendan
  • Is Microsoft TechEd 2005 Too Expensive?

    If you go to the Microsoft Tech·Ed 2005 site, you’ll find that if you “Register by April 15, 2005, and get the Tech·Ed 2005 early registration rate of just $1,695. That’s 15% off the regular rate of $1,995.”

    From this article, TechEd: Ballmer pushes greater platform integration there were 11,000 attendees at Tech·Ed 2004

    So, I did a little math:

    Now, okay.  I admit I have no idea how much it costs to run an event like TechEd.  And I’m not so naive to try to suggest that Microsoft should loose money on the event, heck maybe they already do.  But, I’m wondering if MS just might be Loosing Potential Profit on TechEd.  If you read Joel on Software - Camels and Rubber Duckies about product segmentation, and you apply this to Teched, MS may be missing out on a lot of sales.

    I’m not going this year, because as an independent consultant, I can’t afford $1,695.  I mean, I could go to Paris for a weekend for that kind of money. Okay, here’s a barrage of Rumsfeld-style self-questioning:

    “Would I go for $1000?”  Probably not. 
    “What’s my price point?”  I think I could safely say I’d purchase a ticket for $595. 
    “Am I too cheap?” Yes
    “Could MS Charge me $595 and still make money?”  Probably.
    “But don’t they sell out anyway at the high price, how would they make space for the cheap seats?” I’m not sure, but they can figure out this one, I mean come on, they’re Microsoft.

    So, how about a little more market segmentation? Hey, they may make some more money! Here’s a pricing suggestion:

    • Tech·Ed 2005 Universal Pass  – $1,995 ($1,695 early bird)
    • Tech·Ed 2005 Developer Pass (no lunches, no parties) – $995 ($595 early bird) 
    • Tech·Ed 2005 Keynote Pass (keynotes and expo only) – $295 ($195 early bird)
    • Tech·Ed 2005 Expo Only – $95 ($55 early bird)

    And I know, MS does have some free developer events. The MSDN events are great!  And the code camps (from what I hear) are even greater!  But we all want to go to TechEd, I mean, it’s sorta like our Mecca, right?

    So, until I get my cheap seat, I’ll be putting this banner on my blog.

    -Brendan

     

  • An AggregateCompactBlogList Control for CommunityServer

    Earlier this week, Dave Burke left a comment to my We've Been Community Serverized! post.

    I'm thinking it would be nice to have a list of CodeBetter.com bloggers on your aggregated page when time permits. Have all of you .NET studs listed on one page.

    This, unfortunately, is not an out of the box control for Community Server, so I went source code spelunking to figure out how to do it.  I’ll have to say, I’m digging the way they built the CS application. Is very well thought out.  The code separation is great.  Ease of skinning and modification was definitely a high priority for them, and it shows.  It’s not all rosy under the covers but for version 1, it’s one of the best open source code apps I’ve seen.

    Without further ado, here’s how I created the “Sorted Blogger List”

    Step 1. Download the Source Code

    Get my source mods here.

    Step 2. Add CollectionView.cs to your Project

    You’ll need an easy way to sort the business entity collections to enable sorting of the blogger list (by post count, for automatic blogger ego stroking ;) ). You can add the code from my Sort/Filter Your Business Entity Collections with a NEW CollectionView to your project somewhere. I added it to my “CS\src\Components\Provider\” directory, not sure if this was the right place or not, but it works.

    Step 3. Add AggregateCompactBlogList.cs Control

    Add this source file to your “CS\src\Blogs\Controls\AggregateBlogControls” directory

    Step 4. Add the Skin-AggregateCompactBlogList.ascx Control

    Add this source file to your “CS\src\Web\Themes\default\Skins\Blogs” directory

    Step 5. Add the Control to Your default.aspx page

    The final step is to add the control somewhere, like so: 

    <blog:aggregatecompactbloglist id="AggCompactBlogList" runat="Server"/>

    That’s it. You should now have a list of all bloggers, grouped by blog category, just like good ol’ .TEXT used to have.

    -Brendan

  • Low Hanging Fruit : an Open Source Software Project Idea

    I have a friend who runs a coffee shop here in Norfolk, and he's looking for a simple cyber cafe software for the public pc that he has in the shop. 

    All it would need is a configurable countdown timer, a configurable splash screen, and restrict the user to IE or FF.  What I'd like to see is a source-code provided open source app.

    Seems to me that this would be ridiculously easy in .NET winforms to do, right?   If you did it right, you could even create a client-server app and sell it to all those Internet cafes out there.  I don't have the time to do it with all my other commitments, but I know some of you out there are aching for ideas.

    -Brendan

  • We've Been Community Serverized!

    We’re now running CommunuityServer. Thanks to Scott Watermasysk for the great product, and Kevin Harder for his awesome .Text to Community Server Conversion Utility.

    Also, thanks to Geoff who did all the research, and figured out much of the migration stuff. Once we can wrap our heads around this great new application, we’ll be doing some fun stuff.

    Stay Tuned…

    Brendan

  • Sort/Filter Your Business Entity Collections with a NEW CollectionView

    You’ve probably heard a lot of talk about why you should use Business Entities rather than DataSets.  There are good arguments for and against using Typed DataSets as Business EntitiesAnd even very recently, there’s some people changing their minds on the issue.

    I’m generally for the raw Business Entity approach, typically from the business layer up, especially when exposing data at the end of Web Services. Sahil has promised to make me see the Typed DS light, but right now, I’ve actually developed quite a bit of non-typed DataSet BE objects in my framework.  If you’re like me and gone down this route, you may have found that once you get the hang of it, it’s not too hard to DataBind your BEs to your UI controls.  Then you may have created some strongly-typed collections containing your BEs, and naturally, you’ve needed to bind these collections to a DataGrid, which is easy. So you’re really proud of yourself, and you show your boss this great work, and they say to you…

    “Great. Nice Grid. What happened to my sorting?” 

    You then you mumble something about how your collections aren’t sortable, but they are better than DataSets nonetheless, because you can add your own business logic to them easily, and they’re more generic, and they might work better on the wire, and you look up at them and with a blank stare they say to you…

    “Great. Nice Grid. Um… What happened to my sorting again?”

    So what are you gonna do? You could create a DataSet out of your Collection and pass that off to your Grid, but did someone say hack? You could add sorting to all of your collection objects, but did someone say tedious

    Do I have a perfect solution? No. But I do have a solution that works pretty well for me, and lets me add sorting and filtering to my DataGrid-bound BE collections.  A few months back, I posted about some code I’d worked on to allow  Sort and Filter Strongly-Typed Collection Classes

    Using this class is easy. Say you want to bind your strongly typed collection to a DataGrid, and enable sorting and filtering. Simply pass your collection class to the constructor of the CollectionView, and bind your grid to the CollectionView instance instead.

    Like I said, I’ve been using it and it’s working pretty well for me.  I’ve recently added sorting and filtering of child object’s properties, and some better handling of null values.  So without further ado, here’s the new download.

    UPDATE - 7/25/05 - Jordan Bowness has translated the code into VB. You can download that file here. Thanks Jordan!

    Enjoy!

    -Brendan

  • New Hardware for CodeBetter, and I didn't Code Better

    Because Codebetter.Com’s traffic has been growing at a fairly fast rate, I’ve been in touch with our hosting provider about ways that our hardware can keep up with our level of traffic.  They recently suggested that we be moved to a better hardware platform, which they graciously agreed to do for us.  They assured me that this process would be seamless, and so I gave them the go ahead to do it, which they did in the middle of the night, last night.

    Since this particular hosting provider has always provided me with prompt support and near flawless performance, I trusted that the site wouldn’t be down.

    Well, if you tried to visit us this morning, you know that we were showing the classic ASP.NET “Yellow Screen of Death.”  “CodeBetter?” You’re thinking, “Yeah Right!” In fact, the site was hosed to such a point, where I couldn’t even put up a “Technical Difficulties” page.

    So, this wasn’t a very good example of how to code better.  I should have had better communication with them throughout the process. I should have suggested to them that we test the new server before making the DNS switch.  I know better.

    Oh well, live and learn, I guess.  Hopefully the new hardware will be faster, and the site will be more reliable.

    -Brendan

     

  • A Strongly-Typed Cache State Object

    Here’s the second installment of my three posts on Strongly-Typed ASP.NET State wrappers, see yesterday’s post, A Strongly-Typed Cookie State Object to get started.  This version stores state in the HttpCurrent.Cache object, which has performance benefits over the Application object.

    Okay here’s the code for the CacheStateObject

      public class CacheStateObject : StateBase

      {

        public CacheStateObject() {}

     

        /// <summary>

        /// Creates a new <see cref="CacheStateObject"/> instance.

        /// </summary>

        /// <param name="stateKey">State key.</param>

        public CacheStateObject(string stateKey) : base(stateKey)

        {}

     

        private object lockObject = new Object();

        protected TimeSpan cacheTime = TimeSpan.FromHours(1);

     

        /// <summary>

        /// Stores this instance.

        /// </summary>

        /// <returns></returns>

        public override void Store()

        {

          lock(lockObject)

          {       

            System.Web.HttpContext.Current.Cache.Insert(stateKey, this, null, System.DateTime.Now.Add(cacheTime), TimeSpan.Zero);

          }

        }

     

        /// <summary>

        /// Removes this instance.

        /// </summary>

        /// <returns></returns>

        public override void Remove()

        {

          lock(lockObject)

          { 

            System.Web.HttpContext.Current.Cache.Remove(stateKey);

          }

        }

     

        /// <summary>

        /// Restores this instance.

        /// </summary>

        /// <returns></returns>

        public override Object Restore()

        {

          return System.Web.HttpContext.Current.Cache[stateKey];

        }

      }

    And here’s an implementation class code snippet, taken from my WSMQ project:

      public class RequestCacheObject : CacheStateObject

      {

     

        /// <summary>

        /// Creates a new <see cref="RequestCacheObject"/> instance.

        /// </summary>

        public RequestCacheObject() : base("RequestCacheObjectState")

        {}

     

        /// <summary>

        /// Gets the instance.

        /// </summary>

        public new RequestCacheObject Instance

        {

          get { return (RequestCacheObject) base.Instance; }

        }

     

        private Hashtable queueRequests = new Hashtable();

     

        /// <summary>

        /// Containss the request.

        /// </summary>

        /// <param name="qr">Qr.</param>

        /// <returns></returns>

        public bool ContainsRequest(QueueRequest qr)

        {

          return (queueRequests.ContainsKey(qr.QueueName + qr.QueueRequestId));     

        }

     

        /// <summary>

        /// Purges the requests.

        /// </summary>

        /// <param name="age">Age.</param>

        public void PurgeRequests(System.TimeSpan age)

        {

          foreach(string key in queueRequests.Keys)

          {

            if(((QueueRequest)queueRequests[key]).RequestDateTime < System.DateTime.Now.Subtract(age))

            {

              queueRequests.Remove(key);

            }

          }

        }

     

        public void AddRequest(QueueRequest qr)

        {

          this.queueRequests[qr.QueueName + qr.QueueRequestId] = qr; 

        }

      }

    And here’s an example of how this gets used in the WSMQ Web Service.

        /// <summary>

        /// Enforces that the request is relatively unique

        /// </summary>

        /// <exclude />

        private bool IsUniqueRequest(QueueRequest req)

        {

          requestCache.Instance.PurgeRequests(Configuration.ItempotencyTimeout);

     

          if(req.QueueRequestId != null && req.QueueRequestId.Length > 0)

          {

            if(requestCache.Instance.ContainsRequest(req))

              return false;

     

            req.RequestDateTime = System.DateTime.Now;

            requestCache.Instance.AddRequest(req);

            requestCache.Instance.Store();

     

            return true;

          }

     

          return true;

        }

    Now, a couple of things to be aware of here.  You may need to manually remove references within your cache class, if you’re using it like I am in the above example. If you don’t you could end up with eternally cached items (until the worker process is recycled).  If you’re using it in the traditional way of caching some heavily used data, you should be fine, since you probably won’t be continuously adding to the item. 

    -Brendan

  • Mark Russinovich From Sysinternals is Blogging

    Visit Mark's Brand Spanking New Blog Here.

    This one was just too important not to post on CodeBetter’s main feed.  And if you don’t know about Sysinternals yet… My God!  Where have you been?

    -Brendan

  • A Strongly-Typed Cookie State Object

    A couple of weeks ago, I posted about A Better ASP.NET State Pattern, which essentially demonstrates a strongly-typed wrapper base class for storing ASP.NET state.  In this post, I showed one implementation of this pattern, which used Session to store the state.  I hinted that it would be easy to use other back end storage mechanisms for your state objects:

    Note that you can create one that stores state in ViewState, or Application or Cache or in the Database, or on your cell phone. The point is, you just derive from StateBase, and implement the abstract methods.

    This week I’m going to do a series of three posts to demonstrate different back end storage mechanisms for storing Page State in Cookies, Cache, and ViewState.  Today, I’m going to start with a Strongly-typed cookie wrapper class, called CookieStateObject.

      [Serializable]

      public abstract class CookieStateObject : StateBase

      {

        public CookieStateObject()

        {

        }

     

        protected System.DateTime expires = System.DateTime.Now.AddYears(1);

     

        /// <summary>

        /// Creates a new <see cref="ViewStateObject"/> instance.

        /// </summary>

        /// <param name="stateKey">State key.</param>

        public CookieStateObject(string stateKey) : base(stateKey)

        {}

     

        /// <summary>

        /// Stores this instance.

        /// </summary>

        /// <returns></returns>

        public override void Store()

        {

          string serializedVersion = SerializationHelper.XmlSerialize(this);

          System.Web.HttpContext.Current.Response.Cookies[stateKey].Value = System.Web.HttpUtility.UrlEncode(serializedVersion);

          System.Web.HttpContext.Current.Response.Cookies[stateKey].Expires = expires;

        }

     

        /// <summary>

        /// Removes this instance.

        /// </summary>

        /// <returns></returns>

        public override void Remove()

        { 

          System.Web.HttpContext.Current.Response.Cookies.Remove(stateKey);

        }

     

        /// <summary>

        /// Restores this instance.

        /// </summary>

        /// <returns></returns>

        public override Object Restore()

        {

          if(System.Web.HttpContext.Current.Request.Cookies[stateKey] != null)

          {

            string serializedVersion = System.Web.HttpContext.Current.Request.Cookies[stateKey].Value;

            return SerializationHelper.XmlDeSerialize(System.Web.HttpUtility.UrlDecode(serializedVersion), this.GetType());

          }

     

          return null;

        }

      }

    This class Serializes the object to XML, UrlEncodes the XML, and stores it as a cookie.  You can get a copy of An XML Serialization Helper Class here.  Here’s an example of an implementation of the CookieStateObject:

        public class CameraState : CookieStateObject

        {

     

          /// <summary>

          /// Creates a new <see cref="CameraState"/> instance.

          /// </summary>

          public CameraState() : base("Camera_STATE")

          {}

     

          private ArrayList m_arrCameraID = new ArrayList(); 

          private  ImageWidth m_imaCameraImageWidth = ImageWidth.Small;

     

          /// <summary>

          /// Gets the instance.

          /// </summary>

          public new CameraState Instance

          {

            get { return (CameraState) base.Instance; }

          }

     

          public ImageWidth CameraImageWidth

          {

            get

            {

              return m_imaCameraImageWidth;

            }

            set

            {

              m_imaCameraImageWidth = value;

            }

          }

     

          public ArrayList CameraIDs

          {

            get

            {

              return m_arrCameraID;

            }

            set

            {

              m_arrCameraID = value;

            }

          }

        }

    And here’s an example of how this class can be used:

        private CameraState state = new CameraState(); 

     

        private void AddSelectedToView()

        {

          this.state.Instance.CameraIDs.Clear();

     

          foreach(ListItem item in this.chkCameras.Items)

          {

            if(item.Selected)

            { 

              this.state.Instance.CameraIDs.Add(item.Value);

            }

          }

     

          this.state.Instance.CameraImageWidth = ImageWidth.Thumbnail;

          this.state.Instance.Store();

        }

    A couple of things to note here.  Cookies have a maximum size of 4KB.  My Serialized, UrlEncoded Camera object above is about 1.3K when filled with the maximum amount of data that I expect it to ever hold.  You should be very aware of this maximum, and make sure you’re well below it in practice, however this is true of any data you intend to store, no matter where you decide to persist it.   If you run into space limitations, you can tweak the serialized Xml using attributes. 

    Using a strongly-typed wrapper for state objects can greatly reduce runtime errors, and make your code easier to read and mantain over time.  Hope you find this useful!

    -Brendan 

More Posts Next page »

Our Sponsors

Free Tech Publications