5 ms·
> Let’s start with a general guideline for programming Go: write Go programs by writing code, not by defining types I find this interesting - I think I typical
by shpongled 5y ago
> Let’s start with a general guideline for programming Go: write Go programs by writing code, not by defining types
I find this interesting - I think I typically do the reverse: I generally start by thinking of my program in terms of types and then write code to perform operations/transformations on those types (obviously this doesn't work 100% of the time).
That being said, I have never written any Go, but I can't imagine I would approach it differently.
- obphuscate 5y agoI generally think type first in Java and most other languages purely by convention - it is just a social and programmatic norm. That being said, Go's conciseness lends itself to creating working code quickly and generally the type system aims to just be "good enough", broadly trying to force you to get working code first and invent the types as they are opportune. This is also why (aside from fear of hurting compilation speed) that generics were only just added after many years; which some people, myself included before I actually used Go and loved it - think is needed to use a language for anything beyond "toy" purposes (you don't actually need generics most of the time). In practice this works out really well (especially since with Go you never need to extend interfaces, you automatically are known to implement an interface implicitly by just possessing the same function signatures an interface possesses), and is liberating and freeing: I don't go down a rabbit hole of thinking I need to support future cases and define AbstractAnimal, AbstractMammal extends AbstractAnimal, Dog extends AbstractMammal. This also highlights the other side benefit - since you aren't thinking what each object's operations are you can use composition and define the traits that a Dog possesses, and lo and behold later, since those trait interfaces are decoupled you don't have to repeat them if you realize Snake can implement Hiss() just like Cat can even though they both might traditionally extend and inherit down orthogonal branches (where you would have to duplicate or do wonky shenanigans like attach it to AbstractAnimal and return UnsupportOperation where not actually implemented). The bottom line is it forces you to not even have to think about YAGNi because you compose only what is needed to accomplish each task on the fly.
- kaba0 5y agoThat’s not much different than just using interfaces/traits though (with the added benefit or hindrance depending on person of Graph::walk may be different than Animal::walk)
- pansa2 5y agoI feel that this hints at a fundamental division between two ways that different programmers approach problems. I’m the opposite to you - I tend to think logic-first. So, for example, when thinking about a parser I’d start by writing code to read tokens. I’ve struggled to follow tutorials that instead start by defining types to represent an AST. Different approaches to problem-solving also lead to different preferences in terms of programming languages. In particular, I’m perfectly happy working in dynamically-typed languages for small-to-medium projects. Many programmers seem to be opposed to dynamic languages on principle - I believe that’s related to thinking types-first.
- exdsq 5y agoHow can you approach a problem with logic before knowing what that logic will manipulate? For example you say you'd start writing code to read tokens but a token is a type
- pansa2 5y ago`Token` isn’t a type that a parser has to define - it comes from the previous stage (the lexer), or could even just be `string`. When writing a parser it’s already defined - so do you start the parser by working with the types you already have, or by immediately defining more types? I’d write a parser by first writing code to open a file (for example) to get a collection of tokens, then loop through them and decide what to do for each one. I’d use those decisions to guide my design of the output types. Others, it seems, start by designing the output types up front and use that to guide the design of the program logic.
- eru 5y agoIn something like Haskell, you often write your parsers via parser combinators. So you wouldn't be writing loops (or their Haskell equivalent) at all.
- eru 5y agoI suspect the difference depends on what your types can provide? So in something like Haskell the types are strong enough that going with a types first approach makes a lot of sense. Often once you have the types laid out, many functions will only have a handful of sensible implementations that are even possible at all. In something as primitive as C or Go (before generics) types don't tell you much at all. So laying them out first doesn't give you much at all. You might make a mental (or physical) note of what you are trying to achieve on what data, and then start coding. In Haskell you could express a lot of the content of that note in the types; but in C and Go many or even most things are done via side-effects, and their type system doesn't track these at all.
- beebmam 5y agoI'd personally rather think at a high level about design before writing software or defining types. But a rough description of the Inputs and Outputs of some new feature/application seems more important to me than writing code.
- SPBS 5y agoImplicitly it means is not to model a program purely through types and how they interact with each other. In general you do start programming by defining domain types (through a combination of structs, slices and maps), but it is up to the programmer to wire up the behaviors between them and not by expressing behaviors through the type system (ML-style functional programming) or by defining type hierarchies to model the real world (Java-style OOP).
- _0w8t 5y agoI think it all depends on the problem. If it is known how and what the code need to do, like transform the input in a particular way, then the data structures will naturally follow from actions. But if actions are not known or too abstract, like show a graph or create an app to calculate taxes, then defining data structures first will be beneficial as it allows to make actions more detailed.
- broose_goose 5y agoI think you’re conflating “domain types” and types. Here, types is an implementation detail that can be abstracted away / refactored after the logic makes it clear you can reuse things and such
- beltsazar 5y agoLinus Torvalds agrees with you: > git actually has a simple design, with stable and reasonably well-documented data structures. In fact, I'm a huge proponent of designing your code around the data, rather than the other way around, and I think it's one of the reasons git has been fairly successful […] I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships.
- masklinn 5y agoThis is also very much the norm for high-performance code, when you reach boundaries the code is often secondary to the data structure or memory layout.
- gnuvince 5y agoI agree with the importance of the memory layout of data structures, but I read the original article a bit differently from you and the person you are replying to. A common approach to programming is to model the problem, almost to anthropomorphize the components of a system. In this style of programming, the organization of data structures isn't about how to lay out bytes in memory, but about a role needed in the resolution of a problem. I almost think of it as having a bunch of little actors that we want to arrange in a certain way in a scene, shout `.action()`, and have the work be done. This is a style of programming that I was really into just a few years ago, but when I compared myself to other programmers that I really looked up too, I realized that they didn't engage in this type of programming theater. Their code _did_ have types, but it was to group data together, not to tell a story; it was very concrete and practical. And time and time again they produced better programs than I did, often in less time than me, and they avoided questions that would plague me for days (e.g., whose responsibility is it to do X?) So what I understood from the article is to avoid creating types upon types upon types to model the conceptual problem, and rather write code (which certainly includes data structures) that handles the data of the problem.
- skybrian 5y ago