🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Documenting efficiently

Started by
3 comments, last by Shaarigan 5 years, 7 months ago

I'm what you might consider a "casual prosumer" when it comes to commenting. I comment important stuff, but only if the code isn't written in a self-explanatory way. Which is why I've also adapted a really simple and descriptive naming scheme and done away with any and all notation systems. 

That being said, there are occasions where I want to either document a whole system of code or provide a summarized walk-through on a per-function basis. This is where I find myself in a frustrating spot since none of the solutions on the market seem to be quite for what I want. So I figured I'd list things I want to achieve and what I want to avoid in hopes that I'm either not familiar with something or perhaps am simply not configuring stuff properly.

I'm willing to pay for a good solution. 

The dream wish list of things I want and need:

  • full documentation generation, a la Doxygen
  • a non-verbose (lightweight) and non-monolithic style
  • non-XML style markup (eg the way Natural Docs does it, not Doxygen)
  • no block comments in documentation (I use block comments extensively to manage code flow during development)
  • partial documentation (I really don't want to provide an explanation for each and every argument and return type)
  • a concise format with a clear layout, so no \param and \return shenanigans automatically filled in for me
  • no duplication of obvious information (eg the function name) in the comments
  • inline documentation
  • no explicit flow direction (in/out/inout) in documentation, but rather taken directly from code - I already provide this information!
  • proper macro expansion

I've tried Atomineer and it doesn't work for me at all. So far the Doxygen style in general is pure bloat in my eyes since it becomes bothersome to maintain as soon as you make something as simple as a name change. Allow me to demonstrate by example:

Here's what a typical function in my code might look like:


_BASEMETHOD
ECBool OnInitialize(
	IN MODIFY ResourceType& object,
	IN const char* type,
	OPTIONAL IN ISignalable* signalable = nullptr,
	OPTIONAL IN uint32 flags = 0) const {
	...
	}

_BASEMETHOD expands to 'virtual'. Atomineer doesn't handle this too well since it is adamant about placing the documentation below that line unless I take care to actually generate it on the word _BASEMETHOD itself.

Here's the default "trite" Atomineer generates:


/// Executes the initialize action
///
/// \author yomama
/// \date 12-Dec-18
///
/// \tparam ResourceType Type of the resource type.
/// \param [in,out] {IN MODIFY ResourceType&} object	  The object.
/// \param 		    {IN const char*} type				  The type.
/// \param [in,out] {OPTIONAL IN ISignalable*} signalable (Optional) If non-null, the signalable.
/// \param 		    {OPTIONAL IN uint32} custHandlerFlags The customer handler flags.
///
/// \return {ECBool} An ECBool.

This is close to being the least useful way to say what the function actually does. None of the auto-generated stuff makes sense, because it's already obvious from the names. In addition, data flow direction is assumed, not extrapolated from markup that already exists in the code (notice the in/out of signalable while certain conditions might force me to accept a non-const pointer, which is nevertheless never written to). The return type is obvious. Even the general description is obvious to the point of being insulting to the reader. 

Of course this is all meant to be manually edited. However, the problem is that:

1) on the one hand, writing this stuff from scratch using this style of markup is time consuming and annoyingly verbose.
2) auto-generating the template and editing is also time consuming, because again, it's way too verbose.

Here's what an ideal way of commenting the above function looks to me:


/// Fill \p object with data and notify \p signalable once the procedure is complete. Runs asynchronously.
_BASEMETHOD
ECBool OnInitialize(
	IN MODIFY ResourceType& object,
	IN const char* type,
	OPTIONAL IN ISignalable* signalable = nullptr,
	/// Type-specific flags. See documentation of related resource type for possible values.
	OPTIONAL IN uint32 flags = 0) const {
	...
	}

That's it. This should be enough to generate feature-complete documentation when the docs are finally built. AND it's easy to read inline while writing code.

A major hurdle is that while I actually kinda like the Natural Docs style, to the best of my knowledge it's only able to generate documentation for things that have actually been manually documented. Facepalm. So no automatic full documentation of classes, inheritance diagrams, etc. This seemingly forces me into using Doxygen, which is much more feature complete, but suffers from the abovementioned stylistic bloat and for some reason cannot handle relatively simple macro expansions in imo-not-so-complicated cases. I simplified the following from a real world example, but this includes auto-generated class implementations, eg:


BEGIN_DEFAULT_HANDLER(foo)

	_BASEMETHOD
	const char* bar() const _OVERRIDE { return "yomama"; }

END_DEFAULT_HANDLER(foo)



which might expand into something like --------->



class foo
	: public crpt_base<foo>
{
	base_interface* GetInterfaceClass() const _OVERRIDE { _STATIC foo_interface if; return &if; }
      
	_BASEMETHOD
	const char* bar() const _OVERRIDE { return "yomama"; }
};
extern "C" _DLLEXPORT base_class* _fooFactory() { return static_cast<base_class*>(new foo); }

Doxygen doesn't even recognize foo as a class.

The bottom line is it seems to me I shouldn't be asking for too much here. I'd really like the clear coding style I've adopted to pay off in more than just the code.

What's your approach? Any suggestions? Ideas or alternative options to explore?

Advertisement
18 hours ago, irreversible said:

What's your approach?

As I was on the go to write a C++ parser/precompiler anyways, I used it to have my documentation schema automatically generated as output for DocuWiki and have it part of my build-pipeline

1 hour ago, Shaarigan said:

As I was on the go to write a C++ parser/precompiler anyways, I used it to have my documentation schema automatically generated as output for DocuWiki and have it part of my build-pipeline

Mine's not really capable of handling full-blown C++ at this time. If you're not opposed to sharing yours along with a sample project, I wouldn't mind trying it out :)

Take a look at GitHub if you want investigate anything I decided to publish

This topic is closed to new replies.

Advertisement