Live data from Hacker News

Absolute truths I unlearned as junior developer (2019)

monicalent.com

221–230 of 269 posts

Re: Absolute truths I unlearned as junior developer (2019)

#221
post #50

Earlier quoted context omitted.

I don't understand this, this is the way every hierarchy work, and how every single job/management role is functioning. It's to solve the problem of communication overhead growing exponentially with larger groups of people. Why does this make you sad? And is it better to have a dysfunctional organisation where people float in and out of poorly defined roles and everyone tries to do everything? Does that really make y…

Is a hierarchy the right way to organise a company? communication does not have to happen from manager down to lower manager and then manager to reports. Why can't one guy at the top just email everyone (and even that does not have to be top down, answers received from God on the mountaintop but can be part of an active conversation (cf Torvalds). One way of looking at this is hierarchy works well for an organisation…

>Is a hierarchy the right way to organise a company?

I think so.

I've twice worked as a software engineer for flat organizations (once as a subcontractor, once as a normal employee) and I really, really dislike it. Strong leadership is important.

There ends up being chaos, uncertainty, and a distinct lack of accountability.

Re: Absolute truths I unlearned as junior developer (2019)

#222

>I learned all that fancy Angular-specific JSDoc syntax. My code was always twice as long because it had so much documentation and so many comments That's a very bad habit. Code should be self documenting. If you need to write comments to explain what the code does, you've done a poor job at writing it.

Comments aren't bad per se, but they should explain Why vs. How.

Re: Absolute truths I unlearned as junior developer (2019)

#223
post #203

Earlier quoted context omitted.

You need coordination. You don't necessarily need hierarchical coordination.

Coordination without any kind of hierarchy has N!/2 complexity. That gets overwhelming way to soon. Have an idea that requires everyone else to change something. N!/2 conversations to have. (Or one big meeting with the same sort of complexity). Need to change your approach to match what others are doing, gotta make a 1-on-1 connection. If they need to change their approach, they need to coordinate with others, contin…

Isn't hierarchy standing in for encapsulation here? Companies interact with one another in a coordinated way with neither a hierarchy, nor needing to know what every other company is doing

Re: Absolute truths I unlearned as junior developer (2019)

#224
post #9

For me, it was that I thought that being a good programmer was that I write clean code with enough abstraction and indirection to make it future proof. Boy I was wrong. Unless you’re doing the same thing you’ve done for years, you can’t tell the future. And just when your unnecessary abstraction is wrong, this the reason why we’re talking about tech debt in the first place. Because nobody wants to touch it. Unfortuna…

this is exactly what I like in Golang

Re: Absolute truths I unlearned as junior developer (2019)

#225
post #65
post #22

Earlier quoted context omitted.

There are abstractions that are not domain related, those exist as well, and I'd consider them more a part of product design, but software design can benefit from good abstractions at multiple levels and constantly do, but knowing how to use good abstractions and design them is very hard, bad ones or bad use of them will be worse than none. For example, a schema is an abstraction. Choosing to have a strictly defined…

I can almost guarantee you that any codebase with a "Player" class that looks anything like your example is a very poor codebase. It shows me they just didn't know where to start, so they started by throwing everything in there. Abstractions are always about the consumer of the abstraction, not the implementer. No consumer needs everything in "Player", so it's a terrible abstraction, and it's not just a data type or…

> They're about what you need

I've no experience with game dev, but in other areas of development what you need is often not known ahead of time (which I believe the parent is trying to say). Operating under those conditions makes the Position abstraction somewhat arbitrary (until it's obvious it's needed by other parts of the system). Aggressive refactoring and robust testing are necessary when operating under these conditions.

Re: Absolute truths I unlearned as junior developer (2019)

#226
post #59

> Things like indendetation, formatting, naming – god forbid you did it differently than I would have. I agree with chilling out about this when it's a human making the changes...except now that we have autoformatters we can actually be more pedantic about this than ever before :) If the autoformatter doesn't agree with what you wrote, bam, red CI. > Everyone writes tests A big thing I've learned over the years is th…

Much of the time, once my code is the way I want, there's almost nothing to test. Any tests I write would just be an echo of the implementation itself. I think if you're using your static type system to its fullest and writing clean, "obviously correct" code, 80% of your tests are simply not necessary at all. It goes: - Bad code: almost no tests. - Good code: lots and lots of tests. - Great code: almost no tests.

Testing is to ensure your code functions the way external users expect it to. There's a reason SQLite has an extremely robust test suite even if their code is great.

Testing that the internal interfaces / abstractions in your system is less important - which I believe is what you're getting at. Those tests are definitely echoes of the implementations. Often they're for other developers.

Re: Absolute truths I unlearned as junior developer (2019)

#227
post #22

Earlier quoted context omitted.

There are abstractions that are not domain related, those exist as well, and I'd consider them more a part of product design, but software design can benefit from good abstractions at multiple levels and constantly do, but knowing how to use good abstractions and design them is very hard, bad ones or bad use of them will be worse than none. For example, a schema is an abstraction. Choosing to have a strictly defined…

A (json) schema is a specification, which is the opposite of an abstraction.

An abstraction is something that can be made concrete. For example in OOP, Classes and Interfaces are abstractions.

An abstraction has no material presence, so in code, concretions are the actual data in memory in their exact place and precise arrangements and linking and all that on a precise machine.

Source code is an abstract representation of a running program for example. Everything in source code form is an abstraction.

Generally an abstraction has gaps, it can't actually be run into the exact behavior you want on its own.

A schema is an abstraction, because schema isn't executable into the concrete running behavior you're trying to implement. A schema or a data specification (which is just another word for schema), is definitely an abstraction. It abstracts over the actual concrete data you will have at runtime.

Everything that is not in the final concrete running form it needs to be at runtime is an abstraction.

A specification abstracts the implementation away, it's an abstract idea of what you want, but does not specify the implementation.

Unfortunately the concept of abstraction is itself very abstract, but one thing a lot of people don't realize is how many things are actually abstractions.

Even a simple function is an abstraction. It can only run once provided actual values to its arguments, it is but a template abstracting the idea of mapping inputs to outputs using some logic. You need an instance of it with actual values for its arguments to be able to run it, a function with concrete values provided as arguments is now a concrete thing, but the function definition, i.e, the code for it is simply an abstraction.

You can further abstract over abstractions, a function signature abstract further the implementation away, to be filled in later.

And generally speaking, even a running program is simply an abstraction of reality, a simulation of something real, but this is when you start to enter product design, how to best abstract over the real life use cases you're trying to have a program that can represent, model and simulate.

Programming Languages and other frameworks often provide you means of modeling abstractions, constructs that can help you define your own abstractions. Those tools will vary from language to language, in some OO language like I said you're given Classes, static types, Interfaces, inheritance hierarchies, etc. In some functional languages you'll be given abstract data types, functions, higher order functions, type classes, etc.

I could keep going on, but I find the concept of abstraction itself is often misunderstood.

P.S.: You can easily argue a different definition, arguing semantics has no definite truth, definitions of words are just axioms we define. I believe it is more useful and beneficial to define abstraction as I just did for being able to better reason about and make judgement calls as to how exactly to structure and design software code. I'd encourage others to give it a try, attempt to rediscover abstractions how I just described, and you'll learn a lot in my experience, and you might become a better programmer out of it.

Just my 2 cents.

Re: Absolute truths I unlearned as junior developer (2019)

#228
post #55

Earlier quoted context omitted.

I am curious at what scale do you justify using containers. I was just messing around in AWS making a cluster left it over night (few days), I had a $10 bill. Which is fine but yeah, in contrast my person apps/sites have been running on a $5/mo VPS. Anyway it's still cool to know/eventually use this somewhere but I'm concerned how you keep it fresh if you don't personally use it. edit: I left it on longer than that (…

I start with containers, even if we're deploying single binaries. Local repo of the prod environment is incredibly useful when you inevitably need it. GitHub actions/Gitlab CI build containers out of the box, and deploy to ecs/kubernetes/digitalocean/whatever straight out of the box. I can set up a CD pipeline on a fresh project to AWS with github actions in about 15 minutes that I will never need to touch again unti…

What's your bill like? Or I guess it depends on each person's interest in the cost but yeah. Maybe it doesn't have to be expensive if you do it from a "raw" way.

Re: Absolute truths I unlearned as junior developer (2019)

#229

> That’s why mentors are so important, and the team you work with is worth so much more than a couple bucks in your paycheck. Don’t accept a junior position where you’ll be working alone, if you can help it! And don’t accept your first role (or, honestly, any role) based on salary alone. The team is where the real value is. Couldn't agree more. Of course, with today's attitudes towards us olds, and the average term o…

It's still baffling to me how short avg tenure for SWE is, in general. I feel that after a year, maybe, is when I finally start getting the lay of the land, meet some people, start understanding more of the domain and can start causing impact worthy of my paycheck. I'm now at 3.3 years at my current gig and I'm feeling like I have superpowers, if that makes sense. I think it takes time to be in a position to really d…

It really depends. In my experience, after about 2 years in a specific role you will start to develop expertise in your specific organization and tech stack rather than generalist capabilities. There are good reasons to stay after that (you love the team, could work in the domain forever, getting tons of growth opportunities/raises etc.), but you should understand the tradeoff. You may be trading off learning how to be an effective worker in general vs. learning how to be an effective worker in your specific organization and you may be making significant financial sacrifices vs. people that switch jobs.

Re: Absolute truths I unlearned as junior developer (2019)

#230
post #12

Earlier quoted context omitted.

There's a level beyond that where you actually figure out how to write good abstractions. It's likely you thought you were making good abstractions and useful indirections, but you weren't, hence the problem. Concrete code with little indirection will be better than badly thought out abstractions that are incorrectly designed with unnecessary layers and indirections. That said, good ones, that are well done and thoug…

> actually figure out how to write good abstractions. There's an element of no-true-scottsman in this argument. Most codebases that I've seen have excessive amounts of unnecessary abstractions. It's rare to see a codebase that has too few abstractions. You can of course make the argument that "they just weren't creating the right abstractions", and it's not necessarily incorrect - it's just unhelpful as a piece of ad…

There was a time where there was seldom any abstractions, people wrote in assembly code, it was as close to the concrete machine as you could be. It was painful, complicated, and doing anything was tedious, effortful and slow.

Abstractions were clearly needed. Higher level languages abstracting over the machine lower level details were needed.

Then there was a time where abstractions themselves were very simple, branching and looping were all just done with "goto", it was error prone, confusing, and made working with other people's code bases difficult. Abstractions were clearly needed, something to abstract over the lower level details of branching and looping and memory management with relations to those.

Fast forward to Java. Now we already started with quite a lot of abstraction, yet there were still times when things were more tedious then they needed to be, more abstraction was still needed, it led to the addition of Interfaces, the development of frameworks like Spring, the creation of template languages like JSP, the addition of code-generation tools like Lombok or API generation like Open API.

Once again more abstraction became hugely benefitial, delivering real productivity boosts and still helping to make things clearer, not more obfuscated. Even though it is true at each layer it becomes harder to understand how all these abstractions reduce themselves back to some concrete instance at the end of it all. But if you can trust in them, you need not worry about that, a good abstraction lets you forget and ignore the complex details underneath it, freeing you to focus on more of your higher level concerns progressively closer and closer to your real domain problem and away from the computer machine concerns.

Finally enterprise software reached a point where managing complexity got difficult, so people tried to promote best practices they had learned, basically ways to fit in more abstractions in certain situations that again benefited them greatly. There was a big push to advocate for "design patterns" and other judicious use of abstractions.

Lots of people, often mid-level developers, including me at the time, we went seeking for advice, while we didn't understand why, what's the need that drove this advice, what's the use that benefits from it, we took them to heart: SOLID principles, GRASP, YAGNI, inheritance, interfaces, composition, we took it all at face value and tried to arbitrarily use our limited understanding of them everywhere we could, religiously and impartially.

This frivolous misuse of abstractions yielded the plagued over-engineered, obfuscated, puzzle-like, code bases that a lot of enterprise software suffers from. Where the hell is the actual code doing the actual thing?

This had more senior engineer once again try to push some new "best practice", a new commandment to amend for the misunderstanding of the prior ones: "less abstractions is generally better". Or in other words, just use the abstractions more experienced people have already put in place, stick to your popular framework, follow its existing patterns, stick to simple usage of your programming language, and don't try to be smarter than you are, aka too clever.

This is great advice, I'm absolutely in support for it, and to some developers, they're not ready to hear the more nuanced version of it, it might lead them down the wrong path again.

But, my point is, good abstractions are really awesome, and by definition of what makes them "good" is that they actually help rather than hurt. There's countless examples of good abstractions throughout the history of software development. There's even so many more minor abstractions that everyone implements on a daily basis without even realizing that once again being better at results in better code, like simply choosing what the method will be and what the arguments and return value for it will be. Or choosing where the data will live.

So my point is, in my opinion, a senior engineer is one that knows about the "generally" part of "less abstractions is generally better". A senior engineer knows exactly when less abstractions is better and when more abstractions is better. Don't stomp your growth by once again being religious about a best practice and arbitrarily being against all abstractions because the best practice said to try to avoid them.

Post reply on HN