5 ms·
Absolutely the opposite. The ability to understand Go code seems roughly constant with regards to codebase size. On teams of enough engineers, especially as th
by sagichmal 7y ago
Absolutely the opposite. The ability to understand Go code seems roughly constant with regards to codebase size.
On teams of enough engineers, especially as those engineers rotate in and out of maintenance roles, richer abstractions tend to obfuscate intent and hurt maintainability more than help it.
- stouset 7y agoI just don’t buy it. We already work at a layer dozens if not more abstractions away from what’s really happening underneath the surface. This is essentially an argument that every layer below is good and justified, but that any additional layer is just too much.
- PeterisP 7y agoFor complex, specialized systems what I'm often seeing is that essentially every decent large system gets split into a de-facto domain specific language (no matter if it's with language features or through some specialized libraries or webservices or whatever API) and the implementation of the business logic in that DSL. And, in general, the implementation of that DSL is something like ten times smaller than the amount of code using that DSL. The maintainability of the code is mostly determined not by how good the underlying language is but how good is that DSL. To take an example that's been widely discussed in HN, let's think about machine learning - the look, structure and maintainability of your code is highly influenced by the choice of your framework/"DSL" e.g. pytorch vs tensorflow1.x vs straight numpy vs Caffe will have major differences despite being in the "same language". And in that regard, the features of the core language matter only in regard of whether they facilitate making a good DSL. Of course, some languages fail because their choices result in the "core DSL" i.e. standard libraries that everybody uses being fragmented and confusing; Go has it quite good IMHO for the standard library; but for every specific domain it also matters if the DSL for that domain is good, whether it's an ORM layer or a OpenGL interface or a deep learning framework or an physics simulation library - whether the language abstractions mean that these DSL's (often being interfaces/wrappers to some third-party code written in another language) are going to be good and convenient, or whether the language structures limit the DSL so it becomes unwieldy to use.
- sagichmal 7y ago> For complex, specialized systems what I'm often seeing is that essentially every decent large system gets split into a de-facto domain specific language Every time I've seen this, it's been a disaster. Custom DSLs for business logic are, 100% of the time, a red flag of a development process gone off the rails. (We may work in different industries.) Go prevents you from doing this at a very low level. This is a huge advantage.
- PeterisP 7y agoIf you're writing a React or Django or Laravel or Rails app, then what you're doing is essentially work within that DSL which is quite different from the underlying Javascript/Python/PHP/Ruby language. The same goes for data analysis frameworks such as Pandas, or deep learning such as Tensorflow or Keras - if you're working in that most of your code and calls are going to be within that API/DSL, not "pure" Python. And I'd definitely consider all of the abovementioned as successes and a good thing - if Go would prevent people from writing their Web-CMS systems in a good Web-CMS framework/DSL, or writing their machine learning systems in a good ML framework/DSL, then that'd be a serious limitation. And it's worth noting that many (all?) of these particular systems were actually initially made as custom DSLs for internal use within a single company - Rails for 37signals/Basecamp, Pandas for AQR Capital Management, Django for Lawrence Journal-World, Tensorflow by Google Brain, etc. They were the exact thing that you describe - a custom DSL invented for the business logic that the particular company needed repeatedly. And they were not a disaster but the right thing to do in their case - mostly because they had the ability to make a somewhat good DSL though in all those cases it was an 'okayish' DSL initially and became good only through years of substantial changes. Yes, for every such case there are many bad internal DSLs. "Not Invented Here" is a common problem. You need to ensure that you're using good DSLs, and good DSLs generally gain wide adoption within that domain instead of every company building their own shoddy DSL. I've seen a bunch of nightmarish financial systems with horrible DSLs. However, even in that case the DSL problem was that this DSL was horrible not that a DSL shouldn't have been used - any fix or rewrite would generally require replacing it with a better DSL/framework/whole-encompassing-structural-API/whatever, instead of sticking to the core programming language (which would just result in another emergent "DSL" of some core libraries/classes, which would be lousy compared to something you intentionally design to be usable).
- asdkhadsj 7y agoHaving been a professional Go programmer for ~5 years prior, now working in Rust full time, I actually take issue with Go for large code bases[1]. For me it's mainly due to the lack of generics and helper tools that naturally spawn from generics. Go's solution to having less LOC inside a function is _only_ to create helper methods/funcs. These helpers are bound to specific data structures and often are only applicable to that one use case in that one method that they came from. Your ability to make that helper function apply to more code depends heavily on what data structures are being used. This form of non-generic bloat was far worse for me than the classic examples of `Fooi32()` and `FooString()`. The latter I don't mind at all. Rust aids this process to me by, well, having generics. Converting one data structure into another becomes a breeze, and converting a Slice of those data structures is just as easy. I'll be really interested to see how Go feels once generics make it in - though I suspect I'll stick with more explicit memory management. Speaking of memory management, it would be nice if Go had a way to intelligently indicate which structures are safe for concurrent use and which aren't. I've found in Rust that the explicit nature of the concurrent safety is not something I knew I wanted in Go. I know Go will not likely ever match Rust's safety, but if it at least indicated that something was an thread-unsafe implementation that would be golden. [1] edit: Oh, and there is a disclaimer in this that the projects I'm involved in seem to heavily rely on managing several data structures in repeated ways. Aka, very generic friendly.. so not having generics made my projects extra painful. This is not likely the norm.
- apta 7y ago> actually take issue with Go for large code bases This has been my experience as well. People just parrot what the golang authors say about it being a language suites for "large scale development", whatever that means, without providing anything to back it up. Just because they said it was must be it's true? In practical experience, it's a verbose, clunky, and awkward language to use for any non-trivial code bases.
- marcosdumay 7y agoYour disclaimer isn't really needed. Good generics support leads to good standard libraries, and using standard libraries is the norm. Rust is still too young to take advantage of this, but in due time it will.
- coldtea 7y ago>Absolutely the opposite. The ability to understand Go code seems roughly constant with regards to codebase size. That's what some Go proponents say, not necessarily reality, and there's no study about this, just hearsay. I find Go hurts readability for larger programs because it prevents many structural abstractions that make code more clear and concise (as opposed to mere fancy "clever" code, which it still allows), and because it forces too much boilerplace (error handling, no generics, etc). Every large projects contains re-implementations of the same things (from data structures to algorithms, to parallel processing handling) that could have been done once and re-used forever with generics and a little more power.
- pjmlp 7y agoAnd then there is the copy-paste as means to avoid additional package dependencies.