Hacker News new | ask | show | jobs
by kohanz 4435 days ago
Perhaps this is not the best place for this question, but as a frequent HN reader, I'm constantly told that Go is great to develop in and very performant. However, it's not clear to me how Go suits a web application with relational data.

From what I've gleaned, an ORM does not make sense in Go, so how would this type of application be approached? Writing a lot of ORM-type boiler-plate? A completely different way? Or is Golang a bad choice for such an application?

3 comments

I suppose the Go philosophy would discourage developers from tightly coupling Go types and their relational representations through an ORM. The idiomatic way of mapping your objects to a database is by defining a thin interface around a sql.DB, with first-class operations for your concrete types.

    type User struct {
        ID        int
        Permalink string
    }
    
    type Storage sql.DB
Then you can either do

    func (s *Storage) WriteUser(user User) error {
        if _, err := s.Exec(
            "REPLACE INTO users VALUES (?, ?)",
            user.ID,
            user.Permalink,
        ); err != nil {
            return fmt.Errorf("write user failed: %s", err)
        }
        return nil
    }
or

    func (u User) Write(storage Storage) error {
        if _, err := storage.Exec(
            "REPLACE INTO users VALUES (?, ?)",
            u.ID,
            u.Permalink,
        ); err != nil {
            return fmt.Errorf("write user failed: %s", err)
        }
        return nil
    }
It's a bit more laborious in the sense of keystrokes, but it's also more explicit, which is, on balance and over the lifetime of a large software project, a good thing.
Thank you for the detailed answer.

It's a bit more laborious in the sense of keystrokes, but it's also more explicit, which is, on balance and over the lifetime of a large software project, a good thing.

OTOH, it feels like a high development cost to pay, relative to the alternatives out there. You certainly wouldn't use it for an MVP. Also, it would increase the opportunities to introduce bugs into the application (unless one actually feels they can write something better than, say ActiveRecord, from scratch).

I have a side-project in RoR that would benefit greatly from the performance boost provided by Go. However, the idea of writing all of the ORM functionality that ActiveRecord handles for me (not just managing of objects as you've shown, but the relationships between them) is quite daunting.

    > (unless one actually feels they can write something 
    > better than, say ActiveRecord, from scratch).
The point is that ActiveRecord's method of modeling, especially when it comes to dynamically mapping language constructs to a storage layer via SQL, is too implicit. Too costly. Actively harmful! The point is to get developers to stop thinking in terms of ORM abstractions, and start thinking in terms of the actual transforms and manipulations that are occurring.

    > You certainly wouldn't use it for an MVP.
I think you overestimate the cost of pressing buttons on your keyboard.
The point is to get developers to stop thinking in terms of ORM abstractions, and start thinking in terms of the actual transforms and manipulations that are occurring.

Isn't the point also to encourage code re-use and abstraction? I mean, golang has packages for a reason. I suppose my question is more along the lines of whether we'll ever see a package in go that would standardize the data-object divide or whether this will always be a "roll your own" domain?

I think you overestimate the cost of pressing buttons on your keyboard.

Then why don't we "roll your own" for everything?

    > I suppose my question is more along the lines of whether 
    > we'll ever see a package in go that would standardize 
    > the data-object divide
There is no lucid standardization possible for the data-object divide, in Go or any other language. Too much depends on the semantics of the object and data system. Or, rather said: that standardization (that abstraction) is SQL itself.
what sagichmal is basically saying without saying it is go cant do what you want, you just cant write a generic Active Record framework in go,nor a generic data mapper.

the right approach ,when a language cant do what you want, IS code generation with a third party dynamic language.

If you know ruby for instance, ruby excels at code generation,so you could generate go code from a SQL schema or any manifest,then augment it with custom code in another go file that import the generated code.

Ironically, the "Active Record" concept originated in statically-typed languages -- look at the Java example code in the PEAA book, which looks much like the Go example code here.
Yuk, that's just manually doing what ORMs give you automatically; that's not a good thing, you're being a human compiler.

    > you're being a human compiler.
The transformation from "type instance in my language" to "relational data in my storage engine" is absolutely not "compilation". It's a subtle translation of data and grammar, and as the type relationships grow more complex, ORMs fail. The lesson of ActiveRecord, from the perspective of Go, is that ORMs are fundamentally broken abstractions.
Don't be pedantic, my point was clear and you obviously understood it.

As for the lessons of active record, says who?

I do, for one, but don't take my word for it... lots of very intelligent people have problems with ORMs. http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Compute... presents a good summary of the problems involved (forgive the inflammatory title).

Despite its many problems, SQL remains the best way of interacting with a relational database.

> lots of very intelligent people have problems with ORMs.

And lots of very intelligent people like them. Both statements are meaningless appeals to authority.

> Despite its many problems, SQL remains the best way of interacting with a relational database.

That's your opinion, it's certainly not a fact, and just as many disagree as would agree. Secondly, ORM's don't stop you from using SQL where it's beneficial, so ruling out the ORM because you don't like it for some cases is throwing out the baby with the bath water. For standard CRUD operations, ORM's are the best approach by far. Your hand written CRUD operations gain you nothing but extra work.

Well, Martin Fowler has gone on the record saying that Active Record (the design pattern, of which Ruby's ActiveRecord is one implementation) is not well-suited to sophisticated data models, and he tends to prefer the Data Mapper pattern — which similar to what's being described for Go.
That's not what the OP said, he said the lesson was "that ORMs are fundamentally broken abstractions". Fowler does not believe this, and even if he did, his opinion is certainly not a global lesson as if it were now best practice to consider ORMs fundamentally broken.
expect it is quite hard to write a generic data mapper in go as well. something like Hibernate or Doctrine ORM would be nearly impossible to write with go.i'm not talking about the basic features but advanced features of both frameworks.
that's not the issue here, wether a pattern is good or not is irrelevant.The question is ,is it possible to write something like ActiveRecord and keep its most advanced features in Go. Right now the lack of genericity in the language makes it a no go.
It's definitely possible but it seems like it's too early for any ORM "best practices". Check out gorp (https://github.com/coopernurse/gorp) and beego orm (https://github.com/astaxie/beego/tree/master/orm) for inspiration.

In our case, we had to write a lot of ORM boilerplate.

There are a number of ORM implementations in Go: http://jmoiron.net/blog/golang-orms/

As you said, Go doesn't lend itself to this like some other languages, but it can work.