The organization of a indie developer

ListProject organization is something we all need to deal with on a daily basis.  The way we handle it leads directly to how efficient we can be, how support is handled, and how complete our products are.  No one wants the be the guy who is letting things fall through the cracks.

Project management for an independent can be easy to overlook as you don’t have anyone to answer to, but it is important to have a solid system to keep track of everything.  I’ve been asked by a number of friends over the years how I keep on top of stuff and have had the idea of blogging about it for a while now.

Key Points

I figure it is best to start off with the key points before I describe how I personally implement them.  Here they are:

  • Have a single tool were you keep all your project tasks and support items.
  • Find a tool that is quick, easy and everywhere you are.
  • Make the tool a part of your workflow and review it often.

I think these are things that have made the biggest impact for me.  It doesn’t matter what tool you use to manage things.  It could be a notebook, a text file, or something more advanced.  It just needs to become the place for managing project stuff.  It can’t be a hassle to use and must be as quick to access.  It has to become an indispensible part of your work process.

The rest of this post will be focused on how I’ve implemented these.  Hopefully, it will be helpful or at least interesting to compare to your own workflow.  For the past few years, my key tool for project organization has been RememberTheMilk (RTM).   The rest of this post will focus heavily on how I use RTM to manage things, but most of these types of things could be done with other tools easily enough.

Areas

If you are looking to organize everything, you are gonna need multiple lists.  I keep a number of high level lists or areas.  Personal, Work (day job), and RazorAnt (my company) are the big ones.  Ideas and Someday are special areas that I’ll explain a bit near the end of this post.  The main point here is a have a few high level areas to place my tasks.

The RazorAnt list is the one we are concerned about in this post.  It is a list of every task I’ve record for all my myriad of projects.  (Yes, I have way too many projects between client work and my own projects, but that is a different problem.)  Since I have so many things going on, I like to have them all lumped together in one area.  I assign each task a tag stating what project it is a part of, but they are all part of the RazorAnt list. 

The point of the big list is I can see at a glance which projects have the high priority tasks and which ones have due dates coming up.  This helps me know what projects need the most attention.  It is often the place I start the day at so that nothing gets forgotten.

Project List

Once I’ve settle down to work on a specific project, I pull up the filtered view so I’m just seeing tasks for the project at hand.  This gets rid of the extra noise and helps keep me focused.  The last thing any of us needs is more distractions.  I keep the project list organized by using the priority levels and due dates.  I’ve included a screen shot of one of my current projects that is in the early stages to give you an idea of what this looks like.

Screen shot 2011-07-25 at 11.07.11 PM

Tasks

These are the real key.  As I work in the early stages of a project, I sometimes feel like I’m adding as more tasks than I’m crossing off as I breakdown tasks into multiple steps. Once you do the work of breaking down the tasks into the steps, you might as well make them into tasks. Big items on your list can sit out there until you are ready to deal with them and break them down to manageable chunks.

When I first started writing down all these little tasks I felt like I was wasting time, but it turns out it is more then worth it.  You don’t want to have to figure out the steps again and you can’t always control interruptions and other issues.  Besides, there is a sense of completion as you mark items as completed.

Support

Many indie developers handle support by having customers email them.  I’m the same way.  Emails come in and if the email is a feature request, bug or other issue that requires work, I just forward it to my RTM email address, give it a smart subject line, and it shows up right in my task list tagged correctly.  It is placed right with the rest of my task and doesn’t get lost. 

In the screen shot above, you can see a bug item that came via email.  It has a note icon on it where the body of the email can be viewed.

Project Ideas & Questions

As we work on projects, new ideas are always popping up.  When new ideas or questions come up, I just add a new task with the project tag and a question mark on the end.  If there are lots of details, I usually end up send RTM an email with the details in my head so it gets listed and everything is right there for me.

I can evaluate these question mark items later and not lose focus completely on the task at hand.  It is not uncommon for me to have lots of question mark tasks when I’m in the prototype phase.  Question marks don’t mean I’m going to do these things, just that I’m going to think about them.

Other Lists

If you are anything like me you have a list of ideas for possible apps you’d like to consider.  I keep my project idea list in RTM as well.  These aren’t tasks like everything else, but it is a great listing tool and since I’m in this app all the time, the ideas don’t get lost and get to revisited often.

Hear about a book you should read or a video you should watch?  I put them in my Someday list.  Again, it is simple a place to list things that you might want to revisit.  If after 3 months you no longer care about that book, just delete it from the list.  The key here is again having a place to put something that you see often.

I keep this list at the big area level as I don’t need to see these every day but since I’m in RTM all the time, they are always there and get reviewed on regular basis.  (Roughly weekly for me.)

Why I chose RTM

RTM has some key functions for me.  Since I rely on it so heavily for my dev work and my personal organization, it is important it is always with me.  The iPhone app is great and it automatically syncs with the web site.  Everything is always up to date everywhere.

The easy of entering tasks is huge.  The smart add functionality allows me to put tags, lists, priority and due dates all on the task line as I enter it.  One line of text and enter and I have my task in the right list, tagged and organized.  No messing around with separate fields.

Lastly, the ability to easily manage emailed items is huge.  I can keep my inbox clean and not let it get out of hand.  I simply forward the emails to my RTM address, change the subject (and use the smart add features) and send it.  Nothing gets lost and I don’t have 2 places to keep track of items.

Summary

The goal of this post isn’t to sell you on RTM, but to share the key things I think are important in keeping me on track and showing you how I do that.  There are tons of great tools to help solve this and many of them might work better for you than RTM.  Hopefully, my key points show through in the description of my workflow.

Is it too late for a 2011 goals post?

Well, I have not been blogging much recently and it is something I've actually really been inspired to do recently.  Sadly, it has been tough for me to do so as I've been conflicted on what to write about.

As one of the main developers of BlogEngine.NET for years, this blog came to be a lot of posts about it and other .NET adventures.  Recently though, I've been filling my spare time thinking about iOS development, App Stores, and other crazy things.  While I'd like to write about my thoughts and experiences here it has just seemed to be too much a shift. What better place to hint at this shift than my 2011 goals post?

2011 Goals

1. Release 3 new iPhone/iPad apps. (Updates don't count, but I expect these too.)

2. Release a Mac app in the Mac App Store.

3. Give my sites (this blog included) a fresh new look.

4. Find some quality time to work on an MVC3 app with Razor.

5. Blog more regularly on web development and mobile development topics.

6. Find more direct ways to work together with my kids on projects

7. Read through the Bible

8. Complete a Half Ironman

9. Drink more water, less junk.

10. Read at least one book a month to learn something different.

The first month is almost gone, but I feel like I've got a good jump on the list.  Go me!

Central Penn .NET Code Camp 2009

I had a nice time at the Central Penn .NET Code Camp this past Saturday.  It was my first code camp in Harrisburg, PA and while not as large as the Philly Code Camp I’ve been to a few times, it was a good code camp just the same.  There was a nice mix of sessions and I had a enjoyed getting to chat with fellow developers from the area (and a few from a bit further away.)  I was also shocked to see the swag that was available at this code camp.  It was incredible.  Everyone who stayed the whole day left with at least a t-shirt and a technical book.  My friend Mark scored a ReSharper license and some lucky fella went home with an XBox 360 (whatever that is.)

I gave a talk in the first time slot of the day on the Spark View Engine.  I had not done a talk on Spark before and was very curious to see how it go over.  I didn’t have a huge crowd for the talk but they were a great audience and had lots of good questions and insight.  It was a pleasure to present to them.

In the presentation, I decided to go the route of showing Spark instead of teaching Spark.  I showed a lot of different syntax, discussed spooling, partial files, and ended with an example of using iTextSharp and Spark to produce PDFs.  Hopefully everyone there got a good taste of Spark and will take a moment to download it and give it a try soon.

I promised to put the demo code out on my blog so I’ll include it at the bottom of the post.  It is far from perfect, but it will give you something to play around with.

Anyway, I hope to make it to future Code Camps in Harrisburg.  It was a good time and something local developers should really try to make time for.

Download: CPCC2009-SparkDemo.zip

Exploring Spark View Engine for ASP.NET MVC – Part 3

If you are following along in this series, we have have already looked at getting Spark View Engine setup and some of the basics of markup and layouts.  In this last section, we need to look at some of the pieces of Spark syntax that really stand out.

Conditional Syntax

One of the things that makes a view look ugly in a hurry in the Web Forms world is conditional logic.  If you have an else or an else if as part of the situation, you’ve got <% %> tags all over the place.  Spark makes conditional syntax flow in your html markup.  You can see a good sample of Web Forms vs. Spark at the beginning of the part 1 post on Exploring Spark.

The first way to handle conditionals is with the if and else tags:

   1: <if condition="!Request.IsAuthenticated">
   2:   <p>Hey... Login already!</p>
   3: </if>
   4: <else if="Context.User.IsInRole('Administrators')">
   5:   <p>Hello - You are special.</p>
   6: </else>
   7: <else>
   8:   <p>Hello - I know you.</p>
   9: </else>

There is also a test tag that is very similar and there are a few variations on the how you write the markup but that is the basic principle.  (Note: the single quote is converted to a double quote by Spark.) Another very cool way to handle conditionals is to put the if as part of the html tag.

   1: <p if="CartTotal < 75">
   2:     Get free shipping when you order more than $75 worth of our good stuff
   3: </p>

This p tag will only show up if the condition is met.  In addition, you can still use an else tag underneath the p tag with the if.

One other really neat trick is using conditional logic inside an attribute with a ?{ } syntax.

   1: <li class="listItem inStock?{item.Quantity > 0}">
   2:   ${item.Name}
   3: </li>

In the case above, the class attribute “inStock” will only appear when the Quantity is greater than zero.

Iteration Syntax

To be honest, the first thing I noticed when I looked at a Spark view was how iteration was handled.  It just looked elegant to me.  Like the Conditional Syntax, you can use separate tags for iteration or put the iteration right inside an existing tag.

   1: <for each="var movie in Movies">
   2:   <p>${movie.Title}</p>
   3: </for>
   4:  
   5: <table>
   6:   <tr each="var movie in Movies">
   7:     <td>${movie.Title}</td>
   8:     <td>${movie.Rating}</td>
   9:   </tr>
  10: </table>

ViewData

A lot of views will use ViewData of some type and while you can wrap your ViewData request in ${ } brackets, there is a better option.  With the viewdata tag, you can strongly type your variables in your view.

   1: <viewdata message="string" model="IEnumerable[[Movie]]" />

Note: Spark converts the [[ ]] to < >.  These double square brackets and the single quotes are the only Spark conversions I’m aware of at this point.

Inline Code

One of the really great parts of Spark is that you can continue to use your <% %> syntax if you need to or want to.  If you want to convert a page from aspx to spark.  Rename the file, take out your header and replace your ContentPlaceHolders.  The rest of your <% %> stuff should be fine.

In addition though, if you actually need some inline code, you can just proceed the line with a # character and it will be handled as inline code.  Again, I think it gives the markup a cleaner feel.

Conclusion

There is a lot more interesting pieces to dive into with Spark, but this is just meant to get you started.  If you are interested in more Spark syntax, configuration, or conventions you should check out the Spark documentation.

Exploring Spark View Engine for ASP.NET MVC – Part 2

In my last post, we took a very brief look at the syntax of Spark then dove right into getting setup to try it out.  If you have not looked at the first part of the series, that would be the best place to start.

In this post, we’re going to continue to look at the default project that I converted to use the Spark View Engine (instead of the default Web Forms view engine) and take a look at the syntax and some of the conventions.  (Download it here.)  Let’s start with a side by side look of the both the original View folder and my Spark version’s View folder.

Views-WebForms

ViewsFolder-Spark

You'll notice that the files look pretty much similar to the default application except the extensions have been changed from aspx to spark.  The exception of course is in the Shared folder, we no longer have a Site.Master file.  In its place, we have an Application.spark file and a _global.spark file.  I also added an underscore in front of the LogOnUserControl’s file name.  These change will be  discussed later in this article.

Basic Markup

If you take a look at a simple view, like the Home/Index.spark, you will notice a few difference from the Web Forms version.  First, the Page header line is no longer needed with spark.  In addition, the ContentPlaceHolders are gone.  In addition, there is only one content tagged area instead of the two in the original.

Original Home/Index.aspx:

   1: <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
   2:  
   3: <asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
   4:     Home Page
   5: </asp:Content>
   6:  
   7: <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
   8:     <h2><%= Html.Encode(ViewData["Message"]) %></h2>
   9:     <p>
  10:         To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
  11:     </p>
  12: </asp:Content>

 

My Spark Home/Index.spark:

   1: <content name="title">
   2:     Home Page
   3: </content>
   4:  
   5: <h2>${ViewData["Message"]}</h2>
   6: <p>
   7:     To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
   8: </p>

The loss of a ContentPlaceHolder is interesting.  Spark renders your view differently than Web Forms and one change is the the view will spool named content for placement and render any un-named content where the view is called in the master layout.

The spooling concept is very powerful and we will likely dig into this further in a future post.  For now, I’ll mention you can put your named content areas anywhere inside your view.  You may make multiple entries and they will be concatenated.  You can also set up default values in your Master Layout in case there is no matching named content area in the view you are rendering.

The other important change in these files in the displaying of the ViewData[“Message”].  In the original, it is wrapped in the alligator tags and encoded with Html.Encode().  In the spark version, it is simply wrapped with ${ }.  You might remember that I added some configuration that html encodes all output by default so that part is not needed.  The simple ${ } syntax represents code instead of the <% %>.  Any C# code can be put inside the brackets.

This should bring up the obvious question, what if I don’t want to encode the output?  In that case, you use an ! instead of a $.  When you want to have your output be html, like an Html.ActionLink function or an Html.TextBox function, you’ll need the !{ } syntax.  I really like this syntax as it allows me to be deliberate over what is encoded or not encoded with a single character.

Master Layouts

Now would be a good time to look at the master layouts of the original app and my Spark’s Application.spark.  This will let us see the rest of the Home page that gets rendered when we start up the application.

Original Shared/Site.Master:

   1: <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
   4: <html xmlns="http://www.w3.org/1999/xhtml">
   5: <head runat="server">
   6:     <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
   7:     <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
   8: </head>
   9:  
  10: <body>
  11:     <div class="page">
  12:  
  13:         <div id="header">
  14:             <div id="title">
  15:                 <h1>My MVC Application</h1>
  16:             </div>
  17:               
  18:             <div id="logindisplay">
  19:                 <% Html.RenderPartial("LogOnUserControl"); %>
  20:             </div> 
  21:             
  22:             <div id="menucontainer">
  23:             
  24:                 <ul id="menu">              
  25:                     <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
  26:                     <li><%= Html.ActionLink("About", "About", "Home")%></li>
  27:                 </ul>
  28:             
  29:             </div>
  30:         </div>
  31:  
  32:         <div id="main">
  33:             <asp:ContentPlaceHolder ID="MainContent" runat="server" />
  34:  
  35:             <div id="footer">
  36:             </div>
  37:         </div>
  38:     </div>
  39: </body>
  40: </html>

My Spark Shared/Application.spark:

   1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
   2: <html xmlns="http://www.w3.org/1999/xhtml">
   3: <head runat="server">
   4:     <title><use content="title">Default title</use></title>
   5:     <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
   6: </head>
   7:  
   8: <body>
   9:     <div class="page">
  10:  
  11:         <div id="header">
  12:             <div id="title">
  13:                 <h1>My MVC Application</h1>
  14:             </div>
  15:               
  16:             <div id="logindisplay">
  17:                 <LogOnUserControl />
  18:             </div> 
  19:             
  20:             <div id="menucontainer">
  21:             
  22:                 <ul id="menu">              
  23:                     <li>!{Html.ActionLink("Home", "Index", "Home")}</li>
  24:                     <li>!{Html.ActionLink("About", "About", "Home")}</li>
  25:                 </ul>
  26:             
  27:             </div>
  28:         </div>
  29:  
  30:         <div id="main">
  31:             <use content="view" />
  32:  
  33:             <div id="footer">
  34:             </div>
  35:         </div>
  36:     </div>
  37: </body>
  38: </html>

Comparing the two, we’ll notice that the header line is gone again.  Next, you’ll notice the first ContentPlaceHolder has been replaced with a <use content="title">Default title</use> section.  This is what looks for any spooled content named title.  The place between the tags is where I set a default information in the case there is no content named “title”.  If I didn’t want to add default information, I could have made my tag simply, <use content=”title” />.  While I’m in the header, I will state that you will want to use application based paths instead of relative paths, so I made this change as well.

As you look further down the file, you will come to a crazy looking tag, <LogOnUserControl />.  We’ll talk about this tag in a moment, but let’s continue to scan down the Application.spark first.  After the LogOnUserControl, you notice the use of the !{ } syntax wrapping the ActionLink functions and the <use content=”view” />.  This is where the named view is rendered with in the layout.

Partial Files

Now, let’s look again at that <LogOnUserControl /> tag.  This is simply a fancy way of displaying a partial file/view.  When you name a partial file so that it starts with an underscore, it can be used as its own tag.  The other syntax, if you prefer, would be <use file="_LogOnUserControl" />.  You need to use that syntax is the file does not start with an underscore.

The code for the partial file is exactly what you’d expect, just a snippet of html and code markup.  No special headers are needed.  The code for the LogOnUserControl was actually shown in part 1 of this series so I won’t go back to it now.

This would also be a good time to look at the last piece of the puzzle, the _global.spark file.  It is simply another partial file, but it has a special function.  _global.spark is automatically imported into every single view that is compiled from the location it exists in.  Since I have placed this one in the Shared folder, it will effect every view compiled.  (If you had some specific globals you’d want in just the Home Controller views for example, you could put a _global.spark in the Home view folder.

In my _global.spark, I simply am declaring some namespaces.  By default, the HtmlHelpers, for example, are not available without their full namepace included.  I included a bunch of namespaces that I may want someday, but really only needed System.Web.Mvc.Html.  You declare namespaces in spark like so:

<use namespace="System.Web.Mvc.Html" />

In the next part of the series, we’ll look at more of the Spark syntax including conditionals and iteration.

Recent Comments