Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The line demarcating "external" and "internal" can be quite mobile, and moreover, context-dependent. Especially when refactoring.


No! Never change the behaviour and the implementation at the same time! It is the same for a class or function or monoid or whatever. API change and implementation change should never happen at the same time. If you covered the old behaviour with tests (on the appropriate granularity) you can refactor the IMPLEMENTATION and verify that the systems tested invariants hold buy running the tests. There are a lot of books written about this but really the main idea is this simple.


Could I ask what you mean by "external" and "internal" here? Could different parts of a codebase ever count as "external"?


I think they are referring to behaviour, not "parts of a codebase", as the GP comment used the phrase "external behavior".


I wouldn't make that assumption. For many people "external" means "in a different class to this one", for others "external" means some other process or service (e.g. a DB like MySQL).

It's a widespread problem that people can end up talking past each other, since they make assumptions about the definitions of terminology that other people are using.

I've written about this e.g. http://chriswarbo.net/blog/2017-11-10-unit_testing_terminolo... and http://chriswarbo.net/blog/2020-07-07-more_testing_terminolo...


You're right that terminology is fluid and people can talk past each other. But you have to draw the line somewhere. The original comment by fenomashas only two sentences, the subject of the first was "external behavior" and the second was on the same topic. The comment after that by invalidOrTaken, which you replied to, is also very short and was specifically asking about fenomashas's use of the word "external". We can be as confident as it is reasonably possible to be that invalidOrTaken therefore was asking about external behaviour, not code. (Incidentally, invalidOrTaken's comment was also about clarity of definition, but not the same difference you were questioning - at least if I understood you right!)

My own use of the equivocal language "I think" didn't help here. That was a bit of classic British understatement. But really, the two comments we're talking about are unambiguous.


fenomashas's comment seemed clear to me.

invalidOrTaken's claim that refactoring can affect what is internal versus external, or that it can be context-dependent, was surprising to me. I would consider changes to what's internal versus external as breaking changes; large changes could plausibly be called redesigns. Certainly not refactorings.

The context-dependence of internal/external makes sense, but that makes me think in terms of e.g. "MySQL is external to the application" versus "MySQL is inside the application's container", or even "MySQL is interal to the subnet where the application runs". Architecturally that makes sense, but I don't think it would affect the way I test things, or classify those tests.

On the other hand, invalidOrTaken might be using "external" to mean "other classes", in which case it's easy to imagine a refactoring changing all sorts of (class) boundaries. Likewise, the phrase "external behaviour" could simply mean "the public methods of a class".

I've certainly worked somewhere that claimed to follow "Behaviour Driven Development", where each "behaviour" was a micro-managed implementation detail of a particular method of a class, with a huge pile of mocks to simulate the behaviour of everything else.


What I was envisioning, though I'm sure the motivated reader could find other situations that are similar, was a refactor I was doing a week or so on an internal library.

The "external" interface, as in, the API presented by the library, mostly did not change. But internally blocks were broken apart, new ones formed, and logic ripped from one function and placed in another.

To someone seeing the whole, or "the library," changes were 99% internal (some changes in how options were interpreted).

But from the perspective of any one function, boundaries were crossed quite promiscuously, and if we'd had unit tests for them, we'd have needed to (re-)write some.

It's my experience that we are not very good at saying, "THESE are the chunks into which the program should be divided and thought of," and then never altering from that. There's always some cross-cutting concern that comes up. For this reason, I am suspicious of unit-testing-by-default, as "what is a unit" is often in flux.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: