1. 2

    It’s way simpler than that:

    Removing something from an existing software system causes your users to riot, because they were using it!

    Changing something that’s already there is just as bad. Unless you have an iron grip on the market like Facebook or Microsoft, you can’t really get away with changing anything.

    Even if the software system was perfect on release, the world around it can change and make it not perfect any more, and the only thing many developers are allowed to do to remedy that is add more stuff to it.

    1. 1

      Removing something from an existing software system causes your users to riot, because they were using it!

      Hmm. I suspect it’s subtly different.

      Sometimes users riot because they are using it… and you have not provided better alternative. I have a lot of sympathy with these guys.

      Sometimes users riot because they are using it, but you have provided a much better alternative, but you have moved their cheese. I have very little sympathy for these guys.

      In the commercial world I have seen users riot because “They paid for something that had all the features listed in the brochure. Now you have removed a feature, it doesn’t matter if nobody is using it, it must have less value, so you should reimburse them.”

      Sounds like I’m joking? There are contract management consultants that make a living from this. They don’t use the software, they manage the contractual obligations.

      This is one of the reasons the open source world moves faster… An open source developer in this case can say, “Sure, no problem, here is all the money you paid for it.”

    1. 14

      The best statements on complexity were uttered decades ago..

      “There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.” ― C. A. R. Hoare

      “At first I hoped that such a technically unsound project would collapse but I soon realized it was doomed to success. Almost anything in software can be implemented, sold, and even used given enough determination. There is nothing a mere scientist can say that will stand against the flood of a hundred million dollars. But there is one quality that cannot be purchased in this way - and that is reliability. The price of reliability is the pursuit of the utmost simplicity. It is a price which the very rich find most hard to pay.” ― C.A.R. Hoare

      1. 4

        A lot of voices here say, “Tools”, I will agree with that but say it’s understanding them rather than fluency that counts.

        TDD is the fastest path to done done.

        Active practice. I have a weekly reminder on my calendar to “Learn Something”. Something about a tool, my editor (emacs), programming. And there I try out some experimental idea.

        No cargo culting, learn the reasons behind ideas.

        Asserts. Not sure you understand something about the code? Immediately drop in an assert stating what you think is true. Let the compiler and the tests tell you if you are wrong. If you are not, downstream of the assert rely on it being true.

        1. 12

          Keep in mind Angersock’s Law of Rapid Development:

          It is okay to ship shit as long as shit ships.

          This is mainly if you’re doing web dev, but the thing I’ve seen is that users put a higher premium on rough but available tools than on correct but distant ones. Get your first rough cut in front of people and have them use it, and keep piling on mud until they’re happy.

          As long as the happy path mostly works your software is shippable. Guards, better UX, and clean code can all come in time.

          1. 9

            Depends on industry…. In a deeply embedded system where product recall means return thousands of vehicles to base…..

            No.

            Just plain no.

            However, if you mean “ship a reduce set of features, as long as the features ship (and have value to the customer)”.

            Yes, by all means.

            1. 3

              Exactly.

              If the industry is not webshit, don’t follow that rule at all! Similarly, if you are making libraries or other artifacts that will outlast you, don’t develop that way.

          1. 3

            In a future post, however, I’d like to correct this gloomy course and talk about situations in which automated UI testing can work, in my experience.

            Dated February 19th 2014, no update.

            I think we have our answer, sad though it may be.

            1. 1

              Rubocop and things like it are, I believe the future of programming languages.

              To the extent that programming style and programming idioms matter, they should be checked, and preferable corrected, automagically.

              1. 5

                He seems to think refinements are A Bad Idea.

                I certainly have a gripe with monkey patching, but refinements are a pretty neat packaging of the concept.

                I’ve been using it quite a bit recently and well, why not?

                The Clojurist’s rant against wrapping every thing in an object, for the simple dumb obvious reason that the objects methods are “All you get”. When you have Plain Old Data (pod’s) you have vast libraries that all eat pods.

                Refinements give you the best of both worlds. It’s just a POD when it’s just a POD, it’s an object when it is useful to see it as one.

                1. 29

                  Patterns were never supposed to be applied. They were supposed to give names to common patterns that programmers everywhere were already using. By having a common vocabulary, programmers are supposed to better understand one another. When I say a structure and its methods proxy another structure, programmers know what I mean because they are familiar with the proxy pattern.

                  GoF went too far by defining dozens of patterns with subtle, and mostly pointless, differences. There are only a dozen or so patterns that every programmer should know, things like Proxy, Adapter, Strategy, Visitor, Observer. Beyond that is too detailed for wrote memorization and the remaining patterns can sit in reference. Many of the common patterns are domain specific, e.g. all of the data access patterns like ActiveRecord and Repository. If you don’t write applications talking to databases, you may well never need to know about those patterns.

                  Finally, the worst part of patterns was the tendency of programmers to read some pattern book and want to use every pattern, or their favorite ones, in their current codebase, wether it was applicable or not.

                  1. 9

                    Yes, building a vocabulary is a good way of thinking about it.

                    Instead of “curved sequence of stones supporting each other going up and then down left to right”, we can say “arch”.

                    Patterns are a level of abstraction above that of types+functions, below that of a module/package.

                    1. 6

                      rote*

                      1. 2

                        Patterns were never supposed to be applied.

                        Here’s the list of steps from section 1.8, “How to Use a Design Pattern” of the Design Patterns book:

                        1. Read the pattern once through for an overview.
                        2. Go back and study the Structure, Participants, and Collaborations sections.
                        3. Look at the Sample Code section to see a concrete example of the pattern in code.
                        4. Choose names for the pattern participants that are meaningful in the application context.
                        5. Define the classes.
                        6. Define application-specific names for the operations in the pattern.
                        7. Implement the operations to carry out the responsibilities and collaborations in the pattern.

                        This followed a longer discussion on how patterns solve problems and how to select one for your design needs. This really feels applicative to me. The book does say not to apply them indiscriminately (see last paragraph of chapter 1).

                        I agree that they are probably better used as vocabulary. Based on skimming the beginning of the book and reminding myself of the contents, I do not agree with the interpretation that they were not meant to be applied.

                        1. 4

                          I think @jrwren meant that the original pattern language by Christopher Alexander qas intended that way and after porting these ideas in the software community the misunderstanding startet.

                          Although I do think that pattern. Were always also thought of as something you could imitate. It is just that we have applied then on the “micro” scale.

                          Alexander’s patterns really operate on another level, take the intimacy gradient pattern https://www.kerryveenstra.com/2016/12/27/intimacy-gradient/

                          The visitor pattern in comparison would be on the level of how to put brick upon brick or something. Whereas many alexandrinian patterns describe city planning etc.

                          So maybe it’s time to look for patterns worth describing. I think one aspect I would like to see in software patterns is the question how can software be a hospitable place for individual users and communities.

                        2. 2

                          Yup.

                          Patterns are reoccurring solutions to a reoccurring set of constraints…

                          Which is a strong Heads Up that unless every single one of those constraints are present…. there exists a simpler solution.

                          ie. If it’s in the GoF book, odds on you don’t need it.

                          1. 1

                            Well said. I didn’t mention the importance of “every single one of those constraints” Thank you for reminding me!

                        1. 4

                          Mercurial has always been the friendliest of DVCS’s…. but Evolve made it friendly and powerful…. and evolve just keeps getting better.

                          Everything I do now is done via evolution.

                          Why? Because it allows me to clean up my changesets into steps moving from one thing that compiles, works and is testable, via a coherent meaningful and consistent changeset to another thing that compiles, works and is testable…. even if I didn’t make the changes in that order… but discovered the need at a later point.

                          1. 12

                            Maybe I’m wrong, but… What does exactly stop a company like Google provide pod hosting and end up having access to all pod’s data anyway?

                            I dont imagine people hosting their own pods of information. You still need a way to allow third parties to access to the plain data, so they can use it.

                            Today’s problem with internet and data owning isn’t technical. It’s social and cultural. Imho.

                            1. 2

                              If he has done it sanely, at most such a host would be able to glean is metadata that you accessed it when and from which ip address.

                              They shouldn’t be able to look inside your pod to see what you are reading and writing, or even who you are.

                              Admittedly given how much other data the likes of Google already has, they would be able to do de-anonymise you based on even that little bit of meta-data, but it would be a huge huge decrease in what they have on you presently.

                              1. 1

                                This would require that the POD information is encrypted. Such encrypted nature wouldn’t allow a “recover password” functionality.

                                And today’s society can’t live without that. And won’t understand why there isn’t a recover password option and what does it mean that “everything is lost”.

                                1. 1

                                  That would surely be a valid added service someone could provide.

                                  Key escrow.

                                  User Alice encrypts her private key along with some agreed identifying token with Escrow provider Bobs public key. For a small fee Bob will return Alice’s decrypted private key if Alice can provide the identifying token. eg. Her drivers licence.

                                  If Alice doesn’t trust Bob completely, she can double wrap it with as many independent escrow providers as she wishes.

                                  And today’s society can’t live without that. And won’t understand why there isn’t a recover password option and what does it mean that “everything is lost”.

                                  That sort of translates to in today’s current practices, “I’m not prepared to pay anything and I trust my email provider with all my data and trust him to be unhackable and I trust my email password and my data isn’t worth all that much anyway.”

                                  I’m sure that level of password recovery (and (lack of) data security) can continue be available to you for free.

                                  1. 1

                                    If Alice doesn’t trust Bob completely, she can double wrap it with as many independent escrow providers as she wishes.

                                    I just see too many steps that the user needs to do just to secure its data. Which will never happen, because, as you just said: “I’m not prepared to pay anything and I trust my email provider with all my data and trust him to be unhackable and I trust my email password and my data isn’t worth all that much anyway.”.

                                    1. 1

                                      Partly we’re in the “I’m not prepared to pay anything and I trust my email provider with all my data and trust him to be unhackable and I trust my email password and my data isn’t worth all that much anyway” age of the world because we don’t trust our providers.

                                      I don’t store anything valuable on facebook because I don’t trust the likes of Zuck further than I can throw him.

                                      I keep my money in the bank, because it’s more secure than under my bed…. but if your money regularly got stolen or “lost” whether you had it in the bank or under your bed or in your personal safe…….. Would you even bother accumulating the stuff?

                                    2. 1

                                      I think the Post office should offer that service.

                                      1. 1

                                        In the Bad Old Days I lived in a country with government issued ID books, without which you couldn’t do anything, it was a real pain in the ass, and not terribly secure.

                                        In the current day I live in NZ where there is no mandated form of ID, and if you don’t have a driver’s licence or passport, (or you lose them) establishing ID for any purpose is a nightmare even worse than ID books, and in total probably a fair patch less secure.

                                        In current NZ….. they are doing exactly what you suggest. https://www.realme.govt.nz/

                                        Sort of.

                                        Except it doesn’t provide me with options if I don’t trust RealMe as a really secure service provider (which I don’t).

                                        1. 1

                                          yeah, that’s a problem. I was thinking of a physical process. Show up with fingerprints and some id. You can only get access by visiting in person and checking in. When you checkin you can get copies of private keys or whatever you deposited, and PO can send, encrypted using its public key, your public key. Or something like that. Physical security.

                                          1. 1

                                            Personally I’m a social progressive.

                                            I strongly believe the world still needs to progress in the sense that some things that are currently illegal, should be become legal, and some things that are currently legal, should become illegal.

                                            The ’net is a tool that allows us to move faster from “here to there” so to speak.

                                            Now as a thought experiment, choose an event of historical progress that you agree with (eg. banning of slavery, decriminalization of homosexuality, votes for women…)….

                                            …and now imagine if at the time prior to that change, every opinion you ever had was physically bound to you, and surveillance was perfect.

                                            I’m pretty sure that progress would never have happened.

                                            We’re nearing the point in history where surveillance will be near perfect and ubiquitous…. we need a future where speech can be anonymous.

                                            Thus the identity recovery mechanisms also need to be anonymous.

                                            1. 1

                                              i don’t know if you need an identity recovery mechanism for an alias . A government run one seems especially wrong.

                                              1. 1

                                                You don’t need a recovery mechanism if your data is worthless…..

                                                If the recovery mechanism is designed right, it doesn’t matter who runs it.

                                                It’s more in the realm of neutral infrastructure like a bus stop.

                                2. 1

                                  It’s deeper than social/cultural. Systems tend toward centralization. That’s just what they do.

                                  1. 2

                                    Systems tend toward centralization because social responsabilities tend toward centralization too. Because it’s simpler and just works with a trust mechanism.

                                    Once trust is gone, centralization is gone, too.

                                    If you have a society that is responsible and conscient enough to see the importance of their own data, you’ll get a decentralized system easily, because each individual will be responsible of it’s own data.

                                    1. 2

                                      Social has nothing to do with it. You see centralization in natural physical systems too, due to the same forces.

                                      1. 1

                                        It has to do with social as those artificial systems are born from the society and our interactions. Just see the Conway’s Law: https://en.wikipedia.org/wiki/Conway%27s_law as an example of mapping social structures to software.

                                        1. 1

                                          That’s a manifestation. It happens in purely physical systems too, like leaf structure. There’s nothing social about that. Here’s a talk: https://www.infoq.com/presentations/scalability-variant-structuring

                                          1. 2

                                            I mean: The software borns from society, so, if society changes (being the root of software), software will change, too.

                                            Thanks for the link, tho, will check out :)

                                1. 9

                                  Oh man, where to start?

                                  At home I’m not working on my CoAP library in Rust & Tokio because every time I sit down to work on it I get instantly frustrated. I’m also not working on anything else on my long (and growing) list of other things I’d like to do because every time I start on one of those, I just feel like I should really just be working on the CoAP library. I’m not really sure how I got to this point…

                                  At work I’m not working on my hillshot (the much less ambitious version of a moonshot) project that everyone is excited about and thinks would be a game changer because I’m stuck chasing bugs in a service I took over from our cheap contracting team when we no longer had to use them and had “three weeks” to finish/fix it and have been bodging fixes into for 6 months because we “don’t have time” to fix it properly “now”.

                                  1. 5

                                    Oh man. Good luck, hope you get motivated soon..

                                    1. 2

                                      Good luck with the CoAP library. That could be really interesting.

                                      1. 2

                                        I did a C++ wrapper on libcoap and the internal reactor framework we use awhile back, what in particular is frustrating you? The world of CoAP or the Rust borrow checker?

                                        1. 1

                                          I think it’s mostly that I haven’t gotten over the hump in really understanding futures & tokio. I’m not yet to the point where I know where everything goes. And the biggest problem I have is that when I mess that up there’s a lot of changes that need to be made. Now, part of that is that I’m probably making this more complicated than it really needs to be, but I’m trying to make an interface that is familiar so I’m creating “socket” and “connection” abstractions (to others: CoAP is a UDP protocol that handles all of that kind of stuff itself). It also doesn’t help that any time I make a typo the error messages are really unhelpful and almost always point somewhere away from where the problem really is, this seem to be a pretty common issue when using futures in Rust. Hopefully a lot of this will get better with async & await.

                                          1. 2

                                            Grimace. Yup, the only way to get over that sort of hump is to do, and to make mistakes and to redo and repeat until you really really do understand……

                                            …and then before it all slips away, write a blog post or something and explain it to someone else.

                                            Hint: You never really understand things like that until you have explained it to someone else.

                                      1. 12

                                        A committee, a huge spec, and a set of partially-abandoned reference implementations. Hmm. I’m not hopeful.

                                        1. 3

                                          Personally I’m betting on https://datproject.org/ and in particular https://www.datprotocol.com/

                                        1. 2

                                          I doubt accidental mutation of such things is a frequent problem. Yes, concat mentioned in article is misleading method which mutates receiver instead of returning concatenated list like Array#+. But usually it’s quite clear when mutation occurs.

                                          1. 6

                                            User-land code (in Ruby) is the wild west of mutation. I’d rather not take my chances, especially in very large monolithic code bases.

                                            1. 4

                                              I especially use freeze when I’m exploring somebody elses code.

                                              ie. The mutation is probably not accidental, but I didn’t know about it, or when it would occur.

                                              Conversely if adding a freeze doesn’t break anything…. then I also have some valuable hard data about the code base.

                                              Of course, these requires a fairly good degree of test coverage.

                                            1. 4

                                              Yes, absolutely, freeze everything you can in Ruby. Just like being extremely liberal with final in Java is a good thing.

                                              1. 7

                                                Freezing shared constants is important, but I would push back against liberally sprinkling lots of Ruby code with freeze. Ruby is idiomatically a language that embraces mutability. It’s fighting an uphill, losing battle and YAGNI.

                                                EDIT: I have come around to this perspective after having been a proponent of final being default behavior in Java. My opinion around this isn’t too strongly held, but more a recognition of the friction of going against the grain with that approach. I do value immutability.

                                                1. 3

                                                  Oh, I have a fairly low bar for removing freeze from my constructors….

                                                  ….but then I know and understand why and when I’m mutating this object, I’m not guessing.

                                              1. 5

                                                Thankfully we now have frozen string literals so that takes some of that class of pain away…

                                                But, yes, I love freeze.

                                                I always put a freeze at the end of every constructor….

                                                Sometimes, later, I remove it, but surprisingly seldom.

                                                It improves the quality of my code and uncovers my stupid early.

                                                1. 2

                                                  In my oppinion, connascence should be kept in mind when designing a programming language or a public API or protocol, but if you’re worrying about connascence when trying to implement a new feature in an application, your only making things harder on yourself.

                                                  Unless you want your productivity to quickly grind to a halt, code should be written in such a way that it is easy to change. That means taking the simplest and most direct approach. Once clear patterns arise in the code you have already written, then you should compress the common code by introducing a sub-procedure or function. If you’re trying to design intra-application API’s that minimize connascence you’re waisting time, because you don’t know how your going to use the API yet. You’ll end up not needing functions and data you’ve provided, and/or needing functions and data you didn’t provide.

                                                  This need for pervasive and wide-spread change in application code is why staticly typed languages have a huge advantage in terms of productivity.

                                                  1. 3

                                                    code should be written in such a way that it is easy to change. That means taking the simplest and most direct approach.

                                                    Once the code base is on the wrong side of a few hundred thousand lines of code… Your words take on a stronger, harsher meaning.

                                                    written in such a way that it is easy to change.

                                                    As the code base gets big, way way way bigger than you possibly can hope to read and understand, that translates to..

                                                    “How little do I need to read and understand to make a valid and safe change to this code base?”

                                                    As the code base grows, coupling, direct and connascent, dominate all other considerations.

                                                    Why? Because you must read and understand the implications of change on everything the code you are trying to modify is coupled to.

                                                    Direct coupling is sort of nice, your tools will tell you about it, and you can nail down the semantics of the interface.

                                                    Connascent coupling is a total nightmare, as your tools won’t tell you about it, your integration tests might (if you’re lucky), but your customers will.

                                                  1. 1

                                                    I’ve never heard of this. The name is confusing. The first few examples…

                                                    “Connascence of name is when multiple components must agree on the name of an entity. “

                                                    “Connascence of type is when multiple components must agree on the type of an entity.”

                                                    “Connascence of meaning is when multiple components must agree on the meaning of particular values. “

                                                    It seems like there’s a more intuitive term than connascence out there. If abstracted, it looks like SharedAttributes where attributes are name, type, and meaning. It does look interesting as a list of potential screwups. A few are pretty fundamental like meaning, algorithm, and order. Some others you might cheat around but maybe the cheats themselves are indicating their importance.

                                                    @JohnCarter, would you elaborate on your very, different reaction to this site? I’m guessing you’ve put some thought into it. :)

                                                    1. 2

                                                      One of the most important design principles in terms of modularisation, is that you should aim to reduce the coupling between modules, and increase the cohesiveness within modules.

                                                      We normally think about Coupling between modules in the very limited form, of declarations of symbols, and references to them, where the declarations are in one module and the reference in another.

                                                      ie. The syntactic level of coupling.

                                                      The word “Connascence” means “Grew up together”.

                                                      And refers to the sorts of coupling that arises between modules, when the modules “grow up together”.

                                                      Have you ever taken a krufty bit of old code and tried to reuse it for something different…. and then found everything just plain hurts? There is some undocumented order in which methods must be called, some hidden state that has to be initialized in some undocumented manner, or global state that gets corrupted by the re-use….

                                                      Congratulations, you were bitten by connascent coupling.

                                                      Very very common in krufty legacy systems.

                                                      Have a look at the “Other Resources” page for more on the origins or the term.

                                                      Why is it so so important to understand?

                                                      Because when people complain that software is not re-usable, or is fragile, or is brittle, most of the time the problem comes down to some form of connascent coupling.

                                                      1. 1

                                                        That makes sense. I get the concepts but just never heard of the term. I’ll look into it further.

                                                    1. 2

                                                      Seriously.

                                                      This is one of The Most Important web sites in all of Software Engineering.

                                                      People really really really do need to understand what this is, why it is one helluvah problem, and how to combat it at every stage.

                                                      1. 8

                                                        Hmm. Unhappy with this…. I know many programmers who think they know Good Code when they see it…. but cannot enunciate any principles on which you could use to go forth and write good code.

                                                        But Uncle Bob presents the SOLID principles like hard rules, which rubbed me the wrong way. In fact, I’m pretty sure a system that never violated the SOLID principles would be a giant mess.

                                                        The thing I like about Uncle Bob is he is at least trying. He might not have it down perfect yet… but he is trying.

                                                        I don’t respect criticisms that just says “He is Wrong”. I respect criticisms that say, he is wrong in this concrete case, here is an example, and here is a better principle which resolves this problem.

                                                        The book is silent on improving the architecture of existing systems

                                                        That’s the wrong book for that. You probably want this one https://martinfowler.com/articles/refactoring-2nd-ed.html

                                                        Or “ Working Effectively with Legacy Code” by Michael Feathers

                                                        1. 13

                                                          I think this is an incredibly important development. Seeing what Intel, and to lesser extend AMD, have been doing with their chips is downright scary. Now that they embed their own OS in the chip that you have no access to or control over, the users are becoming locked out of their own hardware. We need open architectures to retain general purpose computing where anybody is able to write and run their own code.

                                                          1. 2

                                                            Strongly agree. There’s stuff like OpenBMC for data-centres, but it’s hard to do when everything’s locked down by vendors.

                                                            1. 1

                                                              Alas, we still need the volumes to go way way up to compete with ARM (and Intel) on price.

                                                              Devkits for these SoC’s are currently way way more expensive than a Rpi for example.