So right off the bat, I'd like to make it clear that I enjoy the Go programming language. It is simple, yet powerful. I am also very much in favor of programming idiomatic Go, using best practices, and using good design patterns. With that said, I am beginning to wonder if the word "idiomatic" is being misused and abused.
The point of me writing this
I am not against idiomatic Go. In fact, I love it! I love that there is a strong community of developers who want clarity and consistency and readability. I am only writing this to communicate two things I have noticed and hope to caution others about: * Misuse : calling something non-idiomatic Go (inaccurately) to further one's point. * Abuse : calling something non-idiomatic Go (accurately) to further one's point. This may well be valid to do in many, if not most, situations; however, it is my opinion that we can miss out on value or innovation if we dismiss too quick. Idiomatic Go is awesome and something to strive for, but it is not the one and only criterion out there. As a prominent Go developer told me, he prefers to invoke "idiomatic" as a description, not a criticism. I hope we all can do that.
Let me share a short example. I came across a guy who was learning about the testing package and found himself wanting to use an XUnit-style assert. He hadn't discovered some of the 3rd party testing libraries that were out there, so he whipped up a quick function that looked like the following:
func AssertTrue(t *testing.T, value bool, message string)
Upon posting this online, he quickly got this response
Based on your update, that is not idiomatic Go. What you are doing is in essence designing a test extension framework to mirror what you get in the XUnit frameworks. While there is nothing fundamentally wrong, from an engineering perspective, it does raise questions as to the value + cost of maintaining this extension library. Additionally, you are creating an in-house standard that will potentially ruffle feathers. The biggest thing about Go is it is not C or Java or C++ or Python and things should be done the way the language is constructed.
Here is what jumped out at me: 1. "that is not idiomatic Go" 2. "things should be done the way the language is constructed"
Is it really non-idiomatic to build on the language to write assertion helper functions? The Effective Go document, which declares most of Go's idioms, has the term "testing" only one time in the entire document. What exactly makes a helper function non-idiomatic? And if it is non-idiomatic, what makes that bad? And if he chose to use a 3rd-party library, is using a 3rd-party library idiomatic or non-idiomatic? Is that a good or bad thing? Let's come back to these questions in a bit.
I recently read a criticism (from a Martini competitor) of Martini, a prominent web framework, along with a response from Martini's author. The criticism had three parts, the first of which focused on the use of dependency injection as non-idiomatic Go. The author of Martini openly acknowledged that Martini is not idiomatic, while at the same time pointing to the dependency injection of Martini as one of the crowning achievements.
Like with all things in development, there are tradeoff decisions to be made. Martini made decisions and as the author says in his response, "This is not to say that Martini is not well designed, I feel like it is one of my better demonstrations of API design that I’ve had in my career." I applaud him for saying this, but let's come back to this in a bit as well.
Idiomatic is good, we all can agree on that. It is something to strive for, we can all agree on that. However, it appears that calling someone's work non-idiomatic Go is become the new way to say, "wow, you must be new, cuz that is not how you code in Go." The notion that the code would be better suited in an idiomatic way may be true in most cases, but is it always true? I think it is worth exploring a bit more.
Misuse: Are people applying the term non-idiomatic correctly (as in the example of the testing library above)?
Abuse: Are people applying the negative connotation appropriately to a well-designed framework that happens to be not idiomatic Go (as in the martini discussion)?
What does it mean to be idiomatic?
Before either one of these questions can be answered, it is important to get an understanding of the what it means to be idiomatic. I figured I'd google it to get a good clear phrase or definition that everyone would already agree on. To my surprise, that clear definition did not exist. Here are some things that I was able to find on the topic: * "In the search for programming idiomatically, learn the ins and outs of your current language; search for unique constructs." * "your program contains statements that are unique to the language; i.e., you actually use the expressive power (or lack thereof – PHP) of the language in your programs." * "A programming idiom is the usual way to code a task in a specific language." * "how best to implement that solution in a given programming language. A language idiom is the expression of a design pattern in a given language. In this sense, design patterns + idioms = quality programs." * "The mantras surrounding to Go community are simplicity, familiarity with the stdlib, and explicit interactions with the type system. " * What's your definition?
"I don't think that word means what you think it means?" The question here is whether or not the people calling something non-idiomatic are even accurate with their assessment. Let's come back to the testing example brought up at the beginning of this post.
Upon looking for information on idiomatic testing in Go, you will quickly realize there is not a wealth of information. There is the testing package doc, the effective go doc, the language spec doc, the table driven tests page in the wiki, and the faq. None of these docs have good information on idiomatic testing. The biggest mention I've seen for not using testing frameworks comes from the FAQ doc. The relevant section is as follows:
A related point is that testing frameworks tend to develop into mini-languages of their own, with conditionals and controls and printing mechanisms, but Go already has all those capabilities; why recreate them? We'd rather write tests in Go; it's one fewer language to learn and the approach keeps the tests straightforward and easy to understand. If the amount of extra code required to write good errors seems repetitive and overwhelming, the test might work better if table-driven, iterating over a list of inputs and outputs defined in a data structure (Go has excellent support for data structure literals). The work to write a good test and good error messages will then be amortized over many test cases. The standard Go library is full of illustrative examples, such as in the formatting tests for the fmt package.
So now the big question. Is the author of the language declaring this to be idiomatic or just stating his preferences? Although I agree that table-driven tests can be a great tool, it is not built into the language. It simply uses the language constructs.
Similarly, many test frameworks, such as GoConvey and Ginkgo, do not replace, but enhance the existing language facilities for testing. They work to retain compatibility with the language CLI tooling and the language constructs. You can even use a testing framework with a table-driven test. The fact that the author of the language finds these testing frameworks to be like "mini-languages" should not cause the community to reject these frameworks or approaches that the guy in my first example tried.
It should also be noted that the style of writing tests in GoConvey, Ginkgo, and the multitude of "matcher" libraries are "mini-languages" widely known and accepted in several different programming languages. Shouldn't that be considered a good thing? Lastly, use of GoConvey or Ginkgo does not circumvent the language's testing facilities nor the intent of the Go language. Your call: Idiomatic or not?
"Hey noob, if you want to program like that, go back to Ruby!" The question here is not whether or not something is idiomatic, we'll just assume it is not idiomatic. The question here is whether or not it should be automatically considered "bad" or the "wrong way" without any other considerations. I guess in order to accurately answer this, the boundaries and scope of what is and is not idiomatic need to be clearly defined.
In the case where the boundaries are not clearly defined, then I'd say it would be unwise to be dogmatic of the precept that all things non-idiomatic are evil.
In the case where frameworks and dependency injection are outside the boundaries of what is considered idiomatic, why be hostile. Why discard such things like dependency injection or frameworks or any library that abstracts the standard library away or does things a different way? Now, obviously, if a dependency injection approach or a particular framework could be idiomatic, that would probably be preferred. I am simply talking to the cases where the baby is tossed out with the bathwater, where the value of what was created is not recognized and blogs are written with titles such as "Three reasons you should not use Martini."
Recently, as a learning exercise, I wrote a plain old merge sort algorithm for []int. Nothing fancy. Then I began thinking of ways to make it work for other data types. I came up with some nice designs, then even wrote a quick proof of concept. It was after that, that I discovered the sort package. Pretty nice stuff in there. Then I began to wonder, sadly, would I get criticized for creating a straight forward, non-interface based merge sort algorithm? I say sadly because the tone in the community has started to cause me to question all things I write (even as a hobby) whether or not it is written in an appropriately idiomatic way. I suppose the questioning is a good thing, but the way the community responds is not.
What if someone came up with a better sorting design and interface that didn't use the sort package? Is that non-idiomatic and therefore bad? I personally would hate to stifle innovative thinking and box developers in to an idiomatic approach when maybe, just maybe there is another way, a better way.
I applaud the Martini author for stating the following because it implicitly declares being idiomatic is not the only criteria for writing good software:
Martini does not line up with the way the stdlib was designed, and it therefore can never be considered idiomatic. This doesn’t make Martini wrong, it is just not going in the direction that the Go community as a whole is going... It is well designed and has a great community around it. Martini is not going away, and I’m not going to stop supporting Martini.
After taking to twitter to ask some prominent members why they agreed so heartily with the martini criticisms, I was told that "since the author martini agreed with the criticisms, maybe I should go think about it some more." From what I read, the author agreed that Martini is not idiomatic-Go, but he did not agree that the design was bad nor that people should stop using it. It's a shame the tone of the community is so harsh towards anything perceived to be non-idiomatic Go.
I get the impression the Go community is hostile toward frameworks as well. I get the impression that most frameworks are considered not idiomatic by the very nature that it encourages developers to code and depend upon some other facility that will do things on your behalf. I get the impression that libraries and helpers are ok, but frameworks are not. Am I a little close here?
I've seen negative remarks toward Martini and Ginkgo and heard developers ask "why would I need a testing framework when it is built into the language." The point is that the framework enhances, not replaces. Any language, Go included, should provide a great starting point to build upon. Frameworks are not bad, they enhance, if designed well.
In the Java community, there are things like JUnit, Spring or all the Apache libraries that have provided tremendous value to the language. It would have been a huge disservice if people walked around saying not to use those things because it was not "idiomatic Java" and that Java developers should be using the standard libraries as much as possible.
Lastly, a prominent Go developer made this statement about frameworks: "the problem with frameworks is newbies think they're needed before trying anything. Learn our ways first :)." Although I can see what he is trying to say, I still think he is throwing the baby out with the bathwater. He described a problem with newbies, not with frameworks. Well designed frameworks provide value. Some frameworks are so valuable (e.g. Spring in Java), I'd point anyone, including newbies, to use said framework.
A word of caution to the Go community
Don't be like a Home Owners Association (HOA) board. Don't treat the notion of idiomatic Go like the CC&R's of the Go community, where you must give a citation for every perceived violation.
Go developers are just that, developers. Developers are innovative, creative, solve problems, hack, and test the limits of the constructs we are given. A language is a facility, a tool. It is meant to be built upon, extended and enhanced. Don't be like an HOA, writing compliance letters to members who use the wrong color paint, or stores something on their patio that you find unpleasing.
Go is still a young language. Be careful where you get your definition on what is idiomatic Go and be careful on how dogmatic you get on applying that dogmatism. These are the roots of the never ending arguments of the last decade: KDE vs. Gnome, LGPL vs. GPL, vi vs. emacs, and on and on and on.
I am primarily a Java developer (15+ years) and am new to Go (2+ months). I have heard the term "idiomatic" more in the last 2 months of playing with Go and reading up on Go than I have in the past 15 years. I can tell that programming idiomatically is a core value of the Go community and I personally like that. I just don't want to see it get misused or abused.