HN user

akeefer

1,787 karma

I'm a software engineer with Guidewire Software, and I pretty regularly publish articles on our development blog at http://guidewiredevelopment.wordpress.com/

I'm also a co-author of the Gosu programming language:

http://gosu-lang.org/

My e-mail is akeefer at gmail

Posts5
Comments355
View on HN

This post kind of misses the main point of services like Wealthfront. You're paying 0.25% in exchange for automatic rebalancing, asset class diversification, and tax optimization. If the combination of those factors is going to increase your yearly return by 0.25% or more (say, from 6.8% to 7.2%), it's worth it. If they won't, it's not.

It's silly to focus entirely on the fee aspect: the point of using Wealthfront is not because it's lower-cost, it's because you expect it to be better-performing from a total-return perspective. They may oversell themselves, and that's a valid criticism, but the OP fails to really analyze the raison d'etre of Wealthfront as a service. Comparing it to a single Vanguard ETF is not a proper comparison.

The Vanguard target retirement fund for 2035, for example, includes four underlying ETFs (US stock, international stock, US bonds, international bonds), whereas Wealthfront portfolios typically have more like six or seven asset classes (differentiating between developed and emerging international markets, and adding in natural resources and real estate). Left to my own devices, I don't have the time or inclination to do the research necessary to do that sort of additional asset diversification myself, determining the ideal allocation and then avoiding too much drift while not incurring too much tax. I also don't have the time to deal with tax loss harvesting, which might not matter for retirement accounts, but does make a difference for taxable accounts: you're likely incurring some taxation issues when it comes to portfolio rebalances, for example, since that necessarily involves asset sales. If you have $100k in wealthfront, you're paying $250/year in fees. If tax loss harvesting can only harvest $1k in losses during the year that offset (or at least avoid) $1k in capital gains, that still pays for the wealthfront fees by itself (if you assume 15% federal and 10% CA state tax on long-term capital gains). So, sure, the fees you pay wealthfront compound over time, but so does the money you pay in taxes. (You do eventually pay the taxes on that gain, of course, but the money you save now compounds over time, so you still come out significantly ahead).

So the question is: does additional asset class diversification plus tax optimization yield at least a 0.25% increase in your total return (net of taxes and fees) in an average year? I believe it does in my case, hence why I have my money with them. It's not because I'm some idiot taken in by slick marketing who can't do math and doesn't know about Vanguard ETFs: Wealthfront's core market is really people who can do math and understand what they're getting for their 0.25%.

Similarly, you can quibble over asset-based fees over fixed fees, but that also misses the point: as long as they make me more money than I pay them, I come out ahead. If I come out ahead, why would I be complaining? If I don't come out ahead, then there's still no point in complaining: just don't use the service. Capitalism at its finest.

Again, it's sad that the OP and most of the comments in this thread don't even attempt to tackle the real value proposition here. Just saying "Stick it in a Vanguard ETF and you'll pay less in fees" is not at all addressing whether or not the core value proposition is valid.

Sure, you can call that structure the design, or the architecture, or whatever you like. Either way, it's a fair question.

As a point of semantics: TDD generally stands for "test-driven development," not "test-driven design," though the article here does make the claim that TDD helps with design.

To reduce my personal philosophy to a near tautology: if you don't design the system to be testable, it's not going to be testable. TDD, to me, is really about designing for testability. Doing that, however, isn't easy: knowing what's testable and what's not requires a lot of practical experience which tends to be gained by writing a bunch of tests for things. In addition, the longer you wait to validate how testable your design actually is, the more likely it is that you got things wrong and will find it very painful to fix them. So when I talk about TDD myself, I'm really talking about "design for testability and validate testability early and often." If you don't have a clue how you want to build things, TDD isn't going to help.

If you take TDD to mean strictly test-first development . . . well, I only find that useful when I'm fixing bugs, where step 1 is always to write a regression test (if possible). Otherwise it just makes me miserable.

The other thing worth pointing out is that design for testability isn't always 100% aligned with other design concerns like performance, readability, or flexibility: you often have to make a tradeoff, and testability isn't always the right answer. I personally get really irked by the arguments some people make that "TDD always leads to good design; if you did TDD and the result isn't good, you're doing TDD wrong." Sure, plenty of people have no clue what they're doing and make a mess of things in the name of testability. (To be clear, I don't think the author here makes the mistake of begging the question: I liked the article because I think it honestly points out many of the types of mistakes people make and provides a reasonable approach to avoiding them.)

I think this is a great explanation of a lot of the obvious pitfalls with "basic" TDD, and why so many people end up putting in a lot of effort with TDD without getting much return.

I personally have kind of moved away from TDD over the years, because of some of these reasons: namely, that if the tests match the structure of the code too closely, changes to the organization of that code are incredibly painful because of the work to be done in fixing the tests. I think the author's solution is a good one, though it still doesn't really solve the problem around what you do if you realize you got something wrong and need to refactor things.

Over the years I personally have moved to writing some of the integration tests first, basically defining the API and the contracts that I feel like are the least likely to change, then breaking things down into the pieces that I think are necessary, but only really filling in unit tests once I'm pretty confident that the structure is basically correct and won't require major refactorings in the near future (and often only for those pieces whose behavior is complicated enough that the integration tests are unlikely to catch all the potential bugs).

I think there sometimes needs to be a bit more honest discussion about things like: * When TDD isn't a good idea (say, when prototyping things, or when you don't yet know how you want to structure the system) * Which tests are the most valuable, and how to identify them * The different ways in which tests can provide value (in ensuring the system is designed for testability, in identifying bugs during early implementation, in providing a place to hang future regression tests, in enabling debugging of the system, in preventing regressions, etc.), what kinds of tests provide what value, and how to identify when they're no longer providing enough value to justify their continued maintenance * What to do when you have to do a major refactoring that kills hundreds of tests (i.e. how much is it worth it to rewrite those unit tests?) * That investment in testing is an ROI equation (as with everything), and how to evaluate the true value the tests are giving you against the true costs of writing and maintaining them * All the different failure modes of TDD (e.g. the unit tests work but the system as a whole is broken, mock hell, expensive refactorings, too many tiny pieces that make it hard to follow anything) and how to avoid them or minimize their cost

Sometimes it seems like the high level goals, i.e. shipping high-quality software that solves a user's problems, get lost in the dogma around how to meet those goals.

I'm not sure that people who use relational databases would be surprised that there can be data-level race conditions. For example, if you write code like: 1) User requests transfer in the UI 2) Query the DB to see if the transfer is legal 3) If so, update the database.

you have to think about race conditions even if the database implements serializability. First of all, you have to have enough of a clue to do steps 2 and 3 inside the same database transaction, or else the isolation level doesn't help you in the least. Everyone who deals with an RDBMS has to worry about transaction boundaries all the time anyway to avoid race conditions, so it's not too much of a leap to assume that people who are used to worrying about transaction boundaries will have to have some idea of what kind of problems those transaction boundaries will prevent for them. Most databases in production systems don't do full-on serializability as an isolation level (and if they do, it's too expensive to turn on), so pretty much every engineer's real-world experience is that if they do a query against table A, then an update against table B based on that data, that they can have a race condition and they need to lock A or materialize potential conflicts.

I guess it's possible that my personal experience or the engineers that I work with are not a representative sample, but if you're working with sensitive issues like money transfers you tend to be really, really super-paranoid about it, and there's no way that something like that is overlooked by a halfway competent team.

Fundamentally, what matters is the set of invariants you want to preserve, and it's usually the case that some number can be preserved for you by the database and some can't and have to be dealt with at the application level. So by "consistency" I mean "some invariants that I care about will be preserved," but that doesn't mean all such invariants are.

For example, if I'm writing a process that merely queries a table to pull back the user's account balance in a single query, read committed isolation might be enough for that particular use case to have "consistency:" I know I'm always seeing some consistent balance, even if it might not reflect transactions that are currently in flight (thus giving me a different answer if I run the query it again in 2 seconds). That's still a better consistency guarantee than if I have a read dirty isolation level (or effectively no isolation), so it's still useful.

If I'm doing an actual update to account balances, however, that level of consistency is no longer good enough, obviously: if all updates hit the same rows in the same tables then snapshot isolation level might be good enough to avoid problems. And if that's not good enough, then I can acquire explicit update locks and such, if the conflict has a risk of update locks across different tables. Even in that case, though, I'll need to worry about application-level invariants (like "a person can only withdraw up to $300 per day.").

So my point is that even without serializable isolation the database can still guarantee some invariants for me, even if it can't guarantee all of them, and that the database can never really guarantee preservation of all of the invariants that matter to me no matter how strong it's guarantees, so I always have to think about what I'm going to handle at the application level anyway.

In the case of my company (which makes applications for insurance companies), we do have to think about those sorts of things, but again, we have to think of a ton of things anyway, and the division of labor between the app tier and the database tier is always something we have to worry about. We do things like build optimistic concurrency into our ORM layer to make most common cases easier to think about, and we have pretty well-defined transaction lifecycles, but for the most complicated cases we have to think about what the potential for race conditions in the database would be, just like we have to think about them at the application level, and then we have to decide how to handle them. Again, even a "true" ACID database wouldn't prevent us from having to do that work, because many of the invariants we want to preserve in the data aren't expressable in the database anyway.

While I agree that it's a hard problem, I'm not sure I'd agree that it's a hard problem to notice. It's such a common problem for anyone dealing with a relational database that I (and pretty much every engineer I work with) would recognize that sort of a problem immediately, in the same way that I always have app-level threading concerns in the back of my head when I'm working in a language like Java. I just take those sorts of things as a given, and my experience working with other engineers is that anyone else who's had to deal much with SQL has had to think about it as well. You develop a sense of when you need to worry about race conditions and when you don't.

Pretty much every ORM solution has some mechanism for dealing with this sort of a problem, as well. For example, the ORM we've built internally uses optimistic locking in most cases, which at least simplifies the problem space that our engineers have to worry about (i.e. they only have to worry about conflicts that can happen due to updates to two different rows, but any conflicts due to an update to the same row are automatically detected).

I'm also firmly in the "having multiple applications writing to the same database is sheer madness" camp, due to these (and other problems).

Again, I'm not saying that these things aren't annoying to think about, just that I think lots of people are used to thinking about them at this point, and it's a pretty well-understood and often well-communicated problem space with a set of known solution patterns, many of which are well-supported by ORM frameworks.

While I appreciate how thorough the article is, it's a bit of a strawman. Pretty much everyone who makes use of a relational database in a professional capacity has to be aware of what transaction isolation level they're using, make their own choice about what to use, and then do things like acquire explicit update locks or do optimistic locking in order to ensure data integrity. But that doesn't mean that the ACID properties are useless merely because you have to do that; it might mean you have to think about a few things more than you'd like to, but it's still a different world than trying to mimic ACID properties in a NoSQL database, and there are still fairly hard guarantees about things like consistency that you get with other isolation levels. For example, with read committed or snapshot isolation, I still have transactionality and can be sure that if I issue a sequence of 10 updates in a single transaction and then commit it, any other single query is either seeing the results of all 10 or of none of them. That's an important guarantee in many situations, and it's a guarantee that I can use to make decisions about how I structure my application logic.

The author of the post basically seems to treat any isolation level below serializability as some sort of sham perpetrated on the development community, and that's not the case: they're still useful, and they're still something that you can use to build the sorts of application guarantees you want. The mere fact that pretty much every database vendor gives you a choice as to what isolation level to use should be a pretty obvious clue that there's no one-size-fits-all answer there, so harping on the non-existence of a serializable isolation level is somewhat missing the point.

This is kind of conflating two different things.

One thing is conventions around things like where curly braces go, naming conventions for classes and methods and different types of variables, how much whitespace to use where, and so forth. Most of these things don't actually matter at all, but code certainly is easier to read if everyone on a team follows the same ones (so that I know that Foo.bar() is a static method while foo.bar() is a method call on a local variable and _foo.bar() is a method call on an instance variable on the class, without having any other deep knowledge of the code). The point of conventions is basically to get everyone to stop bikeshedding about things that don't matter (like which line a curly brace goes on in an if statement), so that they can shut up and go back to writing code. There's no rational way to decide trivial questions like "how much white space should we use," so rather than having people engaging in pointless holy wars over two versus four spaces, we just establish a convention and stop talking about it. It really does make life easier on a team if people are on the same page there, and there are plenty of tools that make it trivial for people to format their code so it conforms to the conventions.

Then there's the issue of "standards," which is a much larger, amorphous topic that probably shouldn't just be trivialized. Trying to encode them formally is probably madness, but when some person on your team writes a 245-line-long function or calls a method "getFoo" when it in fact writes a file to disk as a side effect, you do probably want to have a little chat during a code review to say, "Hey, yeah . . . so that's not really okay, even if the code functions correctly." That's what I think of as "standards:" the assumption that just getting things to work isn't the only thing that matters. And just throwing that out the window and saying "Anything goes so long as it works" is pretty suicidal if you're working on a team.

I haven't read it myself, but http://www.amazon.com/Agile-Estimating-Planning-Mike-Cohn/dp... looks a good description of the story points/relative estimation techniques. They're really not something that should require a whole book to explain, but I can't say I've found any one blog post or article-length writeup that does a good job at it. The summary at http://epf.eclipse.org/wikis/openup/core.mgmt.common.extend_... is pretty good (though I'd ignore the bottom section on "Estimation of Effort"), and the wikipedia article on Planning Poker http://en.wikipedia.org/wiki/Planning_poker is a decent writeup as well.

It's unfortunate that so much of the literature on relative estimation/story points/velocity/planning poker ends up intertwined in agile-development-consultantese, so sometimes reading some of these things, you have to take it with a serious grain of salt and weed out all the BS and dogma to get to the useful and important bits. The important bits there are really pretty simple: * Estimate in terms of points, not days, and estimate tasks relative to one another * Use planning poker (or something like it) within the team to get more accurate estimates * Empirically measure how many points you do in a given period of time to come up with your "velocity". To do that, you have to be pretty honest about things being "done done" before you move on to the next task; otherwise it's too easy to fudge and your numbers are worthless. "Oh, yeah, we did 10 points of work, well, except for writing the tests or doing the styling . . ."

Remember that velocity is NOT a productivity measure, it'll change over time, and it'll change if the team members change or if other external factors intervene, like an increase in support requests or something. So this technique kind of only works if your organization isn't already dysfunctional: as soon as velocity is seen as a productivity measurement, you're pretty screwed.

That's pretty much it. The relative estimates let you prioritize work appropriately (i.e. "I'd rather have these five 1-point stories than this one 5-point story, so we'll do those first"), and the velocity lets you track how fast you're actually going and about when you'll be done with a given chunk of work, so you can adjust plans as needed.

Note that relative estimation doesn't work nearly so well for large-scale estimation, or for greenfield development where you don't know what you're doing yet. For large-scale planning, my company will generally just give a SWAG in terms of points (we think this feature is 100 points) to give us at least some initial idea of expected relative sizes of things, then we'll compare that initial SWAG to the actual points as we break things out into more bite-sized stories that we can estimate more accurately. If we feel like we're half way through the feature and we've already done 70 points of work, that's a signal that we need to up our estimate for the remainder of the work. Steve McConnell's book is good as well, though honestly we don't really do much in the way of confidence-based estimates at this point. My experience is that out of every 10 projects we do, 8 or 9 will be within 20% of our initial SWAG and 1 or 2 will blow out to 2 or 3x the initial estimate. Of course, we never know which ones will blow out, we just know something will. In other words, we don't bother with confidence intervals at the individual feature level, we just do it at the macro level. So if a team has a velocity of 10 and we have 26 weeks to deliver a release, giving us a hypothetical total capacity of 260 points, we'll "commit" to maybe 2/3 of that. So we say "Okay, this first 170 points we're pretty sure we can get done. Anything after that will be a bonus."

There are two serious problems with this post, and it really saddens me that I see these sorts of posts so frequently here, with so many concurring voices.

First of all, cost absolutely 100% has to factor into prioritization decisions. That doesn't require absolute estimation, but it does demand relative estimation (which he mentions tangentially at the end of the post). If Feature A will deliver $100,000 in revenue but take 18 months and Feature B will deliver $10,000 in revenue but take 1 week, the choice is pretty obvious. What matters is never "return" but always "return on investment." If you don't know anything about the I side of the ROI equation, you're doomed to make bad decisions. With no estimate at all, and just a snarky "it'll take as long as it takes, shut up and let me work" response, you'll inevitably focus on the wrong things.

Secondly, many of us do in fact have deadlines, and they're not just total BS. If you have a customer that you're building something for, they have to be able to plan their own schedule, and just telling them "well, maybe we'll ship it to you in 10/2012 or maybe in 6/2013, you'll get it when you get it" doesn't fly. And it's totally reasonable that it doesn't fly: if they have to, say, install the software, or buy hardware to run it on, or train users, or migrate data from an old system, or roll out new products of their own that are dependent on the new system, they clearly can't plan or budget those activities if they have no clue whatsoever when they'll get the new system.

And if you do have a deadline, you kind of want to know, to the extent that you can, if you're going to make it or not so you can take corrective action (adding people, cutting scope, pushing the date) if need be. You can't do that if you have no estimates at all.

Relative estimation of tasks with empirical measurement of the team's velocity works pretty well; it doesn't work in all cases, but it's pretty much always better than absolutely nothing.

There's a huge, huge difference between doing relative point-based estimation and date-driven, pointy-haired-boss estimation, and it's a total disservice to the software community that so many engineers seem to not really understand that difference, and seem to think that the only two options are "unrealistic date-based estimates" and "no estimates."

TL;DR - Don't just rant for 3000 words about how estimation is horrible and then add in one sentence about relative estimation. You'll do the world much more good if you just help educate people how to do things the right way and spare the ranting.

The only thing I've ever seen work (and I've seen it work well) is to avoid estimating based on time. Instead, you estimate things relatively and then empirically measure how long things take (known as the "velocity" in agile parlance). So the programmer doesn't have to think about the 1001 things that they have to do in order to complete a task, or all the distractions or BS or overhead they'll have to deal with, they just need to think: is task A about as hard as task B, or is it twice as hard?

There are a key pieces to making that work. First of all, you give your estimates in terms of "points", not hours or days. Secondly, you estimate tasks relatively to one another, not absolutely: a 3-point task is about 3-times as much work as a 1-point task. Third, you have multiple people give the estimates, often using something like "planning poker" (where everyone on the team selects their estimate and reveals them simultaneously, then discusses if they're different), which ensures they're more reliable. Fourth, you measure the velocity of the team (not individuals, the team) over time. It often takes a while for it to get anywhere close to stable, as people get used to the project, the technology stack, each other, and so forth.

That's the only thing I've ever seen work, and it can actually work pretty well. It prevents the developers from having to account for all the non-coding things: you don't have to think "Well, this will take 2 hours of coding, 2 hours of test-writing, 1 hour of debugging, 1 hour of docs . . . but I also have 2 hours of meetings a day, and I get pulled off to firefight customer problems periodically, so really it'll take 4 calendar day." You just measure all that stuff empirically: if you have a bunch of meetings or firefighting, your velocity slows down, but your estimates don't have to change to account for it.

It also avoids wishful thinking, especially if you're rigorous about what counts as something being "done". It's harder to lie about whether or not you're going to hit your dates if your measurements say you're going too slowly; it's far easier to be in denial when all you have are time estimates, since those are easier to fudge than relative estimates of difficulty or empirical measurements of velocity.

(Of course, as with any measure of productivity, it's subject to abuse by idiots. But as a scheduling and measurement tool, it can be invaluable.)

Apple is what it is because they tightly control the end-to-end user experience, from the hardware to the software. You can't maintain that and open up the hardware ecosystem; it's an either/or choice. So far, their choice has worked out really, really well for them, so why should they mess with that?

I'm sure you're aware of Apple's fairly disastrous entry into the world of Mac clones back in the day. What you're arguing now is essentially the same theory back then: clones would benefit them by increasing the marketshare for their OS. Instead, clones just cannibalized Apple's own sales and diluted their brand with a bunch of crappy knock-offs. I'm not sure why anyone would expect it to play out differently now.

Sure, it might be in your interest as a consumer to have choice in hardware, but I don't see how it's in Apple's interest to do so. They seem to be doing pretty well precisely because of the choices they've made to lock things down, not in spite of them.

I'm not sure that's the right question to ask.

More important, in my view, is the reverse side of that luck equation: if you assume that input A leads deterministically to outcome B, then if you didn't get outcome B, obviously you didn't put in input A. Replace "A" with "hard work" and B with "economic success" and you have a nice justification for killing the social safety net, for example: obviously people who aren't successful must not be working hard enough.

So accepting that luck plays a role in success doesn't just affect your view of someone's success, it affects your view of other people's potential lack of success, which is an even more important thing to have if you want to have empathy for your fellow human beings.

Unfortunately, cognitive dissonance being what it is, a desire to attribute your own personal success to hard work rather than to luck makes it harder to attribute other people's failures to bad luck, and inclines you to assume that they must "deserve" their situation in life.

So I think it's less important to play the "what if" game there with specific situations, and more important to realize that people who haven't been successful might have been unlucky (or less lucky), rather than to try to decide whether someone successful was lucky or not.

Your presumption is that there are jobs available; according to the bureau of labor statistics, as of March 2012 there were 3.4 unemployed people for every job opening (roughly double the ratio at the start of the recession back in December 2007).

Wait a minute: you say that our expenses versus income is too high, but then also say that higher taxes won't solve anything? Unless you're arguing that higher taxes won't increase government income (which is a totally specious argument that people make all the time, but which isn't backed up in the least by any actual historical analyses), then higher taxes absolutely could solve the deficit problem. Federal tax revenues as a share of overall GDP are historically low right now, and merely letting the Bush tax cuts expire for good would solve almost all of the "deficit crisis." For example see http://economix.blogs.nytimes.com/2011/07/26/are-the-bush-ta... or http://baselinescenario.com/2011/10/03/how-big-is-the-long-t...

So I guess it depends on what problem you want to solve, but if you're worried about the federal deficit, then higher taxes (even in the form of just eliminating the bush tax cuts) will absolutely help to solve that problem.

Within the JVM, object references are strictly separate from integers. Object references are stored within a structure they call an OOP, short for "ordinary object pointers", and the gc works by inspecting the contents of oops and potentially changing them if objects are moved around in memory (as happens if the gc is moving things between generations, or doing heap compaction). If you're curious about it, you can get some information about OOPs on the page discussing the CompressedOops flag implementation: https://wikis.oracle.com/display/HotSpotInternals/Compressed...

The problem with all these debates about "optimal" office layouts is that they're all a series of non-repeatable experiments: someone can always say "Sure, you were successful doing X, but if you'd done Y instead you would have been more successful."

The hypothesis that Y is superior then becomes non-falsifiable: if someone doing Y fails, it wasn't because they did Y it must have been another factor, and if someone not doing Y succeeds, then they would have been better off doing Y. At some point, the argument becomes completely unhinged from any real-world experience.

So really, all I can say is: we have open-plan offices, and we've been successful/productive/kept employees happy, so clearly it is possible for open-plan offices to work. For someone that's convinced that open-plan offices can't possibly be a good idea, and who rejects other people's real-world experiences, what is there left to argue over? The hypothesis becomes non-falsifiable and there's no point talking about it.

To your point about conversations, when people are sick or on leave or working remotely those conversations don't happen and we suffer as a result. We haven't found any replacement for impromptu conversation, or for gaining knowledge through overhead conversations, and so on.

Just as a stupid example (though this sort of thing happens all the time), suppose Chris goes to ask Bob a question, and Alice is setting next to Bob. Bob thinks the answer is that you have to do A, but Bob's wrong, and Alice knows it: the right answer is now to do B. On top of that, Denise, who's also sitting there, hears the answer as well, and just learned something effectively by osmosis.

If Alice wasn't sitting there, able to hear the question, she wouldn't have jumped in, and Chris would have gotten the wrong answer and wasted hours or days doing the wrong thing. Denise also wouldn't be clued in to how things should work either. If Bob had a private office that Chris went to, or it was a one-off IM or phone call, you'd have the same problems. Did everyone get a little distracted by overhearing that conversation? Yes. But ultimately, that productivity hit was worth it, because Chris was saved a ton of time and Denise and Bob gained useful knowledge.

If you can convince people to use something like Campfire where they route all communication through such that people who are remote or momentarily absent are included, I think that can take the place of overhearing those conversations, but it's impossible (in my experience) to convince people to do that when they're working in the same building: people would rather just go chat face-to-face since it's much higher bandwidth than typing.

At Guidewire we've worked in an open-plan office for basically the whole life of the company (roughly 10 years), and it's worked really well for us (by whatever metric you like: successful products, financial success, employee retention). Yes, it can be distracting to people, so most people bring headphones, and it's important for people to be considerate and move discussions or phone calls into side offices and conference rooms.

At least with the type of software we build, though, communication is absolutely critical, and it's amazing how much a difference of even 10 feet makes in the frequency with which people talk. The optimum layout for us is roughly 1 or 2 clusters of 4-6 desks per "pod" (i.e. a cross-functional team consisting of developers, product managers, and qa that are all working on the same area of the product). At that level, when people are talking about something, what they're talking about is almost always relevant to you, so it's not necessarily a distraction: they're talking about your code and your project, so it's a good thing that you can overhear and participate in the conversation if you wish. If you didn't hear those conversations, you'd be out of the loop. It's often better to be a little more distracted and all on the same page than have a team of 5 engineers plowing ahead in different directions.

That's a common conflation when talking about software engineering in general: it's not just how much you get done, it's what you get done. If you get a ton of work done on the wrong thing, you might feel really productive, but you're not actually creating any value. At least with our software, a high level of communication is necessary for most projects to ensure that everyone is on the same page and rowing in the same direction. When that communication breaks down, projects start to fail.

Your mileage may vary, of course, depending on the size of your team and the nature of what you're building. (And it goes without saying that a giant warehouse with desks arranged like an 1890's cloth factory is a terrible idea; you have to consider lines of sight, and acoustics, and other environmental things. Not all open plan offices are the same.) But this assumption that open plan offices have been "proven" to be sub-optimal flies in the face of plenty of empirical evidence from companies like mine that have used them very successfully.

Why software sucks? 14 years ago

I'd be curious to hear why you're so anti-IDE: do you have extensive experience working in Java with a good IDE like IntelliJ? I've heard this "IDE's are to help mediocre programmers be mediocre" argument before, but it's so alien to my experience with IntelliJ (which I've used every day for about 10 years now) that there's nearly no way to reconcile that argument with my personal experience. When I'm writing C or Javascript, I'm hesitant to, say, rename a method, because finding and fixing all references is a pain. In IntelliJ, it's trivial. The end result is that I refactor my Java code much more aggressively than code in a language where I don't have a (good) IDE. Similarly, while you use the REPL to explore libraries, I use the IDE: exploring source in a Java project is trivial because every class and method is instantly cross-linked, and my IDE knows where all the code is (including for my libraries). It's not exactly the same as a REPL (I can't call the method right then, of course, but I'll get to that in a minute), but it serves a different purpose, and your argument in that linked post about how IDEs aren't made to read code is, honestly, laughable: it's way, way easier to read and explore a Java code base within an IDE than it would be in a text editor and a REPL. Now, you can argue that Java itself is verbose enough that reading it is painful because of all the boilerplate: sure, that's a fair point, but it has nothing to do with an IDE. If you had a language with cleaner syntax and an IDE, that would be better than just a language with cleaner syntax and a REPL when it came to reading code.

In addition, it's worth pointing out that many Java programmers use unit tests as a poor-man's REPL; it's not the same, but it serves a similar purpose: I want to write some code, then execute it to make sure it does what I think. It's less dynamic, but it has the advantage of leaving you with regression tests, and it does let you explore and quickly iterate your code. If I'm not sure how to use a library, I'll do exactly what you'd do with a REPL: I'll write some code to use the library, then write a simple test that executes that code, and then I'll iterate my way to a correct solution. Again, the integration of the IDE with the unit tests makes running, debugging, and bouncing between the test and the code much easier than it would be in, say, vim/emacs and a terminal.

My point is that good programmers in any language find a way to do the sort of iterative evolution and exploration of code that you act like is only possible with a REPL, allowing them to fix errors early.

Many of your other points here are good, I just really feel like your "the REPL is essential" argument is pretty misguided.

Sure, but that's not what I was arguing against; my point is that just because that's how market works it doesn't mean you can't say there's not a "shortage" of some skill. If the only companies that can hire engineers have to be able to pay them $600k a year, wouldn't you reasonably say that there's a shortage of engineers? I sure would. If supply was so large that great engineers were working for $40k per year, wouldn't you suggest that there was a glut/oversupply of engineers?

In either case, saying there's a "shortage" or a "glut" isn't saying anything about supply and demand, it's implying some sort of course of action that you should take: i.e. go study engineering (yourself) or promote engineering schools (as a society), or go study something else/promote other types of skills.

I'm not arguing over market economics, I'm arguing that just because supply and demand work like that it doesn't mean you can just dismiss anyone who talks of there being a "shortage."

It's true that many people who say "there's a shortage" are really saying "I can't find a top 1% engineer who will work 60 hours a week for $80k a year in Silicon Valley." Well, duh: raise wages, provide better working conditions, or look elsewhere.

But I think you've taken it too far by defining "shortage" in such a way that it's impossible. If I said "A profitable company with sane hours is having trouble finding high-quality engineers at $120k+ a year" it's a little more reasonable to say, "Hmm, maybe that means that there's a 'shortage' of good engineers, in the sense that society and the economy as a whole would benefit from having more talented engineers." Just saying "look elsewhere" or "pay more" completely sidesteps the whole point, which is that where there's a "shortage" there's an obvious opportunity to profitably address it in a way that benefits the economy and society.

To use your analogy, if the beef supply was constrained such that the cheapest hamburger was $100, would you say, "There's no shortage: supply and demand have met at a price of $100?" Or would you say, "Wow, hamburger prices increased by like 20x, there's a shortage of hamburgers?" I think most people would say the latter; the former simply isn't a useful definition of the word "shortage." It means that relative to some general idea of "normal" (as defined by previous conditions, or conditions in related markets), the market seems distorted by a lack of supply.

To your points:

1) Sure, but effectively all income is multiple-taxed. Suppose I run my own business, and am paid by a consumer with their money that they earned as wages. If I turn a profit, I then pay taxes on that income. By this logic, I shouldn't have to pay taxes, because the consumer that paid me was using after-tax dollars, so taxing my income from them would be double-taxation, right? The double-taxation argument is simply not very-compelling because there's no one true wellspring of money; if there were, you'd just tax the source and call it good. But reality is way more complicated than that, and money is always taxed multiple times as it moves around the economy.

2) I don't think you're correct about there being empirical evidence of capital gains rates affecting those things. For example, see http://www.slate.com/blogs/moneybox/2012/01/19/capital_gains.... As far as I know, there's no credible empirical evidence that cutting capital gains rates deterministically helps investment or saving, or that raising them hurts those things. Sure, you can pick and choose examples with those outcomes, but you can also find plenty of empirical examples where those effects didn't happen. It's totally misleading to act like that's a settled question in economics.

3) He's paying more in taxes because he ended up earning more money. So yes, he deserves to pay more in taxes than Sally, because he earned more money. Otherwise, you could easily say "Sally decided to work part time and made less money than Fred. Does hard-working Fred really deserve to pay MORE in taxes than Sally?" Yes, yes he does; unless you really think that a poll tax is a good idea, even a flat-tax advocate would have to argue that someone who makes more money should pay more in taxes.

That's a great, succinct way to put it. It pretty much exactly matches my experience, too: out of every 10 things I estimate, a couple go a little faster, most of them are within 10-20% of the estimate, and one or two of them blow out to 2-3x the estimate. (And of course, if I knew which ones would blow up ahead of time, I'd revise the estimates upwards initially so that didn't happen . . .). If you have 6 projects to do that you estimate at one month each, you need to give yourself closer to 9 months to get it done if you want to have any chance of finishing on time, because it's a near certainty that at least one of those projects is going to blow up on you.

That's a fair point; there's no simple way that I know of to do that in any language (though many languages avoid having both constructs), and the general solution is to write parallel sets of methods to operate on the two types of data structures.

But again, other languages do offer the ability to write methods that apply to all collections, without the "complexity." Sure, it's different, but in Gosu for example you can write an enhancement method on the Collection interface, or on the List interface, and now everything that implements Collection or List has that method. It's then a matter of whether or not the objects in question implement that appropriate interface or not. Your new functions apply to everything that implements those interfaces, and if you want a new thing to have all those methods then you just implement the interface and you get all 50+ functions for free.

Scala offers a particular way to solve that problem that has its own plusses and minuses, but it's not the only way for a language to let you do that, and it's certainly not the "simplest" way to accomplish that goal.

See my examples below for how to do it in Gosu (via enhancements). In C# it's pretty much the same (via extension methods). Both are statically typed languages. Again, not 100% the same as Scala, and each comes with a different set of tradeoffs than the Scala approach (i.e. they're statically dispatched in Gosu), but they're certainly both reasonable, and much "simpler", solutions to the problem of "how do I add a filterMap function to all arrays or collections that works pretty much how I want it to."

I have to respectfully disagree. First of all, the things he shows aren't inherently complex: adding an additional function to the existing collections library is something that's possible in other languages in less confusing ways (see other examples in this post). The various concepts required to solve the problem in Scala like implicits and higher kinds might be inherently complex, but the problem he's trying to solve isn't inherently complex. And while the Scala solution might not be 100% identical to, say, just adding the method directly to a class in Ruby (since in Scala it's type-safe, etc. etc.) that's still missing the point. The point is that if you sit down and say "I want to add a method to all my collections that works like the existing methods," in Scala it requires an understanding of a huge number of complicated intersecting concepts, whereas in other languages it doesn't.

Secondly, excusing complexity by saying "it makes things possible that wouldn't otherwise be possible" isn't really enough of a justification. The question is: do those exact things need to be possible? Or is there some way that gets me 90% of the way there without the complexity, and that's good enough? More power isn't always better, which was a big part of the point of the article. Just dismissing it by saying "well, the complexity lets you do powerful things" doesn't really refute the point of the article, it totally misses it.

There's a tradeoff to be made. You might make those tradeoffs differently than I would, which is totally understandable, but we should at least be able to have a conversation about the fact that there is such a tradeoff without people dimissing statements like "Scala is complex" out-of-hand.

In Gosu, it's pretty much the same (though enhancements are statically dispatched and thus subject to a different set of limitations):

enhancement MyEnhancement<T> : T[] { function filterMap() { . . . } }

Roughly the same in C# with extension methods, though with C# you explicitly import the extension method while in Gosu they're automatically always there (sort of good, sort of bad). Again, not exactly the same as the dynamic language examples, but enhancements/extension methods do allow you to extend existing classes in a reasonable fashion while still being amenable to all the other advantages static typing gives you.

It's certainly a related problem: with Go-style implicit interfaces, neither a person nor a machine really has the context to know if something that conforms to the interface is actually intended to be used that way, or if it just happens to have the same method signatures. As you say, getName() is a pretty common sort of method name that could mean a bunch of different things, and not everything with a getName() method is necessarily interchangeable with everything else. Explicit interfaces require more work by the programmer, but make those intentions explicit to both other programmers and to automated tools.

In Gosu, we already have Java-style explicit interfaces, but we're likely going to add in Go-style implicit interfaces as a language option as well, since they're not completely interchangeable. The more I think about it, the more I think that you often want implicit interfaces for method arguments, and explicit interfaces for return values. That's oversimplifying, but as a library author you often want to say "this method works with anything that has foo() and bar() on it," so you want an implicit interface so people can use your library with existing code without changing that code to add explicit interface declarations. But if you're providing objects back as the result of a function, you might want to be more explicit and make harder guarantees about exactly what sorts of things they return.

In general I like the way Go interfaces work (we'd like to do something similar in Gosu as well); they let you decouple different parts of a system much better than you can if you have to explicitly declare interfaces.

When discussing putting something like this in Gosu, the main disadvantage we came up with was around tooling. Probably not a big issue for Go, given that I haven't really heard of too much focus on IDE/refactoring tooling there, but if one were to implement such tools, the implicit interfaces make things a bit harder. For example, if I have a Nameable interface with a getName() method, and 20 classes in my system have a getName() method but only 3 of them are actually used as Nameables, if I want to refactor the getName() method in a system like Java, I'll know which classes explicitly implement Nameable and thus which classes to refactor. In Go, it's a hard problem, because you have to know which classes are ever used as Nameables; that's no longer a property of the class itself, but rather something you have to derive from your code base. It similarly makes IDE functions like "find usages" or "find implementors" much harder to implement. (Technically they're not 100% intractable, but they're certainly much harder to do well.)

Those tooling issues are really the only drawbacks we could come up with, though. Otherwise I think the Go approach is much more flexible than the Java one.