21

My question is in a similar vein to this one.

My research requires code. I can write code and I know some things about writing good code. Both for readability, (e.g. standardised doc string, descriptive variable names, comments that describe the intention) and safety (assertions in the code, unit tests, sensible error messages). Adding these things takes me more time than omitting them.

At present I will typically do a bare minimum on my first attempt. So I will put a one line doc string in; use descriptive, but occasionally inconstant, variable names; and few comments. If the code doesn’t work first time I will go back and add unit tests and generally improve it's quality until it is functional.

If at a later stage part of the code needs altering significantly, (perhaps I realise I need it in parallel), then lots of the "polish" will need redoing. This does not make it enticing to polish more earlier on. Occasionally I will chase my tail over a fault that turns out to be originating in an older section of code, that I might have caught if I have been more thorough first time.

The code I write is almost always only used by myself.

Clearly there is a trade-off between doing things by the book and producing results fast. What would you look at to decide if you had found a good balance between these things?

  • 6
    "If at a later stage part of the code needs altering significantly, then lots of the "polish" will need redoing. " This applies to some aspects more than others. For example, comments: yes, they get outdated quickly. As for variable names, with the refactoring support by present IDEs, there's no excuse for using non-descriptive names. Unit tests are by far the most pragmatic way to ensure that you don't break something when altering your code, so there's a strong incentive to write them. – lighthouse keeper Mar 23 '18 at 10:42
  • 5
    Write unit tests! At least in a very general way. Always have at least 1 example where you are 100% sure what the result should be and you can run from time to time to see if you screwed up. Helps with sanity. My opinion about code now: Make everything tidy, and put it in github. You are the only reason why you are the only user, you may have a huge amount of users if you make your code open. Plus its better science, more transparent. There are even ways of making your code citable as academic output. – Ander Biguri Mar 23 '18 at 15:36
  • 8
    Just remember, you write good code as if the person who has to maintain this code is a psychopath who knows where you live. Do you trust yourself six months from now to not be both of those things? If you don't, write good code from the get go!! – corsiKa Mar 23 '18 at 15:39
  • 2
    @TheoreticalPerson Also lost of researchers replicate the same code again and again because no one shares. Often as a researcher I just want to test what paper A says, and 99.9% of the cases, the only way to do that is code it myself, which ends up being too much effort, and end up not doing it. You are probably (or shoudl be) using git, you just need to make the repo public. You seem to be in the UK, there is already a lot of support for this by the RSE community! – Ander Biguri Mar 23 '18 at 16:21
  • 2
    'for research' makes a difference (as opposed to 'commercial', or 'open-source submission'). Maybe you want to even edit it further to 'for research which is publishable and replicable' – smci Mar 24 '18 at 0:35
27

As the

code I write is almost always only used by myself

you only have yourself to please. So the only sensible answer is to balance things to minimize the frustration to yourself. Don't do things you see as frustratingly slowing you down until you are more frustrated by the problems caused by not doing them.

However, the more strategic question is whether you want to continue writing code that will only be used and seen by yourself. If you want to advance your career through collaboration with peers, or by building a group of researchers to work on and with your codes, then it will be better to do more earlier.

You then know you've found a good balance when the collaborators you want to work with still want to work with you after they've spent some time with your code.

  • This seems very sound. It would be useful to find a good balance without burning bridges though. Can you think of a way to "test the waters" here? – Clumsy cat Mar 23 '18 at 10:56
  • 2
    If possible, find out how the collaborator codes, or what general codes they use, and follow as many of their approaches as seems feasible: I'd think of that as the academic version of the principle of least astonishment. If there's no information available (eg taking on new students) then look at conventions within your research field: if they're going to have to learn, make them learn an approach that's applicable more broadly. – Ian Mar 23 '18 at 11:12
  • 4
    And in the UK (where OP seems to be at) there is a lot of good support groups for helping researchers code properly organized by the RSE (research software engineering) community (as you probably know ;) ). – Ander Biguri Mar 23 '18 at 16:26
  • 10
    I would only modify this to point out you also want to please your future self. It's very common, but very discouraging, to come back to your code after some time has passed, and find it totally incomprehensible . – Charles E. Grant Mar 23 '18 at 16:49
  • 10
    I'd like to point out as a software developer that "only used by myself" and "will always be understandable to me" are not the same thing. I have several projects whose code is only for myself, and when trying to maintain them, I constantly find myself wishing I'd documented more (and, as a result, documenting more) because, after six months of not working on the project, I've forgotten all the random little quirks that have to be followed. Because of that, it makes sense to write good code, even if you're the only one who'll ever see it. – Nic Hartley Mar 23 '18 at 19:54
9

You said:

The code I write is almost always only used by myself

but I find this remark a little short-sighted.

In the moment, code may be used almost exclusively by the author/student-researcher, but eventually that student will graduate, and there may be some follow-on research to do. Woe to the next graduate student who inherits that mess, or the summer intern who gets hired to clean it up!

There are plenty of good reasons to invest a little time in writing better-engineered code:

  • You (and others who may join the research team) will be able to further build upon a well-designed architecture
  • What seems “self-documenting” now may be harder-to-follow than you think six months from now
  • A lot of code gets ultimately gets used for longer than the original author speculated
  • The more complex your code becomes, the harder it will be to debug later

Sure, there’s a tradeoff between immediacy of results and building for the future. But I’d cautioned against getting lulled into a false sense of security and churning out code as fast as you can with little regard to future maintainability and extensibility.

  • 2
    With respect, that's more of an observation on the question than an answer. I know there are benefits to good code practices. I know someone else may eventually obtain my code. There are also advantages to be had in generating results at a decent rate, and I want advice on finding a balance. Can you talk more about where you think caution becomes excessive, or what must not be omitted? – Clumsy cat Mar 23 '18 at 11:26
  • 5
    @TheoreticalPerson Repeatability is an extremely important property of good research. If you cannot reproduce the same results (and possibly preform new additional verification) say 10-20 years from now, then you have performed poor research. This applies to all research, with or without code. You should not underestimate how difficult it is to revive old single author, single one-off purpose code later on. And regarding almost always only used by myself: that should be utterly irrelevant. Or do you consider research that only you are able to reproduce to be good research? – hlovdal Mar 24 '18 at 8:14
5

As you would with any other document, write for your audience. That is, write your code to make it help, as best as possible (yet still at reasonable cost), those who are reading it. Consider:

  1. Will anybody other than you be reading the code, now or in the future? If it's a one-off script that you will quickly discard you need not worry much about readability. If nobody else is likely ever to look at it, you need to think about how likely your future self is to remember what was going on at the time and understand the conventions you used.

  2. If others are likely to read your code, how technically adept with that particular language and libraries, and in general, are they likely to be? Can you use standard conventions used by programmers experienced in that language? Do you need write things in a way that experienced developers who don't know that particular language can quickly understand what you're doing? Do you need to avoid standard things (e.g., list comprehensions) that inexperienced developers might not understand well?

  3. How well will the other developers understand the problem domain? Do you need to provide a detailed explanation of what you're doing and why you're doing it, or do you expect that when they look at a line they'll, e.g., immediately see that it's a form of Black Scholes equation and understand how and why it's being used there?

Keep in mind that making things more descriptive and adding more comments does not necessarily make your code more readable; for some audiences that may even make it less readable. Just as mathematicians can more quickly comprehend a dense equation than a long description of the equation written in "plain English," experienced developers familiar with a domain will take considerably longer to read verbose code written for a beginner than they will tight code written for an expert that communicates exactly what is needed and no more. As an extreme example, read this:

def double_a_number(number_to_be_doubled):
    ''' Given a number, this will return twice that number.
        Parameters:
            number_to_be_doubled: the number to be doubled
        Return Value:
            The doubled number.
    '''
    return number_to_be_doubled * 2

and then tell me if you think anybody would find it easier to understand than:

def double(x): return 2*x

Also be careful not to fall into the classic trap affecting inexperienced (and, sadly, even many experienced) developers of putting slavish devotion to rules ahead of the readability that those rules were supposed to promote. "Inconsistent" variable names and the like are not necessarily a problem (except for whomever is writing your lint configuration files) if your focus is on communicating with other developers rather than satisfying arbitrary rules.

And my last bit of personal advice, since you mention docstrings, always remember that a comment is only there because you couldn't write clear enough code. If you feel a function needs a docstring, look first to see if you can't improve the function name, change positional parameters to named parameters, or use any other techniques to make the code state more clearly what it's about. (And if someone's telling you to put in docstrings anyway, refer them to my example above.)

  • 1
    I never thought about docstrings that way, but your example makes a good point. – Clumsy cat Mar 23 '18 at 19:31
2

I think for the main question, "when is the code good enough?", the answer is simple: when it does what you want it to do, and you can be confident that the answer it gives you is correct.

There is definitely a trade-off for making your code nice, however. To me, that comes up in two places:

  1. What if, six months later, you want to revisit your research results and see if you can come up with some improvements, or maybe you had hit a dead end so you are coming back to see if you can finish the work. Can you read your code from six months ago, and pick back up modifying it? Or is it too convoluted to follow and use? Ideally, you should be able to come back to your code in a year and easily understand what you were doing.
  2. Your research does not exist in a bubble. Your next research project will probably be somewhat related to your previous one. Can your code be reused? Can parts of it be reused? Even if there are few benefits in your current project to making your code nice and modular, you may save yourself lots of time and effort down the line if you do this. Important functions and algorithms can then be moved over to your new setting with minimal adaptation. A side benefit is that you can replace certain pieces of your code with alternate implementations to see if you can get better results.
2

How careful you are should be a pragmatic choice.

The point of the disciplines is to help you write working code (which you can keep working and extending).

This is not an academic exercise (Perhaps this is the wrong forum in which to make this comment). There are "no points for box-ticking good practices" (perhaps there are in your environment).

The good practices are hard-won lessons from the commonality of programming practice. In an environment where many programmers collaborate on code, which will often be maintained over a longer time than ever anticipated, they help to limit the confusion and re-work needed.

You sound like you are well on the way.

If you are near the beginning of your programmer-journey, I would recommend you explore the meanings of "DRY", "YAGNI" and "SOLID". And I would put in a special mention for unit testing.

In my own experience, unit-testing:

  • helps you document what you intended the code to do when you sat down to write it, and it will let you check that it is still doing it, even when you make some apparently completely unrelated change miles away in your code, months later. Including little details like nothing will be reported as null or nothing will be reported as empty-string.
  • winkles out your misunderstandings of your primary language or the associated framework and libraries you merely glanced over the documentation for, before adopting. These misunderstandings make for time-consuming bug-fixing if you have to find them out by debugging the consumer of your mis-implemented code.
  • will encourage you to write appropriately granular code: it is such a nuisance trying to write unit tests for code which tries to squeeze too much activity into each routine (method, subprogram, etc.).
  • is best begun before you actually create the code which it will later test. This might help you to focus more clearly on what your code ought to deliver.
  • will find out early for you, when your early code-design needs to be thrown away. This will discourage you from soldiering on with a wrong design which you've made too much investment in already to be willing to throw away. It's all about making working code, not about enshrining your first master-plan.
  • 1
    "will encourage you to write appropriately granular code" I never thought about unit tests that way but your absolutely right. – Clumsy cat Mar 23 '18 at 17:10
0

You say:

The code I write is almost always only used by myself

Like others, I don't share this opinion. The code is GUARANTEED to be used by at least two people:

  1. You
  2. You three months from now.

Good internal documentation doesn't take that long, and will in the long run save you time and effort.

0

The code I write is almost always only used by myself.

This comment seems somewhat misguided and I should predicate this by saying I write a lot of research code myself as well. The reason why I think this statement is misguided is because the code is being used for something (e.g., prepare data for analysis, analysis, modeling, etc.) and is ultimately going to impact any manuscripts you prepare. As such, ensuring that your code is readable by others is part of ensuring that your work is repeatable by others as well. Furthermore, if your code solves a problem that others have (quite common in research as well!) others may as for part of it to use in their own research.

That being said, with practice it is possible to write fairly readable code the first time around and just requires a bit of discipline. Some IDEs will force this upon you by checking variable names (e.g., do they conform to camelCase?), function names, function length, unit test coverage, and so forth. This tends to be a lot since it is unusual for people to go back and spend a lot of time improving code - once you have the results the bias tends to be to move on to the next project.

So the bottom line is that you should try to write code that is good enough to share with others the first time around. You never know when a reviewer may ask to see the relevant source code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.