Comments on Doc Comments

I was reviewing some VBA code over at Code Review Stack Exchange the other day and it got me to thinking about comments. The code wasn’t too bad, but there were so many comments in the code that, well…

I just read over this again and I think the fact that I mention the comments so often really highlights the issue. I barely even looked at the code because I was too distracted by all the comments.

To be clear, the comments I’m referring to were document style “header” comments and left over cruft from a pseudo-code first style of development. Comments like this were before each and every method in the module.

'/======================================================================================================================================================
'/  Author:  Zak Armstrong
'/  Email:   zak.armstrong@company.co.uk
'/  Date:    12/August/2015
'/  Version: 0.2
'/
'/  Is Called By:   None
'/
'/  Calls:          Open_Workbooks
'/                  Initialise_Worksheets
'/                  Initialise_Collections_And_MetricHeadings
'/                  Initialise_Providers_And_Advisers
'/                  Insert_arrAscentric_LifeCo_Column
'/
'/                  Sheet_Data_To_Array
'/                  Filter_Sheet_Arrays
'/                  Aggregate_Sheet_Data
'/
'/                  Allocate_Business
'/
'/                  Print_Adviser_Report
'/                  Print_Provider_Report
'/
'/  Description:    All Company Wealth Business is contained in the Subsheet. This macro produces adviser totals for business (assets and fees) in the previous year
'/                  (month by month breakdown) by aggregating the subsheet into one giant table and then assigning each piece of business to an adviser, a Month and a business type.
'/                  The report can then be easily configured for any desired outputs (E.G. by adviser, by provider, by type of business)
'/
'/  Change Log:     | Author            | Date          | Description of Changes
'/                  -----------------------------------------------------------------------------------------------------------------------------------
'/                  |Zak armstrong      | 12.08.2015    | Started v0.2 from scratch. Major difference: now aggregating all subsheet data first and
'/                  |                   |               | only then allocating each piece of business.
'/                  |                   |               |
'/                  |                   | 14.08.2015    | "Finished" Writing Macro. Had succesful test run.
'/                  |                   |               |
'/                  |                   | 17.08.2015    | Reviewed all code, replaced a lot of hard-coded references (e.g. specific position numbers) with
'/                  |                   |               | dynamically generated ones. Re-structured main allocation sub.
'/                  |                   |               |
'/                  |                   | 18.08.2015    | Finished Writing Format_Adviser_Report, Format_Provider_Report, restructured macros from 1 module to 3.
'/                  |                   |               |
'/                  |                   | 19.08.2015    | Double-Checked Code, Slight re-structuring/obfuscation before posting to Code Review (Stack Exchange)
'/                  |                   |               |
'/======================================================================================================================================================

The important pieces got lost because there was just too much there to sift through. The second problem is that, because there was one of these at the top of every method, it was hard to see the code from 30,000 feet up and get an overview of what it does. That’s a problem that could just as easily show up in C#, and I see it too often.

    public interface IMergeView
    {
        /// <summary>
        /// Returns a boolean value indicating if the OKButton is enabled.
        /// </summary>
        /// <returns>Boolean</returns>
        /// <example><code>view.OkButtonEnabled = true;</code></example>
        bool OkButtonEnabled { get; set; }

        /// <summary>
        /// List of Strings that populate the source selector.
        /// </summary>
        /// <returns><see>
        ///         <cref>IList{string}</cref>
        ///     </see>
        /// </returns>
        IList<string> SourceSelectorData { get; set; }

        /// <summary>
        /// List of Strings that populate the destination selector.
        /// </summary>
        /// <returns><see>
        ///         <cref>IList{string}</cref>
        ///     </see>
        /// </returns>
        IList<string> DestinationSelectorData { get; set; }

XML doc comments are great. I love the information that they provide to intellisense, but far too often, they just repeat what the code already says. When they do that, they’re just getting in the way, breaking our concentration. The example above provides no additional information. We already know what they do because they have meaningful names. Adding this extra cruft just gets in our way.

I’m not trashing on doc comments though. They really are a great thing to have. We just need to be sure that we’re using them for the right things in the right places. For example, this gem was buried in that VBA header comment.

'/  Description:    All Company Wealth Business is contained in the Subsheet. This macro produces adviser totals for business (assets and fees) in the previous year
'/                  (month by month breakdown) by aggregating the subsheet into one giant table and then assigning each piece of business to an adviser, a Month and a business type.
'/                  The report can then be easily configured for any desired outputs (E.G. by adviser, by provider, by type of business)

This is a good header comment. It says why and how instead of who and what. It provides valuable information to the maintainer of the code. Unfortunately, it was buried inside this monolithic comment block at the top of the method. This should have been the entire doc comment. This and nothing more. Heck, I might have even put this into a Description Attribute.

So what about our C# XML doc comments? I asked some developer friends of mine for their perspective on doc comments and I got some really interesting answers.

This is one of the things I do still like about Objective-C over Swift. Because you only really need doc comments in/on the public stuff, and in Objective-C, the public stuff is in the .h. And your actual implementation is in the .m.

Nick Griffith – author of importBlogKit

[It’s] best is to code against interfaces, and xml-doc the interface, leaving the code uncluttered.

Mathieu Guindon – Co-Owner/Developer of Rubberduck

I think this is wonderful advice. Documenting the interface keeps all of the clutter out of the implementation. We haven’t really talked about what to document yet though. We briefly touched on the fact that I don’t think doc comments should simply repeat the code, so what should they say? Nick had this gem to add.

If there is any weird behavior, you can document it. And if you don’t document any weird behavior, you have documented that there shouldn’t be any weird behavior.

Right! We document anything that isn’t obvious. Just like any other comment in our code. We don’t comment the obvious in our implementation, we shouldn’t comment the obvious in our documentation either. Keep it simple, keep it clean. Here’s an example of what I consider to be good doc comments.

    /// <summary>
    /// Stores user name and password credentials.
    /// </summary>
    /// <remarks>
    /// Do no use internally. For COM Interop only. Use <see cref="SecureCredentials"/> instead./>
    /// </remarks>
    public class Credentials : CredentialsBase<string>
    {
        /// <exception cref="NullReferenceException">If either argument is null, an exception is thrown.</exception>
        public Credentials(string username, string password)
            :base(username, password)
        { }
    }

    /// <summary>
    /// Securely stores user name and password credentials.
    /// </summary>
    public class SecureCredentials : CredentialsBase<SecureString>
    {
        /// <exception cref="NullReferenceException">If either argument is null, an exception is thrown.</exception>
        public SecureCredentials(string username, SecureString password)
            : base(username, password)
        { }
    }

It’s minimal. It gives you a high level overview at the class level and only documents the “weird” parts. In this case, one class isn’t to be used internally, but exists only to expose to COM clients. That’s important information to have when you’re looking at available options in your intellisense.

Another thing to look out for is assumptions about the state of the object when a particular method is called, or the range of it’s parameters. Possible exceptions and runtime errors are also a great thing to see. It lets people consuming your API know what exceptional situations they might need to handle. In .Net, there’s even a comment tag specifically for exceptions.

Before I ramble on too much, let’s sum this up.

  • Be concise. If you ramble too much, nobody listens. (Take this blog post for instance.)
  • Don’t repeat what the code already says.
  • Document the why and how, not the who and what.
  • Document the unordinary and potentially surprising.
  • Use a form of documentation that will show up in intellisense. (i.e. don’t use Doxygen for .Net code. Sure, the documents are pretty, but it doesn’t show up in intellisense.)
  • Stay out of the way of your code. Document the public interface, not the implementation. If your documentation is getting in the way, consider using included document files instead.
  • Document possible exceptional behavior that may need to be handled by the client.

, , , , , ,

Leave a comment

That’s not real experience

I recently had a pretty big change in my life. My company went through an internal reorganization. I was left with a choice of moving my family a few hundred miles or finding new work. Since the prior wasn’t really an option for us, I took the opportunity to make a career move. 

Now was as good a time as any. Luckily, I didn’t have too much trouble finding a replacement job, but finding it was quite an experience. It turns out that nobody is interested in hiring a VB6 developer these days, and if they are, they want to make your job title “Excel Analyst” and severely underpay you. Seriously people, a good VBA dev is worth their weight in gold compared to all the people writing spaghetti with the macro recorder. Find a real programmer and pay them what they’re worth. You may spend more now, but it will save you tremendously in maintenance costs. But I digress…

VB6 was replaced by .Net twelve years ago, so I was looking to move on from VBA development and (professionally) into .Net development anyway. Getting my foot in the door without any professional .Net experience turned out to be quite a task though. I can’t tell you how many times I heard a recruiter or HR screener say, “But where is your .Net experience. All I see is this open source project. Don’t you have any real experience?” Even now, months later, that statement makes my blood boil. Let me tell you folks, experience writing open source software is real experience. The last time I checked, Rubberduck was at over 35,000 lines of code excluding the ANTLR generated code. It’s as large and complex as any CRUD app I’ve created in 5 years of professional software development, if not more so. Open source development teaches you more than just code though. It teaches you a number of other things as well. 

  • How to effectively work with source control and a remote team. 
  • Customer Service / Help Desk 
  • Project and feature management. 
  • How to determine which tasks will be accomplished in a sprint. 
  • How to configure a build server for automated testing. 
  • How to effectively document

The list goes on, at least if you’re doing it right. 

The funny thing is, once my resume got past these clowns and in front of other developers, finding work was easy. Other programmers already understand that open source experience is real development experience. They understand that not only do you have to write the code, but you have to architect and design the system too. Plus they get a chance to see your work, up front, before they ever meet you. Outside of visual design type work, I can’t think of another field where this is possible. That’s all without mention of the passion it takes to do what you do as a job for a hobby. If you’re hiring right now, do yourself a favor and let your HR people know how you feel about open source projects on resumes. Otherwise, you’ll never even know that you’re filtering out great candidates. 

There were some other priceless gems from the job search too. One place I applied to was looking for a SQL/ETL dev. 

Can you send us some code from your current employer?

No. I cannot. Even if I wasn’t contractually bound by a non-disclosure agreement, I will not send you code I was paid to write for somebody else. However, thank you for letting me know about the level of ethics at your company and that I don’t want to work for you. 

Here’s another great conversation I had with a senior developer at a firm. I had just finished answering the question “What is Dependency Injection?”

Him: So what IoC container are you using?

Me: I’m not. 

Him: What do you mean you’re not? How are you doing dependency injection without an inversion of control container?!

Me: I’m just using Pure (poor man’s) DI. You don’t need an IoC container to inject dependencies into a class. At this point, there’s no need for the overhead of framework. 

Him (stunned): But… How can you do DI without an IoC?! 

I’m still shaking my head over that one. Here was this “senior” dev who had no clue what dependency injection really is and couldn’t wrap his head around the fact that you don’t need a fancy framework to do it. Don’t get me wrong, they’re great and we’re moving Rubberduck to the Ninject framework for our DI, but you don’t need it. Again, thank you for letting me know that I don’t want to work for you. 

Finally I found a great company and had a fantastic interview. We just sat around talking about code for a few hours. They asked about my VB6/VBA experience, even though they were hiring a .Net developer, because they realized that a good programmer can do it in any language. They asked about my open source project. We talked about OOP and different design pattern (and anti-patterns). They admitted that the legacy code base was awful and in need of some serious love. The whole experience was laid back and honest. Today, even though the legacy code base truly is terrible to work with, I love working there because the people are fantastic to work with. 

So, to all of the people who tossed my resume because open source experience isn’t real experience and the people who decided that I suddenly couldn’t telecommute after 3 years of working that way, I’m sorry. You’ve missed out on working with a smart, passionate developer. I’ll be here turning spaghetti into something to be proud of for the foreseeable future. 

And I couldn’t be happier about it. 

Leave a comment

VBA and Git the Sequel: This Time it’s Integrated

I’ve talked before about using Git with VBA and also about the importance of using source control and other tools for our work. Truthfully though, using source control with VBA is still hard. This is mostly because getting the code modules into and out of the VB Project is hard, and harder to do right. Well, you may have heard that there’s a new duck in town. It’s taken me about 6 months of spare time, but Rubberduck v1.4 not only has a source control COM library that you can use right in VBA to work with Git VBA repositories, but you can also now branch, commit, pull, push, and merge right from inside of the editor.

Read the rest of this entry »

, , , , , ,

2 Comments

Mocking the VBA Editor: Moq an IEnumerable that Works with Linq

It’s been a rough morning here. I’ve just spent six hours trying to properly create a mock for the VBProject interface. There’s very little information out there about this, so I thought I’d take a moment to jot this down and save someone else the headache. For all the grief this gave me, the solution is amazing simple.

Read the rest of this entry »

, , , , , , , , , ,

6 Comments

Using Hampers Testing: Enter the Factory

I’ve been writing a lot of C# lately, and paying a lot of attention to my test coverage while I’m at it. Everything was going great until I wanted to use the FolderDialogBrowser to let my users select a directory.

FolderDialogBrowser implements IDisposable, so I naturally reached for a Using block.

using (var folderPicker = new FolderBrowserDialog)
{
    if (folderPicker.ShowDialog() != DialogResult.OK)
    {
        return;
    }

    //...
}

Then I stopped dead. I can’t do that. This will display a GUI and any hope of running automated tests against this method is lost. Read the rest of this entry »

, , , , , , , , , , ,

Leave a comment

What’s Up Duck?

I’ve been promising you an update on my pet project, Rubberduck, for quite some time now. I apologize for taking so long to get around to it. Both the project and this blog tend to come last in the grand scheme of my life, so it sometimes takes me some time to get around to things. I’m afraid that may be more or less the theme of this post.

Read the rest of this entry »

, , , , ,

Leave a comment

Iterate over a date range in VBA

After years of VBA development, I’m still learning about the language every day. I was absolutely surprised when I tried this today. You can iterate over a date range just like you can iterate over a range of integers.

Public Sub LoopOverDateRange()
    
    Const startDate As Date = #5/13/2015#
    Const endDate As Date = #5/20/2015#
    
    Dim d As Date
    Dim i As Integer
    i = 1
    For d = startDate To endDate
        Debug.Print "Iteration " & i & ":" & vbTab & d
        i = i + 1
    Next
    
End Sub

This code will result in the following output.

Iteration 1:    5/13/2015
Iteration 2:    5/14/2015
Iteration 3:    5/15/2015
Iteration 4:    5/16/2015
Iteration 5:    5/17/2015
Iteration 6:    5/18/2015
Iteration 7:    5/19/2015
Iteration 8:    5/20/2015

Enjoy!

, ,

2 Comments

Capturing A Stored Procedure’s Return Value in VBA

Christopher J. McClellan:

Nice little primer on accessing stored procedure return values through ADODB in VBA.

Originally posted on Ramblings:

Those of you who have ever done any serious programming with SQL Server stored procedures will know that they return an integer value to their caller on completion. The default value is ‘0’, which indicates success, and any other value indicates a failure at some stage in its processing. VBA has the power to capture these return values through the ADODB.Command object but, in order to do so, there are a few points you should consider.

1. Invoke Parameters.Refresh before Execute.
2. Specify adCmdStoredProc as the CommandType.
3. Specify an OLE DB provider but don't use MSDASQL.
4. If the Stored Procedure consists of more than one statement (most do) make sure it starts with SET NOCOUNT ON.
5. Poke/prod any returned, open recordset before examining the Return Value.
6. Use a TRY..CATCH block in your Stored Procedure to handle exceptions.
7. Use additional error handling in your VBA code.

View original 1,012 more words

Leave a comment

What is SQL, PL/SQL, T-SQL and difference between them

Christopher J. McClellan:

A brief history of SQL.

Originally posted on SQL with Manoj:

Today I got an email from a student who is pursuing his Bachelors degree in Computer Application (BCA). He visited my blog and sent me an email regarding his confusion with terms like SQL, T-SQL, PL/SQL, and asked me what is differences between them and how are they related? I had a chat with him and told the basic differences, but he further asked me how they are related to Microsoft SQL Server, Oracle, MySQL, etc? As he is studying SQL only based upon Oracle in his course curriculum, these all terms were not clear to him, so I cleared all his doubts while chatting with him.

After a while I had a same reminiscence that when I was a student I also had these doubts and confusions, and there was nobody to guide me, but I gradually came to know about this and it took some…

View original 728 more words

Leave a comment

JDA Focus 2015

I don’t normally write about my work here, but I just spent the last week in sunny Orlando, FL at JDA Software’s Focus conference. I figured I might as well sum up the experience here before its all over and begins to fade.

For those of you not familiar with JDA, they’re a software company who has a range of products spanning the entire supply chain from manufacturer right down to actually placing the product on the shelf. My work brings me into the macro and micro space planning realms. Or rather, I support the people  in my company who use the Floor Planning and Space Planning software.  This involves automating that software and interacting with JDA’s database product.

Read the rest of this entry »

, ,

Leave a comment

Follow

Get every new post delivered to your Inbox.

Join 330 other followers