I'm reminded of the TempleOS guy quote "An idiot admires complexity, if you build something so clusterf***ed that no one can understand whats going on, they're going to think you're a god"
Possibly off topic, but I love talking about Terry and TempleOS. I admire Terry's attempt with TempleOS. It seems most people really didn't understand what he was after (i.e. a Commodore 64 experience on modern hardware.) I just don't admire Terry as a person: i.e. a racist, homophobic, misogynist suffering psychological disorders.
@@curio78 Nobody is right or wrong on this one, because it's a philosophical semantics argument. There are just as many arguments structs could be considered objects as arguments arguing they are not. It's like trying to argue whether or not your shadow is a tangible thing. Endless debate ensues with no possibility of conclusion.
Really smart code is elegant to purpose/domain not complex. People get confused about that. They get afraid to use any but the most boring idioms of a language even if that means way more boring code to wade through that takes those that deal with further from the actual problem domain being addressed. But hey, everyone knows what each line means.
@@GK-we4co I needed that. Something that drives me absolutely crazy is how Go keeps talking highly of its brand new clever ways of doing things. The issue is that they completely miss the mark every single time. Error handling is a great example of that.
As a backend developer that is migrating a not so insignificant body of code from C++ to Go, I can say that Go is a Godsend. When we code in C++ we are constantly second guessing ourselves and feel like we are trying to avoid mines in a minefield. We are far more productive and have progressed much faster in Go.
Exactly. Overengineering is the absolute worst thing you can do for any project. The reason why go is a popular language and very popular specifically with startups is because it is very easy to get started with. There's nothing wrong with that and to say otherwise it's just idiotic.
The counterpoint to that is that you do want your core libraries to export an API that allows your code to be both short and not clever. That is a lot harder to do if the library code is not allowed to do clever things. No generics? Then all of a sudden, libraries can't export a good BTree data structure of any fixed type. No metaprogramming? Enjoy dealing with ORMs that use a DSL that compiles to Go instead of just being implemented in Go, which is literally much worse than any in-language trick a library could have used up to and including advanced macro usage. The flipside of having a dumb language is that your libraries become much more horrible. Limiting application code to be dumb is good practice. Limiting libraries to be dumb makes it hard to make the application code dumb. You will end up writing code that no one wants to read instead of code that is basically a configuration file.
@@TheMrKeksLp if that was the case java wouldn't have been so famous for so many years. I get your point, especially nowadays when it seems github copilot will be the next best programmer, but you can have simple and good at the same time, maybe not python levels of simple but Go is in a good spot i think
What I like about Go: 1. It's a sane balance of very familiar paradigms, but it doesn't go too hard on any of them. So you've got OOP patterns, composition, procedures, first class functions, etc. It takes a lot of what's good about these things without borrowing too much to become dangerous. 2. It eliminates a lot of cognitive burdens by not allowing you to get too clever. Abstractions need to stay fairly simple. The type system lends itself well to creating interfaces that are clear, concise, and easy to reuse, extend, etc. 3. The standard library is excellent, consistent, and serves as a great reference for how to do things in your own code. 4. Super portable, snappy feedback loop, standardized tooling, makes for super easy development and deployment experiences. What I don't like about Go: 1. It isn't intuitive for a lot of developers, and they reach for familiar patterns that don't quite work in Go. They end up feeling defeated and frustrated. I've seen this across all experience ranges. I've even seen a team drop Go for Rust in a case where Go made so much sense, and instead they punished themselves with Rust for months because... I don't know, Rust is better? I mean, it's awesome, but sometimes you just need a dumb API or CLI and Go will let you iterate on it super fast. And let's not kid ourselves, half the stuff we build will get thrown out or deprecated; making it 1000% bug-proof and memory safe and so on isn't important or necessary when you can get like 95% of the way there with Go. If something proves itself, go ahead and write it in something else, but don't cheese-grate your brains over it. 2. Still don't like error handling 3. I'd be 10x happier with some sort of expressive pattern matching syntax 4. The gopher
"1. It isn't intuitive for a lot of developers, and they reach for familiar patterns that don't quite work in Go." The counter-crux of that article, got to choose the right tool and then not try to use like another tool. Banging a single nail with a wrench can work with a heavy wrench, but really get a hammer when building a house. Article complains GO is "simple" while wishing for a different feature set that already exists in another tool that is literally shown in the article.
I really like that I can just look at a foreign Go module and grok what's going on pretty quickly, because there are barely any fancy language constructs to be aware of. I'm decently proficient in Rust, but looking at libraries, I often struggle to figure out what's going on because of macro invocations, weird Trait hacks, or unsafe code.
Don't get me wrong. I know how convoluted and rapidly evolving Rust and C++ are, but it doesn't have to be one way or the other. The GO team took the concept of api stability too seriously which lead to the language becoming stagnant. Just look at how long it took for them to support generics. How were Docker and K8s developed without this simple feature is beyond me. And that's just one aspect of the language. The others are the useless and obnoxious code formatting rules and the terrible module system. They could've done something about those things but nothing. God, I hate this language so much.
Readability is important to teams, users and the future self. It's hilariously sad how devs on the slope of the bell curve tend to be oblivious to Literate Programming being smart and want dumb inscrutability is as the "smart" thing.
@@parlor3115 C++ may be rapidly evolving, but it's a lot like vomiting into a bucket that hasn't been emptied in a while. It's a big stew of unpleasantness. It's like the goal is to make every feature clunky and hard to use, but at least you can say it's there.
@@parlor3115 Just look at how long it took for them to support generics. in almost every case when you think generics is the solution, it will be the worst solution. You basically throws type safety away from your type safe language to do some fancy pants things, hoping someone that will use it later making sure it has the right characteristic to be used in the generics that we create. I come from JVM languages (kotlin, java) which is a language that in love with generics, and I very much use it extensively. But I have program go for 2 years now and does not miss it at all.
@@SleepyHarryZzz why is red flag? can you tell me? for my opinion, we can discuss and talk to him to get attractive information or sharing the knowledge right? I think it's good
@@ZephrymWOW I see, that people is not smart, just full of ego, it's not smart people, the discussion is making the decissons what is best. Don't generalize people like that, it's not smart or clever people, just ego
Just for those who aren’t familiar, D has a Uniform Function Call Syntax system. You can suffix call a function on an object and it rewrites it so that it calls the function and passes the object as the first argument. Eg. A.writeln is equivalent to writeln(A)
@@some1and297 I mean, in theory, an attribute is a noun and a function is a verb, right? Like, if you see A.readText, you expect that to be a function call because it has a verb in it. But A.textContent is likely to be an attribute because it’s all nouns. I don’t really see a problem with it.
@@some1and297 It makes reading the code easier though. Take the example from the Video: [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln You could write this as writeln(reduce!((a, b) => a + b)([1, 2, 3, 4, 5])) When reading this, you usually read from left to right. So you read "writeln", ok, we are printing something, what are we printing? "reduce", ok, looks like we are printing the result from condensing an array by adding the elements, what is that array? Oh, it's just the numbers from 1 to 5, ok. Most programmers are used to that, because that is how it is in most languages, but for the other way around you don't need to keep that much context in your head. You read it in the same order it is executed in. You take an array with the numbers from 1 to 5, condense it by adding them up, write the result. But as always, tools can be used badly. For example writeln can take multiple arguments to print multiple things. So one could write "hello ".writeln("world"); to print "hello world". Just because you can use a tool doesn't mean you should always use it.
I'm a C programmer and ended up using Go for my webserver, I'm happy that it's simple to learn and use for this purpose and fast in production since it's a compiled language
@@vaisakh_km my main open source project is about 20k lines of code in C99 I can't post about it or my comment will be deleted, but I also do contracting for companies I am an auto-didact
IMO, "clever" code in modern languages is often less efficient from a big-picture perspective. It's often slower than easier-to-read code, and it can add a financial cost in terms of the extra time required by non-original authors to understand and debug it. (EDIT: I used to have to decipher FORTRAN, which HAD to be "clever" because of system resource constraints.)
Most "clever" programmers ignore the cost you are mentioning. But some want that, if only they can understand the code, then they have to be in the company forever or make the company some bleeding of money through their code.
i think it is difficult to generalize here. i have seen some programmers who sincerely have a lack of trying to understand programs from a systems perspective. they try to make things easy in every regard, but i have seen how that complicates things in the long run. sometimes you just need some complex and clever code at the right place, to make life easier for everything else. prime has taught me well about the importance of performance and given me ideas how to achieve it, so i get that using loops instead of functional programming is better in some languages (hi @older javascript versions), but clever abstractions can be so powerful, that it would just make you a lot more unproductive if you did not use them and make life a lot harder (also regarding bugs). in such cases performance really has to be an important thing, if i would consider giving up an elegant abstraction. so i personally prefer the language that allows such powerfull abstractions, because that allows me to solve problems better. but sure with great power comes great responsibility and i am more of a guy that sees that as a challenge. i feel like you constrain yourself too much, if you don't take powerfull abstractions into consideration just because it is difficult to understand when to use them correctly. and you will never be able to solve certain complex problems without them imo.
I would really challenge people who think they write "easy to read" code to start regularly showing their code to people who are not working on the same project or ideally not even with the same technology. I think you will find out that the biggest factor in quickly understanding code is familiarity with the project and the problems. This can't really be acquired through any other means than just reading the code. And usually the more code there is to read, the longer it takes to familiarize yourself with it. I think this is how the "DRY" concept started and how it grew to it's absurd conclusions. I definitely don't think you should abstract everything, but it really does help, when you don't have to go through 30 dialog components and check if each one really does the same thing.
What is "clever code"? Are we saying that 100 lines of readable code is better than 10 lines of code that accomplishes the same and runs faster, and who is doing the "reading"?. I think if the 10-line-code followed conventions then its preferred, for me "clever code" is acceptable as long as there are good merits, and its not superficially clever when in fact the code is poorly architected and littered with magic. As for the video's comparison, lets stop the bias, that D code is by far more elegant than Go, and I'm sure it will be even more evident in a large application.
One thing about Go being so simple is that you can dig into the source code of any library (especially the standard lib) and understand what code is running under the hood super easily. I had to look under the hood of the Azure Blob Storage SDK in Go today and could see exactly why it didn't like a parameter I was giving it. I also dug into the std lib to see why a stream I was building was EOFing early etc. It's so powerful to read these libs made by way smarter people than I and understand exactly what is getting run on my computer, such a blessing.
I'd say that it's more advanced to have a more primitive language, not dumbing things down. You need features designed in such a way that you could implement them out of more primitive functions. Using high-level features with no idea how it's implemented isn't "advanced".
Precisely why I fell in love with Go. I've not been able to do this with any other language I've worked with. I've always dreaded trying to sniff through people's code and have banged my head against the desk in confusion many times. Didn't happen when I did this with GO....
@@unicodefox yeah except that it usually takes you to a definition file so you have to find it yourself and the actual code will be made up of crazy shorthand for everything. Go has only a single way to do things so once you learn it you can read all of it easily.
I checked once a Go library. In a single file of about 2000 lines, it was declaring an empty object (or "structure", whatever) and then it was full of receiver methods for that empty object. How is that supposed to be easily readable? I only understood it was designed like that after I scanned the whole 2000 lines to actually see every function was a receiver method, whereas in pretty much every other language you declare a class and put the methods in (a class doesn't need to have any fields), and what I do in those cases is just follow the closing bracket and I would know all these 2000 lines are methods within that class cause they are within the brackets. But in Golang they are on the same level. They could literally be half of them just functions. Very bad design. Very hard to read.
I've never used Go (I'm a beginner), but I have used Lua, another simple language. I love that I can have Lua's complete syntax memorized after a few days of work, I like that there are 0 surprises and everything works exactly how you'd expect. If I want to do something clever, I can use metatables. It was cool implementing my own type system and it helped me understand how OOP works.
As someone who had to deal with a large (500k+ loc) project written in Go, here's my perspective: Go is great, if you were going to write it in C you are going to feel right at home along with a few more conveniences. But there is a limit to the size/complexity that a project can grow to in Go before becoming a horrible mess. Of course every language has this limit, but it seems that Go's ceiling is much lower than other languages due to how it amplifies every single line from a modern language (e.g. Rust) to ~10 lines. It is very good for async programming though. So if all you do is reply to server request with relatively simple internal logic, then Go is perfect.
This sort of mimics my experience working on one of the largest golang code bases on the planet. Sure you can use golang for smallish programs that you would have written in Python or Ruby, but you get types. But the anemic design of the language leaves much to be desired when you work on large programs. While the "uncolored" async approach they're using is better than the typical async/await approach, it's still half baked. The `go` keyword does not handle the return type of the function being run, so you have to resort to hacks like passing in a channel then selecting on it. The Java folks have the right idea with Project Loom (virtual threads). They integrate very nicely with Futures/CompletableFutures, so you don't have to use hacks to pass channels and wait on them. They are also building a structured concurrency API to nicely handle timeouts and cancellations, unlike the hacky golang way of having to pass context.Context to all async functions, thereby reverting to a colored approach.
@@guillemgarcia3630, unfortunately not, my Java and typescript experience is fairly limited. I have, however, worked on C++ projects that are an order of magnitude larger, but felt much more cohesive. Obviously this is anecdotal, but in C++ (and I would imagine other expressive languages) the ability to express your ideas is much more stratified, while on Go and C it feels like you must first translate those ideas to the most basic constructs. For example if I want to find an element in a container in C++ I can use std::find_if, and it'll work for any container. In Go you must write a loop, and if your container is anything other than a slice or map, prepare for pain. Of course find_if is only the most trivial example, but this applies to basically any algorithm. Another famous example is following and mapping one collection of items to another, in rust you simply do in.iter().filter(...).map(...).collect(), in go this one liner expands to about 5 lines, meaning every time you perform such an operation you need to parse the loop and understand what it does instead of the names of the operations literally spelling out what's going on. And of course seeing such things once or twice is simple, but when dealing with a huge code base and trying to follow the logic, this inefficiency of expression and communication ends up eating a significant amount of brain cycles.
@@Afief Well said, this is one example of what I meant in my other comment where I said that a simplistic (naive) language (golang) pushes complexity onto the user instead of being able to express it cleanly and concisely.
@@zhamed9587 I fully agree. Not being able to express the things we want to express in the language means we copy pieces of logic all over the place that should have been encapsulated and standardized. Map, filter, reduce...etc are just the most basic and obvious candidates.
Yeah, the type of programmer that writes code as complicated as possible, to flex how "smart" they are, then call you dumb if you do not understand their code maze
@@rj7250a No one is saying you have to write complex code. However, the language needs to support some complex constructs because reality is complex, and there is no getting away from a base level of complexity for many systems. By making the language anemic and dumb, the golang authors simply pushed the burden onto the programmer and the code, resulting in messy verbose spaghetti code bases that take so many lines to describe something that would have taken half or less code to model in a good language like Java or C#.
@@rj7250a fr and let's be honest the guy who wrote the article probably sucks too & that's why he's writing articles and not actually coding something.
@@mythbuster6126 I had a harder time making sense of the tinygrad llama example than kubernetes but that's just me. Although I didn't go through all of kubernetes only a few source files.
The .writeln stuff is what he was describing as "alternate function call syntax", also known as uniform function call syntax in C++ lands (where people have been trying for years to put it into the language, without success). Essentially you get to call non-member functions with the same syntax as member functions, which lets you use post-fix notation so that the code reads in the order of execution: first I take this list, then I join, then write, where the usual order would have you read the same operations from the inside out.
@@ko-Daegu Because the majority of people who watch prime know how to program the equivalent of someone who has taken 2 CS classes or less. But, Rust all the way... Which is fine of course, but it's funny seeing people have completely nonsense strong opinions. At least have nonsense weak opinions!
@@derschutz4737When I first heard about Rust memory safety features, I thought, I gotta learn this language. Then I looked at some production Rust code and thought, nah, I’m good. Zig looks promising as a replacement for C/C++.
I'm consciously trying to migrate myself from being primarily a C++/Python programmer (the former being my job) to a Rust/Go programmer and honestly the contrast is so stark. My seeming inability to figure out package management in Go aside, once I get going, its really really easy to write code I'm happy with in Go, that I know behaves the way I expect. Rust on the other hand it feels like I'm falling from one rabbit hole into another just to get beyond the basics (I'm not knocking Rust in any way here -- but its a 'commitment' language like Java or C++). Take it with a grain of salt as I'm still a pretty junior dev -- but I find that anything that helps me in six months understand what the hell me today was thinking is a massive win. The programs I've had the least BS maintaining were the ones where I didn't try to be cute or clever, where I prioritized readability and simplicity of the design over everything else. At least for me, your always dumber looking at your code down the road. Sometimes it pays to throw future you a bone.
Regarding D and the `writeln` example you mentioned, I think that is D's "uniform function call" syntax, which allows you to express a normal functional call using method call -style syntax. It is a nice feature of the language. IIRC, the "bang" syntax indicates a template instance, in this case calling a templatized function. D is a really nice language but much of the mindshare went to Go and Rust -- the former likely because of the simpler programming model that the author is complaining about and the latter because D's standard library largely depends on garbage collection, which I think made it less attractive for D's original target audience. Andrei Alexandrescu, one of the big D contributors, had a really interesting post on Quora about this a while back, which has unfortunately been deleted.
What look like methods are indeed just function calls with the first argument being the thing that comes before in the chain, so you can chain function calls as if they were methods. It makes for incredibly nice and straight forward code overall. D is excellent, but this blog post did nothing to sell it properly. Go doesn't need to be D, though, and I don't get why people are so offended by its popularity. Most popular languages are shit, honestly, and Go is preferable to most of the other ones for a good chunk of work.
@@vuongnh0607l It pretty much is the pipe operator. C++20 ranges accomplish more or less the same thing using a literal | symbol (only it uses template magic instead of a language feature).
You shouldn't need to have a PhD to understand what pieces of code are doing. That's why I love Odin/Golang/Zig and how they spell things out without NEEDING an LSP.
But if others are NOT confusedly bamboozled by your inscrutable arcana then how will you make sure others know how your so much smarter than them? ❓🤔🤡 /s
@@TheNewton Because it's actually rather simple. "Inscrutable arcana" is rather 'clever' but it's just a matter of understanding each others coding styles. I have a pretty good idea of your style since it's the usual way of doing things, which is fine, but I can pretty easily teach you how to read mine if you're a good learner.
Good point on TypeScript, I love what you can do with the type system, but it’s more of a foot cannon than a foot gun. If you hit a weird edge case that the TypeScript devs didn’t think of you’ll blow off your whole lower body and have to start over.
I was literally talking to a colleague today about how DRY is too confining in many cases. I'd rather repeat a function than create weird logical statements to have the function do multiple things.
If you have multiple signatures for the same method its probably worth a refactor... nowhere near as bad as multiple inheritance but yeah not ideal and I see juniors going ape with DRY all the time
The quote is right, but Go definitely doesn’t fulfill this definition. Do simple as possible, but not simpler. The article is right, just there could be better examples.
24:00 In Dijkstra's wise and eternal words: « The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague. »
What I hate about many languages (but go especially) is the inability to discern optional/fallible values and sum types in general. After using Rusts Option/Result and enums, I just notice how terrible writing other code is. Go makes this even worse by just returning (value, error) instead of Result. And implicit nullability is also terrible but go also makes some decisions like representing "missing" strings as empty strings. Struct fields in go are also zero-initialized by default, so forgetting to set a field yields a bunch of terrible runtime problems. I like simplicity and have a bunch of hope for zig for example because it is still kept simple without making so many terrible decisions.
This is something I see all the time sentiment-wise with folks who are outside, and in this case inside, the tech world: the idea that Google hires the best and the brightest. For unrelated reasons this annoys me, because you don't really know one's capabilities or motivation to work on a project until you have them. You can vet that they know what they're talking about, but only so far. This mindset creates a world where we adopt the way business looks at us, and make it our point of view, rather than advocating for ourselves and our capabilities. Even if it's just advocating for where we're at and that we're getting better, it should be the default in the face of businesses that want to take you for what you're worth and then dump you when they feel like it's good for their bottom line.
I mean you can use proxies that predict job performance; research is pretty clear that job performance can at least on an aggregate scale be predicted reasonably well. Google’s hiring bar is not what it was in 2007, but it’s still very high, especially for its top teams.
Yeah, I don't doubt those big companies have geniuses working for them, but most people are just average. Also you will have many great devs who will never works for those companies because their hiring process sucks and they just don't want to have to put up with it.
Honestly from my experience the only really "hard" language used in large escale is C++, people like to act like java is hard, but it isnt, is just over verbose and annoying. All the other mainstream languages out there are pretty easy
I think it depends on the ROI of clever, which largely depends on how bright the dev is. If you understand "clever" it can save you tons of boilerplate and allow for very terse, clear code. But if your project is long lived and you have rotating crew of 'commodity' devs you really need to consider your LCD. The damage a 'good' dev leaves behind when a company typically hires clowns is immense. The design will be compromised out of ignorance and words like 'spaghetti' are all but certain.
You are amazing. I love to watch you before sleep, in transport, while eating, and literally all the time. Thanks for providing this amazing new type of content
If I remember right, D has UFCS which means you can do things like expression.writeln and expression gets passed to the writeln function as the first argument. I've always thought that was kind of interesting, but I didn't really think about how non-obvious it is what's happening here
Has Prime ever read Amos' blog article "I want off Mr. Golang's Wild Ride"? That article contains much more compelling reasons for potentially avoiding Go 😂
i'm a golang dev and have used many other languages before, C PHP Java JS C++ Python and more, but Golang is by far my favorite language. I've been writting real time concurrent multichanned subroutines websockets and Doing that with anything else than Golang would've been hell. I wonder how you can make a point by giving an I/O example that any language can easly handle if you don't go in depth of the strengths and weaknesses of the language/runtime ! Go is a MASTERPIECE ! Kindly, the french tourist
I would have used Go for my new project, because of the simplicity and fast compile and run test cycles, if it had support for extension methods. So I ended up going with Dart instead. Dart is also simple like Go, but not quite as simple, it has some of the things Go is missing without getting too crazy. It also can compile to and run on many different platforms, and has a fast compile and run test cycle like go. Dart has turned into, basically, a modern, better designed Java/JVM that can also compile to JavaScript. With Dart, the compiled executables have a small Dart VM inside them, so it doesn't put the burden of runtime environment/version on the user like the JVM does.
The original Go pitch by Google was basically, they wanted to make a sweatshop to program boring web services in massive numbers. So Go was to be so simple you can hire kind of "unskilled labor". But yes I don't like super expressive code.
My main complaint about Go last time I tried it is that the GC is horrible for long-running processes because it does not defragment memory, so trying to run something that allocates memory frequently longer than a day will usually lead to it crashing. Which is the reason why go programmers ended up pushing docker and Kubernetes on us so that they could just automatically reboot their unstable programs. If go just had some equivalent of Rust's Send/Sync traits or some restriction on sharing mutable data in channels, they could refcount all data that is shared between goroutines like how Erlang/Elixir handle shared state because immutable structures cannot have reference cycles. And when you have that you can have the simplest stop the world defragmenting GC applied per goroutine, and still be real time because other processes can take over while one process is GCing. In my opinion the fact that the go runtime frequently crashes unless you are extremely paranoid about heap allocations is the one thing that makes it go from a potentially amazing language to a mid to low tier one that you use primarily to fill a gap if your coworkers don't know any other language that compiles to a native executable.
"why go programmers ended up pushing docker and Kubernetes on us so that they could just automatically reboot their unstable programs." That is an interesting take, dockerGOKubernetes as a self-fulling end-to-end bug-as-a-feature solution feature-set.
Not really. Java is much more superior on almost every aspect. I used golang in large programs before at a well known company, and it sucked big time, caused many issues. It is not a good fit for large programs, very poor modeling capability. People who say these things about Java usually don't haven't been keeping up. For a long time now, you can pass methods as parameters in Java, and you have streams (something that golang lacks). Now, you have records, sealed types, pattern matching, virtual threads (better than golang) and many more cool features coming like string interpolation, all of which golang lacks.
@@zhamed9587 I’m baffled. Virtual threads are not in improvement over platform threads, but just a process for how the jdk manages these threads. In some cases the binding of these threads has performance penalties, but in general they are pretty performant. So? Both languages have access to concurrency across cores, and javas is not always superior. And go not having pattern matching and string interpolation; what is this parallel universe you come from?
So the issue is that people can only hold about 7 things in their working memory. Go being too simple will force you to write alot of if statements. Each if statement will raise the cyclomatic complexity, which will make it harder to mentally parse. Each time you read code, you must place it in your short term memory and run a mental emulation of it. If there is too many moving parts, then you must commit the other parts to long term memory, which impedes productivity. In the file output code example, it has a cyclomatic complexity of 4, which for this might be fine, but imagine adding features to it. You will only have room for 2 or 3 more if or for loops until it is too much to mentally parse. That is why we extract out to functions to reduce complexity and increase readability (over straight imperative). On top of that, instead of writing a million defensive coding lines at the start of each function, it would be more optimal to have some object schema that can be used to validate incoming data in a function. This way you can lower your cyclomatic complexity while maintaining code correctness. This approach is called "Data Oriented" programming.
Been doing golang in my free time for the past few months. Learned a ton, I thought it was just a newer php language but absolutely loved the single exe compared to my starter language C#. But because I really really want to get into graphics programming I started learning C++ and OpenGL. I was not expecting to need a build system 😅 I thought compilers just did that 😅 pain.
@@nickgennady Bro I wanted to comment C too. I'm just getting started on graphics programming, I learned a little bit of c++ but it's not for me. Too much oop baggage. Advanced pointer usage is hard enough, I'm not about to add oop to it.
@@codegambit2507 Yha OOP sucks. I was told it was everything in college. I spent years trying to write OOP and not be spaghetti code. In the end I had no luck. I found out about DOTS in Unity and I loved it. Now I do procedural code with data orientated design. Good call. OpenGL is hard enough and adding OOP would be nightmare
Go gives you a feature rich library like Java/C# without the problems of the JVM and the Microsoftness of C# and the performance of compiled languages.
15:00 "I really don't get this writeln at the end" Not sure if you heard about it after, but in D that's UFCS, or Universal Function Call Syntax. In a few words, it means that a function with signature e.g. fn(T) -> U can be written with dot notation after some T. So writeln("some string") and "some string".writeln are the same thing. And since writeln can take in any type...
I could almost accept it if it were .writeln() instead of just .writeln (so that the syntax is similar to a method rather than looking like it's an attribute).. but even then, I feel like it opens a bag of worms where you constantly have to worry about whether any functions or methods you create have the same name as a different function/method somewhere else which would make it very easy to misread what the code is doing. There's not enough of a clear upside to it to me to want to create that kind of ambiguity.
I write Go, get shit done w/o headaches, startup doing great and making a lot of money, I go home early and play with the wife and kids. I can't wait for AI to write everything for me so I can just focus on the product. The author can keep his smart languages.
24:13 some smart ass had a python one liner in our code which did the following , accept array , map reduce over the array, filter the array with a ternary using an inline key lambda call over multiple subelements and used this as an lambda so it could be called functionally anywhere it could be imported . That smart ass was me
As someone who daily drives Golang, the biggest problem of go is the lack of standardized well-known apis. I understand that the Go team wants it simple so they didn't put in any higher level feature that many languages have. list manipulations is a big one. I personally think these features are standardized in many languages for a reason. I've seen so many different and independent attempts in our codebase to accomplish what a list api would do either through the use of an external lib or haphazard adhoc solutions. The thing is, if you added your solution or a lib to the codebase, you must advocate it within the team so that others won't end up implement it again and again. it's also not guaranteed that your implementation would meet others' needs, resulting others adding their adhoc impl on top of your impl that will almost certainly be a non-congruent, hard to understand hot mess.
The don't-repeat-yourself-principle doesn't mean you must never repeat yourself. It means, if you're doing the exact same thing, with almost identical code, you combine it.
I really just call it a guideline. Like SOLID principe and all those ideas. I just look at those as concepts to be aware of, but never as laws. Most important is always to think yourself and make your own great decisions. Engineering things is all about making trait offs. And this includes software programming.
The meme, when I was young in the 80’s; new programmers write simple code (ala GO style). As they get more experienced, their code become more and more complicated, until one day they reach god level and they go back to writing simple code. I don’t understand these programmers who feel everything should be done in one line of code. I like readable code. This is also the reason I put the opening { on a new line and have plenty of white space. It’s just easier to read than a wall of text.
Ultimately there is no language where developers are not expected to be smart. The writer of this article just implies not repeating yourself and making abstractions for the ease of development is The Only Way to be smart. And while that can be very smart, there are also other avenues one can be smart in. For example provable safety, or good performance. Go is optimised for that kind of smartness. That’s why the testing is build in, and why dependencies are frozen by default to protect against breaking changes. You can write go like every other language, and you can write most languages with the same mentality as go. But you probably have better time when choosing the language that is designed around your needs. To get a perspective why simplification at the cost of verbosity could be desirable, consider a world where everything was written in lisp.
Yea. C# was making a delete method that would take three connected entities in SQL and remove them completely in order. It worked until I tried testing the method on entity 1 and 2 without the 2 being connected to entity 3 and ended up clearing the entire table. Luckily I have done dump s**t before and I made a backup before testing.
A smart programmer is not a programmer who writes clever code on a regular basis. A smart programmer is a programmer who writes SIMPLE code!!! Making complex things simple - this is called smart. This article is written by a dilettante or a junior programmer that likes clever code thinking that it makes him smarter.
I always strive to write simple code, but sometimes the complexity of reality comes in and forces you to write more complex solutions. That's just how it is. It always depends on the context: small projects vs big projects, need for parallelism, and much more can influence how easy it is to write simple code and when you may need to resort to more complex solutions. So I would say: Clever programmers write code in a way that fits the context of the project, and that may not always be simple code.
@@DevVader Of course you can't always write simple code. I write clever code too. But only when I have to. And when I do so I write a ton of comments explaining that complexity. In "simple" parts of code I don't use comments at all and try to make my code more readable. I think this is the way.
Been writing a Go backend for an indie game. It's great. I really like the json marshall/unmarshall system. Ive written a handful of powerful functions and systems to create a few abstractions that allow us to write new API endpoints quickly with very little boilerplate. Go is clean!
At my last job I had to dig into a Golang codebase written by Python OOP-heads. I can tell you that no matter how many features you abstain from putting into a language so that idiots don't shoot themselves in the foot with them, a dumb programmer will figure out a way to make it 10x more complicated than it should be. Oh, there's no inheritance you say? Hold my beer! I'll make so many interfaces on top of interfaces that do almost nothing to put Escher to shame.
Premature optimization is so bad. I've encountered it multiple times, and it often results in major refactors later on because we can't predict what product needs will be in the future.
first language for getting a paycheck was C and was so for several years, and indeed Go had some C feels - but to truly use as a systems programming language the garbage collection and awkwardness for interfacing with arbitrary C ABIs is not ideal. So it seems to have sufficed for a certain category of middleware, i.e., various cloud infrastructure stuff. Am generally a fan of Go but don't consider it adequate to, say, write an operating system - as C was used to implement Unix.
@@kamalmohamed6611 Trueing hard, some of us are stuck in Python or worse, Java, and then there's this guy humblebragging how he worked with Rust AND now Golang?!?
I mean, both of them have the type very explicitly embedded in the assignment statement. I personally don't use auto a lot, but if I had some sort of statement like idk, maybe truncating a double in C++ to a long with a quick cast, it makes perfect sense to me. Who needs the type written out twice? ```c++ double x = 17.5; auto y = long(x); ``` it's incredibly clear to me that y is of type long. Obviously a very contrived example, but ya know.....
No, it's Herb Sutter's cppfront/c++ syntax 2. Give it a Google, it looks pretty cool (he's one of the committee members, looking to get this in the spec, too)
"Oh wait, that’s C isn’t it?" Not even close. A huge proportion of C++'s problems come from backwards compatibility with C and its horrible 1970s design.
@@isodoubIet i'll admit that there's some silliness in C. It becomes more apparent when you play with zig and Odin. C++'s problems also become apparent when you play with those "C killers". C++'s problems are from a lack of focus and buying into all the stupid trends through the ages. Simple Works. Imperative works, and adding bloat and making programs slower is a psyop by cloud companies to make more money. IDK what the solution is. I saw the C++ simplification proposals, they seem nice. they look kinda like Odin and Zig lmao.
@@defnlife1683 For example, everyone now recognizes that implicit conversions are a major source of errors, and those originally come from C. Or the horrific initialization syntax with its many gotchas including the most vexing parse, etc, also from C. Array and function decay rules and reams of complexity and treating special cases exist only because C picked some wrong defaults that seemed like a good idea in the 1970s. Newer languages like Rust, Zig, or Odin have benefited from not being designed (and not being backwards-compatible with anything designed in) in the 1970s and get to avoid these. C++'s supposed lack of focus is largely overblown. You can find examples but the main problems you encounter are because the language is built on a base that's very complex and needs to handle many weird corner cases. The ISO evolution model and the committee's reluctance to fix mistakes is also a part. "Simple Works. Imperative works, and adding bloat and making programs slower is a psyop by cloud companies to make more money." I can buy that but C++'s main strength is its ability to provide zero or near-zero cost abstractions, an ability that's unmatched by any of its newfangled competitors (even carbon; jury's still out on Cpp2 which is just an embryo at this point).
“return errors by values is the only way” - it’s an inferior way. Adding “if” to check the result after every single function invocation while in 99.9% of cases you can’t do anything about the error other than propagate it up the call stack - it’s horrendous, not only it’s extremely verbose, it’s also more error-prone and relies on the fact that the programmer “handles” the error. This is why exceptions were invented, any modern imperative language that doesn’t support exceptions is trash
Couldn't agree more about DRY. You should strive for DRY where it makes sense, but sometimes, creating some meta class or function that combines two seemingly similar function points into one unwittingly tightly couples certain cases that you find out later aren't as similar as originally theorized.
I feel the issue often is not in language but in the idea being implemented. We just sat down and looked concurrency bug, started to analyze it, and realized a better solution was to simplify the whole mechanism first. It does not so much matter what language is chosen for implementation when the concepts are hard enough. And in the case of concurrency, anything that can be removed makes it much easier (or likely) to understand properly.
Clever code (or even horrible, hacky code) is fine if it's fully contained behind a clean interface. But few languages guarantee internal horribleness cannot leak out
I may sound like a heretic here, but VB6 (whilst extra-ordinarily archaic and abandoned) falls into the category. It's limited feature set makes it extremely easy to read, and perfect for some use cases (we still have a 120k LoC library in VB6), but there are limits - even if it was still alive I would not want to do anything more with VB6. This may not be a perfect analogy, but the limited language constructs can mean getting a solution up and running quickly, and often more performant, but long term maintenance will begin to suffer.
This dude wrote a single POC program for a personal project after taking one evening to study up on Go, and has the balls to say he doubts Google's claims that it is a good fit for large teams, a company who uses the language extensively in large teams. Awesome. 👏
He's quite right. I worked on golang at a company that has one of the largest code bases in the world, and it was a mess. It's an overly simplistic, anemic language that can be used for simple small things, but when you have large programs with many people working on it, sure it's better than php or python, but that's not saying much. Languages like Java and C# do a much much better job for large and involved programs. No comparison really.
@@danniixxp I elaborate somewhat in a top level comment I posted in this same video. Scroll down to see it and let me know your thoughts. That's not even to mention nice syntactic features that C# has (and Java is getting) like string interpolation.
@@danniixxp great frameworks, and actual semi decent type systems. We don't just use interface{} everywhere which means you might as well be using Python. Write a Union function in Go that Unions two lists. . .. yeah it's a 1 liner in C#.
You can now use the keyword "any" instead of "interface{}" which cleans it up a lot if you do need to use it (maybe temporarily while throwing the initial bits together).
@@codingsafari true, I'd just use it for temporary things you haven't defined yet though I'd just make a named empty interface in that case as a placeholder. I don't think you should use either interface{} or any in production (outside generics) unless you need it. I just brought up "any" as an option as it seemed his biggest issue with it was having to read and write interface{}
a month or so, i did a couple of weeks work experience for a software development team at a company and spend most of my time there writing software in go. it was mostly stuff like http requests, json handling etc. I personally agree with the title of the video, coming from rust I honestly feel like go is catered more towards developers who want to just get stuff done easily and have easy to read code without any advanced patterns. to me it just feels quite limiting and simplified. having to write out an 'if err != nil' block after every function call got really repetitive and i found myself really wishing i had access to some of the patterns that rust has to make code more concise and less repetitive. i do like the idea of goroutines but again you can pretty much do the same thing in rust.
this ^^ but its not exact same any is more like template / generation of a function for a specific type whereas interface{} is the most base type being passed in as an argument and runtime argumenting ensues
FWIW the go version of the first thing could've been 21 lines instead without buffering the whole thing in memory, so it'd work for actual large files. But hey, the man likes the d. package main import ( "io" "log" "os" ) func main() { var input io.Reader = os.Stdin if len(os.Args) >= 2 { f, err := os.Open(os.Args[1]) if err != nil { log.Fatalf("Can't open %q: %v", os.Args[1], err) } defer f.Close() input = f } if _, err := io.Copy(os.Stdout, input); err != nil { log.Fatalf("Can't copy to output: %v", err) } }
3:57 LIke: "They all noobs but we want them to immediately compete with space agencies." • • • • • Yeah… Am I the only one having a weird mixed feeling about this "noble" goal ? 😂
My primary comaplaint is that I don't have the ability to call free on memory I know I no longer need. Ironically, the more I program in golang, the more I'm thinking about switching to C or C++.
What’s the request dedupe algorithm you were talking about? Typically that’s handled with idempotency tokens, but you’re talking about some clever diffing stuff. Can you share some more deets (nuts) about that?
I love your article videos, but I do wonder if it is possible for your layout to not obscure the rightmost quarter of the page. I struggle with auditory processing, so being able to read along makes these videos much more parsable for me. But I tend to find myself dodging your face and also chat. The former is not much of a problem, as you are usually reading the top half of your screen. but chat is almost always obscuring text I am attempting to read.
If statements are always better than ternary operators, change my mind. And not just because ternary operators confused the absolute fuzz out of me for several years before I sat down and spent an hour learning how they work. Ternary operators invite new programmers like me to display their intelligence in the codebase by running the line length out into JavaScript levels of insanity when an if statement does _exactly the same thing._ Heck, _any_ feature that encourages developers to be smart should be discouraged, IMHO. As you mentioned at the end, it just turns into a clusterbomb of epic proportions just _waiting_ for something to go wrong. Have I dealt with code that was too smart? Yes. It was mine. I thought I'd display my intelligence in the codebase by only using GOTO for everything. When I had to use that program later, I rewrote it like a normal person. "It takes twice as much intelligence to debug code as it does to write the same code. Therefore, if you write to the limit of your intelligence, you are by definition not smart enough to debug your own code." -author unknown. I try to live by that statement.
I remember writing a critical piece of software in C, run into some undefined behavior and was so pissed that rewrote the whole thing in golang in 2 days. Rest client, concurrency. Log/csv parsing, db persistency. And almost the same speed. Now I only write C when needed (voip pjsua things etc)
Seems like a really biased article where the author just puts in his own ideologies. Also feel like he put in those additional whitespaces to make the go program look bigger
The interesting part is that the code we are refactoring was written a year ago, believing it to be the best-optimized solution. But during refacting we see that, it is one hell of a sh*t we have written at that time.
I feel like this has given me insight into different types of problem solvers and I love that I learned that from you. I also don't like your take, but I appreciate we have different strengths and strategies. Take care 😀👋
I'm reminded of the TempleOS guy quote "An idiot admires complexity, if you build something so clusterf***ed that no one can understand whats going on, they're going to think you're a god"
Tony Hoare made the distinction between simple programs with obviously no errors, and complex programs with no obvious errors
@@justinforder2835Just want to clarify that Sir Tony Hoare is not Terry A. Davis. One was God, the other wrote for God.
Possibly off topic, but I love talking about Terry and TempleOS.
I admire Terry's attempt with TempleOS. It seems most people really didn't understand what he was after (i.e. a Commodore 64 experience on modern hardware.)
I just don't admire Terry as a person: i.e. a racist, homophobic, misogynist suffering psychological disorders.
@@curio78 Nobody is right or wrong on this one, because it's a philosophical semantics argument. There are just as many arguments structs could be considered objects as arguments arguing they are not.
It's like trying to argue whether or not your shadow is a tangible thing. Endless debate ensues with no possibility of conclusion.
Really smart code is elegant to purpose/domain not complex. People get confused about that. They get afraid to use any but the most boring idioms of a language even if that means way more boring code to wade through that takes those that deal with further from the actual problem domain being addressed. But hey, everyone knows what each line means.
At a company, half of the 500k lines of golang code in the codebase were leaked. Luckily, in this half, all the lines were "if err != nil {"
😂 my hands are sore from writing that boiler plate code... I wish there is a better way of catching errors
@@fortuneosho8137 Monads.
@@GK-we4co I needed that. Something that drives me absolutely crazy is how Go keeps talking highly of its brand new clever ways of doing things. The issue is that they completely miss the mark every single time. Error handling is a great example of that.
@@GK-we4co Gonads
but hey ..... EXCEPTIONS .. BAD... THE OCULT!
As a backend developer that is migrating a not so insignificant body of code from C++ to Go, I can say that Go is a Godsend. When we code in C++ we are constantly second guessing ourselves and feel like we are trying to avoid mines in a minefield. We are far more productive and have progressed much faster in Go.
Anything is better than C++
@@NathanHedglin Never have truer words been spoken. I cannot agree with you more.
@@NathanHedglinExcept for Lisp, Prolog and Forth.
@@NoX-512 and JS
@@NathanHedglin even C 😛
Absolutely based! The moment you transition from junior to senior developer is the moment you realize that clever code is the worst.
Exactly. Overengineering is the absolute worst thing you can do for any project. The reason why go is a popular language and very popular specifically with startups is because it is very easy to get started with. There's nothing wrong with that and to say otherwise it's just idiotic.
"A junior dev tries to write code only a senior dev could understand, and a senior dev tries to write code that even a junior could understand."
@@draakisback I mean there are plenty things wrong with simple languages. They are just popular because people are lazy and don't want to think a lot
The counterpoint to that is that you do want your core libraries to export an API that allows your code to be both short and not clever. That is a lot harder to do if the library code is not allowed to do clever things.
No generics? Then all of a sudden, libraries can't export a good BTree data structure of any fixed type. No metaprogramming? Enjoy dealing with ORMs that use a DSL that compiles to Go instead of just being implemented in Go, which is literally much worse than any in-language trick a library could have used up to and including advanced macro usage. The flipside of having a dumb language is that your libraries become much more horrible.
Limiting application code to be dumb is good practice. Limiting libraries to be dumb makes it hard to make the application code dumb. You will end up writing code that no one wants to read instead of code that is basically a configuration file.
@@TheMrKeksLp if that was the case java wouldn't have been so famous for so many years. I get your point, especially nowadays when it seems github copilot will be the next best programmer, but you can have simple and good at the same time, maybe not python levels of simple but Go is in a good spot i think
What I like about Go:
1. It's a sane balance of very familiar paradigms, but it doesn't go too hard on any of them. So you've got OOP patterns, composition, procedures, first class functions, etc. It takes a lot of what's good about these things without borrowing too much to become dangerous.
2. It eliminates a lot of cognitive burdens by not allowing you to get too clever. Abstractions need to stay fairly simple. The type system lends itself well to creating interfaces that are clear, concise, and easy to reuse, extend, etc.
3. The standard library is excellent, consistent, and serves as a great reference for how to do things in your own code.
4. Super portable, snappy feedback loop, standardized tooling, makes for super easy development and deployment experiences.
What I don't like about Go:
1. It isn't intuitive for a lot of developers, and they reach for familiar patterns that don't quite work in Go. They end up feeling defeated and frustrated. I've seen this across all experience ranges. I've even seen a team drop Go for Rust in a case where Go made so much sense, and instead they punished themselves with Rust for months because... I don't know, Rust is better? I mean, it's awesome, but sometimes you just need a dumb API or CLI and Go will let you iterate on it super fast. And let's not kid ourselves, half the stuff we build will get thrown out or deprecated; making it 1000% bug-proof and memory safe and so on isn't important or necessary when you can get like 95% of the way there with Go. If something proves itself, go ahead and write it in something else, but don't cheese-grate your brains over it.
2. Still don't like error handling
3. I'd be 10x happier with some sort of expressive pattern matching syntax
4. The gopher
"1. It isn't intuitive for a lot of developers, and they reach for familiar patterns that don't quite work in Go."
The counter-crux of that article, got to choose the right tool and then not try to use like another tool. Banging a single nail with a wrench can work with a heavy wrench, but really get a hammer when building a house.
Article complains GO is "simple" while wishing for a different feature set that already exists in another tool that is literally shown in the article.
There is so much wrong with the Go language, only reason why its popular is there is no alternative right now that fits this niche so well.
I love the gopher, much cuter than ferris
The gopher 😂
I agree - I feel most of the issues with the Go language could be solved by introducing sum types and pattern matching.
I really like that I can just look at a foreign Go module and grok what's going on pretty quickly, because there are barely any fancy language constructs to be aware of. I'm decently proficient in Rust, but looking at libraries, I often struggle to figure out what's going on because of macro invocations, weird Trait hacks, or unsafe code.
Don't get me wrong. I know how convoluted and rapidly evolving Rust and C++ are, but it doesn't have to be one way or the other. The GO team took the concept of api stability too seriously which lead to the language becoming stagnant. Just look at how long it took for them to support generics. How were Docker and K8s developed without this simple feature is beyond me. And that's just one aspect of the language. The others are the useless and obnoxious code formatting rules and the terrible module system. They could've done something about those things but nothing. God, I hate this language so much.
Readability is important to teams, users and the future self.
It's hilariously sad how devs on the slope of the bell curve tend to be oblivious to Literate Programming being smart and want dumb inscrutability is as the "smart" thing.
@@parlor3115 man the module system truly is the worst lol
@@parlor3115 C++ may be rapidly evolving, but it's a lot like vomiting into a bucket that hasn't been emptied in a while. It's a big stew of unpleasantness. It's like the goal is to make every feature clunky and hard to use, but at least you can say it's there.
@@parlor3115 Just look at how long it took for them to support generics.
in almost every case when you think generics is the solution, it will be the worst solution. You basically throws type safety away from your type safe language to do some fancy pants things, hoping someone that will use it later making sure it has the right characteristic to be used in the generics that we create.
I come from JVM languages (kotlin, java) which is a language that in love with generics, and I very much use it extensively. But I have program go for 2 years now and does not miss it at all.
I would be terrified of having a guy like the author in my team.
I had
IMO anyone implicitly putting themselves in the bucket of "Smart Programmer" is a pretty immediate red flag
@@SleepyHarryZzz why is red flag? can you tell me? for my opinion, we can discuss and talk to him to get attractive information or sharing the knowledge right? I think it's good
@@afifdev Because people like that talk from ego not experience.
@@ZephrymWOW I see, that people is not smart, just full of ego, it's not smart people, the discussion is making the decissons what is best. Don't generalize people like that, it's not smart or clever people, just ego
Just for those who aren’t familiar, D has a Uniform Function Call Syntax system. You can suffix call a function on an object and it rewrites it so that it calls the function and passes the object as the first argument.
Eg.
A.writeln is equivalent to writeln(A)
I wish this feature was in more languages, it's awesome.
@@fakt7814 look up "koka language"
Still feels pretty cursed, idk. Like trying to tell if someone is calling an attribute or a function on an object seems like hell.
@@some1and297 I mean, in theory, an attribute is a noun and a function is a verb, right? Like, if you see A.readText, you expect that to be a function call because it has a verb in it. But A.textContent is likely to be an attribute because it’s all nouns. I don’t really see a problem with it.
@@some1and297 It makes reading the code easier though. Take the example from the Video:
[1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln
You could write this as
writeln(reduce!((a, b) => a + b)([1, 2, 3, 4, 5]))
When reading this, you usually read from left to right. So you read "writeln", ok, we are printing something, what are we printing? "reduce", ok, looks like we are printing the result from condensing an array by adding the elements, what is that array? Oh, it's just the numbers from 1 to 5, ok.
Most programmers are used to that, because that is how it is in most languages, but for the other way around you don't need to keep that much context in your head. You read it in the same order it is executed in. You take an array with the numbers from 1 to 5, condense it by adding them up, write the result.
But as always, tools can be used badly. For example writeln can take multiple arguments to print multiple things. So one could write
"hello ".writeln("world");
to print "hello world". Just because you can use a tool doesn't mean you should always use it.
I'm a C programmer and ended up using Go for my webserver, I'm happy that it's simple to learn and use for this purpose and fast in production since it's a compiled language
Hey this is literally me.
c prorammer means, learning c in collage, or having a job the uses c and/or contributed extensively in big c opensource projects??
+ u can do this all in the std lib vs using a 3rd party header (which tbh I have no problems with)
@@vaisakh_km Professionally and open source as well
@@vaisakh_km my main open source project is about 20k lines of code in C99 I can't post about it or my comment will be deleted, but I also do contracting for companies I am an auto-didact
IMO, "clever" code in modern languages is often less efficient from a big-picture perspective. It's often slower than easier-to-read code, and it can add a financial cost in terms of the extra time required by non-original authors to understand and debug it. (EDIT: I used to have to decipher FORTRAN, which HAD to be "clever" because of system resource constraints.)
traits in rust is "clever" in some sense, but it makes things really nice
its the one thing i wish all languages had, a trait system
Most "clever" programmers ignore the cost you are mentioning. But some want that, if only they can understand the code, then they have to be in the company forever or make the company some bleeding of money through their code.
i think it is difficult to generalize here. i have seen some programmers who sincerely have a lack of trying to understand programs from a systems perspective.
they try to make things easy in every regard, but i have seen how that complicates things in the long run. sometimes you just need some complex and clever code at the right place, to make life easier for everything else.
prime has taught me well about the importance of performance and given me ideas how to achieve it, so i get that using loops instead of functional programming is better in some languages (hi @older javascript versions), but clever abstractions can be so powerful, that it would just make you a lot more unproductive if you did not use them and make life a lot harder (also regarding bugs). in such cases performance really has to be an important thing, if i would consider giving up an elegant abstraction.
so i personally prefer the language that allows such powerfull abstractions, because that allows me to solve problems better. but sure with great power comes great responsibility and i am more of a guy that sees that as a challenge. i feel like you constrain yourself too much, if you don't take powerfull abstractions into consideration just because it is difficult to understand when to use them correctly. and you will never be able to solve certain complex problems without them imo.
I would really challenge people who think they write "easy to read" code to start regularly showing their code to people who are not working on the same project or ideally not even with the same technology.
I think you will find out that the biggest factor in quickly understanding code is familiarity with the project and the problems. This can't really be acquired through any other means than just reading the code. And usually the more code there is to read, the longer it takes to familiarize yourself with it. I think this is how the "DRY" concept started and how it grew to it's absurd conclusions.
I definitely don't think you should abstract everything, but it really does help, when you don't have to go through 30 dialog components and check if each one really does the same thing.
What is "clever code"?
Are we saying that 100 lines of readable code is better than 10 lines of code that accomplishes the same and runs faster, and who is doing the "reading"?.
I think if the 10-line-code followed conventions then its preferred, for me "clever code" is acceptable as long as there are good merits, and its not superficially clever when in fact the code is poorly architected and littered with magic.
As for the video's comparison, lets stop the bias, that D code is by far more elegant than Go, and I'm sure it will be even more evident in a large application.
One thing about Go being so simple is that you can dig into the source code of any library (especially the standard lib) and understand what code is running under the hood super easily. I had to look under the hood of the Azure Blob Storage SDK in Go today and could see exactly why it didn't like a parameter I was giving it. I also dug into the std lib to see why a stream I was building was EOFing early etc. It's so powerful to read these libs made by way smarter people than I and understand exactly what is getting run on my computer, such a blessing.
I'd say that it's more advanced to have a more primitive language, not dumbing things down. You need features designed in such a way that you could implement them out of more primitive functions. Using high-level features with no idea how it's implemented isn't "advanced".
Precisely why I fell in love with Go. I've not been able to do this with any other language I've worked with. I've always dreaded trying to sniff through people's code and have banged my head against the desk in confusion many times. Didn't happen when I did this with GO....
this is one of the things i like about writing javascript, if youre running an LSP you can just, cmd+click into a library
@@unicodefox yeah except that it usually takes you to a definition file so you have to find it yourself and the actual code will be made up of crazy shorthand for everything. Go has only a single way to do things so once you learn it you can read all of it easily.
I checked once a Go library. In a single file of about 2000 lines, it was declaring an empty object (or "structure", whatever) and then it was full of receiver methods for that empty object. How is that supposed to be easily readable? I only understood it was designed like that after I scanned the whole 2000 lines to actually see every function was a receiver method, whereas in pretty much every other language you declare a class and put the methods in (a class doesn't need to have any fields), and what I do in those cases is just follow the closing bracket and I would know all these 2000 lines are methods within that class cause they are within the brackets. But in Golang they are on the same level. They could literally be half of them just functions. Very bad design. Very hard to read.
I've never used Go (I'm a beginner), but I have used Lua, another simple language. I love that I can have Lua's complete syntax memorized after a few days of work, I like that there are 0 surprises and everything works exactly how you'd expect. If I want to do something clever, I can use metatables. It was cool implementing my own type system and it helped me understand how OOP works.
As someone who had to deal with a large (500k+ loc) project written in Go, here's my perspective:
Go is great, if you were going to write it in C you are going to feel right at home along with a few more conveniences.
But there is a limit to the size/complexity that a project can grow to in Go before becoming a horrible mess.
Of course every language has this limit, but it seems that Go's ceiling is much lower than other languages due to how it amplifies every single line from a modern language (e.g. Rust) to ~10 lines.
It is very good for async programming though. So if all you do is reply to server request with relatively simple internal logic, then Go is perfect.
This sort of mimics my experience working on one of the largest golang code bases on the planet. Sure you can use golang for smallish programs that you would have written in Python or Ruby, but you get types. But the anemic design of the language leaves much to be desired when you work on large programs. While the "uncolored" async approach they're using is better than the typical async/await approach, it's still half baked. The `go` keyword does not handle the return type of the function being run, so you have to resort to hacks like passing in a channel then selecting on it.
The Java folks have the right idea with Project Loom (virtual threads). They integrate very nicely with Futures/CompletableFutures, so you don't have to use hacks to pass channels and wait on them. They are also building a structured concurrency API to nicely handle timeouts and cancellations, unlike the hacky golang way of having to pass context.Context to all async functions, thereby reverting to a colored approach.
I mean, have you worked in a typescript 500k lines codebase? or a java 500k lines codebase?
I haven't, just curious how it does compare.
@@guillemgarcia3630, unfortunately not, my Java and typescript experience is fairly limited. I have, however, worked on C++ projects that are an order of magnitude larger, but felt much more cohesive.
Obviously this is anecdotal, but in C++ (and I would imagine other expressive languages) the ability to express your ideas is much more stratified, while on Go and C it feels like you must first translate those ideas to the most basic constructs.
For example if I want to find an element in a container in C++ I can use std::find_if, and it'll work for any container. In Go you must write a loop, and if your container is anything other than a slice or map, prepare for pain. Of course find_if is only the most trivial example, but this applies to basically any algorithm. Another famous example is following and mapping one collection of items to another, in rust you simply do in.iter().filter(...).map(...).collect(), in go this one liner expands to about 5 lines, meaning every time you perform such an operation you need to parse the loop and understand what it does instead of the names of the operations literally spelling out what's going on. And of course seeing such things once or twice is simple, but when dealing with a huge code base and trying to follow the logic, this inefficiency of expression and communication ends up eating a significant amount of brain cycles.
@@Afief Well said, this is one example of what I meant in my other comment where I said that a simplistic (naive) language (golang) pushes complexity onto the user instead of being able to express it cleanly and concisely.
@@zhamed9587 I fully agree. Not being able to express the things we want to express in the language means we copy pieces of logic all over the place that should have been encapsulated and standardized. Map, filter, reduce...etc are just the most basic and obvious candidates.
"This language was offered in the simplest form to meet your inferior mental capabilities." sounded like this.
agreed
Yeah, the type of programmer that writes code as complicated as possible, to flex how "smart" they are, then call you dumb if you do not understand their code maze
@@rj7250a No one is saying you have to write complex code. However, the language needs to support some complex constructs because reality is complex, and there is no getting away from a base level of complexity for many systems. By making the language anemic and dumb, the golang authors simply pushed the burden onto the programmer and the code, resulting in messy verbose spaghetti code bases that take so many lines to describe something that would have taken half or less code to model in a good language like Java or C#.
@@rj7250a fr and let's be honest the guy who wrote the article probably sucks too & that's why he's writing articles and not actually coding something.
@@mythbuster6126 I had a harder time making sense of the tinygrad llama example than kubernetes but that's just me. Although I didn't go through all of kubernetes only a few source files.
The .writeln stuff is what he was describing as "alternate function call syntax", also known as uniform function call syntax in C++ lands (where people have been trying for years to put it into the language, without success). Essentially you get to call non-member functions with the same syntax as member functions, which lets you use post-fix notation so that the code reads in the order of execution: first I take this list, then I join, then write, where the usual order would have you read the same operations from the inside out.
Just because you can handle something more challenging doesnt mean that you should.
With the exception for Rust, of course
🦀
Why do I fee majority of rust lovers barely write any rust right ?
Go is like writing a paper on rockets using a 5 year olds vocabulary
@@ko-Daegu Because the majority of people who watch prime know how to program the equivalent of someone who has taken 2 CS classes or less. But, Rust all the way...
Which is fine of course, but it's funny seeing people have completely nonsense strong opinions. At least have nonsense weak opinions!
@@derschutz4737When I first heard about Rust memory safety features, I thought, I gotta learn this language. Then I looked at some production Rust code and thought, nah, I’m good.
Zig looks promising as a replacement for C/C++.
@@ko-Daegu yep, rust has some kickass confusion engines with multiple ligma algorithms
"This'll be a Rust article"
AND THEN D LANG, FROM THE TOP ROPE
I'm consciously trying to migrate myself from being primarily a C++/Python programmer (the former being my job) to a Rust/Go programmer and honestly the contrast is so stark. My seeming inability to figure out package management in Go aside, once I get going, its really really easy to write code I'm happy with in Go, that I know behaves the way I expect. Rust on the other hand it feels like I'm falling from one rabbit hole into another just to get beyond the basics (I'm not knocking Rust in any way here -- but its a 'commitment' language like Java or C++). Take it with a grain of salt as I'm still a pretty junior dev -- but I find that anything that helps me in six months understand what the hell me today was thinking is a massive win. The programs I've had the least BS maintaining were the ones where I didn't try to be cute or clever, where I prioritized readability and simplicity of the design over everything else. At least for me, your always dumber looking at your code down the road. Sometimes it pays to throw future you a bone.
6:36 Zignificantly better
Regarding D and the `writeln` example you mentioned, I think that is D's "uniform function call" syntax, which allows you to express a normal functional call using method call -style syntax. It is a nice feature of the language. IIRC, the "bang" syntax indicates a template instance, in this case calling a templatized function.
D is a really nice language but much of the mindshare went to Go and Rust -- the former likely because of the simpler programming model that the author is complaining about and the latter because D's standard library largely depends on garbage collection, which I think made it less attractive for D's original target audience. Andrei Alexandrescu, one of the big D contributors, had a really interesting post on Quora about this a while back, which has unfortunately been deleted.
What look like methods are indeed just function calls with the first argument being the thing that comes before in the chain, so you can chain function calls as if they were methods. It makes for incredibly nice and straight forward code overall.
D is excellent, but this blog post did nothing to sell it properly. Go doesn't need to be D, though, and I don't get why people are so offended by its popularity. Most popular languages are shit, honestly, and Go is preferable to most of the other ones for a good chunk of work.
@@mccGoNZooo that sounds like a combination of pipe operator and currying, with dots and braces
@@vuongnh0607l It pretty much is the pipe operator. C++20 ranges accomplish more or less the same thing using a literal | symbol (only it uses template magic instead of a language feature).
always here for the go slander
its... an intense one
I'm an extreme coder, I code bare arsed.
unsafe { }
You shouldn't need to have a PhD to understand what pieces of code are doing. That's why I love Odin/Golang/Zig and how they spell things out without NEEDING an LSP.
But if others are NOT confusedly bamboozled by your inscrutable arcana then how will you make sure others know how your so much smarter than them? ❓🤔🤡
/s
@@TheNewton Because it's actually rather simple. "Inscrutable arcana" is rather 'clever' but it's just a matter of understanding each others coding styles. I have a pretty good idea of your style since it's the usual way of doing things, which is fine, but I can pretty easily teach you how to read mine if you're a good learner.
Wow nice selection. Odin, Golang, and Zig are really great languages.
Good point on TypeScript, I love what you can do with the type system, but it’s more of a foot cannon than a foot gun. If you hit a weird edge case that the TypeScript devs didn’t think of you’ll blow off your whole lower body and have to start over.
I was literally talking to a colleague today about how DRY is too confining in many cases. I'd rather repeat a function than create weird logical statements to have the function do multiple things.
This
Rule of thumb: if you can remove an if statement, you're not repeating yourself.
If you have multiple signatures for the same method its probably worth a refactor... nowhere near as bad as multiple inheritance but yeah not ideal and I see juniors going ape with DRY all the time
"An idiot admires complexity. A genius admires simplicity." -- Terry A. Davis
The quote is right, but Go definitely doesn’t fulfill this definition. Do simple as possible, but not simpler. The article is right, just there could be better examples.
24:00 In Dijkstra's wise and eternal words: « The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague. »
What I hate about many languages (but go especially) is the inability to discern optional/fallible values and sum types in general. After using Rusts Option/Result and enums, I just notice how terrible writing other code is. Go makes this even worse by just returning (value, error) instead of Result. And implicit nullability is also terrible but go also makes some decisions like representing "missing" strings as empty strings. Struct fields in go are also zero-initialized by default, so forgetting to set a field yields a bunch of terrible runtime problems.
I like simplicity and have a bunch of hope for zig for example because it is still kept simple without making so many terrible decisions.
Totally agree. Go is a really nice language when it comes performance and ease of use, but man do I hate a lot of the design decisions.
Zero initialization is amazing tho, it's a simple and cheap solution to a potentially dangerous problem
@@marcs9451 I disagree, just force initialization of anything that doesn't have a default value
@@marcs9451what's it solving?
This is something I see all the time sentiment-wise with folks who are outside, and in this case inside, the tech world: the idea that Google hires the best and the brightest. For unrelated reasons this annoys me, because you don't really know one's capabilities or motivation to work on a project until you have them. You can vet that they know what they're talking about, but only so far. This mindset creates a world where we adopt the way business looks at us, and make it our point of view, rather than advocating for ourselves and our capabilities. Even if it's just advocating for where we're at and that we're getting better, it should be the default in the face of businesses that want to take you for what you're worth and then dump you when they feel like it's good for their bottom line.
I mean you can use proxies that predict job performance; research is pretty clear that job performance can at least on an aggregate scale be predicted reasonably well.
Google’s hiring bar is not what it was in 2007, but it’s still very high, especially for its top teams.
Yeah, I don't doubt those big companies have geniuses working for them, but most people are just average.
Also you will have many great devs who will never works for those companies because their hiring process sucks and they just don't want to have to put up with it.
This channel is probably one of the best things that I discovered at this year. Thank you Prime
Honestly from my experience the only really "hard" language used in large escale is C++, people like to act like java is hard, but it isnt, is just over verbose and annoying. All the other mainstream languages out there are pretty easy
I think it depends on the ROI of clever, which largely depends on how bright the dev is. If you understand "clever" it can save you tons of boilerplate and allow for very terse, clear code. But if your project is long lived and you have rotating crew of 'commodity' devs you really need to consider your LCD.
The damage a 'good' dev leaves behind when a company typically hires clowns is immense. The design will be compromised out of ignorance and words like 'spaghetti' are all but certain.
Great take " What is the ROI of "clever" "
Though incredibly difficult to measure and validate in a code editor.
Was the damage done by the "good" dev... or the "clown" ones?
You are amazing. I love to watch you before sleep, in transport, while eating, and literally all the time. Thanks for providing this amazing new type of content
thank you my man
If I remember right, D has UFCS which means you can do things like expression.writeln and expression gets passed to the writeln function as the first argument. I've always thought that was kind of interesting, but I didn't really think about how non-obvious it is what's happening here
Has Prime ever read Amos' blog article "I want off Mr. Golang's Wild Ride"? That article contains much more compelling reasons for potentially avoiding Go 😂
i'm a golang dev and have used many other languages before, C PHP Java JS C++ Python and more, but Golang is by far my favorite language. I've been writting real time concurrent multichanned subroutines websockets and Doing that with anything else than Golang would've been hell. I wonder how you can make a point by giving an I/O example that any language can easly handle if you don't go in depth of the strengths and weaknesses of the language/runtime ! Go is a MASTERPIECE ! Kindly, the french tourist
I would have used Go for my new project, because of the simplicity and fast compile and run test cycles, if it had support for extension methods. So I ended up going with Dart instead. Dart is also simple like Go, but not quite as simple, it has some of the things Go is missing without getting too crazy. It also can compile to and run on many different platforms, and has a fast compile and run test cycle like go. Dart has turned into, basically, a modern, better designed Java/JVM that can also compile to JavaScript. With Dart, the compiled executables have a small Dart VM inside them, so it doesn't put the burden of runtime environment/version on the user like the JVM does.
The original Go pitch by Google was basically, they wanted to make a sweatshop to program boring web services in massive numbers. So Go was to be so simple you can hire kind of "unskilled labor". But yes I don't like super expressive code.
Absolutely. You're unskilled? Apply for a job at Google.
Good thing im not a smart programmer
My main complaint about Go last time I tried it is that the GC is horrible for long-running processes because it does not defragment memory, so trying to run something that allocates memory frequently longer than a day will usually lead to it crashing. Which is the reason why go programmers ended up pushing docker and Kubernetes on us so that they could just automatically reboot their unstable programs.
If go just had some equivalent of Rust's Send/Sync traits or some restriction on sharing mutable data in channels, they could refcount all data that is shared between goroutines like how Erlang/Elixir handle shared state because immutable structures cannot have reference cycles. And when you have that you can have the simplest stop the world defragmenting GC applied per goroutine, and still be real time because other processes can take over while one process is GCing. In my opinion the fact that the go runtime frequently crashes unless you are extremely paranoid about heap allocations is the one thing that makes it go from a potentially amazing language to a mid to low tier one that you use primarily to fill a gap if your coworkers don't know any other language that compiles to a native executable.
Huh! Interesting! I never heard about this specific GC issue on golang
"why go programmers ended up pushing docker and Kubernetes on us so that they could just automatically reboot their unstable programs."
That is an interesting take, dockerGOKubernetes as a self-fulling end-to-end bug-as-a-feature solution feature-set.
@@TheNewton Let it crash, as they used to say in Erlang for the last like 35 years :)
if it's bad for smart people it makes it the anti-java. another reason to use it.
true
Not really. Java is much more superior on almost every aspect. I used golang in large programs before at a well known company, and it sucked big time, caused many issues. It is not a good fit for large programs, very poor modeling capability.
People who say these things about Java usually don't haven't been keeping up. For a long time now, you can pass methods as parameters in Java, and you have streams (something that golang lacks). Now, you have records, sealed types, pattern matching, virtual threads (better than golang) and many more cool features coming like string interpolation, all of which golang lacks.
@@zhamed9587 Java dumb and bad lol
Nothing wrong with Java when you don’t need the performance of C.
@@zhamed9587 I’m baffled. Virtual threads are not in improvement over platform threads, but just a process for how the jdk manages these threads. In some cases the binding of these threads has performance penalties, but in general they are pretty performant. So? Both languages have access to concurrency across cores, and javas is not always superior. And go not having pattern matching and string interpolation; what is this parallel universe you come from?
So the issue is that people can only hold about 7 things in their working memory. Go being too simple will force you to write alot of if statements. Each if statement will raise the cyclomatic complexity, which will make it harder to mentally parse. Each time you read code, you must place it in your short term memory and run a mental emulation of it. If there is too many moving parts, then you must commit the other parts to long term memory, which impedes productivity.
In the file output code example, it has a cyclomatic complexity of 4, which for this might be fine, but imagine adding features to it. You will only have room for 2 or 3 more if or for loops until it is too much to mentally parse.
That is why we extract out to functions to reduce complexity and increase readability (over straight imperative).
On top of that, instead of writing a million defensive coding lines at the start of each function, it would be more optimal to have some object schema that can be used to validate incoming data in a function. This way you can lower your cyclomatic complexity while maintaining code correctness.
This approach is called "Data Oriented" programming.
Been doing golang in my free time for the past few months. Learned a ton, I thought it was just a newer php language but absolutely loved the single exe compared to my starter language C#.
But because I really really want to get into graphics programming I started learning C++ and OpenGL.
I was not expecting to need a build system 😅 I thought compilers just did that 😅 pain.
Nice. I’m just started doing graphics with OpenGL ES and C as well. I’m trying to keep it simple with 2D rendering only for now.
@@nickgennady Bro I wanted to comment C too. I'm just getting started on graphics programming, I learned a little bit of c++ but it's not for me. Too much oop baggage. Advanced pointer usage is hard enough, I'm not about to add oop to it.
Dude, that is the reason i switched to Rust. Because i did not want to develop three diffirent build chains for my game xD
@@codegambit2507 Yha OOP sucks. I was told it was everything in college. I spent years trying to write OOP and not be spaghetti code. In the end I had no luck. I found out about DOTS in Unity and I loved it. Now I do procedural code with data orientated design.
Good call. OpenGL is hard enough and adding OOP would be nightmare
@@voidwalker7774 yeah same
Go gives you a feature rich library like Java/C# without the problems of the JVM and the Microsoftness of C# and the performance of compiled languages.
@@fastasashark Poop... Agreed!!!
The .writeln() in D, works because of Uniform Function Call Syntax, aka foo(a) is equivalent to a.foo().
yeah, i don't like this
i dislike things i don't read left to right
One of the reasons that I hate Ruby
@@ThePrimeTimeagen I liked your comment but pipe operators are awesome
@@ThePrimeTimeagen I think it's literally reading left to right. createPerson().addAddress().writeLn() vs writeLn(addAddress(createPerson)))
@@asdqwe4427 ruby is love
15:00 "I really don't get this writeln at the end"
Not sure if you heard about it after, but in D that's UFCS, or Universal Function Call Syntax. In a few words, it means that a function with signature e.g. fn(T) -> U can be written with dot notation after some T. So writeln("some string") and "some string".writeln are the same thing. And since writeln can take in any type...
I could almost accept it if it were .writeln() instead of just .writeln (so that the syntax is similar to a method rather than looking like it's an attribute).. but even then, I feel like it opens a bag of worms where you constantly have to worry about whether any functions or methods you create have the same name as a different function/method somewhere else which would make it very easy to misread what the code is doing. There's not enough of a clear upside to it to me to want to create that kind of ambiguity.
I write Go, get shit done w/o headaches, startup doing great and making a lot of money, I go home early and play with the wife and kids. I can't wait for AI to write everything for me so I can just focus on the product. The author can keep his smart languages.
24:13 some smart ass had a python one liner in our code which did the following , accept array , map reduce over the array, filter the array with a ternary using an inline key lambda call over multiple subelements and used this as an lambda so it could be called functionally anywhere it could be imported .
That smart ass was me
As someone who daily drives Golang, the biggest problem of go is the lack of standardized well-known apis. I understand that the Go team wants it simple so they didn't put in any higher level feature that many languages have. list manipulations is a big one. I personally think these features are standardized in many languages for a reason. I've seen so many different and independent attempts in our codebase to accomplish what a list api would do either through the use of an external lib or haphazard adhoc solutions. The thing is, if you added your solution or a lib to the codebase, you must advocate it within the team so that others won't end up implement it again and again. it's also not guaranteed that your implementation would meet others' needs, resulting others adding their adhoc impl on top of your impl that will almost certainly be a non-congruent, hard to understand hot mess.
The don't-repeat-yourself-principle doesn't mean you must never repeat yourself. It means, if you're doing the exact same thing, with almost identical code, you combine it.
I really just call it a guideline. Like SOLID principe and all those ideas. I just look at those as concepts to be aware of, but never as laws.
Most important is always to think yourself and make your own great decisions.
Engineering things is all about making trait offs. And this includes software programming.
The designers of Go fell for a "think of the children" argument
The meme, when I was young in the 80’s; new programmers write simple code (ala GO style). As they get more experienced, their code become more and more complicated, until one day they reach god level and they go back to writing simple code.
I don’t understand these programmers who feel everything should be done in one line of code.
I like readable code.
This is also the reason I put the opening { on a new line and have plenty of white space. It’s just easier to read than a wall of text.
D is pretty awesome tbh. It’s as simple as Go, doesn’t have any of the warts of C++, and it’s not dogmatic like Rust
why was D not successful then? poor marketing?
Ultimately there is no language where developers are not expected to be smart.
The writer of this article just implies not repeating yourself and making abstractions for the ease of development is The Only Way to be smart.
And while that can be very smart, there are also other avenues one can be smart in. For example provable safety, or good performance.
Go is optimised for that kind of smartness. That’s why the testing is build in, and why dependencies are frozen by default to protect against breaking changes.
You can write go like every other language, and you can write most languages with the same mentality as go. But you probably have better time when choosing the language that is designed around your needs.
To get a perspective why simplification at the cost of verbosity could be desirable, consider a world where everything was written in lisp.
Yea. C# was making a delete method that would take three connected entities in SQL and remove them completely in order. It worked until I tried testing the method on entity 1 and 2 without the 2 being connected to entity 3 and ended up clearing the entire table. Luckily I have done dump s**t before and I made a backup before testing.
A smart programmer is not a programmer who writes clever code on a regular basis. A smart programmer is a programmer who writes SIMPLE code!!! Making complex things simple - this is called smart.
This article is written by a dilettante or a junior programmer that likes clever code thinking that it makes him smarter.
I always strive to write simple code, but sometimes the complexity of reality comes in and forces you to write more complex solutions. That's just how it is.
It always depends on the context: small projects vs big projects, need for parallelism, and much more can influence how easy it is to write simple code and when you may need to resort to more complex solutions.
So I would say: Clever programmers write code in a way that fits the context of the project, and that may not always be simple code.
@@DevVader Of course you can't always write simple code. I write clever code too. But only when I have to. And when I do so I write a ton of comments explaining that complexity. In "simple" parts of code I don't use comments at all and try to make my code more readable. I think this is the way.
@@vitiok78 The D code posted in the article is very simple.
Been writing a Go backend for an indie game. It's great. I really like the json marshall/unmarshall system. Ive written a handful of powerful functions and systems to create a few abstractions that allow us to write new API endpoints quickly with very little boilerplate. Go is clean!
I went through real clever scala code and its so freaking hard to understand.
At my last job I had to dig into a Golang codebase written by Python OOP-heads. I can tell you that no matter how many features you abstain from putting into a language so that idiots don't shoot themselves in the foot with them, a dumb programmer will figure out a way to make it 10x more complicated than it should be. Oh, there's no inheritance you say? Hold my beer! I'll make so many interfaces on top of interfaces that do almost nothing to put Escher to shame.
If you build something idiot proof they’ll build a better idiot.
9:31
it is very simple code
And I like that it is not just some magical lines of some library doing it
but I can actually see what is happening
Premature optimization is so bad. I've encountered it multiple times, and it often results in major refactors later on because we can't predict what product needs will be in the future.
first language for getting a paycheck was C and was so for several years, and indeed Go had some C feels - but to truly use as a systems programming language the garbage collection and awkwardness for interfacing with arbitrary C ABIs is not ideal. So it seems to have sufficed for a certain category of middleware, i.e., various cloud infrastructure stuff. Am generally a fan of Go but don't consider it adequate to, say, write an operating system - as C was used to implement Unix.
Mate, I just got reallocated into a golang project (was on rust for like 3 years).
ok, that hurts
@@ThePrimeTimeagen agreed
But ,you have the opportunity to work on any of those cool languages 😭.
@@kamalmohamed6611 Trueing hard, some of us are stuck in Python or worse, Java, and then there's this guy humblebragging how he worked with Rust AND now Golang?!?
I'm sorry
I mean, both of them have the type very explicitly embedded in the assignment statement. I personally don't use auto a lot, but if I had some sort of statement like idk, maybe truncating a double in C++ to a long with a quick cast, it makes perfect sense to me. Who needs the type written out twice?
```c++
double x = 17.5;
auto y = long(x);
```
it's incredibly clear to me that y is of type long. Obviously a very contrived example, but ya know.....
A simpler rust would be nice for us Smooth brains.
Maybe Bjarne will do that 10% C++ thing he mentions. Oh wait, that’s C isn’t it?
No, it's Herb Sutter's cppfront/c++ syntax 2. Give it a Google, it looks pretty cool (he's one of the committee members, looking to get this in the spec, too)
"Oh wait, that’s C isn’t it?"
Not even close. A huge proportion of C++'s problems come from backwards compatibility with C and its horrible 1970s design.
@@isodoubIet i'll admit that there's some silliness in C.
It becomes more apparent when you play with zig and Odin. C++'s problems also become apparent when you play with those "C killers". C++'s problems are from a lack of focus and buying into all the stupid trends through the ages.
Simple Works. Imperative works, and adding bloat and making programs slower is a psyop by cloud companies to make more money.
IDK what the solution is. I saw the C++ simplification proposals, they seem nice. they look kinda like Odin and Zig lmao.
@@defnlife1683 For example, everyone now recognizes that implicit conversions are a major source of errors, and those originally come from C. Or the horrific initialization syntax with its many gotchas including the most vexing parse, etc, also from C. Array and function decay rules and reams of complexity and treating special cases exist only because C picked some wrong defaults that seemed like a good idea in the 1970s.
Newer languages like Rust, Zig, or Odin have benefited from not being designed (and not being backwards-compatible with anything designed in) in the 1970s and get to avoid these. C++'s supposed lack of focus is largely overblown. You can find examples but the main problems you encounter are because the language is built on a base that's very complex and needs to handle many weird corner cases. The ISO evolution model and the committee's reluctance to fix mistakes is also a part.
"Simple Works. Imperative works, and adding bloat and making programs slower is a psyop by cloud companies to make more money."
I can buy that but C++'s main strength is its ability to provide zero or near-zero cost abstractions, an ability that's unmatched by any of its newfangled competitors (even carbon; jury's still out on Cpp2 which is just an embryo at this point).
“return errors by values is the only way” - it’s an inferior way. Adding “if” to check the result after every single function invocation while in 99.9% of cases you can’t do anything about the error other than propagate it up the call stack - it’s horrendous, not only it’s extremely verbose, it’s also more error-prone and relies on the fact that the programmer “handles” the error. This is why exceptions were invented, any modern imperative language that doesn’t support exceptions is trash
Couldn't agree more about DRY. You should strive for DRY where it makes sense, but sometimes, creating some meta class or function that combines two seemingly similar function points into one unwittingly tightly couples certain cases that you find out later aren't as similar as originally theorized.
Reading articles behind paywall on RUclips is the new level of the Internet !
I feel the issue often is not in language but in the idea being implemented. We just sat down and looked concurrency bug, started to analyze it, and realized a better solution was to simplify the whole mechanism first. It does not so much matter what language is chosen for implementation when the concepts are hard enough. And in the case of concurrency, anything that can be removed makes it much easier (or likely) to understand properly.
that quick "...because we all know we are dealing with arch users" got me lol
Love that confusion engine!! Esp. how it reaches around! Also agree about the over worship of DRY.
Clever code (or even horrible, hacky code) is fine if it's fully contained behind a clean interface. But few languages guarantee internal horribleness cannot leak out
I may sound like a heretic here, but VB6 (whilst extra-ordinarily archaic and abandoned) falls into the category. It's limited feature set makes it extremely easy to read, and perfect for some use cases (we still have a 120k LoC library in VB6), but there are limits - even if it was still alive I would not want to do anything more with VB6. This may not be a perfect analogy, but the limited language constructs can mean getting a solution up and running quickly, and often more performant, but long term maintenance will begin to suffer.
This dude wrote a single POC program for a personal project after taking one evening to study up on Go, and has the balls to say he doubts Google's claims that it is a good fit for large teams, a company who uses the language extensively in large teams. Awesome. 👏
Wow good stuff Prime. (proceeds to comment 1 minute after upload with 1 view)
much insights, such foreknowledge
Everything that guy has said in the article makes me question how much Go he actually knows or has written...
He's quite right. I worked on golang at a company that has one of the largest code bases in the world, and it was a mess. It's an overly simplistic, anemic language that can be used for simple small things, but when you have large programs with many people working on it, sure it's better than php or python, but that's not saying much. Languages like Java and C# do a much much better job for large and involved programs. No comparison really.
@@zhamed9587 Java shill is in all the comments
@@zhamed9587 Could you elaborate on what what makes Java and C# better for large involved programs?
@@danniixxp I elaborate somewhat in a top level comment I posted in this same video. Scroll down to see it and let me know your thoughts. That's not even to mention nice syntactic features that C# has (and Java is getting) like string interpolation.
@@danniixxp great frameworks, and actual semi decent type systems. We don't just use interface{} everywhere which means you might as well be using Python.
Write a Union function in Go that Unions two lists. . .. yeah it's a 1 liner in C#.
The only thing I find annoying with go is the manual error checking and logging. Other than that, it's great
I've done some Go and I enjoyed it, but I really missed the ability to control mutability at compile time.
You can now use the keyword "any" instead of "interface{}" which cleans it up a lot if you do need to use it (maybe temporarily while throwing the initial bits together).
@@codingsafari true, I'd just use it for temporary things you haven't defined yet though I'd just make a named empty interface in that case as a placeholder. I don't think you should use either interface{} or any in production (outside generics) unless you need it. I just brought up "any" as an option as it seemed his biggest issue with it was having to read and write interface{}
a month or so, i did a couple of weeks work experience for a software development team at a company and spend most of my time there writing software in go. it was mostly stuff like http requests, json handling etc. I personally agree with the title of the video, coming from rust I honestly feel like go is catered more towards developers who want to just get stuff done easily and have easy to read code without any advanced patterns. to me it just feels quite limiting and simplified. having to write out an 'if err != nil' block after every function call got really repetitive and i found myself really wishing i had access to some of the patterns that rust has to make code more concise and less repetitive. i do like the idea of goroutines but again you can pretty much do the same thing in rust.
What's the library for golablng to avoid "4 hard cases for channels"?
A simple language is not bad. C is simple but powerful.
C++ 🤮🤮🤮
i am on this team
90% of C++'s bad parts come from C.
For anyone not too familiar with go, the interface{} can be substituted with any since go 1.18
this ^^
but its not exact same
any is more like template / generation of a function for a specific type whereas interface{} is the most base type being passed in as an argument and runtime argumenting ensues
Another reason to avoid go. Compiled yet still not type safe
And it doesn't "handle errors", it checks for them and prints them out. You could literally do the same with try the open and read catch e print e.
FWIW the go version of the first thing could've been 21 lines instead without buffering the whole thing in memory, so it'd work for actual large files. But hey, the man likes the d.
package main
import (
"io"
"log"
"os"
)
func main() {
var input io.Reader = os.Stdin
if len(os.Args) >= 2 {
f, err := os.Open(os.Args[1])
if err != nil {
log.Fatalf("Can't open %q: %v", os.Args[1], err)
}
defer f.Close()
input = f
}
if _, err := io.Copy(os.Stdout, input); err != nil {
log.Fatalf("Can't copy to output: %v", err)
}
}
We're nit sure if the confusion engine is working at the moment which means we think its finished, but we're not sure
Bro really said functionalhieroglyphiclambdastream.println is more readable than Go
3:57 LIke: "They all noobs but we want them to immediately compete with space agencies." • • • • •
Yeah… Am I the only one having a weird mixed feeling about this "noble" goal ? 😂
"Confusion engine" cracked me up! sometimes I get this vibe with every other framework made for javascript..
My primary comaplaint is that I don't have the ability to call free on memory I know I no longer need. Ironically, the more I program in golang, the more I'm thinking about switching to C or C++.
What’s the request dedupe algorithm you were talking about? Typically that’s handled with idempotency tokens, but you’re talking about some clever diffing stuff. Can you share some more deets (nuts) about that?
I love your article videos, but I do wonder if it is possible for your layout to not obscure the rightmost quarter of the page. I struggle with auditory processing, so being able to read along makes these videos much more parsable for me. But I tend to find myself dodging your face and also chat. The former is not much of a problem, as you are usually reading the top half of your screen. but chat is almost always obscuring text I am attempting to read.
i'll give some thought to this :)
So I love go but := is auto so wouldn’t count it against D but fully agree with you that go is cleaner
If statements are always better than ternary operators, change my mind. And not just because ternary operators confused the absolute fuzz out of me for several years before I sat down and spent an hour learning how they work. Ternary operators invite new programmers like me to display their intelligence in the codebase by running the line length out into JavaScript levels of insanity when an if statement does _exactly the same thing._
Heck, _any_ feature that encourages developers to be smart should be discouraged, IMHO. As you mentioned at the end, it just turns into a clusterbomb of epic proportions just _waiting_ for something to go wrong. Have I dealt with code that was too smart? Yes. It was mine. I thought I'd display my intelligence in the codebase by only using GOTO for everything. When I had to use that program later, I rewrote it like a normal person. "It takes twice as much intelligence to debug code as it does to write the same code. Therefore, if you write to the limit of your intelligence, you are by definition not smart enough to debug your own code." -author unknown. I try to live by that statement.
I was driving when listening to you! I had to stop because you killed me man! The "confusion engine" is so much! 😂😂😂
I remember writing a critical piece of software in C, run into some undefined behavior and was so pissed that rewrote the whole thing in golang in 2 days. Rest client, concurrency. Log/csv parsing, db persistency. And almost the same speed. Now I only write C when needed (voip pjsua things etc)
Seems like a really biased article where the author just puts in his own ideologies. Also feel like he put in those additional whitespaces to make the go program look bigger
there was some significant whitespace additions
The interesting part is that the code we are refactoring was written a year ago, believing it to be the best-optimized solution. But during refacting we see that, it is one hell of a sh*t we have written at that time.
Can you provide more information about problems with channels and which library solves them. Thanks!
I feel like this has given me insight into different types of problem solvers and I love that I learned that from you. I also don't like your take, but I appreciate we have different strengths and strategies. Take care 😀👋