SubMain - CodeIt.Right The First Time!

/Community

Support Community for SubMain Products
 Home Products Services Download Purchase Support
in Search
 
Home Forums Blogs Tutorials/CIR Tutorials/GD Downloads
Welcome to SubMain Community Sign in | Join | Help

SubMain Blog

February 2017 - Posts

  • Add Custom Content to Your Help Documentation

    For the last several years, I've made more and more of my living via entrepreneurial pursuits.  I started my career as a software developer and then worked my way along that career path before leaving fulltime employment to do my own thing.  These days, I consult, but I also make training content, write books, and offer productized services.

    When you start to sell things yourself, you come to appreciate the value of marketing.  As a techie, this feels a little weird to say, but here we are.  When you have something of value to offer, marketing helps you make interested parties aware of your offer.  I think you'd like this and find it worth your money, if you gave it a shot.

    In pursuit of marketing, you can use all manner of techniques.  But today, I'll focus on a subtle one that involves generating a good reputation with those who do buy your products.  I want to talk about making good documentation.

    The Marketing Importance of Documentation

    This probably seems an odd choice for a marketing discussion.  After all, most of us think of marketing as what we do before a purchase to convince customers to make that purchase.  But repeat business from customer loyalty counts for a lot.  Your loyal customers provide recurring revenue and, if they love their experience, they may evangelize for your brand.

    Providing really great documentation makes an incredible difference for your product.  I say this because it can mean the difference between frustration and quick, easy wins for your user base.  And, from a marketing perspective, which do you think makes them more likely to evangelize?  Put yourself in their shoes.  Would you recommend something hard to figure out?

    For a product with software developers as an end user, software documentation can really go a long way.  And with something like GhostDoc's "build help documentation" feature, you can notch this victory quite easily.  But the fact that you can generate that documentation isn't what I want to talk about today, specifically.

    Instead, I want to talk about going the extra mile by customizing it.

    Introducing "Conceptual Content"

    You can easily generate documentation for your API with the click of a button.  But you can also do a lot more.

    GhostDoc Enterprise features something called "Conceptual Content."  Basically, it allows you to customize and add on to what the engine generates using your code and XML doc comments.  This comes in handy in ways limited only by your imagination, but here are some ideas.

    • A welcome page.
    • A support page.
    • A "what's new" page.
    • Including a EULA/license.
    • Custom branding.

    You probably get the idea.  If you already look to provide documentation for your users, you no doubt have some good additional thoughts for what they might value.  Today, I'm going to show you the simplest way to get going with conceptual content so that you can execute on these ideas of yours.

    How It Works at a High Level

    For GhostDoc to work its documentation-generating magic, it creates a file in your solution directory named after your solution.  For instance, with my ChessTDD solution, it generates a file called "ChessTDD.sln.GhostDoc.xml."  If you crack open this file, you will see settings mirroring the ones you select in Visual Studio when using GhostDoc's "Build Help Documentation."

    To get this going, we face the task of basically telling this file about custom content that we will create.  First, close out of Visual Studio, and let's get to work hacking at this thing a bit.  We're going to add a simple, text-based welcome page to the standard help documentation.  To do this, we need the following things.

    • Modifications to the GhostDoc XML file.
    • The addition of a "content" file describing our custom content,
    • Addition of a "content" folder containing the AML files that make up the actual, custom pages.

    Let's get started.

    The Nuts and Bolts

    First, open up the main GhostDoc XML file and look for the "ConceptualContent" section.  It looks like this.

    <ConceptualContent> <ContentLayout /> <MediaContent /> </ConceptualContent>

    In essence, this says, "no conceptual content here."  We need to change that.  So, replace the empty ContentLayout entry with this (substituting the name of your solution for "ChessTDD" if you want to follow along with your own instead of my ChessTDD code.)

    <ContentLayout file="ChessTDD.content" folder="Content\" />

    Next up, you need to create the file you just told it about, ChessTDD.content.  This file goes in the same directory as your solution and looks like this.

    <?xml version="1.0"
    encoding="utf-8"?> <Topics> <Topic id="4684cc2f-3179-4871-b7a4-ad69f0f260a3" visible="True" isDefault="true" title="Welcome"> <HelpKeywords> <HelpKeyword index="K" term="Welcome" /> </HelpKeywords> </Topic> </Topics>

    For the ID, I simply generated a GUI using this site.  This ID simply needs to be unique, and to match the next file that we'll create.  Next up, create the folder you told ContentLayout about called, "Content."  Then add the file Welcome.aml to that folder, with the following text.

    <?xml version="1.0"
    encoding="utf-8"?> <topic id="4684cc2f-3179-4871-b7a4-ad69f0f260a3" revisionNumber="1"> <developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink"> <introduction> <para>Welcome
    to our help section!</para> </introduction> </developerConceptualDocument> </topic>

    Notice that we use the same GUID here as in the content file.  We do this in order to link the two.

    Let's Give it a Whirl

    With your marked up Ghost Doc XML file, the new content file, and the new Content folder and welcome AML file, you can now re-launch Visual Studio.  Open the solution and navigate through GhostDoc to generate the help documentation CHM file.

    blog-custom-content-help-docs

    There you have it.  Now you can quickly add a page to the automatically generated help documentation.

    Keep in mind that I did the absolute, dead simplest possible thing I could do for demonstration purposes.  You can do much more.  For example:

    • Adding images/media to the pages.
    • Have cross-links in there for reference.
    • Add snippets and examples.
    • Build lists and tables.

    As I said earlier, you'll no doubt think of all manner of things to please your user base with this documentation.  I suggest getting in there, making it your own, and leaving a nice, personal touch on things for them.  When it comes to providing a good user experience, a little can go a long way.

    Related resources


    Learn how GhostDoc can help to simplify your XML Comments, produce and maintain quality help documentation.

    About the Author

    Erik Dietrich

    I'm a passionate software developer and active blogger. Read about me at my site. View all posts by Erik Dietrich

  • CodeIt.Right Rules Explained, Part 3

    In what has become a series of posts, I have been explaining some CodeIt.Right rules in depth.  As with the last post in the series, I'll start off by citing two rules that I, personally, follow when it comes to static code analysis.

    • Never implement a suggested fix without knowing what makes it a fix.
    • Never ignore a suggested fix without understanding what makes it a fix.

    It may seem as though I'm playing rhetorical games here.  After all, I could simply say, "learn the reasoning behind all suggested fixes."  But I want to underscore the decision you face when confronted with static analysis feedback.  In all cases, you must actively choose to ignore the feedback or address it.  And for both options, you need to understand the logic behind the suggestion.

    In that spirit, I'm going to offer up explanations for three more CodeIt.Right rules today.

    Use Constants Where Appropriate

    First up, let's consider the admonition to "use constants where appropriate."  Consider this code that I lifted from a Github project I worked on once.

    blog-codeitright-rules-part3-1

    I received this warning on the first two lines of code for this class.  Specifically, CodeIt.Right objects to my usage of static readonly string. If I let CodeIt.Right fix the issue for me, I wind up with the following code.

    blog-codeitright-rules-part3-2

    Now, CodeIt.Right seems happy.  So, what gives?  Why does this matter?

    I'll offer you the release notes of the version where CodeIt.Right introduced this rule.  If you look at the parenthetical next to the rule, you will see "performance."  This preference has something to do with code performance.  So, let's get specific.

    When you declare a variable using const or static readonly, think in terms of magic values and their elimination.  For instance, imagine my UserAgentKey value.  Why do you think I declare that the way I did?  I did it to name that string, rather than using it inline as a "magic" string. 

    As a maintenance programmer, how frustrating do you find stumbling across lines of code like, "if(x == 299)"?  "What is 299, and why do we care?!"

    So you introduce a variable (or, preferably, a constant) to document your intent.  In the made-up hypothetical, you might then have "if(x == MaximumCountBeforeRetry)".  Now you can easily understand what the value means.

    Either way of declaring this (constant or static, readonly field) serves the replacement purpose.  In both cases, I replace a magic value with a more readable, named one.  But in the case of static readonly, I replace it with a variable, and in the case of const, I replace it with, well, a const.

    From a performance perspective, this matters.  You can think of a declaration of const as simply hard-coding a value, but without the magic.  So, when I switch to const, in my declaration, the compiler replaces every version of UserAgentKey with the string literal "user-agent".  After compilation, you can't tell whether I used a const or just hard-coded it everywhere.

    But with a static readonly declaration, it remains a variable, even when you use it like a constant.  It thus incurs the relative overhead penalty of performing a variable lookup at runtime.  For this reason, CodeIt.Right steers you toward considering making this a constant.

    Parameter Names Should Match Base Declaration

    For the next rule, let's return to the Github scraper project from the last example.  I'll show you two snippets of code.  The first comes from an interface definition and the second from a class implementing that interface.  Pay specific attention to the method, GetRepoSearchResults.

    blog-codeitright-rules-part3-3

    blog-codeitright-rules-part3-4

    If you take a look at the parameter names, it probably won't surprise you to see that they do not match.  Therein lies the problem that CodeIt.Right has with my code.  It wants the implementing class to match the interface definition (i.e. the "base").  But why?

    In this case, we have a fairly simple answer.  Having different names for the conceptually same method creates confusion. 

    Specifically, maintainers will struggle to understand whether you meant to override or overload the method.  In our mind's eyes, identical method signatures signals polymorphic approaches, while same name, different parameters signals overload.  In a sense, changing the name of a variable fakes maintenance programmers out.

    Do Not Declare Externally Visible Instance Fields

    I don't believe we need a screenshot for this one.  Consider the following trivial code snippet.

    public class SomeClass
    { public string _someVariable;
    }

    This warning says, "don't do that."  More specifically, don't declare an instance field with external (to the type) visibility.  The question is, "why not?"

    If you check out the Microsoft guidance on the subject, they explain that, the "use of a field should be as an implementation detail."  In other words, they contend that you violate encapsulation by exposing fields.  Instead, they say, you should expose this via a property (which simply offers syntactic sugar over a method).

    Instead of continuing with abstract concepts, I'll offer a concrete example.  Imagine that you want to model a family and you declare an integer field called _numberOfChildren. That works fine initially, but eventually you encounter the conceptually weird edge case where someone tries to define a family with -1 children.  With an integer field, you can technically do this, but you want to prevent that from happening.

    With clients of your class directly accessing and setting this field, you wind up having to go install this guard logic literally everywhere your clients interact with the field.  But had you hidden the field behind a property, you could simply add logic to the property setter wherein you throw an exception on an attempt to set a negative value.

    This rule attempts to help you future-proof your code and follow good OO practice.

    Until Next Time

    Somewhat by coincidence, this post focused heavily on the C# flavor of object-oriented programming.  We looked at constants versus field access, but then focused on polymorphism and encapsulation.

    I mention this because I find it interesting to see where static analyzers take you.  Follow along for the rest of the series and, hopefully, you'll learn various useful nuggets about the language you use.

    Learn more how CodeIt.Right can help you automate code reviews and improve your code quality.

    About the Author

    Erik Dietrich

    I'm a passionate software developer and active blogger. Read about me at my site. View all posts by Erik Dietrich

  • GhostDoc Says the Damndest Things

    Editorial note: most of the GhostDoc bloopers below are a history, but they provide for a good laugh. We encourage you to share the GhostDoc goofs you have encountered – they are great for entertainment as well as give us a chance to improve the product.

    Some years ago, I was doing work for some client or another.  Honestly, I have no recollections of specifics with the exception of a preference for exhaustive commenting.  Every class, every method, every property, and every field.

    Of course, I didn't learn this at first.  I didn't even learn it in a reasonable time frame.  Instead, I learned it close to handover time.  And so things got a little desperate.

    Enter GhostDoc, My Salvation

    Now, depending on your perspective, you might scold me for not diligently commenting all along.  I will offer the explanation that the code had no public component and no intended APIs or extensions.  It also required no "why" types of explanations; this was simple stuff.

    The client cited policy.  "We comment everything, and we're taking over this code, so we want you to do the same."  Okie Dokie.

    Now, I knew that in a world of code generation and T4 templates, someone must have invented a tool that would generate some sort of comments or another.  At the time, a quick Google search brought me to a saving grace: the free tool GhostDoc.

    While it did not allow me to carpet bomb my code with comments in a single click (and understandably so), it did allow me to do it for entire files at a time.  Good enough.  I paid my non-commenting penance by spending an hour or so commenting this way.

    And do you know what?  It generated pretty respectable comments.  I recall feeling impressed because I expected empty template comments.  Instead, GhostDoc figured out how to string some verbs and nouns together.

    But It's Not All Roses

    Let me get specific about capabilities and limitations.  Had I tried to generate documentation for my Chess TDD codebases's MovePiece method, GhostDoc would have treated me to this comment.

    /// <summary> /// Moves
    the piece. /// </summary> /// <param
    name="origin">The origin.</param> /// <param
    name="destination">The destination.</param> public void MovePiece(BoardCoordinate
    origin, BoardCoordinate destination) { VerifyCoordinatesOrThrow(origin, destination); var pieceToMove = GetPiece(origin);
    AddPiece(pieceToMove, destination); RemovePiece(origin); pieceToMove.HasMoved = true;
    ReconcileEnPassant(origin, destination, pieceToMove); }

    See what I mean?  I did a pretty good job with clear naming in this method, and GhostDoc rewarded me with a method header that stands on its own.  MovePiece() moves the piece.  Specifically, it moves the origin to the destination.  Not too shabby!

    But what about less intuitive naming structures?  Well, sometimes, things can get weird.

    Do you know there was a Visual Studio addon that generated comments from method names? I once inherited a project full of these. pic.twitter.com/fuFjZjz4LJ

    — Dan Abramov (@dan_abramov) December 15, 2016

    Yes, that's right.  The ubiquitous "main" method for a C# application "mains the args."

    What Else?

    Okay, that ought to furnish a chuckle.  But now that you see the issue, you can probably start to imagine all manner of ways to flummox the poor tool.  (As an aside, you can probably also understand why they want to force you to pay more attention to the generated comments than just saying "generate comments for the whole solution.")

    What do you think used to happen back then for a no-op method that you named "DoNothing?"  You'd get "Does the Nothing."  Good work on conjugation, but still missing the intent.  How about an event handler called "AfterInsert?"  That's right.  "Afters the Insert."  And "TaskComplete?"  "Tasks the completed."  Now, here's a tougher one: "OnClose."  You probably weren't expecting "Oncloses the instance."

    Of course, other idiomatic programming concerns also befuddled the tool in different ways.

    • ToModel() --> "Toes the model."
    • ToTitleCase() --> "Toes the title case."
    • ToComment() -> "Automatics the comment"
    • ForgetPassword() --> "Forgets password"
    • SignOut() --> "Signs the out"

    Or how about

    Historically, you could make GhostDoc generate some pretty hilarious comments.  This means that if you simply generated the comments and paid no further attention, you might look pretty absurd to someone auditing commit history.  Fortunately, my oversight of the generated comments saved me from that fate.

    Laugh at the Tool?

    So should you laugh at GhostDoc?  Well, sure.  These comments are funny, and everyone ought to have a sense of humor.

    But on a deeper level, no, not really.  Natural language processing presents a difficult problem.  Imagine yourself writing code to process class, method, and variable names.  At first, you might thing it easy.  But then you'd hit things like "ToString()" and "TaskComplete()."  As a human and programmer, you understand these nuances.  But how do you make your code do the same?

    Oh, sure, you can hard-code some overrides for unique situations.  But that will quickly become cumbersome.  As you can see, you have a hard problem on your hands.

    What You Can Do

    What should you do, then, as a user of GhostDoc?  Well, first and foremost, don't just mindlessly generate comments.  At the bare minimum, do what I did.  Mindlessly generate comments, but also look to make sure that they make sense, correcting any that don't.

    But, beyond that, use GhostDoc as a starting point for meaningful communication.  Generate XML doc comments only when doing so to communicate with someone, either via code comments or IntelliSense/help documentation.  And when you do that, understand that GhostDoc simply offers you an intelligent starting point.  The tool does not purport to replace you as a programmer or a communicator of your intent.  It just gets you started.

    Improving the Situation

    Of course, GhostDoc has improved over the years.  For instance, if I write a ToString() method and generate, it no longer offers me a "toes the string."  Instead, it does this.

    /// <summary> /// Returns
    a <see cref="System.String" /> that
    represents this instance. /// </summary> /// <returns>A <see
    cref="System.String" /> that represents this
    instance.</returns> public string ToString()
    { return "I'm
    a board.";
    }

    Now, GhostDoc actually does something pretty sophisticated.  It figures out that ToString() has a special place in the language and adapts accordingly, explaining that place with a marked-up comment.

    Similarly, if you try to reproduce some of the shenanigans I detailed above, you will receive less obtuse results.  The people working on the GhostDoc codebase are constantly seeking to improve the quality of the generated comments, even if they only serve as a starting point.  But they could always use some help, so here is what I propose.

    Luckily, there is a Summary Override feature in GhostDoc, and you should use it to improve the future generated comments once you find a new blooper.

    Write in or comment with funny or weird things that you can get GhostDoc to produce when you generate documentation.  Seriously.  It'll give you, me, the readership, and the tool authors a good laugh.  But it will also bring deficiencies to their attention, allowing them to address, correct, and improve.  So go ahead.  What are your favorite GhostDoc bloopers?

    Learn more about how GhostDoc can help simplify your XML Comments, produce and maintain quality help documentation.

    About the Author

    Erik Dietrich

    I'm a passionate software developer and active blogger. Read about me at my site. View all posts by Erik Dietrich

  • You Can Use GhostDoc's Document This with JavaScript

    If you haven't lived in a techie cave the last 10 years, you've probably noticed JavaScript's rise to prominence.  Actually, forget prominence.  JavaScript has risen to command consideration as today's lingua franca of modern software development.

    I find it sort of surreal to contemplate that, given my own backstory.  Years (okay, almost 2 decades) ago, I cut my teeth with C and C++.  From there, I branched out to Java, C#, Visual Basic, PHP, and some others I'm probably forgetting.  Generally speaking, I came of age during the heyday of object oriented programming.

    Oh, sure I had awareness of other paradigms.  In college, I had dabbled with (at the time) the esoteric concept of functional programming.  And I supplemented "real" programming work with scripts as needed to get stuff done.  But object-oriented languages gave us the real engine that drove serious work.

    JavaScript fell into the "scripting" category for me, when I first encountered it, probably around 2001 or 2002.  It and something called VBScript competed for the crown of "how to do weird stuff in the browser, half-baked hacky languages."  JavaScript one that battle and cemented itself in my mind as "the thing to do when you want an alert box in the browser."

    Even as it has risen to prominence and inspired a generation of developers, I suppose I've never really shed my original baggage with it.  While I conceptually understand its role as "assembly language of the web," I have a hard time not seeing the language that was written in 10 days and named to deliberately confuse people.

    GhostDoc, Help, and IntelliSence

    I lead with all of this to help you understand the lens through which to read this post.  As a product of the strongly typed, object-oriented wave of programmers, my subconscious still regards JavaScript as something of an afterthought, its dominance notwithstanding.  And so when I see advances in the JavaScript world, I tend to think, "Oh, cool, you can do that with JavaScript too!"

    I'll come back to that shortly.  But first, I'd like to remind you of a prominent GhostDoc feature.  Specifically, I'm referring to the "Document This" capability.  With your cursor inside of a method or type, you can use this capability to generate instant, well-formatted, XML doc comments.  Thoroughly documented code sits just a "Ctrl-Shift-D" away.

    If you work with C# a lot and generate public APIs and/or help documentation, you will love this capability.  It doesn't absolve you of needing to add specific contest.  But it does give you a thorough base upon which to build.  For example, consider this method from my ChessTDD example codebase.

    /// <summary> /// Gets
    the moves from. /// </summary> /// <param
    name="startingLocation">The starting location.</param> /// <param
    name="boardSize">Size of the board.</param> /// <returns>IEnumerable&lt;BoardCoordinate&gt;.</returns> public override IEnumerable<BoardCoordinate> GetMovesFrom(BoardCoordinate
    startingLocation, int boardSize = Board.DefaultBoardSize)
    { var oneSquareAwayMoves = GetAllRadialMovesFrom(startingLocation, 1); return oneSquareAwayMoves.Where(bc => bc.IsCoordinateValidForBoardSize(boardSize));
    }

    I took that un-commented method and used GhostDoc to generate this.  Now, I Should probably update the summary, but I really don't see any other deficiencies here.  It nails the parameter names, and it even escapes the generic return type for readability.

    It Works with JavaScript, Too

    Now, as I've said earlier, I don't really play much in the JavaScript world.  I generally focus on application code and server side stuff, delving into the realm of the client side browser only when necessary to get things done.  So you can imagine my reaction to learn that GhostDoc can do this with JavaScript too.  It can produce sophisticated XML doc comments that allow for use in generating help and with IntelliSence.

    Actually, if I really want to embarrass myself, I'll confess that my initial reaction was, "JavaScript code has IntelliSence?"  I think maybe I knew that, but I assumed that such a thing would offer little value in a dynamically typed language.  Shows what I know.  But then, once I got over that initial wave of ignorance, I thought, "cool!" at the idea that you could generate documentation for JavaScript.  I then wondered if well-documented JavaScript was more or less rare than well documented C#.  That jury has yet to come back, as far as I know.

    Let's Take a Look

    Let's take a look at what GhostDoc actually does here.  To demonstrate, I created a branch of my ChessTDD project, to which I added an ASP MVC front end.  This plopped some JavaScript right in my lap, in the form of the default files in the "Scripts" folder.  To see this in action, I popped open modernizr-2.6.2.js and found a method upon which to experiment.

    blog-ghostdoc-with-javacript-01

    ShivMethods sounded... interesting, in a prison yard sort of way.  As a publicly consumable library, it already has documentation.  And, as I learned by playing around, that documentation already gets picked up by IntelliSense.  But I figured I'd see what happened by using GhostDoc anyway, for comparison's sake.

    So I lazily put my cursor randomly inside the method and fired away with a Ctrl-Shift-D.  Check it out.

    blog-ghostdoc-with-javacript-02

    As you can see, GhostDoc puts the comment inside of the method and behaves largely as it would with C#.  In case you're wondering about the stylistic difference, GhostDoc does this because it's the more Microsoft-preferred way.  To underscore that, look what happens now when we consume this method with IntelliSense.

    blog-ghostdoc-with-javacript-03

    As you can see, IntelliSense gives preference to the comments generated by GhostDoc.

    The Takeaway

    What's my main point here?  I simply wanted to share that you can use GhostDoc for JavaScript just as you can with C# or VB.

    Forget about my crotchety ways and biases.  Your JavaScript/client-side code is every bit as important as what you write anywhere else.  You should treat it as such when documenting it, creating help for it, and making sure users know how to consume your libraries.  So make sure you've got Ctrl-Shift-D at the ready when using Visual Studio, regardless of where the code gets executed.

    Learn more about how GhostDoc can help simplify your XML Comments, produce and maintain quality help documentation.

    About the Author

    Erik Dietrich

    I'm a passionate software developer and active blogger. Read about me at my site. View all posts by Erik Dietrich

    

This Blog

Syndication

 
     
 
Home |  Products |  Services |  Download |  Purchase |  Support |  Community |  About Us |