Blog

Why do Salespeople Believe in Magic?

File this one under techies complaining about non-techies. Over the years, I have noticed a pattern with salespeople, they have a firm belief in wishful thinking. They honestly believe that wishing something to be true will magically make it so.

Wishful_Thinking

The specific pattern I noticed many a time goes something like this.

The customer wants something done and goes through their account manager to request that. The account manager — a fancy name for salesperson — commits to a date without talking to the developer first. They then go to the developer and tell her something to the effect of “yeah, I’m going to need that by Friday morning.” The exasperated developer explains that this is not feasible and the account manager responds by simply repeating that they will need it by Friday. They usually leave at this point satisfied that everything is fine.

Come Friday, the account manager is then horrified to discover that the feature is not ready. “But we made a commitment with the customer,” they’ll say, emphasizing the “we” that never was.

This has happened some many times in my career that I should no longer be surprise and yet I still do. Every time.

Of course, what they are really doing is trying to put pressure on the developers so that they will hurry up and deliver on the desired timeframe. And to be fair, it can sometimes work, but if the developer tells them in no uncertain terms that the deadline is not feasible, then the salesperson is taking the risk by herself.

By committing to a date with the customer before talking to the developer, the salesperson has already taken a big risk. They will then try to spread that risk by sharing it with the developer. Since the developer never had a chance to agree with that in the first place, it is only fair that she should be able to refuse to take the risk if she doesn’t believe it is worth it. Why should she?

And yet, we developers often accept the risk by being passive and simply accepting it. This problem can be exacerbated by managers who are also passive. Many years ago I worked at a company where the engineering power that be were submissive to the sales department, which led to some of the worst experiences in my life as a developer, including the Project From Hell.

At the time, I led the engineering services group, so whenever a new project came about that required software development, it had to go through me for analysis. Another group leader analysed the infrastructure projects. Then one day this large project showed up on my desk. I looked over it along with the infrastructure guy and we agreed that it was a monster of a project, including developing a huge distributed nationwide (Brazil) infrastructure, a huge system developed from scratch, and a lot of technology transfer and end-user training.

The project had some timeframes attached to it and although they were tight, they were not what immediately caught out eyes. We saw the pricing they were offering the customer and it was clear to us that it was low. We raised the issue but were told not to worry about it. There are valid business reasons to do projects at a loss sometimes, so it was okay, except the exact wording to us was, “please limit yourselves to your little expertise sphere.” Ok then.

We talked to our teams and we committed to the dates defined in the project documentation. Again, it was a little tight but feasible: we would have many months to get things ready for initial deployment.

About a week after we approved the statement of work, I received a call from the customer. At this point, I had not yet engaged the customer at all, so they had gotten my phone number from their sales rep. The customer was possessed. This person I had never talked to before was shouting at me on the phone that we were late. It took me a while to call him down and understand what the issue was.

As it turns out, the sales team, in an effort to get the customer’s signatures before the end of the quarter, changed the statement of work after we had gone through it, moving the dates to right that very moment. We had not even started working on the project yet and the customer was expecting it to be ready right then. We were late before we even started.

Many stressful meetings later we managed to agree on some new dates, but they were much tighter than the ones originally in the statement of work and would required us to outsource parts of the project to a contractor to help speed up things. Incidentally, what we paid the contractor for only a part of the project was more than what our company made on the project. All because the sales team wanted to make sure they got their commission in that quarter.

The people responsible would eventually be let go of the company, in great part due to this, but that did not prevent the company from losing at least an order of magnitude more than what it made from that project.

And still, I continue to see salespeople ignoring the developers and then trying to share the fallout. Developers need to stand firmly by their professional evaluations of deadlines and technical feasibilities.

Of course, if you turn out to be wrong, all of this is moot.

Goodbye, Mr. Spock.

Leonard Nimoy

I am sad. The New York Times

Leonard Nimoy, the sonorous, gaunt-faced actor who won a worshipful global following as Mr. Spock, the resolutely logical human-alien first officer of the Starship Enterprise in the television and movie juggernaut “Star Trek,” died on Friday morning at his home in the Bel Air section of Los Angeles. He was 83.

I am actually sad. As much as Star Trek was a part of my life, I had not felt this way when other cast members passed away in the past.

I suppose Nimoy was different somehow. My theory is that as Spock, he would (almost) never smile and that made his rare smile that much more important. When I think of Nimoy/Spock, it is his smile that I picture in my mind. When out of character, he was always smiling. This contrast forces an emotional connection or something. I don’t know.

What I do know is I am sad. For whatever’s worth, Nimoy was a part of my life.

You’ll be missed, Mr. Nimoy. I have been, and always shall be, your fan.

Go 1.4 moves the runtime toward Go

I installed Go 1.4 to test a service and found the most interesting changes below my source code. Parts of the runtime and tools are being translated from C into Go. That work is not a promise that applications suddenly run faster; it is groundwork for making the implementation easier to evolve with one type system and toolchain.

The collector is now fully precise. It identifies pointers in stacks and the heap rather than retaining objects because non-pointer data happens to resemble an address. Precision also requires cooperation from writes: write barriers record pointer updates that the collector must not miss while maintaining its view of the object graph. This is infrastructure for collector work, not the concurrent collector people keep casually attributing to this release. Go 1.4 still has stop-the-world collection behavior worth measuring.

Goroutine stacks now start at 2 KiB, down from the larger starting size in previous releases, and grow by copying when needed. This materially reduces initial memory for programs with many mostly shallow goroutines. It does not make deep stacks free; growth allocates a larger contiguous stack and copies live contents using precise pointer information.

Two source-level tools are immediately practical. go generate lets a package record commands that generate source or other build inputs:

//go:generate stringer -type=State

Running go generate is explicit; go build does not run generators automatically. I like that separation because builds should not unexpectedly require every generator or rewrite the tree. Generated files still need a clear policy in the repository, and the directive is a command for developers, not a dependency manager.

The new internal directory convention has an important 1.4-sized footnote. In this release, the restriction is enforced for packages in the main Go source repository, keeping implementation packages inside the standard library and toolchain. The intended rule is that code under a/b/internal/x may be imported only by packages rooted within a/b, but the go command does not yet enforce that boundary for general repositories. Broader enforcement is future work.

example.com/project/internal/wire
example.com/project/server

I can use the same layout in my own repository to advertise intent, but in Go 1.4 that part is still convention rather than a boundary enforced by the tool. It is worth adopting without pretending the lock is already on the door.

After the upgrade I reran tests, allocation benchmarks, and latency measurements rather than assuming runtime changes were universally beneficial. The service used less memory with thousands of idle goroutines, while its GC tail latency remained visible. That is a believable improvement: smaller starting stacks and more precise tracing reduce waste, but write barriers and collection still have costs.

Go 1.4 mostly removes future constraints. More runtime code in Go, complete pointer precision, and barriers prepare the implementation for deeper collector changes. Meanwhile, go generate is useful now, and internal shows where package boundaries are headed.

Where an HTTP timeout actually fires

I added a dial timeout to an HTTP client and assumed I had bounded the entire request. Then a server accepted the connection, sent headers, and dribbled the body slowly enough to occupy a worker for minutes. The timeout had completed its duty before the interesting failure began.

In Go 1.3, the first choice for a simple end-to-end limit is http.Client.Timeout:

client := &http.Client{Timeout: 5 * time.Second}

It covers connection setup, redirects, and reading the response body. If the policy really is “this request gets five seconds,” start there. My narrower transport setting looked like this:

tr := &http.Transport{
	Dial: (&net.Dialer{
		Timeout: 2 * time.Second,
	}).Dial,
}
client := &http.Client{Transport: tr}

The dial timeout covers establishing the network connection. It does not cover waiting for response headers, reading a response body, or the time spent following redirects. DNS resolution may consume part of dialing behavior depending on the platform and resolver path, but the timeout is still not an end-to-end request deadline.

To see the phases, I wrote a deliberately bad server:

func slow(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusOK)
	if f, ok := w.(http.Flusher); ok {
		f.Flush()
	}
	time.Sleep(10 * time.Second)
	fmt.Fprintln(w, "eventually")
}

The client connected immediately and received headers immediately. Its Do call returned a response, then reading resp.Body waited. A connect timeout could not help because the connection was exemplary.

The transport exposes other phase-specific controls. ResponseHeaderTimeout bounds the wait for response headers after the request is written. TLSHandshakeTimeout bounds the TLS handshake. Neither bounds a slowly arriving body. These knobs are useful because failures differ: a slow handshake may indicate different capacity trouble than a handler that never writes headers.

For policies that Client.Timeout cannot express, I can arrange cancellation through the transport’s request cancellation support and a timer. Merely returning from a selecting caller while leaving Do running leaks work: timeout handling must interrupt the network operation, not only stop waiting for its answer.

For direct net.Conn code, deadlines are clearer:

if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
	return err
}

The deadline applies to future reads and writes and causes them to fail after the time. SetReadDeadline and SetWriteDeadline split those directions. A deadline is an absolute time, not an idle timeout that automatically moves after every successful byte. For an idle protocol I refresh it after each accepted unit of progress.

HTTP complicates direct connection deadlines because http.Transport owns and reuses pooled connections. A per-request caller should not reach underneath and set arbitrary deadlines on a connection that may later serve another request. Transport-level controls and cancellation preserve that ownership boundary.

As with the earlier runtime-managed network mechanism, a goroutine can wait without occupying a thread. Cheap waiting is not a timeout policy, though. In-flight requests, response body size, queue length, and elapsed time still need deliberate limits.

Servers have the same issue from the opposite side. A handler can be tied up by a client that sends or receives slowly. Depending on the Go version and server configuration, read and write timeouts establish connection-level deadlines around phases of serving a request. They are blunt instruments, especially for streaming responses, but leaving every deadline at zero means “forever.”

I tested the repaired client with three bad endpoints: one that never completed a TCP connection, one that accepted but withheld headers, and one that streamed a byte periodically. Each exercises a different phase. The output made the distinction visible:

dial stall:    timeout awaiting connection
header stall:  timeout awaiting response headers
body stall:    request deadline reached while reading body

Error strings vary and should not become program logic. I care that each operation terminates, closes its body or cancellation path, and leaves no steadily growing goroutine count.

The temptation is to choose one five-second number and call the system safe. Real policies differ. A metadata request might have a strict total deadline. A large download may allow minutes overall but reject 30 seconds without progress. A streaming endpoint may be intentionally unbounded while still needing heartbeat and cancellation rules.

Timeout errors should remain distinguishable from protocol failures. I check whether a returned network error reports Timeout() rather than matching its text, then include the operation and peer in the higher-level error. Retrying blindly is still wrong: a timed-out request may have reached the server, so non-idempotent operations need application-level rules.

“The HTTP timeout” is not a very useful phrase. There are limits for connecting, handshaking, receiving headers, reading bodies, remaining idle, and completing the whole operation. Naming the phase put the mechanism in the right place; before that, I had a very reliable timeout on the part that was not slow.

My social anxiety screwed me royally this week

By Christopher Walker (Sadness) CCBY−SA2.0(http://creativecommons.org/licenses/by−sa/2.0)CC BY-SA 2.0 (http://creativecommons.org/licenses/by-sa/2.0), via Wikimedia Commons

A few years ago I wrote about how social anxiety makes me use fake accounts on the web.

I love coding. I have done it since I was a kid and it’s the best thing I know how to do. And then there is open source. Open source projects should be the perfect venue for me to have f un. Except I am scared stiff by the idea that someone might laugh at the code. It came to a point where it is impossible for me to contribute. Then I’ve come up with a solution: an alias. For the past several years I’ve lived two different lives online: one as myself and another as an alias. I keep them strictly separate.

Actually I today use more than one single separate life. Looking at my Chrome identities menu I count four (including the real me), but I actually have more around that I have abandoned.

It has allowed me to do what I like to do. I don’t have to be afraid because I know all I have to do is abandon one account and start over with another. It’s a good solution but it has some issues.

I have been offered this great job in the past by the manager of someone I’ve worked together. It was one of the Big Tech Companies, a place I really would love to work. All great, right? Except the offer was not addresses to Roberto Teixeira, but to one of my aliases. Tough luck. I’ve soon abandoned that alias for good.

So yes, it sucks. But not as much as it has sucked this week.

I—under an alias—have been working with a developer of a big open source project out there to try to solve a problem we were having at work. And I found a solution that was pretty clever. That developer checked it out and thought it was great and then we both wrote a proposal and submitted it. And it was accepted and our change will be part of their next major release.

I’m not saying it was something revolutionary or anything. Still, it was something I am very proud of. And there will be a name there in the changelog/release notes/whatever but it will not be my name.

This happened the same week I learned that someone I–the real me; real name and everything–interviewed with a few months ago had dismissed me for not having open source contributions.

In short, I am sad and angry. Fuck social anxiety. 🙁

(photo: Christopher Walker (Sadness) / CC BY-SA 2.0 / via Wikimedia Commons)