1. 23

    There are three levels of frontend interaction complexity:

    • Up to form action=foo method=post and button type=submit. For this, HTML + CSS is the easiest solution.
    • Up to buttons with simple animations. Jquery or vanilla is the easiest solution.
    • Anything over it. React with potentially extra state management libraries is the easiest solution.

    Yes, you don’t need React for websites with minimal interactivity requirements, but as soon as you have to add just a few of those requirements, you quickly regret not having React.

    Also, things like GatsbyJS or NextJS can be configured to output static sites. This may look like totally overkill, except for a tiny detail. You get to use all the module management and import semantics from Javascript to manage your components, which is way better than plain old CSS files and copy-pasta for HTML snippets. Add in Typescript and you have a strong proposition. Though WebComponents may do something similar here…

    1. 4

      There’s a level past React too though. React can’t really do high performance things, so for those you need to turn to Canvas or something and handroll it. Tom MacWright made this point in the now classic “Rethinking the Modern Web”.

      Here’s one way to think of it:

      • Google search: can be handled as HTML, CSS, sprinkles of JS animation
      • Gmail: you’ll want some kind of JS framework to handle all the zillions of screens
      • Google maps: you don’t want a framework doing the map because it will be too slow. The map is canvas or some other smart layer that can load tiles on the fly. (Nav buttons can be whatever.)
      1. 3

        It’s extremely easy to migrate from a simple HTML + CSS site to a site with JQuery or vanilla JavaScript, because JavaScript is basically just a layer over the HTML page that’s already there. React wants to have the center stage, and most knowledge about the underlying technology is useless at best and sometimes even harmful, as React wants everything done in a very specific way.

        1. 15

          See this line of code? https://github.com/manirul41/react-mvc-app/blob/master/src/index.js#L7 It tells React to do its thing on the id=“root” element in the page. What tends to happen is https://github.com/manirul41/react-mvc-app/blob/master/src/index.html#L15 - I/E the only element in the page is that id=“root”.

          It doesn’t have to be like this. You can tell React to render on any subsection of the page, and manage the rest of the page in a different way. (This is the big secret behind all that microframeworks hipe we saw a few months ago). When you do React this way, it becomes another layer of the system. It becomes just an element with incredibly advanced functionality. And you can delete the element with node.parent.removeChild(node) and the React node goes away and the React runtime stops.

          React doesn’t want to have the center stage. People put React in the center stage.

          1. 4

            most knowledge about the underlying technology is useless at best and sometimes even harmful, as React wants everything done in a very specific way

            In my experience, this hasn’t been the case. React outputs some HTML, and you still have to know what HTML to use and how to use it.

        1. 7

          I had a few attempts to learn it, but I failed every time. It is fair to say that I don’t understand it, so I cannot even rant about its features, shortcomings, or flaws.

          Nice 👍🏻

          1. 3

            to be fair I’m using it for one hobby project (not a webdev at day) and still feel overwhelmed by the amount of additional plugins (Redux, how do you do global state for login + user-menu that is decoupled, hooks…). Add the whole JS stack on top (with its 40k modules) and you are starting to feel like every major rust dependency graph is irrelevant in comparison. Vue felt way easier but lacked one major component for one thing I needed (QR code display) and often it’s not obvious how you use any external JS libraries together with these self-managing frameworks.

            1. 10

              Don’t do Redux. Only big sites warrant using it. Start with minimal hooks (useState) passing the state and setters as params. everywhere. Once you understand this, work your way up using contexts and effects. You don’t need more than this for 80% complex sites out there.

              1. 3

                thanks for the explanation, will look into that

                1. 2

                  contexts and hooks are probably the best thing to happen to react since JSX

            1. 29

              UML works for a very narrow view of software development. I found that out when I wrote my thesis in OCaml and had to document it in UML. How do you express a curried function in UML? How do you express a simple function in UML that happens to not be attached to an object?

              And that is only the tip of the iceberg.

              How do you express a complex SQL query in UML? Entity-relation diagrams help modelling the schema, but what about a query with joins and window functions?

              How do you express a map-reduce operation in UML? What’s the diagram for filtering a list, then aggregating the results?

              How do you express a minimally-complex algorithm in UML (think Sieve of Erastothenes)? Why can’t I use pseudo-code, which beats diagrams every day of the week?

              How do you express a reactive user interface in UML? Why do I have to use something like a collaboration diagram, when the state of the interface derives directly the representation of the interface? It’s not the case that the input enables the submit button when it finds itself no longer empty.

              How do you express a Prolog program in UML? Do you think the UML committee has ever known about the existence of Prolog?

              How do I represent a multi-param generic data structure? For example, a mapping/hash table from A to B, where A and B are arbitrary types.

              And then we ignore the old problem of documentation and software diverging over time, and having to update the documentation when the software changes.

              UML comes from an era where Object Oriented (Obsessed?) Design was the whole world, and everything that wasn’t OOD was being forced to not exist. In this era, Architects would draw UML diagrams and cheap Indian code monkeys would do the coding, because we thought that code monkeys would be cheap and replaceable. This was perfect for the MBAs because programmers started to be annoying by not delivering on the expected deadlines, and claiming about the algorithms, the damned algorithms. We wanted to replace them with cheaper and less-whiny ones.

              Turns out that the details of the system are in the code, not in the diagrams, and only the trivial parts of the system would be expressed in diagrams, and the devil is in the details. But this makes programmers non replaceable and fungible, because the better ones can express algorithms that the worse programmers will never understand. And many times, you need these better algorithms.

              All this makes UML not anymore the silver bullet for bodyshops. The broken idea of hiring 1 architect and 100 code monkeys from the consultancy just doesn’t work, because the architect is not expected to dig in the details, and the 100 code monkeys will just make a mess of the details.

              UML was dead on arrival when it ignored most of the details of Software Development. Doesn’t mean though that some parts of UML can be salvaged, such as sequence diagrams, state diagrams, or entity-relation diagrams. But trying to model in UML an arbitrary problem and solution is likely to become wrestling with the language to express anything minimally complex or different.

              1. 13

                How do you express a … UML was dead on arrival when it ignored most of the details of Software Development.

                The UML isn’t supposed to model software down to the query and the algorithm. It’s supposed to model a system and its processes, to assist with the design of a software implementation of that system.

                If the way you think about modelling a system is “what complex SQL queries will I need, and how can I add a functional reactive UI” then indeed the UML will not help as the paradigm of its creators and users is the object oriented paradigm. You are thinking about the problem in a way the UML will not help you to express, so we do not expect it to help with the expression of those thoughts.

                The OO paradigm of the UML isn’t the “objects are inheritance and encapsulation” straw man of blog posts about switching to functional, but the “objects are things in the problem domain reflected in software” of object oriented analysis and design.

                To the extent that the UML and other tools from OOSE were “dead in the water” (an odd claim given their former prevalence), a more convincing reason is that they were sold as efficiency and productivity bolt-ons to programmers without also explaining the need for a paradigm shift. A large number of companies adopted Java, carried on writing structured software, and noticed that they were also having to do this O-O ceremony that doesn’t help them.

                In a few years time they’ll notice that switching to Scala, carrying on writing structured software, and also doing this functional ceremony isn’t helping them, and we’ll all get to have this thread again on the “has currying died and nobody noticed?” posts.

                1. 10

                  The UML isn’t supposed to model software down to the query and the algorithm. It’s supposed to model a system and its processes, to assist with the design of a software implementation of that system.

                  Then I would like to have the class diagram removed from UML, please, because class diagrams define a lot of details of data structures, and that restricts a lot on the algorithms I’m allowed to use.

                  You are thinking about the problem in a way the UML will not help you to express, so we do not expect it to help with the expression of those thoughts.

                  And now you are agreeing with me that many problems and solutions cannot be expressed in UML unless I twist the problem/solution to fit UML.

                  This is not about Object Oriented Programming vs Functional Programming. This is about the fact that I can’t express many things in UML, starting with the whole universe of functional programming, and continuing with database interactions, declarative programming, advanced data structures, compositional semantics, and many others that I haven’t got time yet to study. Each of those alternative ways to do computing beat the others in specific situations, and having to use UML just forces me to not be able to use the right tool for the job because the UML committee decided that it is hammers for everyone. And now I have to make this screwdriver look like a hammer to be able to draw it in UML.

                  1. 1

                    Then I would like to have the class diagram removed from UML, please, because class diagrams define a lot of details of data structures, and that restricts a lot on the algorithms I’m allowed to use.

                    Firstly, you’re welcome to not use class diagrams. Secondly, you’re welcome to only put the details you need into a diagram, and avoid constraining your implementation: the map is not the terrain.

                    And now you are agreeing with me that many problems and solutions cannot be expressed in UML unless I twist the problem/solution to fit UML.

                    I don’t think so. It sounds like you’re saying the UML is bad because you can’t do these things, whereas I’m saying the UML is good when I don’t do these things. “Doctor, it hurts when I lift my arm like this!”

                    1. 16

                      “Doctor, it hurts when I lift my arm like this!”

                      I hate when people use this analogy. If it hurts when I lift my arm like this, that’s probably a sign of some deeper underlying problem! Don’t tell me to not lift my arm.

                  2. 3

                    The OO paradigm of the UML isn’t the “objects are inheritance and encapsulation” straw man of blog posts about switching to functional

                    That straw man is exactly what I’ve been taught at school. Shapes and animals and all that. Sure it’s just for learning, but the next step is invariably “OO is hard”, “OO is complicated”, “OO takes times to master”… the usual conversation stoppers.

                    [UML is] “objects are things in the problem domain reflected in software”

                    That also is likely a mistake. As Mike Acton so eloquently put it, we should not code around a model of the world (in this case, the things in the problem domain). We should code around a model of the data. The things in the problem domain are what you speak of before managers or domain specialists. When you start actually programming however, it quickly becomes about the shape and size and flow of the data, and UML doesn’t help much there.

                    1. 2

                      “objects are things in the problem domain reflected in software” of object oriented analysis and design.

                      What does that even mean ? I have never seen this aspect explained except in the most superficial terms - creating a class which has a method name that reflects something from the domain usually resulting in bikeshed arguments.

                      I am sorry but that is not a model of anything. It is just naming. We can’t call naming modelling. When I am making a model of a circuit in software I can interact with the model, test all the assumptions. When an actual architect uses AutoDesk they are modelling things and can interact with them. BDD does this so it can absolutely be called modelling in some sense. I don’t know if it is the best modelling technique we can come up with but it works.

                      1. 1

                        I’d recommend Eric Evans’s book on domain-driven design. “Just naming” implies that you’ve already decided what the method does and that you want to find something in the problem domain to map it onto. OOA/D says that you have found something important in the problem domain and that you want your software to simulate it.

                    2. 4

                      Spot on. Frankly speaking, this was already crystal clear for many people back them. Many people realised immediately it was snake oil.

                    1. 1

                      I also posted about implementing a similar component. I didn’t cover handling the error state (so I appreciate that you did), but one problem I’ve run into was that when switching between two subtrees with the data loader component at the same level, the component wouldn’t actually be unmounted, which broke a few of my assumptions. I think wrapping it in another component like you did in the final CommentsSection implementation fixes this, though.

                      Also somebody in the comments also pointed to the Apollo Query component, which has yet another API but essentially does the same thing.

                      1. 1

                        Old components may not be unmounted because the final tree contains the same component in between state changes. This can be the case if all your sub-components are divs, for example. In that case, React will happily not rebuild the component, and instead will just change the props of it. Then you need to use the componentWillReceiveProps, that only complicates it and makes for more antipatterns and worse code.

                        Depending on how you can refactor it, you can trick React into rebuilding the whole component, for example by returning an array of a single component with a random key, or some kind of key that changes when you want the DOM tree to be rebuilt. It is a bit annoying, but it’s significantly less annoying than the componentWillReceiveProps route.

                        1. 1

                          Then you need to use the componentWillReceiveProps, that only complicates it and makes for more antipatterns and worse code.

                          Yep, componentWillReceiveProps has only caused me problems. That’s why I prefer hooks in general, they make it easier to spot this kind of errors and correct them “the right way”.

                      1. 1
                        The object may not have neither of the two fields.
                        The object may have only field1, and not field2.
                        Only if the object has field1, then it can have field2.
                        

                        It seems to me that the way these are worded is rather confusing. I can figure it out eventually going through each line, and the #2 creates a contradiction with #3. It seems to me that if #3 is true, then #2 cannot be true.

                        1. 1

                          It definitely could be more clearly worded. I think it’s saying:

                          • Both fields are optional
                          • field2 can only be supplied if field1 is supplied as well
                          1. 1

                            Thanks zzing and chenghiz for the kind suggestion! I’ll tune down the poetical approach to writing.

                        1. 1

                          I must be confused. You’re saying that every application should enumerate every potential combination of data, one-by-one? I don’t see where algebraic datatypes are being applied.

                          1. 1

                            Hi!

                            Enumerating every potential combination is obviously impractical. But thinking about it helps you design types in a better way so that you can reduce the amount of data that is valid. One of the principles I use when designing datatypes is looking for groups of data that are absolutely independent of each other, and thinking about them separately. Then, for the groups of data that are somewhat dependent on each other, there is usually one field that determines the others in some fashion, and I split the data based on this field.

                            The example applies the underlying ideas behind ADTs to look for the final solution. In Haskell, you could think of something equivalent in the style of:

                            data NoFields = NoFields
                            data Field1Only = Field1Only {
                                field1 :: String
                              }
                            data BothField1AndField2 = BothField1AndField2 {
                                field1 :: String,
                                field2 :: String
                              }
                            data InvalidObject = InvalidObject  {
                                field2 :: String
                              }
                            data Fields
                              = NF NoFields
                              | F1O Field1Only
                              | BF1AF2 BothField1AndField2
                              -- Didn't put InvalidObject here
                            
                            1. 1

                              I think I understand. But this seems like an application of structural typing to enumerate permissible combinations of fields, rather than of algebraic datatypes.

                          1. 1

                            I hope they add something like pattern matching to make checking through the cases of the ADT a bit less cumbersome. Given how much ceremony it takes to define and use an ADT, I sometimes wonder if I’m even doing the right thing.

                            1. 1

                              The switch statement is kind of a weak pattern matching. It doesn’t allow you to match on the fields or extract field values easily. I still consider it a good tool for your toolbox, specially if you do Redux. In Redux, you have ADTs, either explicitly declared, or implicitly declared. I prefer explicit in terms of types, so at least the typechecker can spot some of my mistakes.

                            1. 2

                              What I never understand with smart contracts that require off chain data:

                              If it requires an oracle, why not just run it off chain? In this case you’re fully trusting the exchange, so it’s not any more “trustless” than if the buyer’s wallet had an integration with ShapeShift/Changelly/some other instant exchange.

                              1. 1

                                if the buyer’s wallet had an integration with ShapeShift/Changelly/some other instant exchange

                                What if you want to deal with the average exchange ratio? How do you convince these instant exchanges to cooperate to provide the average ratio, considering that they may not want to cooperate? On the other hand, asking each one for an oracle, and having a smart contract that accepts several oracles to compute the average is not that hard.

                                1. 1

                                  What if you want to deal with the average exchange ratio?

                                  Why? The average isn’t useful (in the context of the article). If I want someone to send me $10 USD, I’d ask the exchange how much $10 USD in Bitcoin is, and ask for that amount. The average would mean that I could get more or less depending on which exchange I have an account with.

                                2. 1

                                  I think the idea is that you trust external parties to provide data (because it can be audited), but you don’t trust external parties to run code. I think it makes sense.

                                  1. 1

                                    This is pretty much the takeaway. You can run trusted code on chain, while using trusted data from off chain.

                                    1. 1

                                      You can also run the code yourself.

                                      i.e. User types in their wallet app to request $10 USD. The wallet secretly makes a deal with the user’s exchange and determines that $10 USD will be worth X Coins. The wallet makes a request to the other person for X coins. Using oracles just adds extra cost for not a lot more trust.

                                  1. 19

                                    Easy, Reverse Proxies are better at handling scaling connections, they can terminate SSL and they are battle hardened against the common noise of the internet. Likely all properties 99% of apps people develop do not have.

                                    1. 7

                                      Also reverse proxies like nginx can serve static assets (usually) a thousand times better than your application. They can show custom error pages, or failover to other services when your app crashes. They can implement cheap-ass authorization (401 and the like) over simple apps, discriminate against IP addresses and many other things you totally don’t expect from a software like nginx.

                                      It is not always a good idea to use all these features from nginx (over implementing these features in your app), but good knowledge of your reverse proxy can help you simplify your infrastructure.

                                      1. 1

                                        It is not always a good idea to use all these features from nginx (over implementing these features in your app), but good knowledge of your reverse proxy can help you simplify your infrastructure.

                                        Correct, I usually see a huge number of rewrite rules as a No-No unless they are explicitly necessary (ie, rewriting /<url> to index.php?<url>).

                                    1. 1

                                      To small RAM, 400kb is minimal for mruby.

                                      Hm… 48Mhz is very big. https://hackaday.io/project/13048-flea-ohm-fpga-project show how fast it will be. But too small memory. Second question is how many times i can programming this processor.

                                      1. 3

                                        FPGAs are not intended to have a lot of memory or to work like a processor. They are intended to be optimised to work like a very specific circuit for you to decide. The usual use for a FPGA is a middle point between general-purpose processors and hardcoded application specific integrated circuits. They may not be the best processors, or the best ASICs, but they are reconfigurable and can perform better than processors for specific tasks.

                                        You can reprogram an FPGA effectively infinite times, it stores its configuration in RAM. But sometimes you store that configuration on an external FLASH memory so it survives reboots and stuff, and this external memory may impose a limit on how many times you can reconfigure it.

                                        1. 1

                                          you are wrong. this device have ram ,many program need ram. I give a example. If You would like using processor to run specyfic program (for example windows system , yes exist procesor with instruction windows os)

                                          You melting fpga teoreticaly and this device. second trouble . exist more kind of ram ‘ram’ usualy normal ddr is durable than this fpga ‘ram’.

                                        2. 2

                                          48Mhz is very big

                                          On-board clock frequency is not very important, since PLLs can convert that to any frequency you require.

                                        1. 4

                                          Related: https://www.destroyallsoftware.com/talks/ideology

                                          Some people claim that unit tests make type systems unnecessary: “types are just simple unit tests written for you, and simple unit tests aren’t the important ones”. Other people claim that type systems make unit tests unnecessary: “dynamic languages only need unit tests because they don’t have type systems.” What’s going on here? These can’t both be right. We’ll use this example and a couple others to explore the unknown beliefs that structure our understanding of the world.

                                          1. 1

                                            Author here: Ideology by Gary Bernhardt is definitely part of the inspiration of this article, there is no point in hiding it. And I suggest you all go and check the talk, it’s really good, and goes way beyond programming.