Hacker News new | ask | show | jobs
by justasitsounds 2552 days ago
`is_foolike` is a bad name if you name your methods to only describe how they are implemented internally.

At a high-level, in your business domain, you generally write your code to hide the implementation details and to describe the intention of the method EG. `is_carbonated`

  if is_carbonated(beverage):
    beverage.jiggle(false)
vs

  if beverage.startswith("co2"):
    beverage.jiggle(false)
(edit) for formatting
2 comments

I'm sorry that this will come across as rude, but I feel like you're repeating something you've heard but didn't quite understand.

Yes, at pretty much ANY level, you should write your function names to hide the implementation details and to describe the intention of the function. In my previous post I hinted that the name of the function should "describe what the function does", which is the same as "describe the intention of the function", because if the function doesn't do what it's intended to do, that's a bug.

The reason I say I don't think you understand what you're saying is that none of what you're actually saying applies to the examples you're giving.

`is_foolike` doesn't describe the intention of the method. It gives an entirely vague and inaccurate view of what the method does. So even though we both agree that functions should describe the intention of the method, you're saying `is_foolike` is an okay name even though it doesn't do what you say it should?

`starts_with_foo` describes the intention of the method. It doesn't describe the implementation: `starts_with_foo(x)` might expand to `x.startswith('foo')` or `x[:3] == 'foo'`, but I don't care which, because the name accurately describes what it does either way.

Your example doesn't elucidate. If we're representing beverages as strings which are somehow guaranteed to begin with "co2" if the beverage is carbonated, and we've decided that the deserialization should be mixed into our "high-level, in your business domain", the program is so badly tangled that we're not going to get any truths about good programming from it.

  I'm sorry that this will come across as rude, but I feel like you're repeating something you've heard but didn't quite understand.
You're right, it does come across as both rude and condescending, and you know it, so don't apologise.

  In my previous post I hinted that the name of the function should "describe what the function does", which is the same as "describe the intention of the function", because if the function doesn't do what it's intended to do, that's a bug.
`is_foolike` to me, implies `test_for_abstract_quality_foo`. `starts_with_foo` implies an assertion a string beginning with a particular prefix

  If we're representing beverages as strings which are somehow guaranteed to begin with "co2" if the beverage is carbonated, and we've decided that the deserialization should be mixed into your "high-level, in your business domain", the program is so badly written that we're not going to get any truths about good programming from it
I feel like you're intentionally misunderstanding my point. Please don't critique my entirely fictitious codebase as if it represents anything other than an abstract example. The point being that even though, in this (again) entirely fictitious example, the implementation is very simple, the intention of the method is different from it's implementation
> `is_foolike` to me, implies `test_for_abstract_quality_foo`.

Yes, which is why when `is_foolike` tests that a string starts with 'foo', that's rather unexpected. If `is_foolike` actually describes the intention of the function, then the function testing for the string beginning with 'foo' is a bug, because it doesn't do what it's intended to do.

Referring to "the quality of starting with 'foo'" as "abstract quality foo" isn't hiding implementation details, it's being opaque about what a function does.

Put another way, "what a function does" isn't its implementation. "How a function does what it does" is its implementation.

> `starts_with_foo` implies an assertion a string beginning with a particular prefix

Yes, exactly. Because that is what it is intended to do, we hope, since that's what it does. That's NOT the implementation: there are plenty of different ways to implement testing whether a string starts with 'foo', and the name `starts_with_foo` isn't coupled to any of them.

> The point being that even though, in this (again) entirely fictitious example, the intention of the method is different from it's implementation

Yes. `starts_with_foo` is also different from the implementation, while still describing the intention of the method.

Could you explain to me why you think `starts_with_foo(x)` describes the implementation `x.startswith('foo')` and not some other implementation (such as `x[:3] == 'foo'`)?

Ok, I’m curious. Let’s say that I want to fall into that if statement if my product is named something like “foo”, costs under $100, isn’t discontinued, and has sold over 100 units in the last month. Fine, you can say now I have overcomplicated the domain and I should go back to requirements, but these complicated things do happen. Surely it’s acceptable to name my function “isFooLike” rather than “startsWithFooAndCostsLessThan...” etc, especially if I suspect management may change some of those figures later?

If that’s acceptable, why is an IsFooLike which only checks one condition unacceptable, even though it (imo) expresses the same intention?

> Ok, I’m curious. Let’s say that I want to fall into that if statement if my product is named something like “foo”, costs under $100, isn’t discontinued, and has sold over 100 units in the last month. Fine, you can say now I have overcomplicated the domain and I should go back to requirements, but these complicated things do happen. Surely it’s acceptable to name my function “isFooLike” rather than “startsWithFooAndCostsLessThan...” etc, especially if I suspect management may change some of those figures later?

The idea with naming is to capture as much of the meaning of the function as possible, and 'isFooLike' doesn't really capture any meaning (what does it mean to be like a foo?). In business, there are typically names for the topics, like `is_profitable_transaction` or `meets_sales_targets`, which may indeed encompass some very complex logic, but are a coherent idea, so naming is usually a bit easier than this. But you're right, sometimes the requirements are bad and you don't have a chance to go back to requirements before a deadline. In those cases, I don't think the naming matters much because no name you come up with is going to represent the concept. So I guess `is_foolike` might be the best you could come up with, but it's certainly not good code. I'd also be less likely to pull out a function in the first place because it's a premature abstraction: if the abstraction isn't coherent enough to be named well, we probably don't understand it well enough yet to abstract it out.

> If that’s acceptable, why is an IsFooLike which only checks one condition unacceptable, even though it (imo) expresses the same intention?

It's not the same intention.

In the more complex case, you have a bad name because the name doesn't describe the (overly complex) intention of the code, but there isn't a better one.

In the second case, you have something that does a clear thing, so you should name it what it does. For a more complex case, you're not going to be able to capture every nitpicky detail of what the function does in the name, so you have to describe it in a broader concept. But with a short simple function like this, there really isn't an excuse for using a vague description.

I think you're still ignoring my explanation that what a function does and intends to do is different from how it does it. So I'm going to again insist that the two of you answer these questions to prove they actually understand my points before disagreeing with me:

1. I'm claiming that in correctly-working code, the intention of the code IS what it does. Is there a case where code would do something other than it's intended to do, and this isn't a bug or at least misleading code?

2. I'm claiming that what a function does is not the same as its implementation. Why are you claiming `starts_with_foo(x)` coupled to the implementation `x.startswith('foo')` and not `x[:3] == 'foo'`?

This is a really, really terrible way to name functions, or anything. I have seen code that tried to put the spec in the name, and it was awful.

A name that is long enough to tell you all you might need to know about what the thing named does is too long to be usable at all.

A name needs to be long enough to distinguish it from the other things being named. That's what naming means. If it also gives you a hint about which thing, of the things named, it really does, that makes it perfect.

Anything beyond that adds cognitive load, making it exponentially worse with each syllable added.

In your example `is_carbonated` is a private method. In an public interface you would want to hide the implementation details but surely not in a private method.