1. 3

    So it’s still flat. Flat keyboards drive me nuts.

    1. 5

      Well yeah, the whole point is that it’s intended to be complementary to a Kinesis Advantage or a tented ErgoDox rather than used as a daily driver. This is meant to be used in situations where you would otherwise be falling back to a terrible internal laptop keyboard.

      1. 2

        While I wish that I could pack my Kinesis up and take it with me everywhere, it sure is a monster as far as size/weight. If I ever get the time/will, I’ll have to play with an ErgoDox. It looks like a fun project, at the very least.

        Thanks for a peek inside the process!

    1. 2

      That’s great, but what if your device is destroyed or lost? What if I want to do some collaborative editing on something with my SO?

      Unhosted web apps also lack a good place to store valuable user data, and servers are good for that. So apart from brokering our connections with the outside world, the server can also function as cloud storage for unhosted web apps. This makes sure your data is safe if your device is broken or lost, and also lets you easily synchronize data between multiple devices.

      Oh… so you mean we’re going to send data to a server… That seems to contradict this statement on the front page:

      Also known as “serverless”, “client-side”, or “static” web apps, unhosted web apps do not send your user data to their server.

      Running 100% client-side apps can be useful for certain usage cases, but this website seems to be more zealous than helpful. It’s also light on details and contradicts itself.

      1. 3

        I’m Greg Taylor, one of the Pathwright co-founders.

        I spend most of my time working with Python and Linux. I like trying new things, and love to tinker. Sites like Lobsters are a valuable source of discussion and new shinies for me.

        1. 1

          Quick note: While I tagged this web, Dart can be used to write CLIs and daemons (like Node). It seems to be primarily used for web applications right now, though.

          1. 2

            Error handling in go is really noisy and verbose. err checking everywhere. It’s similar to Java and checking for nulls all the time. I really don’t like this style. I don’t know why go and Java have constant error checking where as in my JavaScript or Python it’s never much of an issue.

            1. 12

              Feels natural, but I come from a C background.

              1. 13

                I come from a try catch background in java and python and I welcome the error handling. I’ve been ignoring errors for far too long. It’s time for me to step up and be a responsible developer.

                1. 1

                  I would argue that a language where exceptions are thrown is a much safer environment to work with than one where exceptions don’t exist: The thing is. Yes. We all should be responsible developers, and yet we all make mistakes.

                  Yes. An uncaught exception will cause your program to terminate, but that’s not a bad thing. An unhandled exception is a spot where you screwed up and more often than not, your program is now in an inconsistent state and code that runs in the future and depends on the operation that just failed might also fail in inconsistent ways.

                  When your program terminates, then you know for sure that no further damage will be done.

                  I like that safety net. I much rather crash than destroy even more stuff as a consequence of missing checking for a possible error condition.

                  Exceptions also help a lot in keeping different components of a bigger application separate as you don’t have to manually propagate errors back up the stack. And when you have a good semantic hierarchy of exception classes, you can handle a whole lot of error conditions in one fell swoop.

                  In the web application I’m working for, I can throw a semantically named NotFoundException, no matter where in the framework it happens and I can be sure that this will eventually be turned into a 404 error for the client. No matter how deep down the stack I am: My method there and then failed to find something? Throw a NotFoundException and it will be dealt with.

                  Especially in the cases where I really can’t do anything but show an error page, I don’t have to add error checking all the way up the stack from where I am. Error handling is constrained to two places: Where the error happens and way up there in the request handler where it’s turned into a nice error page (and a HTTP error). All the pieces in between don’t need to care and thus read much nicer.

                  I think that’s very convenient and I really fail to see how this can be bad design.

                  1. 1

                    It’s actually pretty difficult to accidentally ignore an error condition in Go. The compiler throws out a lot of complaints. You can suppress the errors, but you have to pretty explicit about it.

                    But yeah, exceptions actually would be pretty nice (as long as you are forced to explicitly catch or throw them, as in Java). I think Go uses error codes instead because it encourages you to handle errors at the source instead of waiting for it to propagate out. In my code, I usually just do something like

                     err := functionThatCouldError()
                     if err != nil {
                         panic(err);
                     }
                    

                    This has basically the same effect as an exception in Java or Python. The program exits immediately with a nice stack trace. Although I guess this does require me to type 3 extra lines.

              2. 7

                Because Go doesn’t have JavaScript’s ability to attempt to coerce things into whatever-the-hell-JavaScript-feels-like-doing-right-now, or either of their dynamic type system where things can be added to other things whenever you feel like it.

                Python and JavaScript both have exceptions, and using try/catch when you’re running something that could do less than wonderful things is a good idea. Consider a case where you’re getting input from across the network, and you want to make sure something’s actually an integer. In Python you can’t just run type(variable) is int, because it came to you as a string or bytes. You need to cast it, but casting can cause a ValueError.

                Having exceptions bubble up and kill your program is typically a bad idea. You’d want to handle that, and the way to do it, in both JavaScript and Python is using a try/catch block.

                Go’s use of err everywhere is used instead of try/catch blocks. It makes you deal with errors when they happen, instead of letting them bubble up and be handled later. I think that’s nice. It’s much more explicit than a block at the end of your code that says “some sort of error could happen, and if it does, lets try something”.

                1. 4

                  Yea, I definitely like the error handling better than I thought I would when I first started learning Go.

                2. 4

                  Are you saying that handling any possible (or probable) error is a bad thing?

                  Also, last I checked Java’s error trapping was exception-based.

                  1. 4

                    Because of Java’s “checked exception handling”, which I think we can probably agree at this point was a failed experiment, you end up having to explicitly wrap exceptions at the point where you call an API that generates them. At the extreme, you have things like this (testData is a string, and this is in a test case):

                        InputStream in;
                        try {
                            in = new ByteArrayInputStream(testData.getBytes("UTF-8"));
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                    
                        for (String line : new LineIterator(in)) {
                            p.dispatchLine(line);
                        }
                    

                    If it weren’t for the checked exceptions, in wouldn’t even need to be a variable; it could be inside the for-each thing. bjorn could have been saying, and correctly in my experience, that Golang’s multiple-value returns for errors result in you having to write similarly sequential code.

                    However, I don’t think this is as bad in Golang as it is in Java, because the big problem with it in Java is that any new exception that can appear in some library you’re using must ripple upward through exception specifications, unless you wrap it like I did above. So a small change in one place can result in the need to make many functionally meaningless changes in many other places.

                    What I think bjorn is actually saying, though, is that it’s like how in poorly written Java you have to check for null all over the place, because lots of things that are supposedly a value of some type are instead null, especially failure return values. I think this is probably true of poorly written Golang, too.

                    1. 4

                      I’ve always wondered why Java’s checked exceptions get such a bad name and this is a great example, thanks.

                      I never understood it because I spend a lot of time programming Haskell where the convention is heavily in favor of various kinds of “checked exceptions” in that it’s very often impossible to use values which were created in failing contexts without either bubbling failures upward or handling them.

                      The difference is that Haskell has Functor/Applicative/Monad interfaces which allow you to compose failing contexts and the values within in much more sensible and syntactically light manners. Oftentimes it’s not terrifically difficult to “check” all of your exceptions upon calling an API since you just want to glom them all together and float that new failing context upward—and that’s just (<*>).

                      I don’t think Haskell’s notion of errors is completely successful. At the very least there’s a lack of strong cultural conventions which causes a proliferation of error types. Successful error handling thus becomes a small mire of mapping between various kinds of error types (Maybe, Either e for various e’s). The exception system provides slightly more strength of convention, but it’s broadly frowned upon since you now have to suspect every line of code for failures again.

                      Anyway, that’s my two cents and a bit of an epiphany thanks to your code snippet here. I’d encourage anyone interested in learning more about Haskell’s error types to look at the errors package [0] which has a large number of “mapping” and “code pattern” combinators for error handling.

                      [0] http://hackage.haskell.org/package/errors

                      1. 1

                        I’m glad it’s a helpful example! But I think it’s kind of an extreme case. Most of the time the code needed to cope with Java exceptions isn’t this bad. (For example, most exceptions you have to handle can actually arise, unlike this case.)

                        I haven’t tried Haskell, but it sounds quite a bit more pleasant. Thank you for the reference!

                    2. 1

                      Yeah, this is the answer. The alternative is to just error out whenever an exception happens (which is more or less what Python does). That might be OK for a simple script. It’d be pretty disastrous if you are writing a long-running server.

                      1. 3

                        In Python your server’s top-level loop can catch and log arbitrary exceptions, so that’s not really a huge problem with Python. The deeper problem, I think, is that exceptions can’t convert failure into success; they just let you determine what kind of failure you want to have. But in a language with exceptions, nearly every line of code can fail. It’s just implicit. (In a language with operator overloading and run-time polymorphism, like Python, essentially every line can fail.)

                        Writing code that handles, and especially prevents, every possible error requires a different mentality. You can do it in Python, to some extent (though running out of memory is pretty hard to guard against) but the fact that all those possible errors are invisible in the source code doesn’t help at all. If instead you have to write extra code for each thing that can fail, then you know what those things are, and you also have an incentive to minimize them — to make parts of your code that simply can’t fail.

                    3. 4

                      Sorry to bring up a meta discussion, but why are people downvoting bjorn’s comment?

                      Error codes vs exceptions is an ongoing debate and everyone has their own reasons for liking one over the other.

                      Go’s error handling is verbose.

                      0 points.

                      I’m used to error codes from C.

                      11 points.

                      Why are people downvoting an opinion they don’t agree with?

                      1. 3

                        Because that’s not all of bjorn’s comment. bjorn’s comment mentions that Python and JavaScript don’t have as verbose error handling, but that’s mostly because there isn’t compile time checking to make sure you don’t do anything that could cause an exception without dealing with it somehow.

                        You should still deal with the exceptions in Python and JavaScript, but because there’s no note in the code itself that says “this might cause some problems” you aren’t typically away that those could be problems until they become problems.


                        That said, I didn’t downvote bjorn’s comment, I just think bjorn’s opinion isn’t well formed, or is ignoring why Java and Go deal with errors the way they do.

                      2. 2

                        I have been using go for a while now, and I actually don’t mind the error checking. I am used to explicit-ness in other things from my Python days, so maybe that is why it doesn’t bother me, but I actually enjoy being able to handle the error where it happens

                        1. 2

                          I spend 40+ hours a week in Python land, and I generally enjoy it very much. While I don’t mind Python-style exceptions when I’m responsible for most or all of the code I’m working on or maintaining, often it’s hard to predict what your various dependencies are going to throw at you. With Go, error handling is so explicit that you are more or less forced to know what’s going on, which I like.

                          Go/C-style error handling is a lot more verbose, but it’s refreshing being 100% aware of the error cases and what is going to potentially be sent your way. With Python, you don’t know unless the documentation, unit tests, and the organization of the source code is good.

                        1. 6

                          The author doesn’t seem to have done his homework here. antirez responds in the comments to this post and refutes nearly all of the author’s points fairly well.

                          All in all, it ends up sounding like he’s saying “I tried to use redis as a Postgres replacement and it didn’t work”

                          1. 2

                            Yeah, I’m all for a well-researched, properly thought out rant, but this seems like getting in a car and complaining that it can’t take flight.

                            1. 2

                              In the comments he seems to indicated that it is as good as memcache but slightly slower, but using anything above memcache functionality and it sucks. I totally disagree. Redis is especially suited to putting a bunch of data into memory to manipulated. All the different data structures are amazing for working with a data set that fits in memory. I’d much rather use it then memcache. Redis is a pleasure to use, and that’s it’s strength.

                            1. 2

                              I would love to see benchmarks of serving a web application this way vs. proxying the Go part behind something like nginx and having nginx serve the static files

                              1. 6

                                The only thing by removing nginx (or any other buffering reverse-proxy) from your stack is that you may be opening yourself up to malicious slow clients. Go can handle each request in a goroutine, but that may not save you if you don’t carefully handle larger requests.

                                You can run a safe, secury Go server directly, but given the amount of time the nginx team has spent making it great for this purpose…

                                1. 5

                                  I will say that I have performance tested my Go web applications by themselves and behind nginx. I used the built in benchmark tools that come with Go and the nginx webserver starts erroring and not handling requests during the bench tests and the built in Go http server does just fine and far out performs the nginx proxy. This was done quite some time ago on a windows machine so take that for what it’s worth. I know that the http library in Go has since improved, and that the environment makes quite a difference. With nginx I usually see 20-25k req/sec be handled before it starts having issues, and with go I commonly see 60k without any issue. Go handles static content very well as does nginx, but I think nginx as a proxy is just a bottleneck. I’ve since built a Go proxy for the application instances because of this. Good luck!

                                  1. 2

                                    There are also other considerations besides performance. Nginx has a lot of features that the Go http server library doesn’t, like rate-limiting, https, load-balancing, etc. If all you want is to serve a web app from a single host, you wouldn’t care about these things, but otherwise Nginx gives you a lot of functionality that would take a while to implement yourself.

                                    1. 2

                                      The obvious solution to this, of course, would be for someone to implement a web proxy in Go that has all those features. Then you could get the best of both. I’m curious, though, if the performance drop was caused by the overhead of having to pass requests from one process to another, and not so much Nginx itself. Have you benchmarked your Go proxy to see how it compares?

                                      1. 1

                                        I can’t wait to see someone build a feature compatible with Nginx server in Go. I’m guessing performance wise they’d be darn close, and the code would certainly be much more easily maintained in Go. I’d miss openresty, though, which is extremely useful for providing custom functionality to Nginx, or just straight up raw, dynamic web apps.