- First, I want to say that I realize many of you are not Go developers. While I write a lot about Go, my mailing list isn't exclusively about Go and that is intentional.
- This is a story about an experience I had with Golang, but I think it is worth reading regardless of what language you use. Not only does it explain how something works in Go, but it also helps illustrate why I love Go as much as I do, and just one of many reasons why I think you should try it out.
- So without further ado...
- When I first started writing Go code I was working on a relatively simple web application backed by an SQL database, so the first thing I did was Google "golang sql" which lead me to to the database/sql package.
- While reading those docs I notice this line in particular. The sql package must be used in conjunction with a database driver. See https://golang.org/s/sqldrivers for a list of drivers.
- What? I need something else to go along with the database/sql package?
- "No worries", I thought to myself. "I'll just follow the link and use one of the drivers."
- So I did just that. I clicked the link, found the driver I needed, installed it with go get and then started looking for some code samples to get started. After a few minutes I ran into this little beauty.
- import (
- "database/sql"
- _ "github.com/lib/pq"
- )
- At this point I stopped typing and just stared for a minute. Why the hell am I including a package that doesn't get used? What purpose could that possibly solve? I thought Ruby on Rails had an exclusive license on being magical.
- After that I kinda just let it go. I didn't really need to understand what was going on for my code to work, so I just let it be.
- Everything was jolly until I recently started writing the book Web Development with Go; I was working on a chapter that introduces using the database/sql package and thought to myself, "How can I possibly expect every reader to just let this go? Surely some of them will be asking questions, and others will forget about this unused import. I need to address it." So that is what I am doing today. Addressing the question on many developers mind when they start using SQL with Go.
- Why am I including a package that never gets used in my code?
- Digging into the database/sql/driver package
- My first stop in understanding this was the database/sql package, which quickly lead me to the database/sql/driver package.
- Apparently this mystery had something to do with implementing this package, so it sounded like a sane place to start.
- If you look through the database/sql/driver package you will quickly notice that there really isn't much functional code there. Instead we have a large variety of interfaces being declared, which makes sense.
- Each database would need to implement each of these interfaces a little differently, so it makes sense to provide a common interface and that each SQL variant can implement, but nothing here seems to suggest how we are actually telling our program about that driver we imported, so I headed back to the database/sql package.
- Aha! I found it!
- And then I saw it. The second function listed in the package answered all of my questions.Register(name string, driver driver.Driver) needed to be called to tell the database/sql package about a driver.
- After that all I needed was a simple search on the github.com/lib/pq package to verify my suspicions.
- The reason we don't actually need to do anything with an sql driver is because the init()function gets run before our own main() function ever gets run. This means means that before our code ever runs the lib/pq package gets to register an sql driver that our code then uses, regardless of whether or not we directly interact with the lib/pq package.
- That is why we need to pass a driver name as the first argument of the sql.Open() function.
- Nothing magic is happening; Instead it is just looking up the driver from an internal map that stores all registered drivers along with their name.
- And this is why I love Go
- I know this isn't revolutionary by any means, but what really inspires me about this personal story is just how easy it is to navigate code written in Go.
- It took me less than 15 minutes of digging through both standard libraries and third party packages to find out what was going on and to truly understand what was happening.
- That is unheard of in most other languages. I have dug through countless Ruby and JavaScript libraries trying to debug issues or figure out why something was behaving weirdly only to jump through 10 layers of abstraction, monkey patching, or whatever else. If I am lucky I eventually find what I was looking for, but I end up just giving up more often than I care to admit.
- It simply isn't easy to dig through a complicated library or application that you didn't write in most other languages, but in Go it truly is.
Stikked
