Dota 2 - Advice on programming together

As someone with a bachelor of science in computer science (almost), we spent quite some time on how to organize yourself when working on software, to make it easier to work together. This document will contain my advice and experience on this subject. This topic is obviously completely subjective and the best way is different for individual and every team, still I hope this document will have some value in development, and if I ever work in a team I will make sure they have read this.

So let me start by giving a list of what benefits you get out of your programming by following this document:

PS: This might seem like extra work, and it is, but in the end you benefit from it. Usually when I'm working alone on something personally I don't use most of the things in this document, but when working in a group this is VERY beneficial.

Planning

This one seems pretty straightforward, and it is. Before starting you should have done the others points in this document and you should have a clear division of who does what. Most importantly though, you should set a number of deadlines. I realise this is hard to do correctly, but you should have deadlines. Nothing is more annoying than having multiple people having to stop working on a project because you are waiting for one person who hasn't made his deadline. Tip: Set multiple deadlines for certain steps in the project, it helps structuring the progress of the project and gives a clear timeline you can use to check progress. It is entirely possible somebody (maybe you) can not make his deadline for whatever reason, the important thing is that you let your team know ahead of time, so they can help you or adjust to it.

Repository

Use one, any kind.
If you have no idea what a repository is, read my dota 2 version control guide.

Comments

This might be the most important paragraph in this document. I can't even begin to explain how important comments are when working on the same code with multiple people. Not only will comments help others understand the code you wrote, it will also help you when revisiting old code. This especially holds for larger amounts of code. Read this paragraph. Do this paragraph. It will help, even if you do it when working on a project alone.

Good practice when commenting is asking yourself about sections of code 'is it immediately obvious what this bit of code does?'; If the answer is not 100% yes: Add a comment. This does not have to be a long comment, but just something like '//Changing this variable to hold the caster instead of the target now' will do. If this means you have to add a comment every line: do it. If this means you might not have a comment for multiple lines: fine, as long as the function of those lines is obvious, or described by a previous comment.

So far for the obvious part, now come the 'secret tricks' of the academic programmer. This might seem like just a lot of extra work, but if you have (tens/hundreds of) thousands lines of code this will help, trust me.

Function contracts

Each function should have a contract, no matter which function we are talking about. The level of detail should be defined in the coding standard, ranging from simple to elaborate. The point of a contract is that whatever function is below that contract does not break it. The absolute minimum is a description of the function, what it does basically. I like adding a definition of the input and output to that, which clarifies it a lot. On top of that I like adding the author, so you know who to ask who to ask when the function is not clear or incorrect. A contract with a description, input, output and author can look like anything depending on your coding standard, but I would write it like this:
--[[
    Raises a base number to some power.
    Author: Perry

    Input: a - the base, a > 0 ; b - the power
    Output: a + b
]]

function Power( a, b )
...
Now the nice thing is that contracts ALWAYS hold, so other contributors know what the function does in case they want to use it, and on top of that they get a guarantee that as long as they adhere to the input specs, they will get the correct output as defined. If this is not the case, they know what author to blame. Some more things you could add are pre- and post-conditions, the variables this function modifies, or more extensive descriptions of the different parameters. I do not recommend putting in all those, you will not be happy (unfortunately I know this from experience too, this is nice but too much is very annoying).

Class description

This is not used a lot in dota 2 lua, but it applies to general programming:
Not as important as function descriptions, still useful. At the top of each class add a little description of the class, what it is used for, and who the main author is. You can do this in a few lines only.

Coding standard

What you should always do when working on a project with multiple programmers is defining and agreeing on some kind of standard. This standard can be as detailed as needed, but here are some things you probably should define (you can add anything you like to these yourself!):

Text format

Tabs or spaces for indentation is a common definition in coding standards. Another one is the maximum line width (approximately, this increases readability of code on different resolutions), usually defined in characters. You can add whatever you agree on on top of these first ones if you feel there is a need for it.

Some related guidelines:
- Use descriptive names for variables and functions
- Try avoiding code duplication, if you find you are repeating lines of code, move them to a seperate function
- Watch out for name collisions

Comment format

Like I said in previous parts it is important to define how you comment. Regular comments don't really matter, but you should make solid agreements on the format of your function contracts and class descriptions. Define exactly what should be in there, and save a lot of hassle.

Example

I'll leave you an example of some code written according to these guidelines.
--[[
    Add a vector to this vector.
    Author: Perry
    
    Input: vec - some valid vector
    Output: this vector's length after the addition
]]
function Vector2:Add( vec )
    --add the x and y component of the other vector to the components of this one
    self.x = self.x + vec.x
    self.y = self.y + vec.y
    
    --return this vector's length
    return self:Length()
end

--[[
    Returns the length of this vector.
    Author: Perry
    
    Input: -
    Output: this vector's length
]]
function Vector2:Length()
    --Use the Pythagorean theorem
    return math.sqrt( self.x * self.x + self.y * self.y )
end

--[[
    Set the length of this vector to some value.
    Author: Perry
    
    Input: length - the length to set this vector to
    Output: -
]]
function Vector2:SetLength( length )
    --Calculate relative difference in size between the desired length and current length
    local factor = length/self:Length()
    
    --Multiply this vector's x and y components with the multiplication factor
    self.x = self.x * factor
    self.y = self.y * factor
end