Wiki To The Rescue

Thursday, November 20, 2008 9:09 PM

It's review time at work and I was caught slacking. I realized far too late that I had forgotten one of my goals and that I've not been keeping up with those little nuggets that exemplify how I have been a good little programmer. I was forced to say sorry about the goal and I'm having to drum through extremely horrible memory of a year gone by. My main goal for the next review period is to not suck so back come the next review!

A few years ago I had this strategy of keeping an Outlook post in a special folder where I kept this kind of information. I would just open this post and edit it all year long so I would be uber prepared when the reviews rolled around. Worked quite well I suppose (it's much better than nothing!), but it had one problem - it wasn't in my face constantly reminding me to think about it. As the wife would attest, I have a hard time thinking about anything other than whatever I'm currently obsessing over. Thus it wouldn't ever be as complete as it could be.

So the wheels start turning and I realize the one place that will always be in my face - my browser home page! Like all good employees, I'm pretty sure my browser gets more action than any other program on my computer. So now the only question is what my home page should point to...

My first thought is some kind of CMS. So I open up the browser (or open a new tab - it's already open of course) and start googling for inspiration. Somehow or another I find my way to Stackoverflow and specifically this question. Yes! A wiki is exactly what I need! Well, need might be a bit strong, but I think it'd work excellent and be cool at the same time.

Well, to cut a long story short, I did look into many of the choices, but ultimately settled on screwturn wiki. There were three things that bumped it to the top. First, I did like the interface and ease of use which is ultimately the most important thing. Second was that it was super easy to setup and deploy. This was probably due to the fact that it is written in .net which was the third thing I liked about it. The only thing I wish it has is a markdown editor instead of the standard wiki markup.

So then, how will this help me not feel like a slacker come next review? I uploaded the wiki engine to another subdomain on my website so I can get to it from both work and home. I then set it as my homepage in both places. On the home page of the wiki is a short list of links I hit a lot followed by a section for keeping track of my yearly review info. So now I get reminded to think about it every time I open my browser. And even better, I can edit it constantly in place.

Of course, time will tell whether or not this turns out to be a good long term solution. Hopefully my next post about the subject will be one of joy and happiness due to its success.

Tags: wiki, work

View Responsibility

Sunday, November 9, 2008 8:56 PM

On my current side project, I'm writing an ASP.NET MVC application and have been loving it. Something I find myself doing is breaking up a particular view into the main view that gets asked for by a controller and a few sub views. It is these sub views that caused me to ponder the question of responsibility. I wondered if it was the responsibility of the controller to distinguish between the data needed by the main view and the data needed in each sub view, or was it the main view's responsibility to dole out what the sub view needed. I ultimately came to the conclusion that it is the main view's responsibility. Here is my reasoning.

I think a key ability here is to put yourself in the shoes of another.  Or in other words, be able to see something from different perspectives.

For this particular example, I have an action where the user has asked for a particular agenda by date. So I have an AgendaController and a method called Show. The controller gets the appropriate agenda from the domain and selects a view to display it.

From the perspective of the controller: So I've been asked for an agenda. I'll get the agenda and ask a view to display it. I don't care how it gets displayed, just that it does. So I'll pass the agenda object itself to the view.

From the perspective of the view (the one selected by the controller): So I've been asked to display an agenda. I'll make the date of the agenda be the title of the page and put it here. I want the attendance to go right here, but I'll let the "AttendanceView" render that piece so it will look like it does everywhere else. I'll put the blah blah here, and this thingy over there... etc.

You get the idea. The main view is deciding where to put all the pieced of an agenda. It also decides to delegate some of the more complex pieces to other sub views. When it does that, it needs to pass to that sub view what it wants the sub view to display. For example:

<div class="section" title="Attendance">
   <% Html.RenderPartial("AttendanceView", ViewData.Model.Voters); %>
</div>

So the controller gave the main view an agenda to render and the main view is taking part of that agenda and passing it off to a sub view to handle. This is where I think this separation belongs. I don't think the sub view should have to share the same model type as the main view, and I don't think the controller should have to put that collection of voters behind a special ViewData key for the sub view. I don't even think the controller should have to know there will be sub views. It's the controller's responsibility to get the domain object, and it's the main view's responsibility to make sure that domain object gets displayed.

Of course, all this is just how I'm feeling about it today. I'm sure I could be persuaded to change my viewpoint fairly easy however.

Happy coding!

Tags: .net, architecture, mvc

Less Is More

Saturday, October 25, 2008 6:37 PM

As Bob Koss (on Object Mentor) puts it in Size Matters:

classes are just too damn big and methods are just too damn long

I couldn't agree more! I was recently tasked with adding functionality to an existing website at work. The point in the process where I was to add functionality was in the middle of this nasty page where there were multiple panels that were just hidden or shown depending on where you were in this mini process flow. The aspx was over 500 lines long and the code behind over 1,000! I cried inwardly when I realized the desired functionality was right in the middle of this mess. I did some soul searching and analysis and determined that splitting this mess into multiple pages wouldn't take much longer than figuring out how to add to the existing page without breaking anything.

As I was breaking the page into multiple pages, what Jeff Attwood said in Size Is The Enemy really hit home.

Lines of code are, and always have been, the enemy. More lines of code means more to read, more to understand, more to troubleshoot, more to debug.

The code was extremely difficult to decipher. Not only was so much functionality packed into one page, each method was crazy long and overly complex. At the end of this post is one such method along with how I refactored it after moving it into the new page I created for that piece of the puzzle. I hope you'll agree that the refactored version is much easier to read and understand quickly. And that's the key - to add to a code base without breaking it, you have to be able to understand it and I want to do that quickly. When an analyst or a user says "it's only one new button" or some such nonsense, I want them to be right! Nothing frustrates me more than when a task that seems like it should only take a day or two actually takes a week or two and it's because of the unnecessary complexity left by the yahoo coder before you.

A couple of things about the code below. First, don't bother trying to grok the pre-refactored code - it's just there to note. I assure you I tested and the shorter version captures exactly the same thing as the the longer. Second, one might be tempted to say the shorter version is only better if you understand lambdas and LINQ. To that I say, true. But consider this. A new developer coming on who doesn't know them will only have to learn them once and will then be capably of understanding all the rest at first glance. Doing it the old-school looping, if-else, and temp variables way means the poor developer will have to decipher the craziness over and over again. And each and every time is a lot of unnecessary time added to that simple button request.

So, to summarize: Less Is More!! Make every attempt to accomplish your programming tasks in as few lines of code as possible (short of obfuscation of course!). Always keep it in your mind how difficult it would be for the programmer coming along behind you (that coder might be you months or years later).

Happy coding!

 

The code:

Before I refactored:

private int GetDfuCount()
{
   int maxCount = 0;
   ArrayList systemDFUList = new ArrayList();

   foreach (DFULibrary.DFU userItem in GetUserDfuList())
   {
      if (userItem.Exists == false && userItem.Staged == false)
      {
         if (!userItem.BusinessUnit.Equals("CASE READY BEEF-PORK"))
         {
            maxCount++;
         }
         else
         {
            if (userItem.Reservation == true)
            {
               maxCount++;
            }
         }
      }

      foreach (DFULibrary.DFU systemItem in userItem.SystemDfuList)
      {
         if (systemItem.Exists == false && systemItem.Staged == false)
         {
            bool match = false;
            if (!systemItem.BusinessUnit.Equals("CASE READY BEEF-PORK"))
            {
               foreach (DFULibrary.DFU listItem in systemDFUList)
               {

                  if (systemItem.Product == listItem.Product &&
                     systemItem.Location == listItem.Location &&
                     systemItem.DfuLevel == listItem.DfuLevel &&
                     systemItem.SellingGroup == listItem.SellingGroup &&
                     systemItem.DriverLevelLoc == listItem.DriverLevelLoc)
                  {
                     match = true;
                     break;
                  }
               }
               if (!match)
                  systemDFUList.Add(systemItem);
            }
            else
            {
               if (userItem.Reservation == true)
               {
                  foreach (DFULibrary.DFU listItem in systemDFUList)
                  {
                     if (systemItem.Product == listItem.Product &&
                        systemItem.Location == listItem.Location &&
                        systemItem.DfuLevel == listItem.DfuLevel &&
                        systemItem.SellingGroup == listItem.SellingGroup &&
                        systemItem.DriverLevelLoc == listItem.DriverLevelLoc)
                     {
                        match = true;
                        break;
                     }
                  }
                  if (!match)
                     systemDFUList.Add(systemItem);
               }
            }
         }
      }
   }
   return maxCount + systemDFUList.Count;
}

After I refactored:

private int GetDfuCount()
{
   Func<DFULibrary.DFU, bool> userDfusToCount =
      x =>
         !x.Exists && !x.Staged &&
         (x.BusinessUnit != "CASE READY BEEF-PORK" || x.Reservation);

   Func<DFULibrary.DFU, bool> sysDfusToCount =
      x =>
         !x.Exists && !x.Staged &&
         (x.BusinessUnit != "CASE READY BEEF-PORK" || x.UserDfu.Reservation);

   int userDfuCount = UserDfuList.Count(userDfusToCount);
   int sysDfuCount = SystemDfuList.Count(sysDfusToCount);

   return userDfuCount + sysDfuCount;
}
Tags: architecture, meta

Dynamic sitemaps with ASP.NET MVC

Thursday, October 16, 2008 7:40 PM

I read Jeff Atwood’s post on The Importance of Sitemaps and thought I'd utilize one from the get-go on a site I'm creating for a side project. Seemed simple enough... Well, it didn't turn out a quick 5 minute task like I hoped.

Basically there were two issues. How to return raw content and how to get the encoding right.

How to return raw content was actually pretty easy to find. There's a method on System.Web.Mvc.Controller called Content that accepts a string, the content type, and the encoding. Perfect.

Now, this is probably easy to most, but I've never had to worry about encoding so this one took me a while to get right. First when I tried to serialize my xml document to a string, I ended up with utf-16 in the xml declaration. I knew that's not right because the sitemap specification specifically says it needs to be utf-8.

Help me Google!

The Google gods provided a lot of stuff... and a lot of rabbits to chase and a lot of less than perfect solutions. It was insane how much junk I came across. Many of which provided solutions that basically hacked the phrase "uft-8" into the xml declaration even though the document was physically still utf-16.

In the end I obviously figured it out - or at least, I figured out a solution that works for me and one I feel is somewhat slick. The code:

public ActionResult Sitemap()
{
   XNamespace xmlns = "http://www.sitemaps.org/schemas/sitemap/0.9";
   var root = new XElement(xmlns + "urlset");

   var repository = IoC.Resolve<IRepository<Location>>();
   foreach (var location in repository.FindValid())
   {
      object routeValues =
         new
            {
               state = location.State,
               location = location.Name,
               controller = "Agenda",
               action = "List"
            };

      root.Add(
         new XElement("url",
            new XElement("loc", GetUrl(routeValues)),
            new XElement("changefreq", "daily")));
   }

   var memoryStream = new MemoryStream();
   using (var writer = new StreamWriter(memoryStream, Encoding.UTF8))
      root.Save(writer);

   return Content(
      Encoding.UTF8.GetString(memoryStream.ToArray()),
      "text/xml",
      Encoding.UTF8);
}

The main part that took me so long to figure out is the last part where I'm trying to return the XElement I created. The keys ended up being the use of MemoryStream, StreamWriter with the UTF8 argument, and finally using Encoding.UTF8 to get the string to pass to Content().

That's it for the problems that held me up. I would like to add a final note about a problem I'm still having though. Notice the line where I'm calling GetUrl(). That's a utility method I wrote to get a full url from within the controllers. It's easy as pie from within the views, but I haven't found a built in easy way to do it within the controllers - or anywhere else where you don't have an HtmlHelper to play with. Here is that method, but I am still hopeful that an easier built in method exists that I just haven't found yet.

protected string GetUrl(object routeValues)
{
   var values = new RouteValueDictionary(routeValues);
   var context = new RequestContext(HttpContext, RouteData);

   var url = RouteTable.Routes.GetVirtualPath(context, values).VirtualPath;

   return new Uri(Request.Url, url).AbsoluteUri;
}

Happy coding!

Tags: .net, mvc

Information streams

Thursday, October 9, 2008 6:12 PM

I was going to send this information to someone and thought I would post it instead.

In order to stay as current as I can with what is going on around the community of development, I basically try to stay current on just a few blogs (below), follow links like crazy, and listen to a few podcasts.

For the blogs, the idea is not to completely absorb all of the material that I read (there’s just too much), but rather just kind of plow through it in hopes of catching general themes and hot topics. Of course, I slow down and read the juicy stuff or topics I’m especially interested in, but I rarely spend much time on any given blog entry. This is especially the case for entries that are rich with actual code. I greatly prefer those entries that talk about something rather than show you to the nth degree with a ton of code samples. I just don’t have the time to spend 10+ minutes (sometimes it takes a lot more time than that) trying to fully grok a single entry.

On to the list! This isn’t the ultimate list perfect for all people. It’s just a list that works well for me at the moment. It actually fluctuates quite a bit over time. If you know your bloggers in the dev community well, you may notice there are a few important ones missing. They come and go. I find that sometimes the “great” ones push out a ton of content and will actually cause my unread posts to just build and build. The last thing I need is another vice hanging over my head saying "Come on Rob! Get out there and read – you're falling behind!" I have definitely been known to go to all items and just mark them all as read – there’s nothing saying you have to catch every one.

One last thing... do not visit these one at a time and try to pick out what is new from the last time you were there. Use a reader. I personally would suggest Google Reader simply because it has worked awesome for me. Use whatever floats your boat though.

Enough jibba jabba already!

Ok now, there has to be an easier way to share feeds. I exported my feeds from Google Reader, but couldn’t quickly find a way to get the opml to render in html, so I typed them all :)

 

Now for your listening pleasure... Podcasts!

In addition to reading way too much, I listen to tech podcasts on the drive to and from work. Even for short drives you’d be surprised how much content you can burn through in a week. Here is that list:

 

And that’s it. All of that is my current information stream. Seems like a lot now that I’ve written it all out like this, but it really doesn’t seem like it. I start my mornings by quickly going through all of the new blog entries. I basically just plow through them quickly and leave the ones I really want to read thoroughly unread and come back to them after the initial plowing. If there’s still time in the morning before I need to get to work, I read a few, otherwise I just read them throughout the day on breaks. The podcasts don’t really take effort at all. I just sync up my iphone and listen to them in the truck. I don’t really set aside special time for them. I’ve tried listening while I work, but my tiny brain can’t concentrate on both coding and the podcast content at the same time. One or the other ends up getting neglected (I’ll let you guess which one ;).

Happy coding!

Tags: meta, rss