top | item 29823907

(no title)

eslav | 4 years ago

What does “code like prose” look like? I had a group project in college with a guy who used MS Word to write code in paragraphs..formatted like an English paper (I’m not kidding); is this what you mean?

(Looking back I often wonder how long this guy wrote code like this before someone said “knock it off”..)

discuss

order

marijnz0r|4 years ago

Regarding a unit test it looks something like this in pseudocode:

  function test_addition() {
      given_two_integers(2,3);
  
      when_summed_up();
  
      then_the_result_should_be(5);
  }
Whereas I would prefer something like

  function test_addition() {
      int a = 2;
      int b = 3;
  
      int result = new Addition(a, b);
  
      Assert.AreEqual(result.Sum(), 5);
  }
For a non-coder it might seem more intuitive to read the first example, because it only contains natural language. For a coder it seems more intuitive to read the second example, because it prevents "method hopping" (I have to go into the methods from example one to see what's actually happening inside them).

Jtsummers|4 years ago

It sounds more like the colleague wants a DSL. DSLs can be useful but should also be used with care since they are "mini languages" that stand apart from the host language. A perhaps better (though not necessarily stellar) alternative to the first would be to have a series of calls like:

  function test_addition() {
    given(2,3)
      .when(add) // assume `add` is a function here
      .result_is(5);
  }
`when` could take a lambda as well so that you can pass in anything:

  given(2,3)
    .when(a,b => new Addition(a,b)) // to stick with your second example where the constructor returns a result
    .result_is(5)
This is how many testing DSLs I've seen look, and it's not awful if this style of programming is already present in the language.

But I agree, if that first example is representative of what the colleague wants to do it introduces a lot of "magic". Where are the integers stored? Where is when_summed_up defined and how does it know which function/method to use? Is the entire test in its own class/module so that this can work? Or is this test class/module now polluted with, potentially, dozens of class/module scope variables to store all these hidden variables and many utility functions that disguise what is actually being tested?

Regarding "how to deal with this", bring it up in code reviews, offer alternatives like the above (or some palatable-to-you version of it) for some situations. If their style is so far from yours it may be easier to meet in the middle than to totally break them of it. Emphasize the complexity that their solution is bringing to the table (again, assuming that your example is actually representative, it does make it more complex).

A testing DSL like what I described can be written once, kept in its own modules, extended across the board (not on a per-test basis), and provides a uniform approach to a testing DSL. An ad hoc DSL per test (case or set) is a lot of extra work all around. It is fragile, potentially introduces race conditions which breaks the ability to run tests concurrently, and non-uniform. This last one is really important when working in teams and when working with outsiders to the team. With teams, it makes it harder for someone to jump into a test and understand it. The above DSL is more readily comprehended (even if requiring a bit more upfront study, that upfront study happens once). When working with outsiders from the team, they can look at a variety of tests and understand it well enough, if not perfectly, because it is consistent.

fatnoah|4 years ago

I was having trouble visualizing what OP meant, and this is a great explanation!