HNHacker News
TopNewBestAskShowJobs

spawarotti

330 karma · joined September 12, 2013

submissionscomments
spawarotti··on Don’t mock what you don’t own
This rule is also recommended by section 9.2.4. "Only mock types that you own" of 2020 book by Vladimir Khorikov: "Unit Testing Principles, Practices, and Patterns".

Worth noting is that book also says in 9.2.1: "Mocks are for integration tests only". I agree.

In my opinion this book is the best comprehensive take on testing I ever encountered.

spawarotti··on Ask HN: What developer tools would you like to see?
A tool similar to what you want. It generates input/output pairs from the code, aiming to maximize coverage, and allows you to convert them to unit tests with one click.

https://docs.microsoft.com/en-us/visualstudio/test/generate-...

Also known as its legacy / research project name, "Pex". The underlying algorithm technique is called "dynamic symbolic execution".

There was also similar tool for Java called "Agitar Agitator".

spawarotti··on I'm an addict
I’ve been struggling with the same problem and found a solution that works for me. I was procrastinating up to 8 hours per day, on average.

The core idea is to make a contract with oneself to not exceed a daily budget of procrastination and implement it. Say, 4 hours per day, on average. Everything else follows from it.

There are few critical components to make this work:

1. You need to admit you have a problem that needs fixing. If you procrastinate so much, quite possibly you are depressed. Like, for realz. That's OK.

2. Self-understanding that this is a matter of survival. Either you will make this work, or your life will be truly miserable, up to and including destroying your career, relationships and health.

3. Comprehensive time tracking. If you were watching a YouTube video while eating and spent extra 5 minutes to finish off the video after you were done with your meal, you need to track these 5 minutes. If you pick up your phone in bed just to quickly scroll through pages for 3 minutes, you need to track it. I use Excel for that - very fast & easy if you know the right keyboard shortcuts.

4. You need to do the tracking _yourself_. This is to (a) increase awareness you procrastinated and (b) introduce friction to doing it.

5. Social accountability. I have a weekly session with a coach where I report if I stayed within the quota, or not. But anybody you don't want to disappoint will do.

6. You are good as long as you stay within the budget. If you spend the time you reclaimed by laying on the couch and looking at the ceiling for 3 hours - that's a huge win. More on that below.

7. As always, you cannot neglect your fundamentals: sleep, exercise, proper diet, socializing. But now you will have time to deal with it.

Once you implement this process, few observation immediately come to mind:

1. You have so much more time and mental energy. Wow.

2. If you fail to track these short 3-5 minute burst of procrastination, they quickly add up to half an hour, an hour, two hours. Hence, you really cannot slip on that. If you slip, you also won’t be able to trust yourself, which is critical.

3. You become bored with that extra time, meaning you finally have time to think and talk to yourself. I cannot overstate how important that is. You can use this time to direct your thoughts / visualize better outcomes and hence motivate yourself to do the right thing (aka Cognitive Behavioral Therapy).

4. Once you keep doing it successfully for some time, you can now trust yourself that you are in control. This is huge, because your emotions now will be on your side.

5. You become less afraid of doing productive things, because you actually have time to do them, instead of thinking "what's the point, I have 1 hour in the day left after wasting all of it, I am tired, and I will give into my procrastination cravings anyway".

6. You will sleep way more because now you cannot procrastinate in bed. This will repay your sleep debt and restore your energy levels, making everything else much easier to tackle.

Overall, this strategy works for me very well because (a) I admitted to myself I have a problem that is very serious. This means I need to seek help and develop a process to solve it. And (b) I don’t mind doing comprehensive time tracking of my procrastination time, which is a critical part of the entire process.

Further reading:

"Digital Minimalism" by Cal Newport

"Feeling Good" by David D. Burns

spawarotti··on Hiring discrimination: a problem for men in female-dominated occupations
I think it is fair to not spend time and resources engaging with such ideas, as long as there is a good "decision record" documentation explaining that this subject was already discussed, decisions were made, and there is no point coming back to it. Same as with flat Earth - have some documentation thoroughly debunking the idea and point to it anybody trying to start the conversation again. Tell them they need to first read through all of it. If they are still not convinced after that, they are free to lay out their argument, but it is on them to make the argument strong, which should be, like, really hard, given the plethora of evidence we have that Earth is not flat.

In the examples you gave the "decision record" would be fairly simple - we assume that human rights [1] are a given.

[1] https://en.wikipedia.org/wiki/Human_rights

spawarotti··on The money I saved as a child would buy one picogram of gold today
I think they meant that "a continuing rise in the general price level usually attributed to an increase in the volume of money and credit relative to available goods and services." is theft.
spawarotti··on Ed Sheeran on creative cost of lawsuit: ‘Now I just film everything’
Thought experiment: say to the songwriters accusing Ed Sheeran: we are going to use software to evaluate all the songs you wrote against all other songs in existence. If we find at least one overlap, of any of your songs with any other song in existence that was released before, of the same or longer length as claimed plagiarism, you are getting sued.

I wonder if this would change their attitude to the problem.

spawarotti··on The Shaming-Industrial Complex
That's exactly my point. Understanding the dependent context can be considered the "advanced morality" the parent post asked about.
spawarotti··on The Shaming-Industrial Complex
And how do you know if they are sensitive? Are you going to ask them, or not? If not, why not? If yes, would it still be the golden rule? Or perhaps platinum rule - do unto others as -they- wish, not as -you-.

What I am trying to say is that the golden rule and its applicability is far from obvious. You can consider interpreting it correctly the most basic "advanced morality" you asked about.

spawarotti··on The Shaming-Industrial Complex
What if I am very secure about given topic (e.g., balding), so I feel very comfortable joking about it, even "at my cost". Should I disregard the fact other people might be insecure about it, because I don't mind people "doing unto me" such jokes?
spawarotti··on What does a 1972 paper have to do with the Single Responsibility Principle?
What you are saying might be a manifestation of the "bounded context" pattern/problem:

https://martinfowler.com/bliki/BoundedContext.html

It is a huge topic. Hard for me to discuss this further without knowing the specifics. But intuitively, if it was as simple as "Really all I need is a simple string and a validation function." then you wouldn't need a class with several hundred lines of code.

Or you could have UsaPhoneNumber, JapanesePhoneNumber, etc.

And instead of doing:

IsValidUsaPhoneNumber(str);

you could do:

var usaPhoneNumber = new UsaPhoneNumber(str);

and now you have the validness captured as a type:

https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...

spawarotti··on What does a 1972 paper have to do with the Single Responsibility Principle?
On an "abstract/fuzzy" level I would say that a class with several hundreds lines of code means you are missing some terms in your domain language dictionary. For example, you might be doing a lot of inline operations on strings that represent PhoneNumber, but instead you could extract that logic into a PhoneNumber class. Even if it is only used within the scope of the larger class. Once you apply this a couple of times you will have few classes each with no more than 200 lines of code (in a language like C#).

The critical thing here is: these classes reflect terms from the domain model that can be easily intuitively understood, not some made-up abstractions adding to incidental complexity, like -Manager, -Util, -Provider, -Context, -Wrapper, and so on.

Conversely, you can imagine that you wrote a sentence, took some words from it, assumed these words don't exist, and replaced them with their dictionary definitions. Repeat a couple of times and you have your one big class. Extracting classes to capture domain language terms is like reversing this obfuscation/serialization process.

Cool article on the topic: https://www.yegor256.com/2014/11/20/seven-virtues-of-good-ob...

spawarotti··on Chernobyl power plant captured by Russian forces
There is a Kurzgesagt video about that: https://www.youtube.com/watch?v=JyECrGp-Sw8

If you detonate all nukes you could destroy every city with population of over 100'000, worldwide. About 4'500 cities in total. You would still have around 1'500 nukes left. You would kill at least 3 billion people.

spawarotti··on Favor real dependencies for unit testing
Naturally, I agree that the shouldExecute / ValidateSyntax methods should be tested too, but this is not the whole story.

Let me clarify my point with a more precise example.

Let's say we want to test this:

ParseUrlDomainAndPath(string url) { string validatedUrl = Validate(url); (domain, path) = /* inline logic to extract domain and path from the validatedUrl */; return (domain, path) }

Now I have few options to unit test it:

1. I could mock out "Validate" to return the "url" passed as input, call in the test ParseUrlDomainAndPath("___:||testDomain|testPath"), and assert it returns (testDomain, testPath). Such test might even pass, if the inline logic for extracting domain and path is not too fussy about the delimiters. In such case I will end up with a test telling me "if you call ParseUrlDomainAndPath with URL that has | instead of / and some weird schema of ___, it will successfully return". This is a lie. If you call it in production, it will fail validation. So the test gives you false impression on how the system behaves. You are testing how parsing of domain and path works on URL that has | instead of /, but this won't happen in production. Thus, you are testing made-up behavior. Waste of time.

2. As 1., but instead I could mock out Validate to return whatever validatedUrl I want, completely disregarding url. In such case, what is the point of even having Validate involved in the test here? Instead, let's refactor to functional core - let's take the inline logic, capture it in a method called "ExtractDomainAndPathFromUrl(string validatedUrl)" and pass validatedUrl to it directly. No need to deal with Validate at all, no need to mock anything, no need to fixup any broken mocks. Great!

3. As 1., but as input I pass "foo". The mocked out Validate returns "foo", and we are now trying to extract domain and path from it. This will either throw an exception or return garbage. So our test now has failed. But we don't care about this failure, at all. In actual production behavior the domain and path extraction logic would never even execute, because Validate would fail beforehand. So here we have reverse situation to 1.: In 1. we have a test telling us production will work while in reality it won't (as Validate will throw), and here we "found a bug" (the test fails) that doesn't matter as it is impossible to happen in production. Again, waste of time.

So with 1. and 3. being waste of time, the only option that is left is 2. You have one test that a) checks that Validate behaves correctly and b) checks that ExtractDomainAndPath behaves correctly and c) checks that both of these methods collaborate with each other correctly (aka "mini integration test").

You could now argue that this is wrong, I should have one test for Validate, one test for ExtractDomainAndPath and one test for ParseUrlDomainAndPath that mocks out Validate and mocks out ExtactDomainAndPath. But let me ask: why? In such case you lose the benefit of having "mini-integration" test. When you test ParseUrlDomainAndPath with everything mocked out you test an empty husk of logic, only if the calls are made in proper sequence. You cannot even really assert anything meaningful! (aka "mockery" anti-pattern). You end up with 3 tests instead of 1 and cr*pton of unreadable, brittle mock logic. And chances are, the one test of ParseUrlDomainAndPath that doesn't use any mocks of internal business logic, will already cover significant parts of ValidateUrl and ExtactDomainAndPath, and so will reduce the need of additional "corner case" tests testing these methods directly. Having 1 test with proper in-process dependencies instead of having mocks and 3 tests is just win all over he place: less testing logic, better ability to catch bugs (due to bonus mini-integration testing and realistic data), executable specification aiding in program comprehension, less brittle tests, no misleading green tests, and no made-up, irrelevant failing tests.

There is one more, very important benefit: you can step such test with a debugger and see how all the components collaborate with each other, on real data. But if you use mocks and fake oversimplified data, you get very shallow slices of code and cannot reason about anything relevant.

spawarotti··on Favor real dependencies for unit testing
> I don’t care how that function is implemented, only that it returns a boolean

Let's take your example of "shouldExecute". I assume your unit test operates on some inputs (with the values provided inside the unit test itself, naturally), and "shouldExecute" has potentially some nontrivial logic in it. Say, it reads value of some environment variable and if it is right, returns "true".

Now there are two possibilities:

a) your test inputs are made up. For example, you never set the environment variable value, and coerce "shouldExecute" to always return "true" anyway. The problem with such a test is that it is fiction, not a test of an actual production behavior. Sure, you will test what would happen if the logic would determine it should execute given no environment variable is set, but this will never happen in production. In production lack of environment variable would result in "shouldExecute" returning "false" and you should test for *that*. So you do care about the details of "shouldExecute", because you need to be aware that it returns "true" only if appropriate environment variable is set. And if you don't care if the "shouldExecute" returns true or false, then why do you call it in the first place? What are you even testing? I hope your "shouldExecute" doesn't have any side effects you depend on, and I do hope you do not use code coverage as a goal unto itself.

Plus, such a test cannot be used as "executable documentation", because the inputs are simplified to the point of irrelevance, and cannot help in understanding actual program behavior.

b) your test inputs are realistic, and reflect actual production behavior. This means you will have properly set up the environment variable value so that "shouldExecute" returns true. With that, the test is similar to actual production behavior, has good bug-catching ability, and can serve as executable specification. But here again you will have to worry about "shouldExecute" implementation.

---

Let me offer you another example. Imagine we want to test:

Compile(SourceCode sourceCode) { ValidateSyntax(sourceCode); /* complex logic post-processing the sourceCode here */ }

I could say here "I am testing Compile, and I do not care if ValidateSyntax throws an exception; I will just coerce it to return without throwing an exception".

And then I can write a test that takes as input some simple sourceCode like "blablabla" and claim I have somehow tested the "/* complex logic post-processing the sourceCode here */". But this is silly, in reality such fake input would never survive the validation, and thus testing what happens after is just waste of time. Hence I need to ensure sourceCode passes the *actual* validation, and hence I need to understand the logic inside the "ValidateSyntax" method.

It gets worse. Now imagine we have thoroughly tested the complex logic while using mocked out ValidateSyntax, but now the syntax has changed and thus the validate method behaves differently. If I have a mock of the "ValidateSyntax" method I might still feel good - the test is green, the coverage is still high. Except it is all I lie. I run "Compile" on some production data and it blows up. Why? Because the test was working against a "ValidateSyntax" mock that was mocking the result of validating obsolete syntax, which, now, with the changed behavior, would actually not pass validation and blow up. Basically my test was telling my "Compile" method works IF I assume syntax is still the obsolete one, but it doesn't tell me how my code behaves with the current syntax.

So every time program behavior changes, I need to go through all my mocks that were duplicating that behavior, and see if they are still faithfully reflecting it. Otherwise I risk ending up with a green test suite that tests nonexistent, impossible program executions.

spawarotti··on Favor real dependencies for unit testing
> The heart of the argument presented is that using mocks in unit tests is problematic (...) If you use real implementations

No. As you say, the moment you have a real out-of-process dependency, you no longer have a unit test, but an "integration-with-external world" test.

The heart of the argument is to not mock out internal (in-process) business logic. Instead:

a) do not use mocks (e.g. leveraging Moq); use fakes (aka "simulators"), i.e. proper classes having in-memory implementations of the out-of-process dependencies and crucially

b) replace only out-of-process dependencies, which usually are flaky/nondeterministic. Never replace internal business logic.

If you feel you need to replace internal business logic, you are not following the functional core architectural pattern. After you refactor to functional core you will no longer need to replace any dependencies in your unit test, as there won't be any - you will just call your tested pure method and make assertions on the returned value.

Special case here is testing "top-level/controller" logic. Here you need to use the in-memory fakes, but there will be only few, reused across all tests, and such test will be an "end-to-end internal-business-logic integration test", but still it will have all the properties of a unit test - it will be fast, deterministic, and you will be able to run it as part of a unit test suite out-of-the-box, with no environment setup necessary.

Further reading: https://enterprisecraftsmanship.com/posts/when-to-mock/

> If you want to change code you will always measure the effect it will have on the code and tests are incidental, not the primary concern

Exactly. Mocks are very brittle and break all the time, causing unnecessary rework. If you instead rely on a small set of fakes of out-of-process dependencies, you will drastically reduce test suite rework and improve signal-to-noise ratio.

> Using a real dependency, I would be left in the unfortunate situation of depending on knowledge of the internals of that dependency.

And what happens if the real dependency changes behavior, but you forget to update your mock? You will have a test that will be running against a mock that simulates obsolete behavior, no longer present in production. In worst case scenario the test will be green/passing, while there is a bug in production. Will you remember to always comb over your entire test suite and review all mocks to faithfully simulate actual production behavior?

> It may not allow me to execute specific paths via pure configuration at all.

If you write fakes, you will have full control over how to configure them.

spawarotti··on Favor real dependencies for unit testing
This article espouses what is known as "classicist testing" school of thought and rejects "mockist/London-style testing". I wholeheartedly agree with it. I have been championing it in my team of 20+ devs since many years now, to great effect. You can read more about it in the excellent book by Vladimir Khorikov from January 2020 titled "Unit Testing Principles, Practices, and Patterns".
spawarotti··on Procrastinatory Doom Loops
The funny part is when the person you committed to is yourself.
spawarotti··on FAQs: Why we don’t have them (2013)
Isn't Stack Overflow one big FAQ? So arguing FAQs shouldn't exist is like arguing SO shouldn't exist? Nice in theory, but in practice...
spawarotti··on Selective Unit Testing – Costs and Benefits (2009)
The four quadrants of code types as shown in the article also appear as Figure 7.1 in an excellent book on testing: Unit Testing Principles, Practices, and Patterns, by Vladimir Khorikov, January 2020. https://www.manning.com/books/unit-testing
spawarotti··on How to deliver constructive feedback in difficult situations (2019)
I think you touch on an important point: you have some expectation and the person doesn't share it. But here is the rub - maybe they are right, not you? Why do you assume you are right? Maybe that person indeed is not needed on that meeting. Maybe by being late they are trying to communicate to you this meeting is in fact a waste of everyone's time. Did you consider this?

For me that's one of the main failing points of NVC as I see it represented here - it starts with "I am right, and you need to adjust" instead of "let's find the underlying root cause of the problem together".

spawarotti··on How to deliver constructive feedback in difficult situations (2019)
> You were ten minutes late this morning. I was annoyed at having to wait for you and lose productivity. Could you explain why you were late?

Honestly, this sounds even worse to me than just the observation. IMO a good test is "Would I say this to my boss? If not, then probably I shouldn't say it at all.". I would not say this to my boss. Not even close.

How about instead:

"Hey, I noticed you were a little bit late, which is unusual for you. Is everything OK?"

And if the pattern continues:

"Hey, I noticed you were a bit late in the last couple of meetings. I think it is somewhat important to be on time. Is there anything I can do to help you avoid being late next time?"

spawarotti··on Changes at Basecamp
I think you jumped to conclusions here by assuming bad intent. Perhaps implicitly the new policy assumes it is obvious you can mention your husband and anybody giving you problems because of that is violating the policy.

I do think the policy should be explicit about it. It doesn't help to say "We forbid X" if one side's prominent tactic is to redefine X as they see fit. By analogy, it is not enough to say "We forbid discussions about religious beliefs". One also needs to say "Theory of evolution is accepted here as true".

spawarotti··on The real reason to end the death penalty
I've heard the "1) Low Cost" is false. [1]. Mainly because it takes time and effort to actually execute someone, to give plenty of time to find evidence exonerating them. That delay and proceedings end up being way more expensive than just letting them live.

Re 2): Again from [1], I've heard executions are actually quite expensive. Thus, it doesn't scale well.

Re 3): It doesn't make me feel safe if somebody can frame me and get me killed. It makes me feel safer knowing I have time to prove my innocence.

Re 4): I am very skeptical of this claim. Any solid evidence for this being true? Anecdotal evidence shows the opposite. Most criminals don't have good long-term thinking skills, so they won't recognize the tradeoff between 40 years in prison and death, and use that to not commit a crime.

[1] John Oliver on death penalty: https://www.youtube.com/watch?v=Kye2oX-b39E

spawarotti··on What defines a great company culture?
> What's great for you is not what's great for another.

> Too bad we can't understand this in our politics

Unless you have a very good reason to not get a vaccine and not wear a mask I will expect from you to do these things. Not because I don't understand what's not great for you. It's because I understand the objective reality of the disease.

spawarotti··on Microsoft Power Fx – A low-code general purpose programming language
I wonder how this relates to "Calc Intelligence" or "Project LAMBDA", made by Simon Peyton Jones (of Haskell fame) et al.

https://www.microsoft.com/en-us/research/blog/lambda-the-ult...

> By Calc Intelligence, we mean the research goal of bringing intelligence to end-user programming. The spreadsheet of the future is a trustworthy collaborator and teacher.

> In December 2020, we announced LAMBDA, which allows users to define new functions written in Excel’s own formula language, directly addressing our second challenge. These newly defined functions can call other LAMBDA-defined functions, to arbitrary depth, even recursively. With LAMBDA, Excel has become Turing-complete. You can now, in principle, write any computation in the Excel formula language.

spawarotti··on Making Games on Your Own as an Engineer
I can relate. Similarly, I ensure I put some time into my side-project on a daily basis, but don't coerce myself into very narrowed down optimal path. Once I gain momentum, I have easier time tackling the not-most-fun "shoulds".
spawarotti··on Illegal CFC emissions have stopped since scientists raised alarm
> After the Russian annexation of Crimea during the 2014 Crimean crisis, Ukrainian authorities greatly cut the volume of water flowing into Crimea via the canal, citing a huge outstanding debt on water supplies owed by the peninsula. When the Russian government offered to pay the debt, the Ukrainian government refused. This caused the peninsula's agricultural harvest which is heavily dependent on irrigation to fail in 2014.

https://en.wikipedia.org/wiki/North_Crimean_Canal#2014_Crime...

A video with some narrative around it: https://www.youtube.com/watch?v=Aqq8clIceys

spawarotti··on Making the Monty Hall problem weirder but obvious
I would not say it is a flaw. I think it is a reasonable implicit assumption that there is only one round, unless explicitly stated otherwise.
spawarotti··on Making the Monty Hall problem weirder but obvious
Key observation: you lose when switching the door only if your first pick was winning.

Your first pick had 1/3 chance of winning. So switching has 1/3 chance of losing. Thus it has 1 - 1/3 == 2/3 chance of winning.

spawarotti··on Evil Unit Testing (2019)
Came here to say exactly that. The author is advocating for mockist style of unit testing, which is quite terrible for many, many reasons. What you are describing is classic unit testing, and this is the way to go.

Good article and book about it:

- https://enterprisecraftsmanship.com/posts/unit-testing-depen...

- Unit Testing Principles, Practices, and Patterns

← PreviousPage 2 of 3Next →