1. 8

  2. 1

    Can you tell us more about the project? How did it come about? How long have you been working on it? What’s the site written in / how is it deployed?

    As someone who uses Google Analytics and Mixpanel, I’m a big fan of these type of services. Mixpanel will email you every day with an overview of your bookmarked metrics. I do worry about Google eating your lunch though. What’s to stop them from just implementing this on their end?

    1. 4

      Absolutely, sorry for not seeing this comment earlier.

      I actually worked on Google Analytics for a while. I noted many things that I felt need to be fixed, but fixing them from inside turned out to be really hard as much of the development and design focus went towards premium customers. I noticed that most people love GA but also never bother to check it either because they forget or navigating the interface is too cumbersome (something like 20-40 clicks to get what you want to see on a day-to-day basis) and it’s only getting more complex. GA has been adding more education inline with the product, but I believe taking a course on using a product is the last thing many people want.

      Anyways, I started working on Briefmetrics a few months ago (I left Google a year ago). Originally wrote it in Golang just for fun, to learn Go, but after I had a working prototype I ended up rewriting it in Python (Pyramid/SQLAlchemy/Mako/Celery). Turns out Golang is not great for frontend webapps these days. It’s deployed on a single Digital Ocean node running two Docker containers (Python and PostgreSQL) and probably a PhantomJS docker soon (for rendering fancy d3 charts).

      I’m not too worried about Google eating my lunch. In fact, Google Analytics already has an email report feature—it’ll email you a PDF of any one report at your desired interval, if you can find it and invest 20-30 clicks to set it up. :) The goal with Briefmetrics is to do more consolidated and opinionated analytics right out of the box with zero setup. I have a fair bit of experience in the space (my previous startup was in the social analytics space which was acquired by Google), so I think I can get a good useful baseline of analytics for people—some of which is things that you can’t get from the Google Analytics frontend (by massaging the data from the API into interesting compositions). You’re more than welcome to try both and compare!

      Happy to answer any other questions too, sorry for not adding more about it upfront. :)

      Update: Forgot to mention, I also plan to add integration with other services. Probably going to start with AdWords and some social analytics like Twitter/Facebook.

      1. 1

        I’m really surprised, and interested, by your experience with Go. Python is the main development language in my team. Almost all our web apps are written in Python. But we’re writing more and more things in Go since a little less than one year. In fact, we expect most of our new code to be in Go in the near future.

        I’m curious to understand what specific difficulties you had with web apps development in Go?

        1. 5

          I’d like to preface with saying that I really enjoyed using Go. It’s a great language and I look forward to using it again soon.

          There were three pieces that pushed me towards abandoning it for this specific project:

          1. HTML templating options are still fairly weak. The big options are either using the built-in html/template package which is actually fairly decent (and has neat context-sensitive sanitizing) but it’s still super limited and extending it is a pain. I’m not a fan of strict no-logic-in-your-templates restrictions, so working around that was rough. Other options are using Go implementations of mustache and other simple templates which also have very limited functionality.

          2. That generics thing you keep hearing about. Briefmetrics does a lot of API calls, so caching those calls was fairly critical for development. Right now there’s no sensible way to make a generic memoization/caching library (my half-working attempt is here: http://github.com/shazow/memoizer). Seems the way to go right now is code generation, for which there aren’t many frameworks at the moment (though I saw something related last week).

          3. Prototyping a web frontend in general is a very dynamic process. It’s hard to quickly monkeypatch something to see what it would look like when you’re dealing with a statically typed language. This is not a problem for things that are not user-facing.

          On the other hand, the concurrency features were fantastic. The simplicity of the language and the quality of the standard library is inspiring. I really want to use it again, but probably for a more backend-y project.

          Hope this answers your question. Would be interested to hear in what kinds of problems you’ve run into, too.

          1. 3

            Thanks for sharing your experience with Go!

            About HTML templating: I agree that the Go ecosystem doesn’t offer as much options as Python, Ruby or Node.js. Personally, I’m quite satisfied with the standard library package html/template, and very impressed by the context-sensitive sanitizing. This is very convenient and secure! On recent projects, I’m using client-side templating more. Maybe it explains why html/template is enough for my needs. If you’re used to (and need) something more “imperative” like Mako or Jinja, then it’s true than html/template can frustrate you :)

            About generics: Oh yes, this is the big recurring topic on golang-nuts :) I missed some form of genericity on some occasions, but most of the time I’m okay without it. And anyway, I really dislike the complexity introduced by generics in Java or templates in C++. I understand why Go authors are very cautious with this, considering that keeping the language simple and orthogonal is one of their main goal. In your specific case, I’m wondering why you don’t cache the end result of your API calls, which is probably some kind of JSON string? This way, your caching library has just to learn how to cache slice of bytes, and does not need to be generic. An alternative solution would be for your caching library to just cache values of type interface{}, and you just need to add a type assertion before using them. But I’m certainly missing something and over-simplifying your requirements.

            About prototyping: Coming from Python like you, I haven’t suffered from this problem as of now. The edit-run cycle is as quick as in Python, maybe even more efficient. And I save a lot of time by not having to write docstrings and tests just to describe and check the type of arguments and return values.

            I agree with you a lot about the simplicity, the quality of the standard library and the concurrency being fantastic features of Go.

            As you asked about my own experience with Go, coming from Python, I really liked:

            • The static typing because it eases refactoring and shortens docstrings and unit tests;
            • The structural typing (Go interfaces and kind of “duck typing” instead of classes and inheritance);
            • The ease of programming concurrent applications without threading, without yield from (like in Python Tulip) and without callbacks (like in Twisted or Node);
            • The performance increase;
            • Having anonymous functions;
            • The refreshing simplicity of go test and of the testing package;
            • The super easy deployment with just one binary to copy (no virtualenv/pip/setuptools);
            • And gofmt which gives all the advantage of a well indented Python code without the drawbacks (difficult to copy-paste without mistake) and will make evolution of the language a lot easier by automating rewriting (look at the migration to Python 3…).

            Here is some of the problems I’ve run into:

            • When writing low-level code, networking code, or IO code, the error handling promoted by Go, with explicit return values instead of exceptions, is great. But when writing code more akin to “business rules”, then it can be obscured by error handling. Go convinced me that exceptions are not the panacea (as used by Python, Ruby, Java, C#, C++, etc.) and I like the language making me think about it, but while writing “business oriented” code, I’m still looking for the sweet spot on this topic. I’m using panic/recover more in this specific case, for errors where the only action is to return an error message to the user, and log a trace for the developers.

            • Using the result of a SQL or Redis request can sometimes be little clumsy because of static typing. You either have to define a struct compatible with the result (the recommended way), or return the result as a map of strings to empty interfaces and use type assertions. But really it’s not a big deal, and the benefits of static typing are so great in terms of documentation, ease of refactoring and simplification of unit tests that maybe it’s worth it. Moreover, I’m thinking this problem can be solved by code generation, like what protobuf does by transforming and IDL file into Go files.

            • The language predeclared integer data types are fixed size (8, 16, 32 or 64 bits) with overflow. If you need integers with a size only limited by available memory, like in Python, then you have to use the package math/big, which is quite nice and complete, but you lose usage of the usual operators +-*/ etc. That’s not a big deal, but it requires some adaptation. There is also no built-in rounding function, by design. This is also not a big deal, since you can do for example int64(x + 0.5), but it requires adaptation too. On this topic, the language is definitely more low level, but maybe this is more an advantage than a drawback, even for someone coming from Python/Ruby/Node.js.

            • I had to spend some time to find a strategy to manage dependencies and enable reproducible builds, since there is no official way to do it. After many reads and many thoughts on this subject, I resolved to vendor all dependencies directly in our project source tree, and rewrite import paths. I really like this solution. Despite the time spent I had to spend on this, in my opinion, the end result is a lot more easy to understand, flexible, easy to deploy, than the complex packaging ecosystem in Python (PyPI, virtualenv, pip, distutils, setuptools, tarballs, etc.).

            In my opinion, one strange thing about Go is that it beats Python as its own game by improving on what Python is usually praised for:

            • Simplicity (see the language spec)
            • Explicit better than implicit (for example, errors appear in function signatures as return values in Go, instead of implicit exceptions in Python)
            • Batteries built-in (standard library is really large and production grade)
            • Excellent documentation
            • Orthogonal language features
            • Practicality beats purity (see for example the handling of Unicode in Go with just simple UTF-8 strings, compared to Python solution which is closer to Java)

            Sorry, this is a long long comment :)

            1. 1

              I think our experiences were very similar.

              If you’re used to (and need) something more “imperative” like Mako or Jinja, then it’s true than html/template can frustrate you :)

              Precisely. I am quite addicted to Mako. Not sure I can go back to anything less powerful. :P

              About prototyping: Coming from Python like you, I haven’t suffered from this problem as of now. The edit-run cycle is as quick as in Python, maybe even more efficient.

              Not so much about the edit-run cycle, which I agree is fantastic for a compiled language. Moreso for trying out novel data models and presentations, it takes much less time to quickly hack together some ad-hoc object modifications and see the results (often takes on the order of 20-30 seconds) before doing a “proper implementation"—when using strictly defined types in Go, it’s hard to do things like that (often takes on the order of 10-20 minutes).

              In your specific case, I’m wondering why you don’t cache the end result of your API calls, which is probably some kind of JSON string?

              Mostly because…

              Using the result of a SQL or Redis request can sometimes be little clumsy because of static typing. You either have to define a struct compatible with the result (the recommended way)

              That is, the API libraries I was using defined various different structs, each which would need to be gob-registered and serialized/deserialized into bytes/interface{}’s and properly casted. It actually wasn’t too bad for any singular example (maybe 15-20 lines of code for the naive scenario, bit more for extra convenience), but doing it for N inputs/outputs is a lot of copypasta code which becomes hard to maintain.

              I am looking forward to seeing how the Go dev team addresses the shortcomings from lack of generics (perhaps with built-in code templating?). Other than that, it’s just a matter of time until the ecosystem becomes incredibly compelling (more web frameworks, ORMs, advanced templating, etc).