21 ms·
> I have spent a fair amount of time over the last several years trying to make node act like the browser, or vice versa. And the right thing to resist doing e
by cxr 5y ago
> I have spent a fair amount of time over the last several years trying to make node act like the browser, or vice versa.
And the right thing to resist doing either. It's to think about what "services" your program actually needs to be able to function and then to isolate those parts from the rest of your application by putting it behind a well-defined interface. In other words, the best way to fix the incompatibility problem caused by API mismatches is to never make the mistake of coding directly against the host platform's APIs to begin with. Trying to do it with compatibility shims to make one platform look like the other is a fool's errand. You end up running around trying to achieve parity with a mammoth API surface area (which might never have been especially well-designed to begin with...).
Let's say you're implementing a program similar in scope to UNIX's file(1). For our example, though, suppose you're really only concerned with text files and specifically whether a given text file is using DOS-style CRLF line separators or UNIX-style LF terminators. You really only need two capabilities: a `read` operation to get the contents of a file and a `print` operation to show the output to the user. Does your program care whether that `read` is happening with a Web standards-backed FileReader or NodeJS's proprietary `fs` module? There's no reason it should. Design the best "system" layer that makes the most sense for your application's needs.
You can see this implementation strategy in the way the TypeScript team wrote the code for the TypeScript compiler itself when it was made public. Even in the early days, it could run on multiple platforms—including NodeJS, JScript/Windows Script Host, and various browsers (old or new)—because it didn't overly concern itself with anything except its real job of lexing, parsing, and type-checking its inputs—wherever they came from—and then writing the output in a platform-agnostic way.
- IggleSniggle 5y ago> In other words, the best way to fix the incompatibility problem caused by API mismatches is to never make the mistake of coding directly against the host platform's APIs to begin with. Trying to do it with compatibility shims to make one platform look like the other is a fool's errand. You end up running around trying to achieve parity with a mammoth API surface area (which might never have been especially well-designed to begin with...). It seems like you're making a good point, but I'm confused by your comment. Do you believe we should avoid coding directly against the host platform's APIs, or do believe we should avoid compatibility shims? At some point, you need compatibility shims in order to avoid coding directly against the host platform's APIs. The most that your runtime strives to match existing runtimes, the less you need to worry about writing shims to improve compatibility.
- cxr 5y agoI'm referring to compatibility shims like the ones described: where you have two platforms, so you try to make one look like the other and then target that. I'm saying don't do that. > Do you believe we should avoid coding directly against the host platform's APIs, or do believe we should avoid compatibility shims? Avoid compatibility shims that lead to you writing your application's logic directly against platform APIs. You recognize that you need to read a file, so you write your application logic against the simplest possible interface you can think of that would let you do that: `read`.* You don't try to emulate either platform's API. This sounds like a bad deal, because neither platform provides native support for this interface, and the other approach is tempting, because you already get one implementation of the API for "free" (on whatever platform where that API is native), and you'd "only" have to write the compatibility shim for the other one (or re-use somebody else's shim). This is a mistake. For one thing, people end up misjudging the cost/benefits of each, and for another, the compatibility shim doesn't make the program easier to understand. You end up with quirks of that API infecting increasingly more parts of the program. * What you don't do is go off and design the best, elaborate, pluggable, most extensible abstraction layer that you can think of. You implement `read`.
- pvorb 5y ago> never make the mistake of coding directly against the host platform's APIs to begin with I regularly read this advice and I think it's bad in general. If you only ever work against an abstraction, you lose time and might get a worse end result than the one without the abstraction. And in the end, you might throw it away, if it doesn't prove successful. So move the cost for working with an abstraction into the future as much as possible, when you know the alternatives you have to abstract over.
- eyelidlessness 5y agoI’m not exactly 50-50 on this, but fairly close. It depends! People talk about ‘premature abstraction’ as if spending any time abstracting up front is premature; others talk about abstractions they find generally useful in such an abstract way that it’s easy to mistake those general findings for rules. There’s a distinct set of skills and instincts involved in recognizing a generalization of a problem, and a narrower one in recognizing matching solutions which are actually suited to the specific problem. It’s not a skill/instinct everyone has, but it’s not one that should be immediately dismissed either. And one’s recognition of both can grow and be refined over time. I also think this kind of balanced flexibility should be something we demand as a baseline assumption of the craft: - We’re going to have instincts no matter what, and we should be encouraged to explore them - Some of those instincts will prove right, some wrong; often “wrong” will be grey and murky and temporally separated from trying - When we’ve recognized the error, we should allocate time to correct it with what we’ve learned - As this process recurses, we should assess whether our predictive senses are getting closer to reality, and adjust our risk impulse accordingly