1. 5

    This is so good. An object-oriented approach breaks down when you can’t see how to design the objects you need, so just put procedural code into the objects you have.

    I predict similar “failures” in functional programming codebases as that paradigm continues its journey to the mainstream. In my uikonf talk I called this the “imperative trapdoor”: you can always hide imperative code behind a veneer of objects or functions, but then you lose the paradigm benefits of objects or functions.

    1.  

      Thanks, this is a good observation!

      1.  

        Pure FP with explicit effects can help push you towards a better way, but it’s always possible to end up with an equally enterprisey mess of monad transformers and lenses… hoping effect systems can alleviate some of the former problems. But yes, poor program design will interact poorly with any paradigm.

      1. 14

        I believe that OO affords building applications of anthropomorphic, polymorphic, loosely-coupled, role-playing, factory-created objects which communicate by sending messages.

        It seems to me that we should just stop trying to model data structures and algorithms as real-world things. Like hammering a square peg into a round hole.

        1. 3

          Why does it seem that way to you?

          1. 5

            Most professional code bases I’ve come across are objects all the way down. I blame universities for teaching OO as the one true way. C# and java code bases are naturally the worst offenders.

            1. 4

              I mostly agree, but feel part of the trouble is that we have to work against language, to fight past the baggage inherent in the word “object”. Even Alan Kay regrets having chosen “object” and wishes he could have emphasized “messaging” instead. The phrase object-oriented leads people to first, as you point out, model physical things, as that is a natural linguistic analog to “object”.

              In my undergraduate days, I encountered a required class with a project specifically intended to disavow students of that notion. The project specifically tempted you to model the world and go overboard with a needlessly deep inheritance hierarchy, whereas the problem was easily modeled with objects representing more intangible concepts or just directly naming classes after interactions.

              I suppose I have taken that “Aha!” moment for granted and can see how, in the absence of such an explicit lesson, it might be hard to discover the notion on your own. It is definitely a problem if OO concepts are presented universally good or without pitfalls.

              1.  

                I encountered a required class with a project specifically intended to disavow students of that notion. The project specifically tempted you to model the world and go overboard with a needlessly deep inheritance hierarchy, whereas the problem was easily modeled with objects representing more intangible concepts or just directly naming classes after interactions.

                Can you remember some of the specifics of this? Sounds fascinating.

                1.  

                  My memory is a bit fuzzy on it, but the project was about simulating a bank. Your bank program would be initialized with N walk-in windows, M drive-through windows and T tellers working that day. There might’ve been a second type of employee? The bank would be subjected to a stream of customers wanting to do some heterogeneous varieties of transactions, taking differing amounts of time.

                  There did not need to be a teller at the drive-through window at all times if there was not a customer there, and there was some precedence rules about if a customer was at the drive-through and no teller was at the window, the next available teller had to go there.

                  The goal was to produce a correct order of customers served, and order of transactions made, across a day.

                  The neat part (pedagogically speaking) was the project description/spec. It went through so much effort to slowly describe and model the situation for you, full of distracting details (though very real-world ones), that it all-but-asked you to subclass things needlessly, much to your detriment. Are the multiple types of employees complete separate classes, or both sublcasses of an Employee? Should Customer and Employee both be subclasses of a Person class? After all, they share the properties of having a name to output later. What about DriveThroughWindow vs WalkInWindow? They share some behaviors, but aren’t quite the same.

                  Most people here would realize those are the wrong questions to be ask. Even for a new programmer, the true challenge was gaining your first understandings of concurrency and following a spec rules for resource allocation. But said new programmer had just gone through a week or two on interfaces, inheritance and composition, and oh look, now there’s this project spec begging you to use them!

              2. 2

                Java and C# are the worst offenders and, for the most part, are not object-oriented in the way you would infer that concept from, for example, the Xerox or ParcPlace use of the term. They are C in which you can call your C functions “methods”.

                1.  

                  At some point you have to just let go and accept the fact that the term has evolved into something different from the way it was originally intended. Language changes with time, and even Kay himself has said “message-oriented” is a better word for what he meant.

                  1.  

                    Yeah, I’ve seen that argument used over the years. I might as well call it the no true Scotsman argument. Yes, they are multi-paradigm languages and I think that’s what made them more useful (my whole argument was that OOP isn’t for everything). Funnily enough, I’ve seen a lot of modern c# and java that decided message passing is the only way to do things and that multi-thread/process/service is the way to go for even simple problems.

                    1.  

                      The opposite of No True Scotsman is Humpty-Dumptyism, you can always find a logical fallacy to discount an argument you want to ignore :)

              3.  
                Square peg;  
                Round hole;  
                Hammer hammer;  
                hammer.Hit(peg, hole);
                
                1.  

                  A common mistake.

                  In object-orientation, an object knows how to do things itself. A peg knows how to be hit, i.e. peg.hit(…). In your example, your setting up your hammer, to be constantly changed and modified as it needs to be extended to handle different ways to hit new and different things. In other words, your breaking encapsulation by requiring your hammer to know about other objects internals.

                2.  

                  your use of a real world simile is hopefully intentionally funny. :)

                  1. 2

                    That sounds great, as an AbstractSingletonProxyFactoryBean is not a real-world thing, though if I can come up with a powerful and useful metaphor, like the “button” metaphor in UIs, then it may still be valuable to model the code-only abstraction on its metaphorical partner.

                    We need to be cautious that we don’t throw away the baby of modelling real world things as real world things at the same time that we throw away the bathwater.

                    1.  

                      Factory

                      A factory is a real world thing. The rest of that nonsense is just abstraction disease which is either used to work around language expressiveness problems or people adding an abstraction for the sake of making patterns.

                      We need to be cautious that we don’t throw away the baby of modelling real world things as real world things at the same time that we throw away the bathwater.

                      I think OOP has its place in the world, but it is not for every (majority?) of problems.

                      1.  

                        A factory in this context is a metaphor, not a real world thing. I haven’t actually represented a real factory in my code.

                        1.  

                          I know of one computer in a museum that if you boot it up, it complains about “Critical Error: Factory missing”.

                          (It’s a control computer for a factory, it’s still working, and I found that someone modeled that case and show an appropriate error the most charming thing)

                    2.  

                      You need to write say a new air traffic control system, or a complex hotel reservation system, using just the concepts of data structures and algorithms? Are you serious?

                    1. 6

                      As a former graphic/UX designer I like the affordance angle to programming language and library design. Personally I’m leaning more and more towards ML-style languages or even dependently typed languages than OO languages these days because I find these languages afford me a better ability to design my own domain-specific affordances in the type systems themselves. Alas, they’re not a silver bullet at the moment - there is still work to be done in making those affordances clearer to the user. Sometimes an intricate type signature or datatype can say so much that it is overwhelming, or some incorrectly placed term can result in the type checker exploding a weird error. So at the moment library designers are forced to strike a balance - to a middle ground, trading simple API surface areas with the chance of encountering some runtime errors. We’re making progress though, and that makes me excited!

                      1. 2

                        Interesting! I’ve been working on my own implementation of LambdaPi in Rust (please don’t repost - it’s still a WIP). Haven’t got up to codegen, so I’ll be interested to have a look at the code and see what they do.

                        1. 1

                          Won’t repost. Good luck on it. Glad this can help. :)

                        1. 3

                          Super exciting stuff. I posted another link from this blog yesterday. Will be interesting to see how modular implicits fare in real-world practical use, and whether they have successfully managed to mitigate some of the failings of Scala’s implicits. I’m really hoping they do, so we can finally have a more unified implicit module system that respects the modularity of package ecosystems, whilst also being comprehensible to humans, and robust in the face of refactorings…

                          1. 2

                            Neat! I’m guessing I could use this with other languages too, like Rust?

                            1. 2

                              Skeptic works well for Rust. I used it to write tests for a slide deck :-)

                            1. 6

                              Super thankful that I finally can get to do what I love: bridging the gap between academia (namely programming language and type theory research) and the real world. Also working for a great boss who shares my common interest in finding the balance between correctness and shipping on time seems to have done wonders to my mental health.

                              1. 2

                                Personally, I really like the approach of null punning. You just bubble null values up the call chain and let the user handle them. This avoids having to pepper checks all over the code which is error prone in languages where the checks are optional, and noisy in those that enforce them. In vast majority of cases I find that I’ll have a series of computations I want to do on a piece of data, and I only care whether it’s null at the start or the end of that chain. This is a good longer write up on the approach.

                                1. 4

                                  and noisy in those that enforce them

                                  It’s not if your language has decent support for them - you can easily do the ‘bubbling up’. And it’s not very often you need things to be nillable, so any cost is mitigated.

                                  1. 3

                                    This is the Objective-C approach, as well, and it’s very nice, once you get used to it.

                                    1. 2

                                      It’s horrible in cases where null isn’t actually a valid value; you get the “cannot read property of undefined” problem where you find out about a failure three modules and two thousands lines away from the actual code problem (often in someone else’s code) and don’t have enough information to find out more. Much better to make invalid states unrepresentable and fail fast rather than going into an invalid state.

                                    1. 3

                                      I wouldn’t discourage people, I would just make it clear that this is still an evolving field and it is tough stuff, and not to judge their successes on what this field might become. One alternative for folks interested in this stuff might be Edwin Brady’s Idris book.

                                      1. 1

                                        I hear you. Might try to be careful about that. A few people I know gave up on formal methods because of Idris being too hard to learn. I think that was before the book, though. Do you know of a lot of people that aren’t math strong who were able to follow the book and apply its lessons?

                                      1. 20

                                        A bit unrelated to the linked content, but “Low Hanging Fruit of Programming Language Design” really makes me wish a place/collection/book which documents the lessons (both good and bad) learned in the last few decades of language design.

                                        Language design currently feels like it has plateaued and isn’t really moving forward anymore except in a few specific attributes the language author really cares about.

                                        Having some exhaustive documentation that holds potential design approaches for individual features, possibly with a verdict based on past experiences would help to prevent language designers repeating the same mistakes over and over.

                                        Entries could include:

                                        • The various, bad approaches to operators and operator “overloading”.
                                        • How not to mess up equality and identity.
                                        • Things that don’t belong on a language’s top type.
                                        • Implicit numeric conversions will never work in a satisfying fashion.
                                        • Picking <> for Generics is wrong and broken, as evidenced by all languages that tried it.
                                        • Why ident: Type is way better than Type ident.
                                        • Typeclass coherency is fundamentally anti-modular and doesn’t scale.
                                        • Upper and lower bounds are a – rather uninteresting – subset of context bounds/typeclasses.
                                        • There is no reason to require “builtin/primitve” types to be written differently from user-defined types.
                                        • How to name things in a predictable way.
                                        1. 13

                                          Another good source of lessons would be what Gilad Bracha calls shadow languages. Essentially, any time you find a simple mechanism getting extended with more and more features, until it essentially becomes a (crappy) programming language in its own right. The obvious thing to try in these situations is to throw out that standalone system and instead provide some mechanism in the ‘real’ language for programs to calculate these things in a “first class” way.

                                          Bracha gives examples of ML modules, where e.g. functors are just (crappy) functions, Polymer (which I don’t know anything about) and imports (e.g. conditional imports, renaming, etc.).

                                          Some more examples I can think of:

                                          • Haskell’s typeclass resolution mechanism is basically a crappy logic language, which can be replaced by normal function arguments. Maybe a better generalisation would be implicit arguments (as found in Agda, for example)? One way to programmatically search for appropriate arguments is to use “proof tactics”.
                                          • Haskell types have gained datakinds, type families, etc. which are basically just a (crappy) functional programming language. When types are first-class values (like in Coq, Agda, Idris, etc.) we can use normal datatypes, functions, etc. instead.
                                          • Build/packaging systems. Things like Cabal, NPM, PyPI, RPM, Deb, etc. These are usually declarative, with elaborate dependency solvers. As well as being rather limited in what we can express, some systems require all participants to maintain a certain level of vigilence, to prevent things like ‘malicious solutions’ (e.g. malicious packages claiming to implement veryCommonDependency version 99999999999). I’ve seen a couple of nice approaches to this problem: one is that of Nix/Guix, which provide full functional programming languages for calculating packages and their dependencies (I’ve even written a Nix function which calls out to Tinc and Cabal for solving Haskell package dependencies!); the other is Racket’s old PLaneT packaging system, where programs write their dependencies in-line, and they’re fetched as needed. Unfortunately this latter system is now deprecated in favour of raco, which is just another NPM-alike :(
                                          • Multi-stage programming seems like a language-level concept that could subsume a bunch of existing pain points, like optimisation, configuration, or even packaging and deployment. Why bother with a mountain of flaky bash scripts to orchestrate compilers, build tools, test suites, etc. when we can selectively compile or interpret sub-expressions from the same language? The recent talk “programming should eat itself” looks like the start of some really exciting possibilities in this area!
                                          1. 4

                                            I tried to write something like that, but this is so subjective.

                                            This is probably not a big problem in practice. If you design and publish a language, many helpful trolls will come and tell you all mistakes you made. 😉

                                            1. 6

                                              FWIW, I compiled a list of articles on some of the topics I mentioned above:

                                              Maybe it is interesting for you.

                                              The articles’ conclusion are based on an exhaustive survey of more than a dozen popular languages as well as many minor, but influential ones.

                                              1. 2

                                                Thanks, a few of my writings:

                                                Is there a way to get a feed of your articles? https://soc.github.io/feed/ is empty.

                                                1. 1

                                                  Looks like we agree on pretty much everything in the first two articles. :-)

                                                  I think there are only bad options for dealing with operators (while operator overloading is pretty much broken altogether), but some approaches are less bad then others.

                                                  My opinion is to pretty much use the simplest thing to document, specify and implement, and emphasize the lack of importance of operators to users to stop them from going overboard.

                                                  I believe they get way too much attention given how unimportant they are in the grand scheme of things.

                                                  Is there a way to get a feed of your articles? https://soc.github.io/feed/ is empty.

                                                  I’ll look into that, wasn’t even aware that I had a feed. :-)

                                                2. 2

                                                  For equality, I’m not sure if there should be an equals method in Object (or Any or AnyRef).

                                                  Equality is not a member of a type. (Unfortunately, in Java everything must be inside a class) Equality often depends on context. For example, when are two URLs equal? Sometimes you want to compare the strings. Sometimes the string without the fragment identifier. Sometimes you want to make a request to look what gets returned for the URLs.

                                                  Sometimes, we might prefer to not provide equals at all. For example, does it make sense if locks can be equal?

                                                  The argument pro Object.equals is convenience. For many types there is a reasonable default. Manually specifying equality for every hash map instantiation is tedious.

                                                  1. 1

                                                    For equality, I’m not sure if there should be an equals method in Object (or Any or AnyRef).

                                                    I agree. The considerations don’t rely on it, except as a tool for demonstration. If a language isn’t forced (e. g. by the runtime/host language/library ecosystem) to have it on their top-type it makes sense to leave it out.

                                                  2. 2

                                                    Why are [] better than <> for generics

                                                    I feel like this should be a two-part argument:

                                                    • why re-using <> for generics is bad
                                                    • why [] are better used for generics than for indexing

                                                    Your article is pretty convincing on the first part, but curiously silent on the second. What does Scala use for indexing into ordered collections? Or does it avoid them altogether?

                                                    1. 4

                                                      Scala uses () for indexing into ordered collections, a la vbscript.

                                                      As a language developer, I’ve not implemented generics, so I’ve yet to develop strong feelings about <> in that sense
                                                      As a language user, <> for generics has never tripped me up. That has mostly been In C# and Java, however, and I think both languages keep the places where <> vs < or > shows up mostly distinct. I’d hardly call it a disastrous choice on this side of things, even if it took some extra work on the part of the language teams for them.

                                                      1. 2

                                                        I do know that <> ends up looking painfully ugly, at least in Rust. Also is making it harder to find a nice syntax for constant generics, and is responsible for the ugly turbofish operator.

                                                        1. 1

                                                          I would suppose that is a bit more of a matter of taste, but I’m unsure that [] would be any better on that front, unless ::<> would be replaced by something other than ::[]. Which might be possible if Rust didn’t use [] for indexing. Given the tiny bit of Rust I’ve written, giving up [] for indexing would almost make sense, since you’re often using methods for collection access as it is. I’d have to sit down with the Rust grammar to be sure.

                                                          1. 2

                                                            The important thing to keep in mind is that <> weren’t chosen for any kind of reason except “these are literally the only symbols on the keyboard which kind of look like braces that we can retrofit into an existing language.”

                                                            If you start from a blank slate and ask “what is the best we can do, making the rules of the language simple and easy to understand” the result will be very different.

                                                            Consider two approaches:

                                                            Approach A

                                                            • () brackets: used for method calls, except where they are not: Array construction, array indexing, etc.
                                                            • [] brackets: used for array construction and array indexing
                                                            • {} brackets: used for array construction, method bodies, initializers, …
                                                            • <> “brackets”: used as an operator for comparisons, used for generics

                                                            Approach B

                                                            • () brackets: used for terms, grouping, marks a single expression
                                                            • [] brackets: used for types
                                                            • {} brackets: used for refining a term/type, marks a sequence of statements
                                                            • <> “brackets”: not used, because they are not brackets

                                                            I think no one would say “let’s mix things up and assign brackets to various use-cases randomly” and pick approach A over approach B.

                                                            And yes, Rust would be simpler and easier to read if they kept the use of [] for generics, instead of migrating to <>.

                                                            1. 2

                                                              unless ::<> would be replaced by something other than ::[].

                                                              That’s exactly what I’m thinking. It’s subjective, but I also find that <> makes polymorphic types look claustrophobic, where as [] feels more ‘airy’ and open, due to their shapes.

                                                              Here’s an example from today:

                                                              fn struct_parser<N>(fields: &[Field<N, Rc<binary::Type<N>>>]) -> Rc<ParseExpr<N>> {
                                                              

                                                              vs.

                                                              fn struct_parser[N](fields: &Slice[Field[N, Rc[binary::Type[N]]]]) -> Rc[ParseExpr[N]] {
                                                              

                                                              Ideally I would prefer that the same syntax be used for both value level and type level abstraction and application, but I’ll save that debate for another time…

                                                    2. 3

                                                      Even a list of how different language designs approach the same problem, with respect and without comparing them, would be a huge improvement over what we have now. Should be easier to compile than a “here are the lessons” document since it’s less subjective.

                                                      1. 2

                                                        To compare languages, I’ve used:

                                                        And although I haven’t used it very much, Rosetta code does what you want:

                                                        Of course these are superficial, but surprisingly useful. I draw mostly on the languages I really know, but it’s nice to have an awareness of others. I know about 5 languages really well (written thousands of lines of code in each), 5 more languages a little bit (Lua, Go, etc.), and then there are maybe 10 languages that I don’t know which are “interesting” (Swift, Clojure, etc.)

                                                        I think that posting to lobste.rs or /r/ProgrammingLanguages can help feedback with those. Here is one thread I posted, summarizing a thread from HN:

                                                        https://www.reddit.com/r/ProgrammingLanguages/comments/7e32j8/span_slices_string_view_stringpiece_etc/

                                                        I don’t think there is much hope of getting all the information you want in one place. Because there is so much information out there, and some languages like Swift are new and rapidly developing.

                                                        Personally I maintain a Wiki that is my personal “delicious” (bookmark manager), although I have started to move some of it to the Oil wiki [1]

                                                        [1] https://github.com/oilshell/oil/wiki

                                                        1. 2

                                                          FWIW, I compiled a list of articles on some of the topics I mentioned above:

                                                          Maybe it is interesting for you.

                                                          The articles’ conclusion are based on an exhaustive survey of more than a dozen popular languages as well as many minor, but influential ones.

                                                          (Sorry for the double post.)

                                                          1. 1

                                                            A can also recommend /r/Compilers. At least, I had a nice discussion there recently.

                                                      2. 2

                                                        The best things I’ve found on this are interviews with language designers. But it is scattered.

                                                        1. 2

                                                          That would be nice, but I see several problems:

                                                          • Language design depends on the domain. There’s no right answer for every domain. For any language that someone claims is “general purpose”, I will name a domain where virtually no programs in it are written (for good reasons).
                                                          • Almost all languages features interact, so what is right for one language is wrong for another.
                                                          • Some things are subjective, like the two syntax rules you propose. They’re also dependent on the language.
                                                          1. 3

                                                            Kind of agree with your points, but I believe there is a reasonable subset of topics, where one can provide a conclusive verdict based on decades of languages trying various approaches, like for instance abusing <> for generics or ident: Type being better.

                                                        1. 6

                                                          Interestingly, my argument why I don’t like macros goes somewhere along those lines: If you have something repetetive where people use macros to work around, it’s probably a flaw in the host language.

                                                          I’m not saying they are bad, just that I don’t like them.

                                                          Excluded are obviously languages that are fundamentally based on them.

                                                          1. 4

                                                            Ok, so it’s a flaw in the host language. Isn’t it nice to have macro’s to work around them?

                                                            1. 7

                                                              Possible outcome: every project works around the problem in their own slightly incompatible way, and no-one bothers fixing the problem in the host language because it’s easy enough to work around.

                                                              I like macros as a way to cheaply prototype proposed language changes. I don’t want to see them in production code; debugging from the output of a (nonstandardised) code generator is awful but still easier than debugging from the input, which is effectively what the choice between code generation and macros boils down to.

                                                              1. 8

                                                                I like macros as a way to cheaply prototype proposed language changes. I don’t want to see them in production code; debugging from the output of a (nonstandardised) code generator is awful but still easier than debugging from the input, which is effectively what the choice between code generation and macros boils down to.

                                                                This has, by the way, happened with Rusts “try!()” (which, after some modifications, became the “?” operator).

                                                                1. 2

                                                                  Reminds me of Rust’s primary use of macros: emulating the varargs that the language lacks.

                                                                  My cardinal rule about macros is that if I have to know that something is a macro, then the macro is broken and the author is to blame.

                                                                  Rust also messed up in that regard by giving macro invocations special syntax, which acted as an encouragement to macro authors to go overboard with them because “the user immediately sees that it is a macro” – violating the cardinal rule about macros.

                                                                2. 2

                                                                  Yup, the alternatives are duplication/boilerplate or external codegen until the language catches up. Macros are an decent way to make problems more tractable in the short term (unless your in a wonderous language like Racket), or even to prototype features before they are implemented in the full language. I’d love to see more metaprogramming with a basis in dependant types, but alas there’s still lots of work to be done before that has been made workable for the average programmer.

                                                                  1. 1

                                                                    Sure, that’s why I said they aren’t bad, I just don’t like them.

                                                                    On the other hand, I also don’t have any problem with codegen over macros, its basically the same thing at another phase.

                                                                  2. 1

                                                                    Say that this flaw is becoming obvious a couple of years after the language’s release. In that case the fix may have the consequence of breaking some subset of existing code which is arguably worse than including macros in the language. I don’t know where I want to go with this strawman-like argument other than to say that language design is hard and macros lets the users of the language make up for the designers deficiencies.

                                                                    1. 1

                                                                      I totally appreciate that. I just don’t see “does the language have macros” as the issue people make it. For example, languages with very expressive metaprogramming systems like Ruby have purposefully not included macros and are doing fine.

                                                                      Macros are often an incredibly complex and problematic fix for this, though. Just the patterns list of the Rust macros book is huge and advanced: https://danielkeep.github.io/tlborm/book/pat-README.html

                                                                      (Other languages have nicer systems, I know, but the issue persists: textual replacement is a mess)

                                                                      I totally see their place, for example, we couldn’t define a type checked println!("{:?}", myvalue) in Rust proper without adding a lot of additional things to the language.

                                                                  1. 35

                                                                    Startup mistakes are spending too much time thinking about data stores, and not enough time thinking about making money. Personally I believe that so many startups fail because they obsess and re-engineer their tech stack so much. Most startups (if they ever get to making money) change their initial product/offering so much by the time its out there, that the tech stack decisions they made in the early days aren’t as relevant to the problem they actually end up solving. Use a sane default then evaluate if you actually need anything else. So I whole heartedly agree with his statement just use Postgres, and you won’t regret it.

                                                                    1. 3

                                                                      I agree with you after reading lots of Hacker News and Barnacles. They should spend almost all their time marketing, listening to customers, building/testing features, and so on. That said, it’s still good to consider this stuff ahead of time to give them templates for what to go on that will reduce operational problems early on and/or in maintenance down the road. Like the OP and your Postgres recommendation. Also, like turnkey Postgres appliances for the cheap hosts they’ll probably be using.

                                                                      1. 3

                                                                        100%. I been in numerous failed startups. I’ve seen plenty more. Datastore wasn’t an issue even once…. I’ve seen plenty of startups build on amazing datastores and fail to have any sales and marketing. I’ve seen plenty fail from not having backups, from hiring poorly, from overreaching.

                                                                        Datastores can hurt when you’re scaling up. But you’re scaling up now. Congratulations.

                                                                        Agree that defaults make sense. However, equally it’s worth being aware that you’re going to have scale problems whatever you do. Every serious relational database I’ve seen is a beast. Comes with the territory.

                                                                        1. 2

                                                                          Yup, going with Postgres at the beginning makes sense, because it gives to freedom to experiment and iterate on your domain in the beginning from a solid foundation. Alas the databases that are more geared towards scaling are currently trickier to work with in the face of changing requirements, so mistakes become magnified to quite a large degree. But you’ll eventually want to move to a different model once scaling becomes an issue.

                                                                          At the moment my thinking is that you use a RDBMS under the hood, but pretending it’s CQRS/ES, which maintains an nice separation of concerns between reading and writing and the persistence layer, then you are in a better position to switch to something more scalable in the future, whilst maintaining the advantages of in-place migrations in the beginning when requirements are still up in the air.

                                                                          1. 1

                                                                            I had never heard of CQRS before, it’s quite interesting. Could you elaborate a bit on ES?

                                                                            1. 1

                                                                              Event sourcing…

                                                                              And I’m with /u/brendan on this: focus on the “why” (design) of separating concerns, not the “how” (transport). It’s a long time between MVP and having load that demands Kafka, RabbitMQ, NSQ, NATS, etc. There are designs that need those early but I squint hard at that because they add a lot of complexity and operational overhead when you’re still figuring out how to solve other problems.

                                                                        2. 3

                                                                          Startups don’t exist to make money- they exist to get bought. That’s their profit model: get bought out at a high valuation before your burn outpaces your investment.

                                                                          1. 5

                                                                            Startups don’t exist to make money- they exist to get bought.

                                                                            To be fair, their ability to get bought should depend on their ability to make money, and after these crazy bubble times are over, it will.

                                                                            That’s their profit model: get bought out at a high valuation before your burn outpaces your investment.

                                                                            That’s not a profit model though :) It’s a plan for making a return on the time, effort, and money the founders invested in the startup. It’s a gamble too!

                                                                        1. 2

                                                                          Does anyone know if Chrome/WebKit parallelizes rendering? If not… then Firefox may become the fastest browser, and hold that spot for a long time.

                                                                          1. 2

                                                                            Well it’s massively parallel if you consider that it’s happening on the GPU in shaders. Check out:

                                                                            After that there is work being done to figure out how to do font rasterization on the GPU, parallel layout, etc. The great thing is that Mozilla is now figuring out how to optimize the process of moving stuff from Servo into Gecko, so hopefully this will make moving future improvements into production easier. They’re opening up a huge lead.

                                                                          1. 8

                                                                            Completely agree Wez! Thankfully most of my previous jobs have been pretty loose with pairing - we understood it took energy, but that there was also a huge amount of knowledge sharing that could take place when we chose pairing opportunities judiciously. I’m currently working at a job where I’m working solo all day and really loving the flow states, but I still do miss the amount I can learn when pairing with a fellow dev.

                                                                            1. 4

                                                                              What are lobsters’ thoughts on XML by the way? As a younger person looking back in this age of JSON, it seems like it actually had a bunch of neat ideas, wrapped up in a terrible syntax and some excessive feature bloat. Is there any work being done on salvaging some of it, or it it kind of a lost a cause?

                                                                              1. 8

                                                                                Aside from the awful syntax, XML has terminal featuritis (and, as an immediate consequence, a bunch of useful features; they’re just mixed in with a bunch of less useful ones). Simpler formats are usually better. Personally, in the absence of other requirements, for human-readable data, I’d use JSON; for human-writeable, YAML (though it has its own featuritis issues); for human-unreadable (i.e., binary), protobuf, though there’s actually been a relative proliferation of these lately (others to consider: Cap’n Proto, Avro).

                                                                                At this point, I’d drop XML other than for backwards compatibility. There are enough widely-supported alternatives which hit a useful subset of its features that I don’t expect anyone to put a lot of effort into making a “better” XML.

                                                                                1. 1

                                                                                  If JSON or YAML will suffice, then XML was probably a terrible tool for the job. But I haven’t found a good alternative to XMLNS yet

                                                                                2. 6

                                                                                  There are some good ideas in the XML ecosystem, but IMO the problem with it is that it doesn’t map to most programming language data structures. JavaScript, PHP, Python, Perl, Ruby all essentially have the JSON data model – dynamically typed dicts, lists, strings, numbers, booleans. JSON is the lowest common denominator between them all.

                                                                                  Between those 5 languages, that’s probably 95%+ web apps, so you can see why JSON is a better fit than XML for communicating structured data between processes (not to mention that one side of the wire is usually JavaScript).

                                                                                  The syntax of XML isn’t terrible; it’s only terrible if you use it for the wrong thing. The syntax of JSON is terrible if you’re say writing HTML with it:

                                                                                  { "tag": "p"
                                                                                    "content": ["This is my paragraph with text in ", {"tag": "b", "content": "bold" }, "\n"  ]
                                                                                  }
                                                                                  

                                                                                  That is a horrible syntax for a document, just like XML is a bad syntax for structured data. I think people tend to overthink this. Use XML when you need to annotate text with attributes; Use JSON when you have structured data.

                                                                                  I haven’t used XML lately but I imagine it’s still good for book toolchains and so forth. I think there is a habit of overengineering those kinds of tools though. I use HTML a lot these days and it works well.

                                                                                  Historically people DID try to abuse XML into the role of JSON, e.g. for database dumps (which JSON isn’t even great at.) But people learned a lesson I suppose. There is a tendency to try to make a particular technology “universal”, and apply it to domains where it doesn’t fit.

                                                                                  1. 3

                                                                                    JSON and XML solve totally different problems. You can abuse one to do what the other does, but that way lies pain.

                                                                                    JSON is an encoding for some common data structures and types: map, list, string, number, boolean

                                                                                    XML has none of these, but is a way to graft different kinds of data together in a single document such that parsers can use the parts they understand, and ignore the parts they don’t. Namespaces are the “eXtensible” part.

                                                                                    1. 3

                                                                                      I’ve commented here a bunch on the topic of self-describing data in general, either to explain my view that the real problem is not the data format, but rather the schema… or to plug my incomplete project Modern Data, which I conceived of in a manic episode, so I make no apology for its grand scope, but I’m not sure when if ever I’ll have time to finish it…

                                                                                      The project will someday, maybe be a self-describing schema format for dependently typed object graphs. To be useful it needs not only the basic typechecker, serializers, and deserializers, but also tools like diff and structure editors… The idea is that you could write a Modern Data schema for any existing file format (regardless of whether it’s based on something like XML or JSON, or it’s a low-level format more like PNG), and then gain the full benefit of the tooling ecosystem.

                                                                                      It’s the kind of thing that I think many people would use if it were mature, but it’s challenging to get people interested in building it before it is.

                                                                                      Anyway, the real problem is schemas. :) Every major serialization format I’m aware of has had major controversy over whether and how to support schemas, including formats such as JSON which originally tried to exist without any such support - it’s important enough that people tend to invent schema formats if they aren’t provided. There’s often a desire to make the schema format itself be something not-fully-general which maps naturally onto the kinds of data people want to represent in the underlying format. This is motivated by valid and important concerns about tooling support, but it never seems to actually get to the point where it meets everyone’s needs…

                                                                                      And, of course, most self-describing data formats are more-or-less trees. That means they can’t handle certain situations where performance is important; for that you need arbitrary graphs, often implemented through some sort of intra-file pointer.

                                                                                      1. 1

                                                                                        This sounds super interesting, have you written about it more anywhere else?

                                                                                        1. 2

                                                                                          Kind of, but I’ve never put together a good write-up of the motivation. See https://github.com/IreneKnapp/modern-data, and also somebody I met here once started an effort to redo the documentation, over at https://github.com/tinyplasticgreyknight/modern-docs.

                                                                                      2. 2

                                                                                        It’s a markup language and it’s not terrible at markup.

                                                                                      1. 5

                                                                                        Go doesn’t have exceptions, so the common idiom is for the function to return multiple values, the last one being an error. And, of course, the caller should check that error, and react appropriately.

                                                                                        I don’t use Go much - can someone explain to me why this is preferred over a rust-style Result enum? It seems like returning a separate error value make it more likely that it will be ignored - is there a feature in the language to prevent programmers from ignoring the error?

                                                                                        1. 7

                                                                                          If a Go function returns a value and an error (e.g., (T, error)), then in order to get your T, you would need to explicitly ignore the error with _ as other posters have described. However, if a Go function returns only an error, then you can call that function without acknowledging the error at all. Note that the comparison with unwrap in Rust isn’t quite the same, since an unwrap will panic if there is an error, where as using _ to ignore an error in Go just swallows it and the program continues.

                                                                                          The trade offs between Rust-style error handling and Go-style error handling basically boil down to where you stand on the type safety spectrum. More ceremony in Rust, but less likely to drop errors on the floor. There is also the “the type signature of the function more accurately describes the behavior of the function” aspect of it. On the Go side of things, error handling is enforced basically by very strong convention: if err != nil { return err } and that’s that.

                                                                                          1. 4

                                                                                            Using nullable tuples for something that is semantically a disjoint union? Bleh. Just seems like a really awkward way to do it. :/

                                                                                            1. 3

                                                                                              Yes and no. This argument has been litigated a billion times on the Internet already. You won’t drag me into it. :-)

                                                                                          2. 3

                                                                                            You will get a compilation error if you fail to ignore the returned error.

                                                                                            You can experiment here: https://play.golang.org/p/9XSOZFGbzT

                                                                                            I don’t know Rust, and I have only been using Go at work a little bit, so I can’t really compare and contrast their respective error handling methods.

                                                                                            1. 6

                                                                                              Rust uses sum types, so you do not need a separate return value for errors. Instead, you use the Result type, which has two variants, Ok carries a successful computation, while Err communicates an error. You can then pattern match the result in the caller using a match or use the ? operator to let errors bubble up.

                                                                                              Also see: https://doc.rust-lang.org/book/second-edition/ch09-02-recoverable-errors-with-result.html

                                                                                            2. 2

                                                                                              You have to explicitly ignore it, doing something like x, _ := getX()

                                                                                              1. 1

                                                                                                Cool, makes sense. I guess the part that seems weird to me is that you are able to return both an error and a value. I also suspect that it’s slightly more common to ignore the error using _ than match or unwrap, but I don’t know if that’s actually true or not. I should probably just use go and figure out which one I actually prefer :)

                                                                                                I am very glad that error handling is something that language designers are thinking about now though - this is far better than in languages like C and Python.

                                                                                            1. 3

                                                                                              lisp are the only language which are the only languages that I know which can really make heavy use of REPL

                                                                                              1. 3

                                                                                                Haskell and Ocaml are also pretty decent at this.

                                                                                                1. 1

                                                                                                  The difference is that there is tight integration between the editor and the REPL in Lisps. When I work with Clojure, my IDE is connected to the running application. I can inspect and reload any code in the application straight from the editor.

                                                                                                  1. 0

                                                                                                    From what I understand stativ typing slow you too much

                                                                                                  2. 2

                                                                                                    ipython is excellent, but it doesn’t quite support incrementally writing a module in the same way as a lisp. E.g. if foo.py contains from bar import func, redefining func in bar is difficult.

                                                                                                    Julia has a lovely REPL experience.

                                                                                                    Smalltalks are arguably REPL environments: you can evaluate code anywhere, and the debug/edit/continue experience is amazing.

                                                                                                    1. 2

                                                                                                      With python you can get a little bit closer using Jupyter, since it blends an editing environment with a REPL more than using iPython directly. I try to remember to use it instead of iPython when I need a REPL. It’s especially nice if you’re doing exploratory data work, because you can draw graphs and charts.

                                                                                                      1. 0

                                                                                                        Smalltalk is strange you have not codesource file. Wonder about Julia

                                                                                                      2. 0

                                                                                                        I should have precisr for building a profram

                                                                                                      1. 19

                                                                                                        I’ve seen this argument a lot that you CAN do one in the other, however syntax matters and defaults matter.

                                                                                                        1. 3

                                                                                                          Case in point:

                                                                                                             (assoc map :key value)
                                                                                                          

                                                                                                          In JavaScript:

                                                                                                             Object.assign({}, {key: value})
                                                                                                          

                                                                                                          Which is both more complex, less obvious and less efficient.

                                                                                                          1. 2

                                                                                                            Redux apps can use ES6 spreads for this: { ...map, key: value } - less efficient but certainly not too onerous syntax wise.

                                                                                                            1. 1

                                                                                                              This is not ES2015 (ES6) but ES2017. ;)

                                                                                                              1. 1

                                                                                                                Actually, it is not standardized at all. It is still a stage 3 proposal.

                                                                                                                https://github.com/tc39/proposal-object-rest-spread
                                                                                                                https://github.com/tc39/proposals

                                                                                                            2. 2

                                                                                                              Would anyone do that in real JS? (I don’t write JS, but if the answer is “no”, then I don’t see the point)

                                                                                                              As time goes on I have to admit that FP hype gets on my nerves. I enjoy the functional combinators as much as the next person, I love getting work done in Erlang, I am sometimes grouchy when writing Go when I can’t just map over a container, I love testing pure functions in any language, but maybe it has been python and rust that have made me a little happier in general to fall back on the boring procedural control structures (they support both paradigms, and yet people tend to use explicit iteration instead of the combinators pretty frequently). Readability is nice.

                                                                                                              1. 5

                                                                                                                Would anyone do that in real JS? (I don’t write JS, but if the answer is “no”, then I don’t see the point)

                                                                                                                Can’t speak for others, but we do that a lot in our React/Redux app to avoid mutation of objects from spreading.

                                                                                                                I have been using Python in a functional style, with LCs, map, filter and just about everything from the itertools and operator modules, but it was just not idiomatic. So when I switched to Clojure where this is the dominant way to do things it feels like coming home. I think the procedural control structures, especially when used in places where a map or fold would suffice makes it more difficult to understand what is going on because they could do anything.

                                                                                                                1. 3

                                                                                                                  You might be interested in Coconut (http://coconut-lang.org).

                                                                                                                  1. 1

                                                                                                                    We should use the abstractions that minimize incidental complexity. I like using combinators when they fit on a single clean line. I tend to get lost when reading code that nests them, or is like a chain of 4+ combinators that hasn’t been documented more thoroughly than average. While I enjoy writing clojure and erlang (languages heavily reliant on combinators) they tend to be languages that I despise reading other people’s code for the most. I’m happy when people spend the time to make their stuff clean and fucrs-compliant, but it’s so damn painful for me to follow a nasty chain of nested combinators.

                                                                                                                  2. 2

                                                                                                                    Oh yeah, I have a React/Redux project that sometimes felt like half my code was calls to Object.assign. It’s the easiest way to do a shallow copy of an object so you’re not inadvertently passing references to the same object around and mutating them.

                                                                                                                    Python does cause you to use more of the “boring procedural” control structures, and it does nominally support some functional programming, but some of it is more because of inconvenience than anything else. For example, I write far too many nested for/if loops where filter would be more natural if filter/map/lambda was less clunky and faster. I don’t think this makes it easier to read. I also think its reliance on list comprehensions is wrongheaded, because even now, after knowing Python for… ugh, nearly twenty years… I can never remember the order for iterating through nested lists in a list comprehension.

                                                                                                              1. 6

                                                                                                                What am I looking at

                                                                                                                1. 3

                                                                                                                  I don’t know. How far did you scroll? I scrolled and I scrolled, and there were some notes, and I scrolled and I scrolled, and a few more, and then finally I gave up. Maybe if you get to the year 1000000 it gets good?

                                                                                                                  1. 7

                                                                                                                    Keep reading the notes… patience.

                                                                                                                    1. 2

                                                                                                                      It crashed my mobile browser around ’45 and on restart there was a satellite there.

                                                                                                                      Not sure how football or anything is related. Will probably forget this soon.

                                                                                                                      Too bad I can’t downvote after reading.

                                                                                                                      1. 16

                                                                                                                        You folks aren’t making it to the content… That is unfortunate. :(

                                                                                                                  1. 1

                                                                                                                    It’s like pattern matching!