66 comments

[ 2.9 ms ] story [ 139 ms ] thread
Yeah, I have been looking at why production rules systems (OPS5, Drools, IBM ILOG, etc.) have not caught on and I think one of the problems is that most of these systems make you give every rule a name, which is like saying every line of source code has to have a name.
I've spent half a year of my professional life programming custom business rule engine and my experience aligns with a sarcastic note I've read somewhere: "Business builds business rule engines so they can change their rules and workflows without the need for expensive programmers, but in the end they need to hire even more expensive Business Rule Engine Programmers".

Declarativeness of the system was really nice and named rules really made sense, if the actions you can take are really meaningful. It was more like naming every function set while doing FP.

> Naming is hard because it's a different kind of thinking from the rest of programming. We are coding along, in a nice engineering flow, and all of a sudden, we need a nice, human-readable name. We need to find compassion for the reader from within our cold, calculating programmer trance. This is very difficult.

This makes me think of prescription drugs, and how they all have 2 names, one for marketing to the public, and one for marketing to doctors. [e.g. "Ask your doctor if Savator is right for you. (Dipromelexeline)"]

Bleh.

I think the software development industry should stop doing such a disservice to itself, and start funding more scientific studies in software development.

Random, almost shower-thought hypotheses like 'naming things is hard - we should stop doing it' are given way too much credibility with nothing to back them up.

  > the software development industry should stop doing such a disservice to
  > itself, and start funding more scientific studies in software
  > development.
Yes.

  > hypotheses like 'naming things is hard - we should stop doing it' are given
  > way too much credibility with nothing to back them up.
Also yes, but let's separate generating hypotheses and discussing them from giving them credibility. It's a net win for people to share their shower-time hypotheses with each other. It's a net win for sites like Hacker News to feature them so that the "long tail of thought" can stretch ever longer.

But as you say, we need to keep some perspective and grant that these are hypotheses. For example, a lot of times, people try turning a dial to eleven:

Long iterations are hard, what's the shortest iteration cycle? What if we try releasing every two weeks?

Code review is valuable, what if we review 24/7/365 by pairing or even mob programming?

Long methods are hard to understand, what if we make a rule that they can be no longer than five lines?

And so forth. And they get good n=1 anecdotal results. My hypothesis is that there's a Hawthorne Effect going on: When you turn a dial to eleven, you find yourself forced to observe and think about what's going on very thoroughly, and in the process of doing so, you get better results.

Then you keep doing that, and eventually the new way of doing things is internalized, and you stop being forced to think very hard about things, and you regress to your old level of hand-wavey productivity/quality/whatever.

This little pet model of mine explains why things like this keep popping up, why they are often valuable exercises, but also why, as you say, we should do some real measuring before pronouncing that we're DoingItWrong™.

more scientific studies in software development.

There's an entire field called Software Engineering. But, it's more fun to just do what feels quick and satisfying instead of binding yourself to processes other people dictated.

> Software Engineering

Unfortunately, I feel like that term has been very diluted in the last few years, to the point where I'm not sure it has much difference (at least colloquially) from "programming".

Well, it's typically a multi-year degree program and not a 300 word blog post.

https://en.wikipedia.org/wiki/Software_engineering

Then you have Agile and XP and Scrum as either fast-flux Software Engineering (without all the "formal process/documentation" and instead use informal, but blessed, processes and immediate, undocumented, decision making) or anti-software-engineering depending on how you look at it.

Think: space shuttle or airliners, not social media. Sure, they still aren't perfect, but if you told me my airplane ran on Ruby I'd rather walk to my destination.

It's also typically not an Engineering degree so maybe we should stop calling it that.
You are correct, but it's still the name of an entire field of study. When things have names, we have to use the names the things have when talking about them.

The initial page for it on wikiepdia is interesting too (November 14, 2001): https://en.wikipedia.org/w/index.php?title=Software_engineer...

Especially: Methods have improved through the 1980s and 1990s, but the complexity in requirements have increased fast enough to consume any improvement.

There is also a constant eagerness to develop new tools and try the newest tools in each new project.

If the programmers are good, the system will work, and the customer will not fully appreciate how complex the task was.

That's a strawman of Agile.

Agile is about building the right thing. We found out that gathering the requirements up front and developing an extended timeline and holding deviations to change control ended up building the wrong thing because adapting to change was too painful.

We learned that if we wrote software that documented its behaviors in code, it was sometimes more useful than snapshots of technical documentation. Sometimes that isn't true (public APIs and protocols are the first two that come to mind), and thus the appropriate documentation at the appropriate level is justified.

We learned that even the best engineers are very poor at how long a task will take, but they are relatively good at estimating how long a task will take relative to other tasks. We learned that we could measure how long these tasks take and get a better estimate of the length of time for a total project.

The problem is that the SDLC is a bad process for many classes of software that aren't in the embedded space. Agile is good for some problems (IE, where the requirements are poorly understood) and not others.

Agile is good for some problems (IE, where the requirements are poorly understood) and not others.

That's the true answer. There's no one-size-fits-all solution, but people think (and argue) in absolute terms, not situational nuance.

People routinely mistake knowing the end-goal requirement ("Make a healthcare website") with knowing every sub-task requirement ("uh... we just spent $500 million with the goal of making a website and nothing actually works!").

We're in a fast society. Nobody wants to spend three years in pseudocode and dependency evaluation and documentation and procedures before laying down real code, so the best we can do these days is augment our decision making as our understanding of the problems and goals evolve then resolve all conflicts and confusions in as real-time as possible.

>I think the software development industry should stop doing such a disservice to itself, and start funding more scientific studies in software development.

Hm. I wonder if some of the larger companies are doing that sort of thing and keeping it internal-only or using it for internal coding standards without publishing it in an attempt to gain competitive advantage?

I doubt it. And even if they did, I don't think you should expect their results to generalize.

There's some evidence to suggest that the reason why studies like this so often produce seemingly conflicting results is that there aren't very many universal rules. The same practice can be helpful for one team and harmful for another based on any number of circumstances.

It's even in the same company. My team has very few common problems with our product teams. In fact, some of our experiences are just contrary to the product teams experiences.

Overall, software development is looking more and more like a journey to me. And a journey in the polar sea is different from the journey in the sahara. Just don't leave jenkins at home in either case.

eh, I think that there is a lot of value to standardization. Your average programmer is gonna spend more time reading code than writing it; there's something to be said for getting used to one standard style.
Hear hear.

Computer Science mixed with human factors looks similar to psychology in the early 20th century (we clearly have mommy problems). The statement "there are only 2 hard problems" is cute and pithy but doesn't really match my experience over the last 15 years.

Most of my painful memories relate to: multi-threading, timezones (bloody timezones), migration a system from A to B tech (i.e. SQL to NoSQL), ensuring a distributed system does something once--and only once, refactoring a god object, delegating a problem to an uneven strength team, building a system where the team organization doesn't match the desired architecture, getting the right requirements, dependency management, and deployment. There are probably more but that's beside the point.

There is research to support some of my observations but it's hidden behind paywalls or has thin supporting evidence. Comprehensive studies are hard and a lot of the research uses only students as convenience subjects. There really isn't a strong connection between the research community and practice in order to provide the right measurements.

What I would like to see is adding support to GitHub for community research studies. There is wealth of pure code observations. It would be interesting to allow integration of survey tools and marry that to the code observations. It'll answer some of the problems but not others (i.e. the pain of maintaining a live service). And finally as part of the GitHub EULA this research must be publicly available.

Check out the work around http://quorumlanguage.com/ -- it turns out that these are harder to quantify than we would expect.

For example, functional programming is terrible for beginners and has a high learning curve. People who use it in production swear by it. How do we test this?

Can we trust that what is true for a beginner is true for an expert? How do you afford 10 mid-level programmers for 6 months? Is that a large enough sample size?

The fundamental problem with studies, as I see it, is that we haven't figured out how to constrain the variability yet. We have a lot of work to get out of the hypothesis stage still.

> There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Posts like this give the illusion of saying so much, but at the end of the day, they really say almost nothing at all. What actionable advice is this post really giving? What examples is it pointing to to illustrate the author's point?

  > Use threading. Instead of naming each intermediate value, thread the value through the process without naming it.
What does that even mean?

To be honest, I'm not even really sure what the author's point is. Naming is hard? Naming is bad? Don't name things? Name everything? It just feels like an abstract nonsense piece.

What does that even mean?

It means don't do this:

    int x = k + 3;
    int y = v * x;
    int z = y - foo();
    return z;
Instead, do this:

    return (k + 3) * v - foo();
Makes sense, terribly worded by the author, though. Threading generally means, well threads. Throw the word "process" in there and it makes things even less clear.

Also, for the record, I totally disagree with the author on this. This:

  return (k + 3) * v - foo();
works great, until you need to debug it. Good luck then.
What's the problem? Just put the breakpoint on that line, then check the intermediate values (e.g. with PyDev, you can select parts of the expression to check their results).
Not every IDE is as helpful or forgiving for that kind of debugging. If you have things broken out, it's much easier to step through the intermediate states of expressions like that, and much easier to tweak when you need to fix something. Having everything together in One Expression To Rule Them All is a code smell, IMHO.
Even when using C, you can use gdb to evaluate subexpressions at a breakpoint. I don't see why is it a code smell just because some tools are lacking.

I do think it's a smell if the expressions has side effects, but that's a different issue.

I see it as a code smell precisely because some tools are lacking. I don't code for an ideal world where all tools and developers are perfect - personally, I take a practical approach and code for the real world.
Fair enough, but then it's only a smell in languages lacking in those tools. In my real world, I can debug it just fine.
True, but Unnecessary Variables is also a code smell, and a worse one to me, because it increases cognitive load in larger functions.

In the toy function given, it doesn't really matter, but in general, I think that people should aim to code for clarity, not ease of debugging.

In the author's language, Clojure, it's trivial to print the intermediate value at every stage of a threading macro so you can watch your data as it transforms and pinpoint the problem, ex:

    (defn debug-it 
      [x] 
      (println x)
      x)

    (-> input-value
        debug-it 
        function1
        debug-it
        function2
        debug-it
        function3
        debug-it)
Debug-it could also take a custom message at each line if you wanted the output tagged with names/numbers.

  A = max(3, 5)
  B = max(A, 7)
  C = max(20, B)

  C = max(20, max(max(3, 5), 7))
Threading aka chaining aka composing. You describe a pipeline and then send a whole value through it, thus avoiding the naming of intermediate results. Functional programmers call it "point-free style." It can't save you from naming in general, since each piece of your pipeline will be named, but it saves you from naming "variables."

Here is an example of the main part of a Haskell program (using the "pipes" combinators). It starts two concurrent pipelines. One reads user commands from a queue, encodes them, then writes them to an AMQP server. The other reads results from the AMQP server and runs them through a more complicated pipeline, the details of which aren't very interesting.

    runEffectsConcurrently
       (contents commandQueue >-> encoder >-> writeTo amqp)
       (readFrom amqp >-> decoder
                      >-> skipEmpty
                      >-> logToFile
                      >-> forever (decodeMsg state)
                      >-> toChannel eventQueue)
What I like about this style has to do with how it avoids naming intermediate results. Instead of stuff like loops, anonymous callback functions, and variables, it approaches a declarative specification of the program's structure & behavior. I still had to give names to each component, but I didn't need to come up with names for the values that flow through the pipelines.
Yeah, that makes sense. The author's terminology/wording wasn't clear/helpful IMO.

Beyond that, though - the above code looks great - until you need to debug it.

Personally, I'd rather pay a 'naming tax' on things for the sake of readability / debugability over what the original author is shooting for any day.

I haven't needed to debug it very much. Thankfully, it's easy to insert debugging helpers at any stage of the pipeline.
Interesting, maybe I'm just less familiar with debugging in Haskell.
This is kind of a special scenario since what's described in the pipeline is already an I/O action, which makes it easy to insert logging anywhere (e.g., a "tap" component that prints its input and output w/ timestamp).

Such pipelines aren't necessarily made up of I/O actions though; they can also be pure computations, which cannot perform side-effects such as logging. In that case, you can still insert debugging helpers, but you might need to be slightly creative. For example, if your pipeline generates a list of values, you could put debugging entries into that list.

Generally, though, the saving grace in such a case is that each component will be a pure transformation, which means that you can easily call it with a test input and inspect the output.

There are some step-by-step debugging tools for Haskell, but I haven't used them, and Haskell programmers mostly seem uninterested in that way of debugging. It doesn't fit very well with Haskell's evaluation model anyway. When I work with Haskell, I just debug in a different way, focusing on verifying correctness of functions and their combinations.

> There are some step-by-step debugging tools for Haskell, but I haven't used them, and Haskell programmers mostly seem uninterested in that way of debugging. It doesn't fit very well with Haskell's evaluation model anyway. When I work with Haskell, I just debug in a different way, focusing on verifying correctness of functions and their combinations.

I created hs-scrape[0] to write web scrapers and I frequently use the ghci debugger[1] for step-by-step debugging.

0: https://github.com/codygman/hs-scrape/

1: https://downloads.haskell.org/~ghc/latest/docs/html/users_gu...

The post was for Clojure Gazette, and all Clojure programmers would be familiar with the threading functions.

I have to say, minimizing intermediate holding names makes debugging and writing clear code much easier. 97% of the time, I never miss the "naming tax".

He's apparently talking about Clojure's thread macro specifically. If you're not familiar it can be a way to organize code in a straightforward, human-readable, easily debuggable syntax. Ex:

    (~> (sha1 in)
        (bytes->hex-string)
        (bytes-append #".")
        (displayln))
In pseudo-Python this would be:

    displayln(bytes-append(bytes->hex-string(sha1(in)), #"."))
http://www.greghendershott.com/2013/05/the-threading-macro.h...
I don't agree.

I agree, that naming is hard, of course.

But I don't agree, that you should avoid it at all costs!

Sometimes, the costs are just to high. When by avoiding naming things, you make the program more difficult to understand, you loose much. This could cost you nearly as much, as a bad name and very likely much more than a half-good name.

The article is maybe overblown, but I think there's a good point there. A lot of functionality is one-off stuff that doesn't need to be re-used and won't be, and so trying to come up with a name for a little chunk of code just ends up making the program harder to understand.

So, sure, you can write:

  function processData(err, data) {
    //blah blah does stuff
  }

  db.getData(processData);
But it's actually a lot simpler and more understandable if you just write:

  db.getData(function (err, data) { 
    //blah blah does stuff
  });
If and when you ever need to break that function out into something re-usable, give it a name then, but don't bother with a name unless you need it.
But one of those functions processes data and the other gets data.
I hope that the very generic names you have chosen is just for the example, but otherwise that is exactly the type of names that make a codebase incomprehensible. How about something like

  function CalculateSalesBonus(err, salesmenEmployedByTheLastOfMonth) {
  // do stuff
  }

which actually contains much more information than

  db.getSalesmenEmployedByTheLastOfMonth(function (err, data) { 
      //blah blah does stuff
  });
Once you turn processData() into an anonymous function, how could you write a unit test for it?
Sounds like terrible advice to me. Names make it a lot easier to keep track of things. Even a meaningless name is generally better than no name.
This article is taking its readers down a really dumb path.

"At all cost" even at the cost of readability?

It also ignores the possibility that good names do exist, and that they contribute a lot to maintainability.

The suggestion made is when a good name "cannot" be found, you should try to avoid naming. No. Bad suggestion.

When a good name cannot be found, you probably have muddied up the problem, and should rethink it. Or try harder to find a good name. Also re-examine your ideas about what is "good", avoiding false metrics such as "names need to be under three characters long".

> When a good name cannot be found, you probably have muddied up the problem, and should rethink it.

Absolutely. Software as we know it could not exist without abstration, and abstraction can not exist without names for things. Sometimes a new name is required because a particular concept or application is relatively novel, but if you decline the challenge of naming it then progress stops immediately. No future applications will be built on top of an unnamed abstraction.

As I read it, this article is, quite intelligently, recommending (or at least a consequence of their logic would be a recommendation for) using a point-free style wherever it's applicable. Programming is, primarily, data transform and a focus on the transform, rather than naming the intermediate data items, is typically a lot nicer to read. Name your functions, avoid naming your data if you can.
The Phil Karlton quote is fun and clever. But people should not mistake it for actual wisdom.

Read this paper (for example) and tell me that naming and cache invalidation are harder than that: http://www.sigops.org/sosp/sosp09/papers/klein-sosp09.pdf

i prefer the varian't that says :

There are only 2 hard problems in programming:

1. naming things.

2. cache invalidation.

3. off by one errors.

I see this same issue come up from time to time and I always recall a little saying I heard (unfortunately I don't remember the source).

"If you are having trouble naming something, then you don't fully understand that something."

What I get from that saying is that if I have a function that I am struggling to name, it means that I don't fully understand the problem, and there's a good chance that it is doing to many things. Keep your functions to performing a single task, so they have just that one purpose, then name it after what it does. This improves readability and makes naming things much easier.

You have a variable you can't name, well, what data is it actually holding? If it is holding more than one piece of data (reused) then you are doing something wrong or very hacky.

Follow the same rule as with functions. Keep your variables to holding just one specific piece of data, and name it after that.

Both of these rules not only make naming things much easier, I've found they produce much more readable code, easier to debug code, and generally much less bugs in the code.

There are some good thoughts here, but it isn't all quite coherent yet. So, to add my 2 cents:

There are basically two reasons to name things.

1. Because something is lacking in either the syntax of our PL or our skill in coding, so that we end up giving something a name, when it does not really need one.

2. As a handle on some abstraction, indicating what it is for.

When #1 is the issue, names are best avoided. When #2 is the issue, names are a Good Thing, but a poorly chosen name can be very harmful.

It is similar to sociology or psychology problems.

They use models or paradigms with lot of names mainly because of lack of theory than can connect human sciences to mathematics or physics. In each model they can solve some aspects but the whole.

It looks like zoology or biology before DNA.

Ignoring the fact I think this is bad advice, I actually find 'naming' things to be good fun. I enjoy finding names for projects. Sometimes I won't write the first line of code until I either find a permanent name for the project or a good enough temporary one to name the code directory. Can't reason this really, but its definitely important to me to know I'm working on a named project.
When naming things is hard, it's exactly the reason why you should stop, think, and find a good, fitting name.

If you have hard time naming something in your code, chances are it's because you have a nebulous understanding of that elusive thing. This is obviously bug prone. It's usually a good idea to spend a few minutes searching for a good, precise, descriptive name, and add enough comments if the entity being named is not a temporary variable.

Doing so not just makes later code maintenance easier, it tidies up your understanding and can even lead to finding a bug or another problem (happened to me more than once).

In my team, we're starting to take naming problems as a very, very red flag. Especially if the name makes sense for half the team, and no sense for the other half.

In the most extreme case, we've taken like half a day off with the entire team to discuss just about everything. We went from a name to one of our software to our architecture to our domain and it was just half a day to a day of discussion and merging understandings.

After this, we spend another half a day to a day just cleaning up a huge mess of potential bugs, and after that, naming was simple. And now, a few month later, hell it was worth it.

There are times to break some code out into a separate function, even though the function will only be called in one place, simply because the name of the function will make it more clear what the code is doing.

Note well: This is not "always". Do not do this with every single line of your program. This is not even "often". But once in a while, it can dramatically improve clarity.

Good idea, sometimes.

On the opposite end, I will sometimes go out of my way to name something when there isn't an immediately apparent need.

Also naming can often shorten up a long line.

Trivial example:

  In [15]: SortByLen = lambda x: len(x)
  
  In [16]: SortByLast = lambda x: x[-1]
  
  In [17]: listOfInterest = ['123', '234', '432''12', '12345', '123']
  
  In [18]: sorted(listOfInterest, key=SortByLen)
  Out[18]: ['123', '234', '123', '43212', '12345']
  
  In [19]: sorted(listOfInterest, key=SortByLast)
  Out[19]: ['43212', '123', '123', '234', '12345']
(comment deleted)
Juliet said it best; What's in a name? That which we call a rose by any other name would smell as sweet.
I agree with those that thinks this is horrible advise. If the function of what you are naming isn't clear and precise it is of course hard to give it a clear and precise name. But the solution isn't to avoid giving name. The solution is to make sure that function of what you are naming is clear and precise. That is the hard part, but must not be avoided.
Threads like this are so sensitive to initial conditions. When one initial condition is a dumbed-down, provocative title, we nearly always get a dumbed-down and provoked discussion. That's too bad, because there are some good ideas here.

We changed the title to a representative sentence from the article.

(comment deleted)
This sounds like the currently fashionable argument to avoid comments because they can be inaccurate, go out of date, and after all the code itself should be self-explanatory - just shifted a bit further up the chain.
FP isn't a golden bullet, but at least it often helps to get rid of those temporary variable names that clutter the code.