I was thinking back to DHH's Railsconf keynote from this year:
It largely centered around the Rails community's ongoing effort to keep up with user expectations while creating abstractions that limit the choices developers need to make.
Rails does not get everything right (nobody does), but I think they get this right big time. I find that the JavaScript community proliferates new "useful" technology without giving as much thought to the mental overhead of constantly learning new things and finding out how to fit everything together.
There are a few things at play. Rails has a pretty healthy BDFL model which has created some structure that other communities may lack, and often fails to benefit quickly from the latest and greatest tools or architecture principles. It's occasionally brutal in this way. But the acknowledged tradeoffs keep it healthy.
I would say this is the quality that most keeps me excited about the stack I continue to do most of my work with. I try not to be too much of a fanboy of the tech itself or the people involved, but I continue to really enjoy the effort to keep the mental load for developers under control.
I welcome a debate here, happy coding!
Top comments (18)
The discussion reminds me of a powerful talk from Kathy Sierra - a good watch/listen for anyone interested in cognitive load and becoming a better learner.
She just described all of supervised machine learning, that's fascinating.
Ironically, I usually find abstractions with "concept compression" (aka frameworks) to be easy to get started. But in the long term create a much higher mental load than I would have with a library approach. I can't even count the times I've had to research framework internals because it was not behaving how I thought it should. So not only do I need to solve my problem, but now I need to understand how the framework operates to do so. That's far more mental load than a library, where a library only handles a specific piece like template rendering.
I find nearly everything the speaker says in this video just to be a narrative to support his own efforts, but is far removed from my experience with frameworks (aside from easy to get started). I've used a lot of different frameworks over the years, but not rails specifically. I should also note that I still live with software I wrote (terribly) 10+ years ago. So that certainly colors my experience, and "easy to get started" is not nearly as much of priority for me as easy to maintain. I find that frameworks generally conflict with the latter as timescale increases.
The comparison with Javascript seems a bit different from the video. Javascript's problem is more of an ecosystem/tooling mess. But a lot of platforms aside from rails have opinionated, prescribed solutions... especially for back-end.
Looking at it more broadly, you never have to worry about the TCP/IP stacks you're running on top of anymore. You never have to worry about the Windows API or the POSIX API anymore, as a web developer. For the vast majority of developers, those concepts have been "compressed" to nearly nothing. If you believe what he's saying in the keynote, the problems isn't that this compression doesn't happen, it's that it's not mature for the web development space. In fact, for user facing application developers, I don't think it will ever happen. The end user application will always get pushed higher and higher with the development stack growing underneath them. Today, TCP/IP is pretty much fully abstracted away for all webapp developers. Tomorrow, databases may reach that point.
Well, I do worry about TCP/IP in system design. But sure, when writing code I reach for an HTTP client library, not a TCP/IP library. Although to be fair, HTTP is an open protocol. Frameworks are not protocols. And even then, when the protocol goes wrong you will be struggling if you don't understand the underlying TCP/IP stack. I have had to resort to wireshark traces (and explaining how a 3-way handshake works) to prove to a vendor that a simple HTTP integration with their service was failing on their end.
Well that's kind of his point, throw the TCP/IP stuff to the proverbial Aaron to deal with. It's just that if you're doing the system design, you're playing the role of the proverbial Aaron.
But in other case I mentioned, I wasn't "Aaron" (and not every place has an Aaron). I was just a dev trying to use HTTP(S) to call another service. The vendor said it was a problem on our end, and if I didn't learn TCP/IP it would have been hard to prove otherwise. Regular devs still need to eventually learn how it works in order to fix it when things go wrong.
At the end of the day, customers will not accept "it's not my fault, but the framework" as an answer. They simply want it to work. The customer still holds the dev team responsible for the product, including everything their chosen framework does, good and bad. That's why I prefer libraries, because they can ideally be understood in isolation of the rest of the system. It is harder to do this with frameworks which mix many concerns.
I don't think we actually disagree in principle, but in degree of abstraction.
I'd agree with you there. Libraries, and anything that's that modular, are much easier to deal with than frameworks. I don't think platforms have that problem as much as frameworks do, since you're pretty much only dealing with things in the layer under you instead of other things in the same layer or even in the layer above you.
But it won't work in long term. During 2000's all web development means PHP or java . Now ???
Technology keeps growing. But how do you be a part of it without learning the basics?
To avoid technical debt one has to accept the pressure and learn things
I'm not sure the proliferation of styles and tools is really "learning the basics", it's learning a lot of toolchains that are highly specialized, yet not designed to work logically with existing practices.
Of course, people have to keep learning things, but an environment where progress allows for throwing the baby out with the bathwater for every small evolution, I'm not sure that's progress.
Surface area of what you need to know sometimes increases without having made as much progress on the actual problems being solved.
DHH is one of the masters at stepping back and thinking holistically about things. I think that generally being agnostic as far as tooling goes is difficult but important, as different tools fit different problems and clients/ end users better. Love his example of the hobbled together Lego Millennium Falcon. Great discussion and topic.
After 40 years of developing I've seen many, many languages and frameworks come and go (I started in Fortran and the original Basic, Now I'm coding WPF, React, Angular and several cloud frameworks ...)
Basically, I treat everything as a herd of cats. When I need to grab a cat to catch a mouse I just look (google) for the best cat available and relatively easy to catch (learn). If the cat is nice to work with I pet it (have a good experience).
I really never worry about retaining what I learn. The way it works out for me is that if I repeat the process above enough (thousands) of times the cats I tend to catch a lot hang around my chair because I petted them.
How does this relate to the aforementioned JavaScript and Ruby discussion? Well, basically it's the number of cats. I don't mind too many cats so much as not finding a good cat to catch a mouse (and pet). It's personal preference but I tend to stay away from opinionated frameworks/ecosystems.
I like cats!
(also a disclaimer: I really like dogs as well, probably more than cats ;) )
Of necessity, I've become a big believer in this idea. In fact, I've come to believe that one of the best things a senior developer can do is to introduce thoughtful abstractions in order to reduce that mental load. In doing so, we can help other developers focus on what needs to be done, not necessarily how.
I work in a unique environment - a University. We hire lots of part-time CS students (usually starting in 2nd year), so we have the most junior of junior developers. It is therefore really important for us to keep cross-cutting concerns, like deployment and authentication, out of their way, so that they can focus on implementing the business rules and use cases of an application. This allows us to be force multipliers, increasing the amount of useful work done by other developers, and thus by the organization as a whole. It also reduces our load, as we can trust that our abstractions are always the same, and focus on reviewing the parts of the juniors' code that is actually important.
As an example: We're in the process of finalizing and adopting a specification for RESTful APIs that our architects and those from other universities have been working on, called University API. It's a fairly complex spec, as it need to bring unity and consistency the many complex use cases we've discovered in our decade of doing APIs.
The first few APIs implemented to this specification have been done at a very low-level - lots of manually-written OpenAPI docs, manually-defining HTTP methods and paths, etc. This has lead to lots and lots of duplicated work and even more errors and inconsistencies with the spec.
So, me and a few others took it upon ourselves to abstract this work away from our developers, so that we could implement the rules of the specification once, and give people ways to hook into that to provide their specific logic.
So, instead of defining every little HTTP route, we operate at a very high level. Developers provide implementations of a 'Resource' API, which can have lots of operations and views. They don't worry about how to map all of those to HTTP, they just provide their resources to a 'UAPIRuntime' which assembles them all, figures out the relationships between them, maps them to HTTP, outputs an OpenAPI document, and take care of concerns such as error handling, logging, performance tracing, serializing responses, deserializing requests, authentication, enforcing developer-defined authorization rules, etc. Developers get to focus on the details of their application, and never have to worry about spec compliance - we take care of all of the hard parts of that for them. We are also going to provide lifecycle hooks so that, if we run into cases that our high-level API can't handle, our devs can dive in one level deeper and and make things work how they need to. It also allows to to conduct interesting experiments, like taking an existing HTTP API and re-using the same code to offer a GraphQL API alongside it, with only one line of code changed in the application.
It's still a work in progress, but other such tools have paid big dividends for us. We've really seen that a small group of dedicated, thoughtful people can have a big impact on how hard it is for others to do their jobs.
Fun personal fact: I was sitting front row center for this presentation wearing my Music House t-shirt (that's the music school where I work). I'm still not sure whether DHH picked that up subconsciously at about 28:30 or if he planned his musician example ahead of time.
On a more relevant note, these principles (as well as Rails itself) are what allow me to do the work that I do. I'm building and maintaining our administrative app by myself with no prior experience or formal training. This would not be possible without the tools discussed here. Regardless of whether developers at large favor this approach, the simple fact is that Rails and other similarly-minded frameworks have made software development possible for more people, in more situations, than would otherwise be the case.
I had a hard time getting devs to understand why it's bad to have a ton of old no longer used branches in the repos. Mental work overload is why we get burnt out. It's the little things.
Can you give me an example of what
?
I mean, dynamic just-in-time compilation is fascinating to me...
i like mental load