1. 3

    Would it have been that hard to use infer.fb.com?

    1. 10

      You’d think a tech company could get that right. What really ticks me off is how the banking and financial industry seems to find subdomains so intolerable. It seems like every bank expects you to just implicitly trust any domain with their name in it.

      1. 3

        Or at least get the certificate right.

    1. 1

      Can anyone explain in layman terms how Google can take the GPL license Linux kernel , build some stuff on top of it and have those to be proprietary ? How does this work ? How can the stuff built on top be proprietary ?

      1. 14

        It’s the same thing as building proprietary software that runs on linux. GPL means that google has to release any changes it makes to the linux kernel under GPL as well. Software that just runs on top of Linux/Android can be proprietary.

        1. 2

          It’s basically due to using the “Android” name, which is copyrighted, and having the Google apps (Maps, Play Store, etc) pre-installed. Forking Android and calling it something else is just fine.

        1. 1

          Windows 64-bit link is broken.

          1. 1

            I couldn’t find any mentions of the 64-bit version so I had to look on their download site to grab one.

          1. 2

            It sounds to me like they are deprecating all server services and probably preparing to merge macOS Server into macOS so they’ll have just one computer OS. Am I missing anything?

            1. 5

              Ever since Lion they stopped having a macOS Server version. That’s when the server app appeared the first time which was installing what previously was part of the server OS.

              Over time they removed more and more features from that though, so now all that’s left is OpenDirectory (their LDAP/Kerberos AD equivalent) and their MDM solution.

              1. 2

                It now makes sense why it seems such a dramatic change for me as the last time I’ve worked with macOS Server it was back during the Tiger days. Thank you for clearing things up!

            1. 8

              After reading this post I went back to my almost-dead blog, confident that it will be quite lightweight. The Firefox network tab showed (with cache disabled):

              • 13 requests
              • 360KB transferred (1.00 MB after expanding the gzipped files)
              • Finish: 2.21 seconds.
              • DOMContentLoaded: 829ms
              • load: 1.76s

              I was quite puzzled as this is a static website based on a rather simple Jekyll template. Turns out that the “Like” button that I added a while back generated 5 requests and 204 KB (or 795 KB after expanding) of load. I’m quite surprised of that and I’ll probably resurrect my blog just to remove that like button.

              1. 0

                Is it me, or does a 2x test/code ratio feel like a hilarious waste of time, or not nearly enough?

                1. 2

                  I thought we had a normal ratio for a Ruby/Rails application that has thorough test coverage, but I’d love to hear from others on what their ratio looks like. We didn’t aim to have a certain ratio or anything. We write tests as we’re writing code, and that’s what we ended up with. Lines of code isn’t a consistent metric across different projects since style and conventions come into play, but I thought it was something I could share to convey the size of our application.

                  1. 2

                    The more consistent our architecture became, the more we were able to leverage integration tests, i.e. end to end assertions of the public side effects resulting from a single use case, and have confidence in that use case’s correctness. The average use case simply had far less “exciting” code, relied more on libraries, and far more that could be taken for granted. Unit tests are emphasized in our library code (e.g. internal gems) or in anything “interesting”, which is taken to mean any logic hairy enough that it doesn’t just fall out of air with our bog-standard architecture.

                    Certain policy and permission classes, many of which boil down to a comparison operator or two, are also unit tested by default in pursuit of “tests as documentation” rather than assertion of correctness.

                    I haven’t run the stats in a while but if you ignore view code (any .erb files, css and our javascript whose tests are nonexistent or in shambles), we are sitting at 1:1 or bit lower in our main monolith. In my conversations with others, I would not say that your 2:1 is out of the ordinary, though anything higher might make me raise an eyebrow.

                    At some point if you’re being so thorough that you have excess of a 2:1 test:domain code ratio, you either have a very hairy, naturally complex business domain (and my eyebrow lowers), or you should look into property testing/generative testing.

                  2. 1

                    I think it depends tremendously on how you write tests.

                    EG: If your tests are mostly high-level integration tests it seems quite high; if they’re mostly low-level unit tests it seems low.

                    Similarly, If you’re using a terse style (eg via DSL / metaprogramming) it seems high; if you’re using a verbose style (eg the recommended rspec approach) I’d say you’ve mostly tested the ‘happy path’.

                    1. 1

                      Right, that’s my point. I also was speaking in general, not specifically about a Rails application. I don’t do Rails any longer, but when I did, the codebase was more like 5-8x tests to codes. And of course, in Scala, the type system – for all of my reservations about complexity – allows a much leaner ratio.

                    2. 1

                      If you’re really serious about testing, especially more end-to-end stuff and interacting with the front-end, it’s pretty easy to end up needing 10 lines in a test to check a feature that only required 2 or 3 to implement.

                      There’s some cross-checking too of course, but if writing 3x as much code meant basically no regressions, that’s a decent deal

                      1. 1

                        I depends a lot on the code. For example, in my current codebase I have something like:

                        Maybe(resource).fmap(&:author).fmap( ->(n) { n[:full_name] }).or(Some('Somebody'))
                        

                        This is part of a method that gets a hash that, ideally, looks like this:

                        {
                          author: {
                            full_name: 'John Doe'
                          }
                        }
                        

                        However, there might be some cases where the hash is nil or the hash does not contain the expected keys. So for a line (actually two, since the line is too long for my taste) of code you easily end up with four test cases (hash is nil, hash does not have the :author key, the :author key returns a hash without the :full_name key and the ideal scenario where all the data is present).

                        Then again, you most likely have a bunch of lines of code that are just doing simple things, like check if a property is set or something like that, where the test cases are a lot simpler so you might not end up with a 2x test/code ratio.

                        1. 2

                          I have no idea what your domain/code-culture is, but if you just want something short, maybe plain Ruby is enough? :

                          Hash(resource).dig(:author, :full_name) || 'Somebody'
                          

                          Your short code example looks like a mix of Ruby with Rust, or Haskell monads. Yet, I wonder what happens when resource is an Array. Does that Maybe function swallow the exception? It’s hard to bolt on types where there were none before! :)

                          1. 2

                            The library used is dry-monads and if you pass an array you get an NoMethodError: undefined methodauthor’`.

                            I agree that the dig method is more appropriate for a Ruby codebase and in some places it was used instead of the Maybe monad. The reason why we’re using that (and I was the one pushing it as team lead) was that those constructs are closer to constructs in other languages and one of the side goals that I have is to enable people as much as possible to explore other languages and my feeling is that this kind of code helps.

                      1. 7

                        I‘m not convinced that the current trend to put authentication info in local storage is entirely driven by the thought of being able to bypass the EU cookie banner thing. I think it‘s more related to the fact that a lot of people are jumping on the JWT bandwagon and that you need to send that JWT over an Authorization header rather than the cookie header.

                        Also, often, the domain serving the API isn‘t the domain the user connects to (nor even a single service in many cases), so you might not even have access to a cookie to send to the API.

                        However, I totally agree with the article that storing security sensitive things in local storage is a very bad idea and that httponly cookies would be a better idea. But current architecture best-practice (stateless JWT tokens, microservices across domains) make them impractical.

                        1. 4

                          Hey! You are correct in that this isn’t the main reason people are doing this – but I’ve spoken to numerous people who are doing this as a workaround because of the legislation which is why I wrote the article =/

                          I think one way of solving the issue you mention (cross-domain style stuff) is to use redirect based cookie auth. I’ve recently put together a talk which covers this in more details, but have yet to write up a proper article about it. It’s on my todo list: https://speakerdeck.com/rdegges/jwts-suck-and-are-stupid

                          1. 2

                            Ha! I absolutely agree with that slide deck of yours. It’s very hard to convince people though.

                            One more for your list: having JWTs valid for a relatively short amount of time but also provide a way to refresh them (like what you’d do with an oauth refresh token) is tricky to do and practically requires a blacklist on the server, reintroducing state and defeating the one single advantage of JWTs (their statelessnes, though of course you can have that with cookies too)

                            JWTs to me feel like an overarchitectured solution to an already solved problem.

                            1. 1

                              There’s a third use case: services that are behind an authentication gateway (like Kong) and whenever a user is doing an authenticated request then the JWT is injected by the gateway into the request headers and passed forward to the corresponding service.

                              But yes, a lot of people are using $TECHNOLOGY just because it’s the latest trend and discard “older” approaches just because they are no longer new which is quite interesting because we today see a resurgence of functional languages which are quite old, but I digress.

                            2. 2

                              you need to send that JWT over an Authorization header rather than the cookie header.

                              Well, you don’t need to, but many systems require you to. It’s completely possible — although it breaks certain HTTP expectations — to use cookies for auth² is after all quite an old technique.

                              1. 1

                                This is true – you could definitely store it in a cookie – but there’s basically no incentive to do so. EG: Instead just use a cryptographically signed session ID and get the same benefits with less overhead.

                                The other issue w/ storing JWTs in cookies is that cookies are limited to 4kb of data, and JWTs often exceed that by their stateless nature (trying to shove as much data into the token as possible to remove state).

                              2. 1

                                Could you point me to some sort of explanation of why using localStorage is bad for security? Last time I looked at it, it seemed that there was no clear advantage to cookie based storage: http://blog.portswigger.net/2016/05/web-storage-lesser-evil-for-session.html

                                1. 2

                                  Just as the article says: if you mark the session cookie as http only, then an XSS vulnerability will not allow the token to be exfiltrated by injected script code.

                                  1. 1

                                    Are we reading the same article? What I see is:

                                    • “The HttpOnly flag is an almost useless XSS mitigation.”
                                    • “[Web storage] conveys a huge security benefit, because it means the session tokens don’t act as an ambient authority”
                                    • “This post is intended to argue that Web Storage is often a viable and secure alternative to cookies”

                                    Anyway, I was just wondering if you have another source with a different conclusion, but if not, it’s OK.

                                    1. 3

                                      I disagree with the author of that article linked above. I’m currently typing out a full article to explain in more depth – far too long for comments.

                                      The gist of it is: HttpOnly works fine at preventing XSS. The risk of storing session data in a cookie is far less than storing it in local storage. The attack surface is greater there. There are a number of smaller reasons as well.

                                      1. 1

                                        Great, I would appreciate a link (or a Lobsters submission) when you’ve written it.

                              1. 2

                                How exactly does the EU think it can make people not sell to EU citizens if they have no local presence?

                                1. [Comment from banned user removed]

                                  1. 12

                                    Some pesky EU citizen registers with his e-mail and expects his or her private data to be private. What are those pesky EU citizens even thinking, that data should be left unsecured, sold to third parties and be used in any other fashion for profit at the expense of the customer!

                                    1. [Comment from banned user removed]

                                      1. 7

                                        The fact that you’re using EU and governments interchangeably tells a lot about how much you understand how things work in the EU, especially how laws get passed.

                                        1. 1

                                          The EU is like an additional layer of rulers, on top of your local rulers.

                                          Consider the implications. What do you think I’m missing?

                                          1. 2

                                            Your description is wrong.

                                            There are two main bodies: the European Commission and the European Parliament. The European Commission is responsible for proposing legislation and implementing decisions (and other stuff but that’s not relevant right now) and the European Parliament, whose members are elected by citizens in various EU members. Those members of the European Parliament elect the members of the European Commission.

                                            As a member of the EU, it’s true that you can’t have any kind of legislation that’s against the current EU laws but the same applies to local by-laws vs federal laws, for example. But by no means this can be translated into “a layer of rulers on top of local rulers”. The format is somewhat similar to the US Congress, which is at the federal level, and each state’s elected officials and I don’t think you can call a representative or a senator “a ruler on top of the state ruler”. The European Union is a bit more divided than the US so the dynamics are obviously quite different but it’s very helpful to have something that can minimize the impact of various far-left or far-right leaders (one example would be Hungary’s Viktor Orban, but there are others as well).

                                            Also, what you say implies that there’s some sort of agenda that some people have and steer the EU into one direction or the other. The best argument against that is the convoluted process of passing any kind of laws: basically the European Commission proposes a law, it gets pushed to the Parliament, which can propose some changes and sends it back to the EC and the process is restarted and if they don’t agree on the second reading then a third body, the European Council, is added to the discussion for a “trilogue”. As you can well imagine, this usually takes years. For example, the proposal for GDPR was submitted on the 25th of January 2012.

                                    2. 1

                                      you are actually right, but I think instead of “deciding that you’re fucked” it will most likely be someone who complains for unsolicited mail or something and it will point EU towards the company and they will start investigate. Then it will be 20M per infraction or worse 4% of your income.

                                  1. 4

                                    I’m curious to see how POSIX-compliant the Windows terminal is; when I tried ssh with the Linux subsystem, the Windows terminal couldn’t display Mutt correctly, I think because it was struggling with curses’ heavy usage of escape sequences, but I’m not sure. I ended up having to use MobaXTerm, which is perhaps my least favorite piece of software I still end up using every day. Getting to switch to something lighter and with fewer attention-grabby bits all around my workspace would be excellent.

                                    On that note, if anyone here knows any good, simple terminals for Windows (my dream is alacritty or st, but for Windows), I would love to hear about them!

                                    1. 1

                                      I’ve been using ConEmu for the last six months. While it’s not a POSIX-compliant terminal, I found out that it performs fairly well with most. I haven’t used it with Mutt, though, but Vim works just fine.

                                    1. 3

                                      I find it odd that the author does not say that he’s a Google employee, probably paid by Google to work on NetBSD. I say that because I can’t see many outsiders pushing code into Google’s repos, which kind of makes the NetBSD support semi-official.

                                      1. 1

                                        Well, he does says that this is his activity paid with his own money.

                                        Where he works is not relevant in that case, though he could mention that.

                                      1. 3

                                        I think Travis CI is rather expensive for a side-project that’s not open source as the cheapest paid plan is $69. On Heroku you can use the Nano plan for SemaphoreCI which is free and if you push more than 100 times per month then you can upgrade to the Starter plan which seems very similar to the Bootstrap plan on Travis.

                                        1. 7

                                          I’m afraid there’s a slight misunderstanding of the 2FA concept and a confusion between actual factors and ways to circumvent them: the SMS token does require a possession factor: the actual SIM card, that in theory should be owned by only one user. The same thing applies to the SafeWord hardware token, which requires the possession of a physical device.

                                          The codes used are to verify your claim that you possess something, just like the dents on a key. Anyone with a key with the same dents will be able to open the same doors as you and I think it would be hard to argue that keys aren’t a possession factor. It just so happens that dents are a lot harder to copy than a set of numbers (on the other hand, those numbers do expire after a minute but the dents are static) but they can still be copied and information on how to copy them can be shared but obviously that won’t make the key a “knowledge factor”.

                                          At the end of the article, I saw that some apps are marked as 2FA or 2SA. However, some apps are mobile apps and a lot of people use their fingerprint scanner to unlock their devices so, in some cases, you’d need:

                                          1. The account credentials (the knowledge factor) to log in
                                          2. Your fingerprint (the physical characteristic) to unlock the phone
                                          3. Possession of the SIM card (the possession factor)

                                          I’d argue that in some cases you even have 3FA.

                                          1. 5

                                            Unfortunately SMS codes do not prove possession of the SIM card. Would that it were so - the SIM card does in fact implement a (reasonably) secure authentication process between the phone and network & in principle this could be used to bootstrap a 2FA authentication system.

                                            All an SMS code proves is that the recipient was able to view texts sent to a given phone number: That’s it.

                                            Given that a) phones are insecure, b) phone networks are insecure and c) the SS7 layer that lets mobile networks implement roaming is insecure, SMS messages are not a secure way to deliver authentication tokens for high-value assets.

                                            1. 1

                                              Unfortunately SMS codes do not prove possession of the SIM card. […] All an SMS code proves is that the recipient was able to view texts sent to a given phone number. That’s it.

                                              The point of the article was that the SMS code belongs to the same factor of authentication (“knowledge”) as the account credentials so using an SMS code was a two-step authentication, while I argued that the SMS code belongs to the possession factor as you need to own something (SIM card, in my example) which will make it a 2FA. The author pointed out that he ignored security issues like MITM or SIM cloning and so on and focused on the factor vs step thing.

                                              By all intents and purposes, the SMS code is a different factor (you possess something, like a phone number or a SIM card), not just another step, like a “what’s your mother’s maiden name” question would be (that’s still a knowledge factor).

                                              1. 2

                                                Except you don’t possess a phone number - it’s an abstract concept that relies upon the implementation of the phone network for it to have any meaning.

                                                This is the underlying reason why using SMS to implement a “something you have” 2FA doesn’t work - your phone number is not a physical object & doesn’t have the properties of a physical object that such 2FA authentication schemes rely on for their security. A physical second factor requires that only the owner of the object can view the code by virtue of having it in their possession & that the object cannot be duplicated without the knowledge of the owner. Once you break these properties you no longer have a physical (“something that you have”) second factor.

                                                SMS 2FA is a one time password communicated to you over an insecure, untrusted channel. That’s all it is.

                                                1. 1

                                                  Would you consider something like the Danish “NemID” system, which mails you a physical card of one-time-use codes, legitimate 2FA? On the one hand you do really possess a physical thing that’s needed for the challenge-response. On the other hand, like a phone number, its delivery relies on an abstract concept and system of infrastructure (a mailing address and postal system). Besides the mail/phone difference the other main difference is that the phone relies on this delivery method for each individual usage, while the NemID system batches it, mailing you a card of 140 challenge-response numbers where the individual uses then happen with it being in your possession.

                                                  1. 2

                                                    Well, it’s more secure than SMS 2FA at least!

                                                    If you want to get detailed about definitions, then I would personally say that sounds like a perfectly legitimate second factor scheme, but it’s not a complete “thing that you have” second factor because the thing (the list of one time passwords) can be duplicated without the owner being aware of it. (Obviously you can reduce the impact of this by requiring the use of the passwords in order, so that the holder notices when a factor fails for them. That doesn’t prevent someone else logging in with a copy of the codes at least once however.)

                                                    Likewise, SMS codes as a one-time-password 2FA would make a perfectly fine second factor if the delivery system was actually secure: Unfortunately, it’s not secure :(

                                                    I think one of the reasons people get confused about these definitions is that physical tokens used for “something you have” second factors all generate codes, which makes them think the codes are the point. For a physical factor the point of the code is to prove possession of the factor in a secure fashion: It’s the possession of the object that’s the crucial thing, not the code.

                                                    (As ever with linguistic definitions, none of these things are set in stone - there’s probably a scheme we can come up with that sits exactly on my personal boundary between a ‘thing that you have’ 2FA and other systems! Is a written down password still ‘a thing that you know’? Not really, but it can make up part of a perfectly good authentication scheme that’s good enough for the threat model it’s designed to protect against.)

                                                  2. 1

                                                    I’m not arguing that implementing a 2FA based on SMS codes is ideal, I’m saying that the usage of a SMS token would be in the possession factor instead of the knowledge factor, which was what the article claimed.

                                                    1. 1

                                                      Stretching definitions a bit, I might argue that the most one can really say about an SMS token is that it demonstrates knowledge of the target recipient’s phone number.

                                                      Which makes it a knowledge factor rather than a possession factor, even if it’s intended to be the latter.

                                                      1. 1

                                                        Yes, that’s what I was saying: the intention is to be a possession factor. The original article said this:

                                                        While MITM attack capability is something that should be considered when evaluating overall security, it’s irrelevant when evaluating authentication factors.

                                                        At the same time, I also agree with the fact that poor security will convert what’s intended as a different factor to a knowledge factor (an example would be using the phone’s camera as a biometric sensor but it would also validate a photo of the user).

                                              2. 2

                                                SMS token does not require the actual SIM card to receive it. It’s transferred via a channel between the website and the operator (and most likely another service between them) and then from the operator to the phone. As you can see, it’s not a possession factor: everyone in the chain sees the token and decides its fate.

                                                (I didn’t read the article because it was deleted.)

                                                1. 1

                                                  The intent of the SMS token is to prove that you own the phone number (which means physical access to the SIM card), so it’s used for the possession factor. Is it exploitable if one of the parties handling the SMS token is compromised in any way? Yes, of course, but the same can be said about physical keys as anyone handling your car keys, for example, could be able to copy them.

                                                  1. 1

                                                    Yes, of course, but the same can be said about physical keys as anyone handling your car keys, for example, could be able to copy them.

                                                    Indeed, which is precisely why car manufacturers implemented radio keys as standard that do a challenge / response with the car to demonstrate that they really are the one true authenticated key.

                                                    Of course, car manufacturers were prime NIH merchants who wouldn’t know a secure cryptosystem if one bit them on the backside, so that didn’t work out too well but the intent was there… (Maybe the current generation of car key cryptosystems is actually secure? I wouldn’t like to bet on it though.)

                                              1. 4

                                                I like better to work alone and then document the features I have implemented (with the whys and the hows I did that). However, recently I’ve been doing a bit of pair programming with a slightly-above-junior developer and her feedback was that she loved it.

                                                I also found it very interesting because I’d reason more about the code before actually writing it and once I was done with the reasoning I would write some tests that would convey the thoughts we just had. Initially I was the only one actually using the keyboard and doing the talking while my co-worker was watching but after a while she started contributing with questions or solutions.

                                                At the end of the day, it made me think of the PeepCode Play-by-Play screencasts where you’d see a high-profile open source developer tackle a problem and see what his or her workflow is. A lot of times it’s pretty cool as you learn a lot of things, from code tricks to editor shortcuts.

                                                1. 3

                                                  Isn’t it more likely that the cousin searched for the microprojector and, if they might be friends on Instagram, the ad might have matched his profile too?

                                                  1. 1

                                                    Is it fair to pick on an article that was written for software released more than a decade ago?

                                                    1. 14

                                                      The article was not much less wrong a decade ago, and Microsoft is leaving it up on their site without any warnings.

                                                      EDIT: They do warn that it’s pre-.NET-2.0, but apparently people are still learning from it, even though DES was obsolete before .NET even came out and it teaches wrong how to use DES.

                                                    1. 13

                                                      I’ve known developers who simply won’t do interview processes if they are asked to start out with a take home technical screen.

                                                      1. 6

                                                        I used to accept take-home coding challenges but after my last experience I now flat-out refuse them. I have a CS degree, have been developing Ruby applications for 8 years now (all of this is documented in my LinkedIn profile) and I also have a couple of Github repos so you can see how my code looks like and I also have a job. If you still need a coding challenge to figure out if I’m a good fit for your company then this means that you have doubts about my skills so it’s better to say “no” from the get-go.

                                                        During my last interview I was given a coding challenge right after the company approached me. Requirements were vague (they even specified that in the test) and it took me roughly 8 hours to finish it. They were unhappy with my implementation for various reasons that depended a lot on how you understood the vague requirements and I ended up being rejected.

                                                        At the end of the day, if you hire me as a contractor, I’ll still have to work 30 days for you before I ever see a paycheck. You’ll have plenty of time to figure out my coding skills in that timeframe.

                                                        1. 0

                                                          It me! <3

                                                        1. 10

                                                          I see that most of the discussion is around technical arguments for or against microservices. I found that to be false as very few companies actually benefit from the kind of optimizations you can have using microservices.

                                                          Personally, I’d think that this quote is quite interesting:

                                                          In reality, they need to address the people-related problems via more effective communication. When a startup has multiple dev teams, it is a requirement that they stay coordinated and informed about everyone’s work.

                                                          In my experience working with various teams, remote or local, the communication is the biggest issue by far and having multiple dev teams working on the same codebase yet still being aware of what other teams are doing is, honestly, something very hard to achieve in practice. That’s my biggest gripe with monoliths, not the technical or financial aspects.

                                                          1. 1

                                                            Could you explain how microservices address this problem? Why not just split the monolith into packages with stable APIs other teams can depend on?

                                                            1. 1

                                                              Of course you could do that but I don’t think that many companies will dedicate human resources to a package or library, while they would do that for a microservice. I believe that’s because a microservice still feels more complex than a package. So instead of a team of 10+ developers working on everything, you’ll have smaller teams working on smaller codebases and smaller teams have better communication.

                                                              Also, with microservices you have hard boundaries, starting from the way the source code is stored (probably a separate repository) to the way things are deployed. Packages will have at best decent documentation, but with microservices you’re forced to describe how others should interact with it. You also get some interesting side-effects: it’s a lot easier to quickly assign bugs to the correct person because you now have different domain areas serviced by different teams. Login doesn’t work? Probably it’s the authentication service. Image uploading fails after the image service was deployed? Hmmm, wander what could be the cause…

                                                              I honestly believe that microservices are a lot more useful for scaling teams by splitting them into smaller projects than scaling code, especially when you have teams distributed across the world.

                                                              1. 1

                                                                Of course you could do that but I don’t think that many companies will dedicate human resources to a package or library, while they would do that for a microservice. I believe that’s because a microservice still feels more complex than a package.

                                                                That might be the case and should be addressed at the leadership level.

                                                                So instead of a team of 10+ developers working on everything, you’ll have smaller teams working on smaller codebases and smaller teams have better communication.

                                                                That’s not what I had in mind. I thought about a single repo with the a structure like:

                                                                root/
                                                                  app/
                                                                  lib/
                                                                    payments/
                                                                    crm/
                                                                  test/
                                                                

                                                                For example, payments could expose PaymentService class publicly which would be a facade to the whole library. This would be the only class you could import from other libraries or the top-level app. You don’t need to introduce a distributed system to achieve this kind of separation.

                                                                Also, with microservices you have hard boundaries, starting from the way the source code is stored (probably a separate repository) to the way things are deployed. Packages will have at best decent documentation, but with microservices you’re forced to describe how others should interact with it. You also get some interesting side-effects: it’s a lot easier to quickly assign bugs to the correct person because you now have different domain areas serviced by different teams. Login doesn’t work? Probably it’s the authentication service. Image uploading fails after the image service was deployed? Hmmm, wander what could be the cause …

                                                                I think all these benefits could be achieved using the approach I outlined above without the extra complexity of separate repos, operating multiple services, more difficult end-to-end testing, network-related failure modes and a host of other problems.

                                                                That being said I think certain languages make it more difficult to enforce this kind of separation (although it’s still possible). For example, in Ruby on Rails projects dependencies aren’t required explicitly and classes are autoloaded. You can reference any class from any place in the code.

                                                          1. 9

                                                            Okay, sure. But does that really mean that every language would be better off with monads? From what I’ve seen, buying into monads can strew code with long, confusing type signatures and higher-order functions (e.g., flip, liftM) that leave the code more cluttered and removed from its writers’ intentions than the ad hoc solutions do.

                                                            Every approach to programming touts the pretty examples its creators thought up while it was being designed, but I believe the true test of such approaches is how ugly and unreadable they get at their worst. Learn Rust from scratch and write a basic program that does more than implement a basic calculator in the first week if you want to prove me wrong. You’ll run headlong into the type system before you know it.*

                                                            Now, given that many of the people who clicked through to this thread have probably bought into monads for long enough that they’ve gotten used to them, I’m probably going to get slaughtered. However, even if you are planning to downvote me and write a point-by-point rebuttal about how you had a dandy time with monads/Rust/etc., I hope you understand that I’m not saying that monads and the like don’t fix the problems they set out to fix. In fact, I’m not even saying that they don’t solve those problems well. I’m just saying that any attempt to create a system that abstracts over different types of code will inevitably restrain the programmer themselves, and this can often force them to write more of their code for the sake of the language than for the functionality of the program itself.

                                                            Replacing excessive boilerplate with excessive abstractions is jumping out of the frying pan and into the fire. It’s not the job of a good programming language to avoid boilerplate at all costs, but rather to keep the programmer focused on describing the actual behavior of their program; this precludes both boilerplate and abstractions when they are in excess. We must not let the problems we encounter most often while writing code induce us to implement solutions that create unavoidable barriers to entry as applications scale, especially not for what I think is otherwise some of the most innovative, pragmatic, and forward-thinking work in the field of programming languages today.

                                                            *This is something the Rust developers are aware of and actively working on, but that just gives you an idea of how far into development language designers can get before they realize they’ve created something that only the most patient, intelligent, and experienced developers can wrangle.

                                                            1. 11

                                                              The issue I’ve been noticing is that weaker versions of monads are making it into languages, like Kotlin and Swift which have this ? version of bind. So they have recognized that there is value in the abstraction but only offer the programmer a specialization. But this is a problem because this style of controlling sequencing opens up a lot of doors. For example, while everyone loves to talk about the Maybe monad, that’s actually so 5 years ago. I use the result or Either monad almost exclusively over Maybe. I want to be able to encode the error that happened so I can give the user a more valuable response than “something bad happened”. I use Ocaml and, while not as powerful as Haskell in this regard, I can just switch over to the result monad and get the same pretty code that I had with the Maybe monad (option in Ocaml). You can’t do that in Swift or Kotlin. I’m sure you could hack something in there but in Ocaml and Haskell it’s not a hack, it’s equally elegant no matter what monad you want to use.

                                                              For Ocaml, since we don’t have type classes, you explicitly pick the monad you want to use in a function so the function type doesn’t change but the implementation does. I think the functions I use the result monad on would be significantly harder to understand without being to redefine the sequencing operator so it is a net win.

                                                              1. 4

                                                                Having very little experience with monads and the likes, I believe the goal is to use monads as an abstraction over the lower-level elements in the language, like checking for null values.

                                                                For example, I’d argue that it’s more obvious what this block of code does:

                                                                do
                                                                  a <- getData
                                                                  b <- getMoreData a
                                                                  c <- getMoreData b
                                                                  d <- getEvenMoreData a c
                                                                  print d
                                                                

                                                                which is print the value of d, compared to this:

                                                                var a = getData();
                                                                if (a != null) {
                                                                  var b = getMoreData(a);
                                                                  if (b != null) {
                                                                     var c = getMoreData(b);
                                                                     if (c != null) {
                                                                        var d = getEvenMoreData(a, c)
                                                                        if (d != null) {
                                                                          print(d);
                                                                        }
                                                                     }
                                                                  }
                                                                }
                                                                

                                                                which might print the value of d based on a number of conditions that need to happen at the same time (and we don’t even have the else branches shown which would make the code even more cluttered!). It’s also a lot easier to reason about the code that’s based on the usage of the Maybe monad, at least in my opinion.

                                                                Otherwise, I do agree with the point that, at the end of the day we do ship features, not monads.

                                                                1. 7

                                                                  I don’t think that imperative code is a reasonable point of comparison (which is my biggest criticism of the OP). It’s seemingly trying to play on the fact that a bunch of nested conditionals is really bad and complicated—which I agree with—but I almost never write code like that in imperative languages. Instead, I’d use early returns:

                                                                  var a = getData();
                                                                  if (a == null) {
                                                                    return null;
                                                                  }
                                                                  
                                                                  var b = getMoreData(a);
                                                                  if (b == null) {
                                                                    return null;
                                                                  }
                                                                  
                                                                  var c = getMoreData(b);
                                                                  if (c == null) {
                                                                    return null;
                                                                  }
                                                                  
                                                                  var d = getEvenMoreData(a, c)
                                                                  if (d == null) {
                                                                    return null;
                                                                  }
                                                                  
                                                                  print(d);
                                                                  

                                                                  I’m not saying this is better than the monadic approach, but it certainly offends me a lot less than nesting everything.

                                                                  1. 4

                                                                    Yeah, the nested example was a bit intellectually dishonest in that case. This is what Go opts for instead, and just avoids nesting for callbacks entirely due to co-routines.

                                                                    It is still pretty verbose, but it is simple for everyone to understand.

                                                                    1. 1

                                                                      I see early return as another ad-hoc solution to that case. A priori I wouldn’t necessarily expect a language to have it.

                                                                      1. 1

                                                                        I think it’s reasonable to expect any imperative language to allow you to return a value as soon as you know what you’d like to return.

                                                                  2. 4

                                                                    I definitely agree with you more than I disagree with you. This is why I’m not a fan of the idea of adding monads to Rust, and why I like our hack for error handling. (Although it’s not clear that monads in the general case would work well in Rust anyway.)

                                                                    For example, I rarely write (or need/want) supremely generic code. Adding a type parameter to a type is a big deal and needs to be managed with care. Most uses of generics in Rust I find myself using are things like “give me any argument that can be converted to a file path” or “give me any argument that can be converted into an iterator that yields strings.”

                                                                    With that said, I haven’t seen much Rust code that elevates to the level of genericism that you see in languages like Haskell, and I generally consider that to be a good thing.

                                                                    1. 6

                                                                      This is why I’m not a fan of the idea of adding monads to Rust

                                                                      What do you mean when you say this? Monads aren’t a language feature, per se, but they are the combination of a few laws. You can express monads in a lot of ways even if the language has no concept of them. The Future’s library I saw for Rust had a bunch of and_then combinators which were basically monadic. Ocaml doesn’t “have monads” but you can define an operator called bind or >>= and implement the rules. It happens that Ocaml has a fairly pleasant way to express that which makes working with them not-terrible but that has nothing to do with monads. So I can do monads in Ocaml but they aren’t a language feature.

                                                                      1. 5

                                                                        When I say “monads” I mean “the ability to write code that is generic over any monad.” (Which I gather is consistent with how the OP thinks of monads too.)

                                                                        1. 2

                                                                          You can implement them in almost anything, but I agree with this article that to have the usefulness they have in Haskell the language needs to: “1. Support ML-style function-fu (trivial currying, single namespace). 2. Have type classes. 3. Allow polymorphism on return types.” (The linked article is about why they haven’t caught on in Common Lisp, despite being implementable.)

                                                                      2. 4

                                                                        Every approach to programming touts the pretty examples its creators thought up while it was being designed, but I believe the true test of such approaches is how ugly and unreadable they get at their worst.

                                                                        Funny, this is exactly why I think monads are necessary. The ad-hoc solutions are more readable solutions to those specific cases - async/await allows a more natural/friendly way of doing async than using Futures and general-purpose monad operations, ?.-style operators are a more natural/friendly way of doing early return than using Options and general-purpose monad operations. Even in a language that does have monads, the ad-hoc solutions are valuable sugar. But when you want to do something the language creator didn’t think of, if you don’t have general-purpose monads you’re stuffed.

                                                                        I’m just saying that any attempt to create a system that abstracts over different types of code will inevitably restrain the programmer themselves, and this can often force them to write more of their code for the sake of the language than for the functionality of the program itself.

                                                                        I understand that’s what you’re saying. I still think you’re wrong. The only things the abstraction restrains you from doing is the things that were wrong, and the wrongness will always bite you sooner or later. I’ve written plenty of law-breaking typeclass instances out of a sense of pragmatism and I’ve always come to regret it.

                                                                        Replacing excessive boilerplate with excessive abstractions is jumping out of the frying pan and into the fire. It’s not the job of a good programming language to avoid boilerplate at all costs, but rather to keep the programmer focused on describing the actual behavior of their program; this precludes both boilerplate and abstractions when they are in excess.

                                                                        I suspect you’re saying this because of experience with bad abstractions. Good abstractions are zero-overhead, or at least O(1) overhead: you learn them once and can benefit from them your whole career.

                                                                        We must not let the problems we encounter most often while writing code induce us to implement solutions that create unavoidable barriers to entry as applications scale

                                                                        That’s exactly what implementing only the ad-hoc solutions does. When applications scale is precisely when you need the ability to define your own custom monads and reuse generic functions with them.

                                                                        1. 1

                                                                          Even in a language that does have monads, the ad-hoc solutions are valuable sugar. But when you want to do something the language creator didn’t think of, if you don’t have general-purpose monads you’re stuffed.

                                                                          So clearly there’s a tradeoff between flexibility and simplicity. But given the complex systems to which monads lend themselves, that flexibility won’t benefit most people.

                                                                          The only things the abstraction restrains you from doing is the things that were wrong, and the wrongness will always bite you sooner or later.

                                                                          The abstraction may prevent you from doing things wrong, but you’ll never do things right if you can’t wrap your head around it.

                                                                          I suspect you’re saying this because of experience with bad abstractions. Good abstractions are zero-overhead, or at least O(1) overhead: you learn them once and can benefit from them your whole career.

                                                                          I was referring to cognitive, not computational, overhead. Low computational overhead; high cognitive overhead. (And by the way, even the best abstractions can leak.)

                                                                          We must not let the problems we encounter most often while writing code induce us to implement solutions that create unavoidable barriers to entry as applications scale.

                                                                          That’s exactly what implementing only the ad-hoc solutions does. When applications scale is precisely when you need the ability to define your own custom monads and reuse generic functions with them.

                                                                          The key phrase here is “barriers to entry”. A scaling application necessitates a simple, not a flexible, interface. Writing more “low-level” code is less work than writing less “high-level” code. You shouldn’t have to work around the interface in any application; all the more so for one that is scaling.

                                                                          1. 2

                                                                            So clearly there’s a tradeoff between flexibility and simplicity.

                                                                            No, not at all. ?. or await implemented as a native language operation is no simpler than ?. or await implemented as a monad. Indeed using a monad makes it harder to overcomplicate it with special cases (e.g. Java’s Option would never have made the mistake of erroring on null if they’d implemented it in a “monad-first” way).

                                                                            given the complex systems to which monads lend themselves, that flexibility won’t benefit most people.

                                                                            If a user is happy using ?. and await and understands how they work, it makes no difference to them whether there’s an underlying abstraction that can be generalised or not. The flexibility can wait for them until they need it, and if they never get to the point of solving a problem so complex that they need that power then good for them.

                                                                            In practice, back when I worked in Java every nontrivial codebase ended up needing a bunch of annotations/reflection/agents that were always a disproportionate source of bugs - not because developers were stupid but because they needed to do something the language couldn’t, so they had to step outside the language. In a language with monads that wouldn’t have happened.

                                                                            I was referring to cognitive, not computational, overhead.

                                                                            So was I. Good abstractions save you cognition; instead of having to understand the particular sequencing rules for this new kind of context, you just know it’s a monad and can think about it as such.

                                                                            And by the way, even the best abstractions can leak.

                                                                            No, this is a myth, and in fact monads are a good example; they don’t leak.

                                                                            A scaling application necessitates a simple, not a flexible, interface.

                                                                            The two dovetail, and the monad interface is remarkably simple.

                                                                            Writing more “low-level” code is less work than writing less “high-level” code.

                                                                            Maybe on the initial write, but code is read more than it’s written, so the high-level approach pays dividends for maintainability. Sometimes I’ll write code out longhand to start with and then realise I can simplify it by using State or Writer or some such.

                                                                            You shouldn’t have to work around the interface in any application; all the more so for one that is scaling.

                                                                            100% agreed. Monad is the opposite of that though; it’s such an elegant and simple interface that it’s very easy to conform to. (Indeed one sometimes does so accidentally, and only notices that a given type forms a monad once it’s pointed out)

                                                                            1. 1

                                                                              So clearly there’s a tradeoff between flexibility and simplicity.

                                                                              No, not at all. ?. or await implemented as a native language operation is no simpler than ?. or await implemented as a monad. Indeed using a monad makes it harder to overcomplicate it with special cases (e.g. Java’s Option would never have made the mistake of erroring on null if they’d implemented it in a “monad-first” way).

                                                                              A scaling application necessitates a simple, not a flexible, interface.

                                                                              The two dovetail, and the monad interface is remarkably simple.

                                                                              We have different understandings of “simplicity”. I argue that having monads be deeply ingrained in a language’s design can actually make things more complicated. It does matter whether there’s an underlying abstraction, because that abstraction will have to be propagated to all dependent code.

                                                                              Sidenote: I’m not aware of any monadic implementations of ?. and await and would love to see them! I need to do more research on this front.

                                                                              I was referring to cognitive, not computational, overhead.

                                                                              So was I. Good abstractions save you cognition; instead of having to understand the particular sequencing rules for this new kind of context, you just know it’s a monad and can think about it as such.

                                                                              It is pattern recognition, not inbuilt abstraction, that saves cognitive waste. Abstractions are a good learning aid, but nothing need be forced into the language itself in order to make this learning happen. All the foundational precepts of functional programming can be implemented in straight-up C.

                                                                              And by the way, even the best abstractions can leak.

                                                                              No, this is a myth, and in fact monads are a good example; they don’t leak.

                                                                              In general, one shouldn’t get too comfortable with liberal use of abstraction.

                                                                              Writing more “low-level” code is less work than writing less “high-level” code.

                                                                              Maybe on the initial write, but code is read more than it’s written, so the high-level approach pays dividends for maintainability. Sometimes I’ll write code out longhand to start with and then realise I can simplify it by using State or Writer or some such.

                                                                              You shouldn’t have to work around the interface in any application; all the more so for one that is scaling.

                                                                              100% agreed. Monad is the opposite of that though; it’s such an elegant and simple interface that it’s very easy to conform to. (Indeed one sometimes does so accidentally, and only notices that a given type forms a monad once it’s pointed out)

                                                                              Again, committing to an abstraction is a decision that mustn’t be taken lightly. Monad is an elegant and simple mathematical notion; implementation is inevitably hairier. That’s not to say OO is any better with respect to implementation of theory, just that no abstraction is perfect in practice.

                                                                        2. 4

                                                                          liftM et al are usually code smell, but they’re usually less obnoxious than the stuff I end up doing without monads, like checking for error codes or null pointers after every function call, or using .then() or whatever if I’m using some hip java(script) framework that emulates the Either or Maybe monad.

                                                                          You can usually get rid of them as well, if you use MTL-style monad transformers. A lot of libraries define things in terms of MonadState, MonadIO, etc. constraints so you don’t ever have to call lift<whatever>. I don’t actually remember the last time I used a lift function besides liftIO, which is used for running an arbitrary IO action inside some arbitrary IO-capable monad.

                                                                          In good monadic code, you stick all the “lift”s and “flip”s and stuff in some file that handles the low-level behavior of your monad, and you can do a really good job of making the “business logic” or whatever you want to call it free of clutter.

                                                                          1. 1

                                                                            In good monadic code, you stick all the “lift”s and “flip”s and stuff in some file that handles the low-level behavior of your monad, and you can do a really good job of making the “business logic” or whatever you want to call it free of clutter.

                                                                            But isn’t that just replacing one form of “low-level” with another? I thought the entire point of monads was to absolve the developer from having to do things the tedious, “low-level” way in the first place; after all, they are a “high-level” construct.

                                                                            1. 1

                                                                              The difference is that the join between the low level and high level is more continuous. Writing code that works with a State monad and writing code that works with a hidden variable looks very similar, and in both cases you can pretty easily understand what’s going on at the low level or at the high level. But the monad makes it much clearer how the high-level sequencing interacts with the low-level variable manipulation, and you can easily tell how changing one will affect the other.

                                                                              1. 1

                                                                                …the monad makes it much clearer…

                                                                                Whose job is it to make code clear and concise?

                                                                                As we all know, there’s only so much automated systems can do before they’re out of their depth. Trust me, I’d love to wholeheartedly commit to monads as much as the next guy, but their simplicity comes at the cost of long-term ease of use.

                                                                                1. 1

                                                                                  It’s also really nice in the sense that how the hidden variable can change is consistent. There is only one bind and return in there and the distinction between what is done and performing it in the monad is clear. In ad-hoc solutions, anything can happen anywhere. So even the nastiest monadic code is significantly more “learnable”, IME, than the nastiest imperative code because one still is constrained on where the nastiness can happen.

                                                                            2. 3

                                                                              But does that really mean that every language would be better off with monads?

                                                                              I think this question is meaningless since every Turing-complete language already has monads. Don’t believe me? Monads in C: https://gist.github.com/enobayram/4c9ba6e7723a1622530e56884fc97357

                                                                              The only thing that makes monads special in Haskell is the do notation, which is a syntactic sugar for monads. without it, the example would look like the following in plain Haskell:

                                                                              program =
                                                                                getData             >>= \a ->
                                                                                getMoreData a       >>= \b ->
                                                                                getMoreData b       >>= \c ->
                                                                                getEvenMoreData a c >>= \d ->
                                                                                print d
                                                                              

                                                                              Which is probably better than most other languages.

                                                                              So the question should be, “should every language have an expressive enough type system to express monads and should it have a flexible enough syntax that monadic code doesn’t look terrible in it?”

                                                                              1. 3

                                                                                How would you implement more interesting monads, say, streams and delimited continuations, in C?

                                                                                1. 3

                                                                                  The procedure is quite simple; whenever you see a type class constraint, replace it with an explicit argument accepting a method dictionary. Whenever you need to express polymorphism, replace it with a void * and hope the user won’t mess up the arguments. If you were serious about this, you’d also make all functions accept an extra void * that carries “user data”, so that you can pass around closures for your functions. You’d also implement some form of garbage collection/some architecture to allow for managing lifetimes. In the end, monads would be barely recognizable, but they would still be there, I mean, you could write a function that works on all monads.

                                                                                  Obviously, monads will also be much harder to use without lambdas, so you’d have to define a lot of top level functions that are called step_1_of_x, but my point isn’t to demonstrate monads are a good way to program in C anyway.

                                                                                  1. 3

                                                                                    I see, you’re looking at things operationally. Of course, any sufficiently powerful language can emulate the mechanics of type class dispatch (or any other implementable language feature).

                                                                                    But, for those of us who care about abstractions (like monads or any other algebraic structure), that is kind of missing the point. The point to using abstractions is to have a clearly defined boundary between implementors and users, so that users don’t need to worry about implementation specifics, and implementors don’t need to worry about users’ concrete use cases. The only shared concern between implementors and users should be the abstraction’s semantics. This, I’m afraid, you can’t easily replicate in C.

                                                                                    1. 1

                                                                                      Yeah, it does degenerate to untyped void * goo when you attempt this in C, but it’s still architecturally the same. You can still express monads in the category of monads. If you were an alien with a flawless mind, you could just as easily express and use your abstractions in C as you would in Haskell.

                                                                                      On a more practical note, you can actually do useful stuff with monads using C++. C++‘s templates are flexible enough to express (something like) typeclass dispatch, and in some ways you can even go beyond Haskell, since you have a tight control over what gets statically specialized. You could, for instance, have deep monad transformer stacks that get compiled down to overhead-free assembly. I’m not saying you should do that, but thinking “C++ doesn’t have monads” will unnecessarily narrow your vision.

                                                                                      1. 2

                                                                                        you have a tight control over what gets statically specialized

                                                                                        It’s not clear to me whether you are talking about the fact templates are instantiated at compile time or the fact templates can be specialized, but in either case you lose expressiveness.

                                                                                        • Compile-time instantiation prevents you from having polymorphic recursion (e.g., a Tree<T> containing subtrees of type Tree<List<T>>) or first-class existential quantification (e.g., Java’s infamous wildcards: List<? extends Animal>, although other languages do this more sensibly).

                                                                                        • Template specialization reduces the amount of static analysis that can be carried out in a modular fashion, because, well, templates can be specialized anytime, anywhere. With bona fide parametric polymorphism, you can say “my generic definition is guaranteed to have such and such properties”. With templates, you can only say “assuming nobody else specializes my templates or anything else they depend on in ways that contradict my wishes, the resulting specialized code will have such and such properties”. Assuming nobody will specialize your templates is a very big if.

                                                                                        1. 2

                                                                                          It’s not clear to me whether you are talking about the fact templates are instantiated at compile time…

                                                                                          Yeah, that’s what I meant, but I used the word “specialize” because that’s what haskell uses for something similar to what C++ calls template instantiation. So, in haskell if you have a function f.x a -> [a], you can specialize it for Int -> [Int] with compiler pragmas, and GHC will see it as a possible optimization. In theory this breaks parametricity, since you can easily violate it this way, but you have to be very careful with those pragmas. Which brings us to your second point, in C++, you’re basically always in this “you have to be careful” mode. So, please, for the sake of this discussion forget about how much the compiler helps you avoid shooting yourself in the foot, we’re talking about what can be expressed.

                                                                                          So, for instance, if you have a template in C++, and you’re using it in contexts where all of its specializations need to respect parametricity, you write a comment at the top of its declaration

                                                                                          /* If you intend to specialize this template, please respect parametricity, 
                                                                                           * if you don't know what it is, go func* yourself. (* educate yourself in the 
                                                                                           * ways of functional programming) 
                                                                                           */
                                                                                          

                                                                                          Coming back to your first point, you can very well express polymorphic recursion with C++, if you declare (via comments) List<T> to be parametric, so you can use List<shared_ptr<void *>> to stand for an existential a. You can even wrap this in a type-safe manner within the context of Tree<T>, so, you can for instance define a type-safe Traversible instance for Tree<T>. I would like to implement this for you, but I doubt I’ll find the time to do so anytime soon.

                                                                                2. 2

                                                                                  So the question should be, “should every language have an expressive enough type system to express monads and should it have a flexible enough syntax that monadic code doesn’t look terrible in it?”

                                                                                  You act as though there aren’t far-reaching consequences within a codebase for initial committal to a monadic interface. Different interfaces are best suited to different applications.

                                                                                  1. 1

                                                                                    I don’t see where you got the impression that there aren’t far-reaching consequences. Monads are too powerful an interface to expose to the library user under most circumstances, and the art of software architecture is to find the balance between the interface consumer and implementer.

                                                                                    The point still stands though, if your language’s type system and syntax isn’t powerful enough to make monads practical, the chances are you’ll have trouble expressing profunctors from your application domain’s category to the category of endofunctors in your programming language (or whatever abstraction it takes to express your architecture)…

                                                                                    1. 1

                                                                                      You act as though there aren’t far-reaching consequences…

                                                                                      I don’t see where you got the impression that there aren’t far-reaching consequences.

                                                                                      I was implying there are far-reaching consequences.

                                                                                      1. 1

                                                                                        Sorry, I meant where you got the impression that I implied there weren’t any.

                                                                                        1. 1

                                                                                          Oh okay. In that case I think we agree 100% 😁

                                                                                          Though I didn’t fully understand this part, and would like to:

                                                                                          …you’ll have trouble expressing profunctors from your application domain’s category to the category of endofunctors in your programming language…

                                                                                          1. 2

                                                                                            I strongly believe that beneath the hot dark crust of functional programming, there’s a pressure buildup of what people might one day call “categorical programming” once it erupts. When the dust settles, people will probably call Conal Eliott’s Compiling to Categories work one of the early milestones. You can already see the early signs of this upcoming paradigm applied to real world problems in the Haskell community.

                                                                                            The part you haven’t understood may or may not be meaningful for a real world application domain, but the point is, you can model the relationships in your domain abstractly as a number of categories and functors between them a la OLOGS, then your software architecture can be reduced to functors from those categories to some categories you construct using your programming language(s) (plural, as in for example, your back-end, database and front-end might all be part of the model, so you have your entire system along with the users and the world around it modelled). These are all big words, but the surprising thing is some of that mumbo-jumbo is directly expressible in Haskell. We’re actually using some of this stuff at my day job, and we intend to write about it when we have the time.

                                                                                            1. 1

                                                                                              The part you haven’t understood may or may not be meaningful for a real world application domain…

                                                                                              I sincerely appreciate your saying this. I think the middle ground between our respective positions could be stated in short as follows: “The tenets of FP have amazing application-dependent benefits.”

                                                                                              When the dust settles, people will probably call Conal Eliott’s Compiling to Categories work one of the early milestones.

                                                                                              [If] you can model the relationships in your domain abstractly as a number of categories and functors between them a la OLOGS, then your software architecture can be reduced to functors from those categories to some categories you construct using your programming language(s)…

                                                                                              This all sounds fascinating. Do you know of any interesting papers / talks / blog posts that further what Conal and Spivak & Kent discussed, i.e., preëmpt a move toward real-world application of o-logs to software development?

                                                                                  2. 2

                                                                                    You could say that about every language feature - it’s always possible to greenspun a given feature into a language that doesn’t have it. I think you can draw a line between languages that let you implement useful monad-generic code /in the language/ and languages that don’t.

                                                                                    1. 3

                                                                                      I understand what you mean, but I honestly think it doesn’t apply to monads. do notation is a language feature, but “monad” is a concept from abstract math. C is an extreme example, but you could easily find C++, Java or Python projects that would greatly benefit from expressing some core architectural elements through monads.

                                                                                      1. 2

                                                                                        Monads are a mathematical concept defined in terms of arrows and objects, sure, but the usual sense of “monad” in a programming context comes from identifying those with functions and types, and you can only really say that you have monads “in” the language if you can use them with ordinary functions and types in the language. You can’t really write a monad-generic function in Java because the language won’t let you write the type signature that function should have, and while you technically can work with monads in Python, not having a type checker means you lose most of the benefits. (AIUI this is substantially true in C++ as well; C++ does have type checking but only after template expansion, which makes development of generic code difficult).

                                                                                  3. 2

                                                                                    It seems to me that the problems described in this article are more about syntax than semantics. A good macro system could probably bring the same expressivity benefits as monads in this case.

                                                                                    1. 4

                                                                                      Well, macros can do anything; almost any programming language can be viewed as a named, standardized bundle of macros. I think there’s a lot of value in standardizing on the concept of a monad and a single syntax for it; that allows for reuse both at the syntactic pattern level and for library functions like whileM described above.

                                                                                  1. 2

                                                                                    While I don’t agree with most of the slides (sure, “write simple code” is a great advice but what does simple really mean as long as you don’t have a context?), I was simply amazed by one of the last slides which claimed that the SOLID principle is “too much to remember”.

                                                                                    Aren’t we supposed to be software engineers? Since when five principles with a nice mnemonic are “too much to remember”? Why do we need an even vaguer advice like “write simple code” to replace SOLID?

                                                                                    1. 3

                                                                                      When I think of “the very last word” I think of an application which can bring several messaging services together. This was true for a short period of time with iChat, Adium, and especially Messages (which incorporates SMS as well).

                                                                                      Until SMS goes away, the default messaging app, especially on iOS, will be the most popular and most necessary.

                                                                                      The sad thing about XMPP is that services like Facebook have abandoned it in favor of proprietary networks and so XMPP isn’t as useful as a way to bring everyone together.

                                                                                      1. 7

                                                                                        That is a sad thing about the world and about Facebook, not about XMPP.

                                                                                        1. 1

                                                                                          Disagree. Wide adoption is a characteristic one can judge technologies against. It may have nothing to do with the protocol technically, I’ll give you that…

                                                                                          1. 13

                                                                                            I’m pretty sure that the main problem with XMPP at Facebook was the fact that you could use a third-party client instead of a client built and owned by Facebook.