The freaking out about "oh no I gotta write a small library myself" is absurdly overblown here. Most of the time I see it, it's people flipping out at the very sight of there not being something available off-the-shelf. The actual cost is much lower than the panic implies.
In general, people see ANY time spent in an FP language to solve FP problems as "a waste of time" but they're blind to the wastes of time people treat as "real code" in mainstream languages.
But yeah if you're a software efficiency bean counter, maybe you won't like FP. Fair point.
My opinion is the long-term technical & cultural benefits and opportunities pay off. And as a developer, I am happy to not optimize my development velocity to the utmost if it means I don't have to waste my brainpower writing imperative code. My mind is in a much better state at the very least :)
This isn't a good representation of the argument. People don't want to write libraries because it's more valuable for everyone to spend time writing features using existing libraries, provided there are good libraries available. People aren't "freaking out", they just have deadlines, and you know, other things to do with their lives besides write code that has already been written.
If you choose an FP language like Haskell, you tend to value things beyond that. Stability, engineering culture, retention, big rate, the ability to extend things for cheap only because you did the hard part of using Haskell to begin with, etc
It's just throughput vs latency
I don't think it is.
At work, I'm adding some basic metrics/logging functionality to an internal library, to see how it's being used. The idea is to log a few parameters and the tech lead suggested using JSON format.
No problem right? Well my work environment is quirky and let's just say it is hard to use outside libraries for various reasons. It can happen there is just a lengthy IT process to go through... eventually most reasonable requests will be filled (copied/mirrored internally, or binaries imported). But there is a delay.
This is all besides the point other than to say: I either need to wait a few weeks, or write my own minimal JSON library.
How hard can that be? I mean, it's just JSON. Well earlier today I was checking reddit and saw an announcement that "JSON for Modern C++ was released" (https://www.reddit.com/r/cpp/comments/p69plb/json_for_modern...). Hey cool, I can see what the library looks like and maybe rip off some of their code while I'm waiting for a "please mirror this internally" request to finish.
This library is thousands of lines long... for JSON. I'm not disparaging the author or JSON, it looks like an awesome library with great diagnostics, I'm more trying to point out that even for the SIMPLE format of JSON, a serious library is 10K+ lines. That's a hell of a lot of extra work to put on a team when writing a JSON (or whatever) library probably isn't the actual work that needs to be done.
Elm likely has a JSON library ready to use, but having your seasoned team reinventing the wheel for so many other libraries isn't a good use of dev time. I can't think of simpler libraries to write than JSON and even that is 10K lines long. Other than the insanity of nodejs and leftpad and libraries like that. If the attitude for every single library needed is "we can write that from scratch" the team is never going to get anywhere.
You can define a JSON AST type very simply, and then converting that to wire bytes is also quite trivial. Also simple to test via golden testing (you could even use property testing + shell out to jq to validate the json)
https://github.com/nikita-volkov/jsonifier This one is nowhere near 10k lines - and it is heavily optimized and polished!
> My opinion is the long-term technical & cultural benefits and opportunities pay off.
How, though? These two points contradict each other. Is using FP going to pay off with technical benefits? Or is it just going to reduce your software development efficiency?
I enjoy writing FP code and using niche frameworks like Elm for hobby projects, but I specifically avoid them for production work because I'm familiar with them.
I always hear claims that using Elm and niche languages is going to pay off in vague benefits somewhere down the road, but in practice the payoff never really arrives. I think a lot of developers pushing these niche frameworks tend to mentally dismiss the actual costs and overhead incurred by using something like Elm.
It's tempting to categorize the struggles as "learning" and therefore try to pretend it doesn't count as lost time, but at the end of the day if your team has to spend extra cycles doing extra things just to accomplish basic tasks, it's a drag on productivity.
But if you can't afford for ANY time to not be spent directly on the business, don't do FP. Sounds like a pretty brutal way to work.
FP has _throughput_ benefits, but may come with _latency_ hiccups while your team climbs the learning curve (which may include writing libraries.)
If you have frequent deadlines (or treat 2 week sprints as deadlines), then FP won't jive..and you probably have bigger pain points in your company than PL choice lol.
This is the core point I was disagreeing with:
In my experience (yes, I have used Elm and I enjoy various functional languages), this payoff never comes. There's always something more that needs attention, needs another developer, needs to be refactored because we forgot a use case, and so on.
And also in my experience, by the time you've invested the years of effort required to fill in gaps in the public package ecosystem, it's time to move on to the next niche language trend. I'd rather invest our time and energy in mainstream languages that have staying power, where we're not obligated to carry large parts of the open-source ecosystem by ourselves.
But that was Haskell I guess. It's obviously not a "niche language trend" by now, so it was pretty clear it had staying power.
Definitely has paid off for me personally. My side projects move a lot faster and more stably now that I cut my teeth in production Haskell. A real free 10xer to my skills personally. And I gained the skills by getting my employer to finance my learning lmao.
This probably depends on the complexity of what you need to do, as well as how well you want to do it.
I've seen people writing their own packages and pieces of systems in months, to typically pretty underwhelming results. However when writing code with tests, proper documentation, getting started guides etc., then what you're saying does sound way more plausible, especially if scope creep of any sorts is also present.
Would you care to comment on what sorts of systems take years to properly develop, though? Because in my experience that could be applicable to very few software projects out there.
This is not a "discussion" question, but a "fill my blind spot" question.
I always read how good FP is, and how much better it handles all the complexity. Yet I never see it win from software written with state.
Is there any big and/or complex sofware written in FP that I am overlooking?
If you want real production software, Starbucks Rewards is/was powered entirely by pure Haskell code and made big bucks
Software having complex state actually makes Haskell even better than the competition. Because most state has nuanced rules about its state transitions.
Haskell definitely has more of a learning curve when it comes to dealing with state, but that curve will guide you towards a ceiling mainstream languages can't even approximate.
In business domains with strict audit requirements, it’s a peace of mind thing, to know that “side effects” (aka persistence and the mutation of persisted data) are constrained to a tiny and highly testable corner of your code base.
For OSS, the examples that spring to mind for me are RabbitMQ (Erlang) and Pandoc (Haskell).
What proof of this is there though? People have made the same claims about lots of things: FP, OOP, statically typed languages, dynamically typed languages, LISP variants, etc. The fact is, any of these solutions can work, and you can also write terrible code with any of them.
Maybe in the context of the parent comment this holds true, but in my experience this is like walking on a knife's edge.
There's the very distinct possibility that you'll end up with homebrew frameworks and libraries that are overcomplicated, buggy, not commented and exceedingly hard to work with. I've seen that happen many times and it makes me consider not just whether people want to do that, not whether people have the time to do that, but even whether it's possible for them to do.
In one project people wanted all of their front end components to be custom and as a consequence spent 3x-5x longer building everything, none of their components were Googleable for someone who's been onboarded and thus people forgot how they even work after 2 weeks of not editing them and had to rediscover that later. I tried adding a component sandbox/playbook to help them provide examples, but no one was interested in doing that when they were already behind the expectations of the business. Picking an off-the-shelf framework would have saved them all of these troubles. Maybe there were actual reasons behind the choice of approaching the project this way, apart from padding their resumes, however after inquiring about those, i didn't get a convincing response.
In another case, i had to work on a custom web back end framework, which had been developed by another company, in a country the language of which i don't speak. Curiously enough, all of their code comments were in this language, there yet again was a lack of any sorts of documentation, the implementation was obtuse, slow and any simple changes to the forms took days to implement properly, even when it would take around 30 minutes in established technologies. Furthermore, the actual framework hadn't received any updates in years and therefore i fear to think what sorts of security issues it had. An off-the-shelf framework would have at least been updated and probably would have more decent documentation.
In short:
- never underestimate the ability of people who lack oversight to make things worse
- frameworks and libraries that are used by thousands of people are probably at least decent
- there's definitely also something to be said about how well tested they are and how known the bugs are
- because of the above, popular technologies seem like a pretty safe bet, as does off-the-shelf code appear to be
- of course, despite all of the above, it's perfectly okay to explore new tech stacks and write your own code, just don't half ass itThis is an important point; I think it applies to varying degrees to any less popular language or framework. It’s a little worse with Elm because of the restrictions they’ve placed on JS interop. I'll add that unless you're very familiar with the framework/language you'll be using, it's pretty hard to estimate scope of work; you'll just encounter surprises during implementation along the lines of "wow I can't be believe they don't have a library for x." On the plus side, since the work of implementing these libraries is very generic with regard to any specific application, it's easy to delegate to other employees or contractors.
I’m currently working on a large PureScript project. At various times I’ve had to implement my own base libraries and components, but in many cases I’ve just been able to wrap existing JavaScript code. Some of the key libraries I use, which were developed by other community members are wrapped JavaScript libraries. This has been a pretty powerful mitigation strategy.
In the case of PureScript, I also have the benefit of reusing a substantial amount of front end code on the server. For me, on this particular project, the benefits of using a language with advanced features has far outweighed the above mentioned costs, but I think you've got to look at each situation differently and do that evaluation.
I think you've just defined a pretty good benchmark for when it's sensible to consider a less popular choice. Are you familiar enough with it to be confident of coming out ahead by using it? Perhaps you have a backup plan like the interop you mentioned if some functionality is missing. Perhaps the tool is so much more productive in general that you are reasonably confident any extra development work to fill in the gaps will be outweighed by the overall benefits. But there should be some clear reason you think the risk is justified.
I was completely sold on the Elm architecture, but I used Haskell too long to be comfortable working without typeclasses, so I went through a couple different elm-like frameworks written for PureScript. I settled on one only to later realize what (I think) people are talking about when they say "Elm doesn't compose", which is not well articulated in that statement. I take it to mean: you can never really deal with stateful components in isolation because they have to work off of a unified global data structure. I developed some new tech that makes different tradeoffs and it got me what I wanted.
I knew developing my own framework was going to add a lot of extra work: * Writing the framework (not too bad, actually) * Writing the reusable components and combinators (exactly what you'd expect)
By far he hardest part has been establishing patterns and best practices working with a new and different architecture, I struggled with that for a while.
I'm a strong believer in the points made in Graham's Beating the Averages (actually what brought me to HN) and in my case I'm establishing a tech stack for my current and future projects, so I believe the framework was a worthwhile investment.
(apologies for the lumpy phrasing, insomnia is a pain)
I'm absolutely not an authority on Elm architecture, I just know that my experience doing stuff like forms with validation really sucked.
Good. The longer I do this, the longer I realize that unless your in a race-to-the-bottom industry (something like vying for eye balls to increase ad spend), then this is categorically a bad thing. I would prefer the quality of engineering required in knowing how to do some of these things yourselves.
Take your time. Understand what you are doing. Some of the world class technologies we all know and use daily use minimal dependencies.
And with more malicious code entering more package repositories, it might be apt advice more than ever today.
That never happens in the real world. One always has limited time to produce a viable product. There is always some extrinsic constraint to how much time can be spent taking your time and understanding what you're doing.
Moreover, if you are operating in any commercially viable product space, you're always competing against other firms for finite market share. If it takes x years to ponder and understand how to build and ship a masterful feat of engineering, while some other company ships a "sort-of-works" product with bugs and engineering flaws in <<< x years, the other company will usually win in the marketplace.
Your company usually goes bankrupt, and all the engineers will complain at their next jobs about what a wonderfully designed engineering system they were building, and how awful it is that nobody appreciates such things these days.
How often does substandard technology and technical debt become a drag on a business not long after that first move, allowing someone else to overtake because the poorly built system couldn't scale to production levels or wasn't adaptable enough for changing requirements or failed so often that the early users drifted away? How often do we see developers advocating shortcuts and showing limited understanding of basic software development or computer science ideas, only to see the product they work on being rewritten within a year or two, or the whole team shut down?
You can try to be fastest always. You can often succeed, at first, if you take enough shortcuts. But you can't sustain that pace without enough quality in your people and your code. Planning to throw each implementation away and rewrite with more resources every year or two is a very unicorn-like strategy. It reminds me of VCs whose strategy is to invest liberally, who are fully aware that most of those investments won't work out but they're hoping for one or two in each batch to become the next big hits.
Real engineering isn't done in a vacuum and its goal isn't perfection. Real engineering takes issues like costs and timescales and staffing into account and aims to find a solution that is good enough on all counts. But it still has to be good enough. Producing junk but quickly and cheaply is an effective strategy until it's not and the success of any product using that strategy comes down to little more than the luck of the draw.
My post was addressing the common case where an engineer seems to ignore the 'resource constraints' side of the equation altogether.
Balancing these factors is more art than science. No two projects have the same set of resource constraints, nor the same set of engineering challenges. Luck is a big factor. The solution depends heavily on the exact details of each particular case.
IME retrospectives rarely sound like "We hired a team of strong developers, they did a solid job, but then the business failed as a result". The kind of developers who are strong enough to do a solid job are probably also experienced enough to recognise the other considerations in play and adapt if necessary.
While this is obviously true, I don't think it depicts the actual decision making process that leads to messy codebases and crappy products. In my experience lack of experience and/or laziness play a big part.
A competent tech lead that's passionate about quality AND is willing to be annoying for the greater good makes an enormous difference. I'm talking multiple orders of magnitude difference.
It's the difference between spinning up a k8s cluster + service mesh vs tiny single server vps with basic failover. The former is thousands of hours of dev time across multiple disciplines while the latter a seasoned engineer can handle by themselves.
This is precisely why I try to interview tech leads about what they shipped rather than what they built. There are a lot of otherwise very talented developers out there who will spend years playing around in your codebase, writing beautiful code, but not actually shipping anything useful. Replacing them with shipping-focused engineers, even if they're not as technically competent, usually results in big productivity boosts.
This isn't a popular opinion among developer communities, but it's a common theme in the management forums I'm part of. It's important to have fun and budget some time for things like open-source contributions and library building, but the top priority must always be on shipping product.
Realistically, a couple of engineers writing a library from scratch isn’t going to be higher quality than adopting a mainstream, battle-tested library that accomplishes the same thing.
Writing your own implementations of everything can be fun, but it’s not possible to compete with all of the iterations and reviews that a mainstream library collects over time.
An open source library is necessarily generic and has to be battle tested to make sure it fulfills all use cases, while the library you write only has to cover your own needs that makes it easier to understand, extend and debug
That's true but the vast majority of what you find on NPM is not mainstream, battle-tested libraries.
Libraries that do clear that bar tend to be widely useful but that suggests generality you won't necessarily need for any single use case. A couple of good engineers might struggle to beat a well-established open source library at everything it does, but that is rarely what they are trying to achieve. They just need something that is better for their own specific needs at that time, which might be a useful and realistic target.
Also many "battle-tested" libraries are not really very high quality - they all have bugs, unnecessary complexity and technical debt. Higher degree of testing they get is often offset by the higher number of feature requests, and more features means more complexity and more bugs.
And in reality I saw it many times when a niche library written by a solo developer is of a higher quality than a super popular behemoth written by hundreds of developers over 10 years.
- ubiquitous things, like data structures
- hard to get right things, like time
- implementations of specs, like Unicode
- hardware interfaces, like CUDA
For everything else, I'll take the above and roll my own solution.
> - ubiquitous things, like data structures
There are a few basic data structures in JS, but almost everything else is in user-land.
> - hard to get right things, like time
Date is a notoriously bad API in JavaScript.
- implementations of specs, like Unicode
We just get a String type in JavaScript which is UTF-16, so...
Well, no, we aren't. We are talking about the Elm language, which compiles to JavaScript.
There are also other excellent languages that target JavaScript that have these things.
I've also seen many developers for years adopting mainstream libraries and frameworks wrongly.
The atrocities I've seen built with Ember, Rails, Angular, and the like.
Often these people built their own (albeit less powerful) libraries and could work much better with them.
In my experience, if someone fails at using mainstream libraries, they will also likely fail in creating their own, at least if it is to later be used and maintained by anyone else successfully.
The problem with mainstream libraries is to grasp the mental model of their creators.
I met a bunch of developers who understood software design patterns as they are taught in the GoF book, but couldn't see them when applied in a framework/library. Often this was because the design patterns weren't used 1:1 or framework creators simply used the wrong name for a pattern.
It's not that simple. I realize this may be uncommon, but it's possible to work on a product that is truly worthwhile, that improves peoples' lives, and whose target users urgently need a solution to the problem you're solving. I recently developed a product that I believe meets this description (I won't plug it here). I chose Elixir for the web application. While I think that's a defensible choice, given the real-time nature of the application, I sometimes wonder if I would have been better off choosing a more mainstream language -- one with an official Stripe client library, for one thing. Any day I spent unnecessarily reimplementing something because I chose Elixir is a day that the target users couldn't benefit from my product. And, bearing that in mind, I should get back to work.
Choosing non-popular languages is a trade off yes but not as much as people think especially if you have a good team willing to learn them.
There are also benefits apart from technical ones like better job retention and attracting finer talent without having to filter hundreds of resumes. I will say if your business is made around hiring and making anyone work of the shelf then it's a bad idea.
It gets really hard to maintain after 10 - 15 years. I wish we had rolled our own libraries for some of the simpler functions. Even in PHP this would have made life so much better.
I dunno, having seen both sides, there are pros and cons to each.
Teams that reach for libs quickly often think in terms of libraries instead of solutions (one recent example was some folks who were asking for my advice on some over-engineered client-side PDF generation thing, and me suggesting `window.print()` as a solution, considering this was for an internal tool and you effectively want print stylesheets anyways), and often use them as crutches due to a self-fulfilling cycle of "I don't know how to do X, let's use a library so I never need to find out" (and then pulling in a huge lib to do the job of a literal one-liner regex - `uuid.validate()`, looking at you). In my experience, they also often end up buried by their own complexity due to gluing too many things together. But at the same time, it's hard to argue with the ease with which one can plop a modal dialog or a calendar or a collapsible table in a React app.
I find that teams working with more exotic technologies tend to be more creative with solutions (e.g. "oh there's no zoomable map UI lib bindings, so let's ask ourselves, do we really need a map library for that contact us page or is a static jpg good enough?") and a have a deeper appreciation for how hard things are to implement. But conversely, UX can suffer from too much "creativity". For example, if care is not taken w/ accessibility concerns for some UI element. Or, as you said, things just take longer to ship because people need to reinvent wheels.
edit: Ah, hold on; I just got to where they comment on this. “TypeScript, which adds optional static typing to JavaScript and is probably one of the best things to happen to JavaScript, can partially mitigate the issues with the JavaScript dynamic type system. But being a superset of JavaScript it needs to compromise on elegance and simplicity. It also has several ‘blind spots.’” etc. I don’t know that I’m 100% convinced.
I'm at a company that's transitioning to TypeScript, and the reality is that you can't just flip a switch and have a well-typed codebase: if we just turn `strict` on, `tsc` gives us thousands and thousands of errors. And as we've gone through trying to annotate things, it's clear that in order to get various components to a state where they're properly type-safe, we'll need to almost completely rewrite them.
Compared to Rakuten, our codebase isn't even that huge or legacy - it's often very poorly written, but it's less than 50K lines and less than a couple of years old. No doubt the situation for Rakuten would be even worse; I'm sure huge swaths of their code would need to be trashed anyway.
If TypeScript is ultimately going to force you to rewrite - and still leave you with a less-robust solution - I could see why starting with a clean-slate with Elm would be appealing.
Also TS is just part of a potential solution while Elm comes with all batteries included. You still have to set up your code formater, liner, decide on a framework, state management library and so on and so on. With Elm, you just use elm-format. No arguing about code style, not arguing about how structure your code. There is only way to do it. It is not only a language but a framework. You get everything you need out need out of the box.
> You get everything you need out need out of the box.
This is specious. There's lots of comments about how you don't get everything out of the box and for the parts that are missing it's a pain. Perhaps your particular use cases are covered, that's great.
Is this your experience writing Elm apps in production? I am writing large Elm apps in production and I'm having very different experience to what you just described.
> Our JavaScript application had global variables everywhere, and debugging was a nightmare
Point #3 in their list of cons is especially important for anyone considering Elm:
> Because Elm is not a mainstream language, it is sometimes necessary to reinvent something that could otherwise have been acquired by adopting a different technology.
This is the biggest downfall of Elm projects that I’ve seen in the real world. Teams end up spending half of their time or more solving problems that could have been accomplished quickly with some off the shelf React libraries with numerous tutorials online.
This attracts a lot of developers who enjoy working on libraries and tooling, but it’s not ideal if you’re trying to run a lean team that ships products quickly.
Elm is fun, but I wouldn’t use it unless I could afford to hire a relatively huge team to absorb all of the additional complexity and detours that go into building an Elm app. There’s a constant promise of Elm being faster and easier to write for various reasons, but in practice it always seems to get bogged down in endless gotchas and framework shortcomings that need to be addressed before we can get down to getting real work done.