Hacker News new | past | comments | ask | show | jobs | submit | dvektor's comments login

I can relate quite a bit to your situation, as a self taught developer with years of experience programming, but <2y real industry experience in the last 15yrs.

I was in a situation where I was able to spend on avg. 14 hours a day for ~3 years programming without a single day off, trying to up-skill myself as much as I possibly could. Fortunately I already had much of the context and foreknowledge of what I needed to be learning, so all that time was spent building; instead of trying to learn what to build, or how.

After some time, I was given an opportunity to join a tech startup, and excelled. I wrote the vast majority of their code bases, I manage virtually all of their ops/infrastructure/deployments. I mentor our junior developers, I conduct all our technical interviews, and I make our implementation/design decisions, even tho we do employ other senior developers with many more years of experience than I have.

Many would be skeptical of someone with so little experience on paper being in such a position, and it honestly I believe it will be a very uphill battle you will have to fight when you are given such a high position, when it's time to move companies. To be quite honest I didn't even want the title I was given officially, because I didn't feel it was appropriate from an industry standard. However there is no doubt that it applies if you read the relevant job description.

As to your question specifically, seek out and spend time with more experienced engineers whenever possible. I am very lucky to have friends with many, many years of industry experience working for large tech companies, who I have been lucky enough to be able to work on side projects with, as well as having been able to contribute to open source, as well as building my own projects and taking on contract jobs on the side where I have solo developed a fairly substantial project as well. I am very grateful for these friends and I have learned very much from being able to build with them.

Build as much as you possibly can, work on projects that are far outside the scope of what you do for work, and take on challenges you otherwise wouldn't feel ready for. Try to befriend experienced devs and seek to be a part of communities where experienced engineers are found. There is no substitute for the hours of writing code, but surrounding yourself with others who's observations and code you will be able to learn and benefit from is a good start.


I feel like the medium paywall saved me... as soon as I saw "47 clusters across 3 different cloud providers", I begin to think that the tool used here might not actually the real issue.

[rejected] error: failed to push some refs to remote repository

Finally we can have this with s3 :)



Really appreciated the time someone spent putting that together, good article.

R.I.P Stiver


read: someone had 1.3M they needed to wash


Damien Hirst did a similar thing with his art: https://en.wikipedia.org/wiki/For_the_Love_of_God

I believe Beeple had his NFTs purchased by some platform or NFT investor group. Scammers continue.


Really? What do you feel that it's missing? I write Go for a living but I have also used Laravel (and vanilla php back in the day),and both actix + axum and I think Go really does hit that sweet spot of abstraction level for backends/web services.

I will say that I do prefer Gorm only to be used to scan the table -> model, I'd still rather write the sql by hand but I also don't want to scan the rows every time. But other than that I really cannot think of what it's missing.


Have you given sqlx a try? Manual query writing like database/SQL but convenience wrapper functions that handle the row scanning part for you. I haven't felt the need to use anything else for years now.


I think the point is to demonstrate how things work and are designed, and python is easy for everyone to understand. I don't think the author is recommending trying to write a production web browser in python. (or probably at all ;)


So what do you think of Go after the project? What language(s) did you come from?


IMO, it hits a nice sweet spot between performance and level of abstraction, especially w.r.t. concurrency and networking. Also I found that you get things done incredibly fast. I am mostly doing Python and some C, so Go feels like "somewhere in between".


I agree with a couple points here, specifically I agree that choosing a language based on it's community (and not it's ecosystem) is just silly. And we all know that async ended up being a bit of a thorn in rust's side.

But yeah, rust is very much a systems language: so it will be forcing you to think about memory layout one way or the other. Idk how valid of a complaint that is when you really consider that, and specifically the other alternatives you have.


A complication of the "Rust is a systems programming language" thing is that people adopt definitions of "systems" of varying expansiveness to suit the situation. There are unquestionable systems programming domains --- the kernel is a great example, and one where it's easy to see why Rust is an exciting proposition; same with browsers, the "second OS" everyone runs --- and then more questionable domains. Is the framework-layer code for a CRUD web application "systems" code? How about a container orchestrator?

This isn't a criticism of Rust, but rather of the framing we often use to compare Rust and (say) Python or Java.


Rust makes you think about your memory layout, memory allocation and avoiding thereof, about the specific time you grab and release other resources, about specifics of your inter-thread interactions, etc.

If such considerations are natural for your problem domain, you likely do "systems programming" and also happen know C, have an.opinion on Zig, etc.

If such considerations are the noise which you wish your language would abstract away, then you likely do "application programming", and you can pick from a wide gamut of languages, from Ruby and Python to Typescript to Elixir and Pony to C#, Java, and Kotlin to OCaml and Haskell. You can be utterly productive with each.


What does "think about your memory layout" mean? Can you provide an example? I've seen this brought up a few times on this thread and have no idea what people are referring to when they say it.

As for the rest of your list - I'm not sure why rust is special in regards to "the specific time you grab and release resources" or "inter-thread interactions". Seriously - I have to think about when I acquire and release resources like sockets and file handles python, c, ocaml, java, c#, and every other language I've used. Its not like you can randomly call file.close() or close(fd) (in python and c respectively) and expect to be able to continue reading or writing the file later. Same for inter-thread interactions... all those languages have mutexes too. Like none of that is rust-specific, its just the consequence of using resources and threads in code.


> What does "think about your memory layout" mean?

Here are some of the typical concerns:

- How exactly fields of a record sit in memory, how much room do hey take, taking into account things like padding for aligned access?

- Are related data sit next to each other, and can stay in the CPU cache together while needed?

- Are chaotic memory accesses thrashing the cache?

- Do the data structures avoid gratuitous references / pointer chasing (at least mostly)?

- Are local variables mostly allocated on the stack?

- Does your code avoid heap allocations where possible?

- Do fields in your data structure match a binary format, such as of an IP packet, or a memory-mapped register?

- Are your sensitive data protected from paging out to disk if free RAM is exhausted?

If these questions are not even relevant for your problem domain, you likely are not doing systems programming.


Again, the subtext here is GC versus direct control of memory lifecycles, and it is probably not reasonable to argue that there isn't a tradeoff here --- that every application is as gracefully expressible in one as the other, so long as you "git gud" at it. Both sides of this debate are guilty of deploying that trope.


I'm not arguing that there isn't a tradeoff, or about "git gud". I'm literally and genuinely baffled about how one can magically elide knowing if a file is open or closed (or the equivalent) when using a resource. Like I can't think of a single language that doesn't make you explicitly obtain resources, and most of the GC languages do the same thing as rust for casual closing - just let the handle go out of scope.

Even for memory, a huge amount of the rust I write isn't performance code - I don't understand why it's a mental burden to write

let x = vec![a, b, c];

When the equivalent in python is:

x = [a, b, c]

Nothing about either requires a lick of memory allocation thought, nor about memory layout. Sure in rust I have to think about what I'm going to do with that vec in rust and the mutation story up-front, but after enough lines of python I have also learned to think of that up front there too (ortherwise I know I'm going to be chasing down how I ended up mutating a copy of the list rather than the original list I wanted to mutate - usually because someone did list = $list_comprehension somewhere in the call stack before mutating).

I'm not being disingenuous here - I literally don't understand the difference, it feels like an oddly targetted complaint about things that are just what computer languages do. To the best of my ability to determine the biggest differences between the languages aren't about what's simple and complex, but how the problems with the complex things express themselves. I mean it's not like getting a recursion limit error in python on a line that merely does "temp = some_object.foo" is straight-forward to deal with, or the problems with "for _, x := range foo { func() { stuff with x } }" are easy to understand/learn to work with - but I don't see people running around saying you shouldn't learn those languages because there's a bunch of hidden stupid crap to wrap your head around to be effective. (and yes, i did run into both those problems in my first week of using the languages)

In all the languages there are wierd idioms and rules - some of them you get used to and some of them you structure your program around. Sometimes you learn to love it, and sometimes it annoys you to no end. In every case I've ever found it's either learn to work with the language or sign up for a world of pain, but if you choose the former everything gets easier. When a language makes something seem hard, but it seems easy in my favorite language, well, in that case I've discovered the complexity is there in both, but when it's hidden from me it limited my ability to see a vast array of options to explore and shown a whole new set of problem solving tools at my disposal.

I still don't know what people mean when they talk about "having to think about memory layout"... like seriously to me it's: Thinking about pointer alignment and how to cast one struct into another in C... something I've only had to think about once in any language across a fairly wide range of tasks. If this is what's being referred to, I'm baffled about how it's coming up so much, but i suspect this isn't what people mean, and I don't know what they actually do mean.


> I still don't know what people mean when they talk about "having to think about memory layout"

The best example I'd give is the degree to which you have to ask yourself if you want to use String or if you want to use &str--is this struct, or this function, going to own the string or borrow it from somebody else? If you're borrowing it, who is owning it? Can you actually make that work (this is really salient for parser designs)?

Essentially in Rust, before you can really start on a large project, you have to sit down and plan out how the memory ownership is going to go, and this design work doesn't really exist in most other languages. Note that it's not inherently a good thing or a bad thing, but it is a potential source of friction (especially for small projects or exploratory tools where memory ownership might want to evolve as you figure out what needs to happen).


> the degree to which you have to ask yourself if you want to use String or if you want to use &str

In practice, there isn’t a ton of thinking to do about this: if it’s a struct, you want String. If it’s a function parameter, you want &str, and if it’s a function’s return type, you want String. Doing that until you have a reason not to is the right call 95% of the time, and 4% of that last 5% is “if the return type is derived from an argument and isn’t changed by the body, return &str.

It does take some time when you’re learning, but once you get over the hump, you just don’t actively think about this stuff very much. Google’s research says Rust is roughly as productive as any other language there, so far. That doesn’t mean it’s universally true, but it’s also some evidence it’s not universally false.


> Google’s research says Rust is roughly as productive as any other language there, so far. That doesn’t mean it’s universally true, but it’s also some evidence it’s not universally false.

You shouldn't call this evidence but instead marketing. It was thoroughly debunked for the nonsense that it was in many places such as this: https://www.youtube.com/watch?v=vB3ACXSesGo


If you write Rust like this (insisting that structs always fulfill 'static) you will end up unnecessarily cloning memory way more than you would in a GC'ed language.

In GCed languages strings get allocated once when you need them, get referred to wherever you want, however many times you want (with no new calls to the allocation subsystem), and are freed once when you don't need them anymore, with minimal thought or intervention on the programmers part. Rust is absolutely not like this at all.

I agree with the overall idea that people exaggerate the difficulty of Rust, but come on, this is an exaggeration way too far in the other direction.


That’s why it’s “until proven otherwise.” As you gain experience you can be more subtle about it, and you gain more intuition, but it’s just not that big a deal until you demonstrate it’s a big deal.

I rarely type clone(). Even with this advice, you won’t clone super often. And when you do, it’s a signal sometimes that maybe you can do better, but it’s just not a big cognative burden.


Wading in here a little bit, and I know you've thought about this --- I think it's reasonable to say that there are problem domains where it's a very good thing, and problem domains where it isn't.

I think a subtextual problem for Rust advocacy is that the places where it's a clear win are a small subset of all software problems, and that space is shrinking. Rust would, in that view of the world, be a victim of its success: it's the best replacement we have for C/C++ today, but the industry has moved sharply away from solving problems that way, and sharply towards solving them with Javascript.

(Deno is doing something smart here.)


The way memory allocation and management becomes part of the paradigm of how we write and structure programs, is actually something I really enjoy about rust. It's like how you can do the exact same thing in C++, using the same concepts and tools (for the most part) with different names, but it never felt the same, or as natural. It's definitely helped the way I think about programs as a whole.


I feel the same way when I implement reference counting in a C program. It's certainly clarifying and educational. I think it's hard to argue that it's the most expedient way to write a CRUD application, though. Sometimes the most expedient path isn't the most fun one.


Totally reasonable question. The issue isn't how hard it is to get the memory for the a vector, but rather what you have to do to store references to that vector elsewhere in your code, so that the compiler can prove its bounded lifetime and release resources without creating UAF bugs.


"Systems programming language" has almost turned into a weird slur; instead of using it to refer to languages that can actually handle that task, they use it to attempt to pigeonhole a language into only that.

As in, people don't realize being a "systems programming language" is extremely difficult to get right, and many languages simply can't handle that (and never will, as per internal design requirements unique to those languages); if a language gets that right, they're going to get everything else right too if people decided to use it for that.


See, depending on your definition of "systems programming language", that is just wildly false. A language that nails all the details and ergonomics of expressing a kernel block device driver is almost necessarily going to be suboptimal for exploratory scientific computing or line-of-business app development.

Again: this is about the term, not about the language. I don't think it's controversial to suggest that there is no one ur-language that is optimal for every problem domain!


I don't think the people that use it as a slur actually define it. They use it to mean the language they don't like because they think it has some level of enforced complexity that takes away from the language instead of being an important feature of the language.


Yes: it's about the distinction between global GC and programmer-defined memory management. GC is about as straightforward a tradeoff as you can make: remove a very large class of programmer concerns in exchange for a different performance envelope. It is not reasonable to argue that Rust's memory management doesn't represent a point on a tradeoff space --- that people suggesting GC languages are better fits for some problems just don't grok Rust well enough. That's a common trope, and it's pretty obviously false, just as it would be false to say that kernels should just supply a GC runtime so we can write device drivers in Java.


Meanwhile there are companies doing just that, better let their management know how fool they are selling bare metal real time Java runtimes, Oberon, Go and C# based microkernels.

Even more so the fools that given them money for such products.

/s


Look, I know there are bare metal Java runtimes (I've done assessment projects for some of them), I just don't want to litigate the point. I'm fine with a definition of "kernel programming" that fits Linux and the NT kernel and nothing else.


A quite reducing view of the computing world.


Yeah I use often Rust where Python would be enough. But unless I really need quick/interactive feedback (for exploratory stuff ie.: Jupyter with plots), Rust suits me well.


I enjoy expressing applications in C. Once a week, a story hits the front page here about someone shipping a web app in C. C suits me well. But I don't pretend that's an objectively reasonable engineering decision. It is not.


Generally this. There are obvious reasons you might need to use Oauth2/OIDC... but for side projects, I really don't get why people are so opposed to storing a bcrypt or argon hash, and keeping a session table or using a JWT. I can see "never rolling your own auth" if that meant using your own hand-rolled crypto libraries, but somehow it seems to have became "you must pay for a service or use some magic library".


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: