HN user

srer

304 karma
Posts0
Comments48
View on HN
No posts found.

But fundamentally no one should ever be trying to merge code that hasn’t been unit tested. If they are, that is a huge problem because it shows arrogance, ignorance, willingness to kick-the-can-down-the-road, etc.

Here you are asserting that unit testing is fundamental, and that not believing this is arrogance and ignorance.

I'd suggest your view that your way is "the" way, is an ironic display of arrogance, and perhaps ignorance.

And this perhaps I think is the core of much of the anti-TDD sentiment. It's not that we don't think TDD and unit tests are without their positives, it's that we don't like being told this is the one true way to write software, and if we don't do it your way we are engaging in poor engineering.

Consider it is not an unheard of experience to join the workforce, use a preconfigured macbook with precisely 1 SSD, and spend one's career building on SaaS platforms like AWS Lambda.

In such a world, perhaps those who remember there's a world of flexibility and power within the OS could be seen as welding some supernatural power.

The language has memory-safe concurrency (except for maps, which is weird)...

My understanding is you should operate the other way around. Things aren't safe for concurrent mutation unless it's explicitly documented as safe.

So you can have parallelism without worrying too much about race conditions or leaks.

You might not worry, but I find these the two easiest classes of Go bug to find when entering new codebases ;).

Still, I agree Go is easier to get a web service up and running with.

I work somewhere going through a similar process for much the same reason.

And to be frank, I'm wondering if how it ends is in me looking for a new job.

I know there's good reasons for the business to go through this process, and maybe it is really important for the business future but as an individual it sucks, my main motivator of achieving good outcomes for users, has been derailed by a large amount of procedure instigated under the belief that some auditor I've never met will be impressed.

Now with all this new procedure piled on, all of which is very new and thus immature and untried, I feel my energy to innovate, build new things and just generally drive change sapping away.

So the cost of your company isn't just the direct hours and the auditors fees! There's also a harder to quantify cost, as everything and everyone bends to change every team to work in the way some external entity thinks it should. This loss of autonomy and the loss of spirit is I think potentially far far more expensive than the direct costs.

Of course, maybe we're just going about the whole process poorly. I like to think if you were to do it well maybe it's not so bad. But, to do that I think you'd need abnormally talented staff involved, who are well versed in the topic, enthusiastic and empathetic. Most people involved in these sorts of processes in my experience aren't like that, and I can't say I blame them.

10 hours isn't too bad when dealing with a giant organization. Often problems cut across teams and services, and troubleshooting then liaising and ultimately getting a remediation action through (which might involve producing, testing and releasing a patch) all takes up time. Sometimes things blow out to weeks!

Personally, my last AWS Support ticket was pertaining to Lambdas and I got a very good answer. I was impressed.

It's important I think to appreciate working in support is difficult work, every single day is a customer with their own urgent problem. When urgency is the norm, it's not urgent. And heart? It can be soul sucking work.

In my observation support takes the brunt of the rest of the orgs shortcomings, bad releases, deprecated features, etc, drive customers towards you in unfortunate circumstances. Sometimes there's a whole waterfall of shit raining down on you, and it ain't your fault, and there's nothing you can do or could have done.

And to add insult to injury, you're normally at the bottom of the org pecking order.

As I say, difficult work. I salute all those who do it!

I do the opposite. Across C, Python and Go, I was prepared and had a good understanding of the languages and stdlibs before joining through reading books and working through the exercises.

It worked very well for me, on joining my knowledge of the languages and their stdlibs was respectable, and I could hit the ground running and get patches accepted easily. I could also in each languages case fix weirdness they had in their code because their own knowledge had gaps. That impressed people and made a pretty good first impression.

It's probably not universally true, but in my observation learning on the job much more commonly ends up resulting in sizable gaps in language knowledge.

If you've got a role working in $LANG, I don't see how upskilling in $LANG before you join is a trap. It's commonly knowledge with lasting value that offers returns across jobs.

I've never worked with C++, I hear hints that it's too big to actually learn and instead one must learn a subset. Maybe that's true, and the article more applies there.

A single server is much faster than most people think, too!

In the microservice or serverless arrangements I've seen, data is scattered across the cloud.

It's common for the dominant factor in performance to be data locality, most times this talk about data locality is about avoiding trips to RAM, or worse disk. But in our "modern" distributed cloud things, finding a bit of data frequently involves a trip over the network. In the monolith world what was once invoking a method on an account object, has become making a HTTP POST to the accounts microservice.

What might have been a microseconds operation in the single server world, might become hundreds of milliseconds in the distributed cloud world. While you can't horizontally scale a single server, your 1000x head start in performance might delay scaling issues for a very long time.

A most excellent paper related to this topic that I think should be mandatory reading before allowing anyone an AWS account is http://www.frankmcsherry.org/assets/COST.pdf :)

Leetcode is programming.

It's not sprint planning, 1 on 1s, backlog grooming, jira tickets, slack support, gathering requirements, making estimates, negotiating features with management, responding to alerts, or the million other things you get sucked into as a nominal "software engineer".

But it's definitely programming.

It's a specific style of working, not entirely unlike TDD, with a specific theme of problems which aligns well with the content of undergraduate algorithms and data structures courses.

Is there a degree of pattern matching and rote memorization? Most certainly!

And does pattern matching and rote memorization play a significant part in real world programming? Definitely! If there's not as much memorization happening it's because the art of copy and pasting from stackoverflow supplants the need.

And presented with wishing to learn the content of a university course, what's one rather effective technique to achieve it? To do exercises, a lot of them, and when you're stuck look at how other people solved them.

That's all leetcode is.

Perhaps others think that undergrad course in algorithms and data structures is useless material but I do not. I think it makes you a better programmer.

Cold Showers 4 years ago

As a general rule for dev work, trying to make evidence based decisions is fairly difficult. There's just not that much evidence around yet that can make it obvious as to if in your particular situation what the best choice might be.

And at the end of the day you have to contend with being in a work environment where politics and personalities rule, not science (or engineering).

That said I do wish more devs would take an interest in the available quality literature. Unfortunately I'm far more likely at work to run into an Uncle Bob recommendation at work, than a recommendation of ACM's Digital Library.

I largely agree with you, that rather than introducing Rust into your workplace it's easier to change workplaces.

I currently work in a Go shop. Why Go? Did it win some business value delivering contest? I don't think so, it's just the initial team lead liked Go the most of the languages they knew and made everyone else learn it.

If you read my comment history you'll see I think Go is a mediocre choice. But, it's here to stay in this company and it doesn't matter what new language comes along it won't have the inertia or acceptance of the status quo language. The expected improvement has to be large enough to overcome the associated costs to sell the business case.

This idea of the status quo being somewhat arbitrary, and difficult to change, applies to more than just languages. It applies to everything else, your architecture, your work processes, your culture. A blueprint is set early on by some founding members, and perpetuated potentially forever.

In this world, rather than trying to change a company you change employers. Innovation is change, and to achieve that the individual changes, but leaves their company to remain the same.

Personally, I seek to improve in what I do, to innovate. And I think what we do can be done better and that the tools and systems in-place play a part in that. But will I introduce them at my workplace?

Perhaps not, I think I'll find a new job, and both my old and next company can pay the rather high costs of someone leaving and someone joining. This makes me a little sad, since I like my company and leaving would be a significant amount of institutional knowledge walking out the door.

Lets see what the Go doc example looks like:

  sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
In Python one might write:
  people.sort(key=lambda person: person.name)
Or in Rust:
  people.sort_by_key(|person| person.name); // sort_by is also an option...
I think it's worth calling out exactly what is happening in the Go example:

- We create a closure that captures the people slice

- We pass the people slice and the closure to the Slice function

- The Slice function mutates the people slice, and because the closure captured the slice it sees these mutations too

I get why the Go team wrote sort.Slice like that, and it was perhaps the best they could have done with the language features...But I think we're going to have to agree to disagree on how wonderful it is compared to other languages ;).

Pretty simple for me:

I like working with Free and Open software much more than proprietary software. I think it's important for society, and I have more fun that way too!

Also the payoff for me has been very good, I can learn emacs once and enjoy using it for the rest of my life for all significant written language tasks on a computer.

Perhaps I could be a little more efficient if I were using a jetbrains IDE, but then I wouldn't like what I was doing as much. Enjoying what I do, even if it may look slightly contrived to others, is important in me achieving results at work.

There are significant pockets of non-git users in the developer community ;)

I find hg much more pleasant to use than git, and can generally still work in git based teams while using hg.

I find pijul's approach much more interesting than git's, and look forward to pijul (and others :) pushing forward how we do revision control.

I don't believe git to be the end of the evolution of revision control systems (which for me has looked like cp -> rcs -> cvs -> svn -> git|hg), and find git lacking enough that I look forward to what the next generation does.

Would I argue that you personally should branch outside of your git centric world? Of course not! Just as I've worked with many devs who live their lives gainfully employed only knowing Java, or sys admins who only know Microsoft, it is up to you as to if you wish to explore different approaches and styles to achieve your end goal.

Largely complaints of Rust seem to boil down to the programmer needing to describe object lifetime information in code.

We can, as the original post did, show approaches that are overwhelmingly difficult in Rust because of this but trivial in Go. Alternative approaches, as this post shows, can be relatively straightforward.

In a similar vein, a Python programmer might complain about having to explicitly describe object type information in Go code. One supposes they could show approaches that are overwhelmingly difficult in Go, but trivial in Python.

Python, Go and Rust programs all do have types and object lifetimes. It is just that mistakes in type are not found until runtime in Python, and likewise mistakes in lifetime are not found until runtime in Python and Go.

Personally, after years of Python I came to value describing types in code, and after years of Go I came to value describing lifetimes in code too.

Increasing we automate processes, have programs do the work humans once did.

It's extremely helpful and productive, but it has a darker side. The processes are rigid because machines are rigid, and the designers cater to the 99% cases.

But then the 1% happens, and you're left out in the cold.

In the old world of humans and paper, as wasteful as it was, it was easy for exceptions to be made if the clerk was willing, and if they weren't you'd find another clerk, or a clerks supervisor. The processes tended towards being flexible.

But today, you increasingly don't interact with any humans, or if you do don't be surprised if, in your unusual case, they say "the computer won't let me".

As governments move more and more towards digitization, and embrace machine learning, I expect similar stories might unfold - only it won't be with an opt in social media website.

I work in a company that's all in with serverless on AWS, but unlike you I can't give a glowing recommendation.

The answer should always be "it depends".

IMHO the more distributed a system the more difficult it is to correctly build. Serverless architectures encourage distribution by building your service from different AWS components, commonly say, Lambdas, S3, DDB, SQS, etc, you end up building a distributed system from AWS provided distributed systems.

System performance is commonly a function of data locality, and serverless typically spreads things out. The Lambda's have no persistent state of their own, though DDB is fastish, it's still multiple network hops away. Speaking of performance, you are also always trying to work within the 15 minute / 10 GB lambda hard limits, which has made my current role the one with the most performance management work yet!

Lastly, you require a rather high proficiency in AWS, both in general (IAM polices, roles, cloud formation, cloudwatch, et al), and in specific services - and each service is it's own thing with it's own performance traits and consistency guarantees and semantics. It takes a lot to pick it all up.

Meanwhile, single servers, being whether you rent an EC2 virtual instance, an OVH rented physical instance, or purchase one, have gotten extraordinarily powerful. And postgres has proven to be very useful.

I'm not suggesting people ignore AWS all together, but perhaps using less services could serve a lot of people rather well, 1 EC2 using Postgres RDS and EBS, can do an awful lot. I notice the M6a instances apparently max out at 192 VCPU, 768GB RAM, 50Gbps networking and 40Gbps of EBS connectivity.

Most people know how to run 1 host, everyone has 1 host they use as their work desktop, they have routers and home servers, and they get great data locality and a much easier to reason about system.

Some might allege that such a host will have less uptime compared to what someone might build with a serverless architecture. However, I believe most outages are a result of human error, be it in configuration or code, and by simplifying the system to a host, a DB and a SAN volume, one might be able to make it much more straightforward, which also helps recover from outages much quicker. (Serverless observability is no where near as good as what one gets with a process running on a Linux server you can SSH into.)

Some might say you will hit hard scaling limits, since such a design scales up rather than out. This is true, but AWS is a minefield of quotas and hard limits, and you have to design carefully around them. A Linux host will also have such limits, but AWS Serverless will be a superset, since at the end of the day AWS Serverless is running your process in a Linux firecracker VM anyway.

I don't mean to be an advocate for any part of the spectrum, just that I don't think there's any free lunch here by picking serverless. Much like picking a programming language, I think it might come down largely to what your existing skills are and your personality.

I find interviewing skills are more important than job skills in terms of income.

Trying to get a 20% raise by doing a good job I've found to be a protracted difficult task, but a 50% raise by interviewing? Much easier.

You do need some job skills, but in my experience being fired for not being good enough is rare, and can take a lot of time - during which you're getting paid.

Another thing I've found is I pick up the most exposure to new ideas in that first 12 months in a job.

These two things together means being able to get a new job easily is very useful.

But getting a job is different from doing a job, don't expect the two activities to have much in common. It could be better, but hey 3-4 months of evenings spent programming to get a big step up in the job market is a pretty good deal if you enjoy programming :)

(Personally I've found leetcode useful at becoming a better programmer, though I didn't approach it as memorizing riddles.)

I do that, create the ticket.

I want to believe it means one day we will do that TODO, it'll beat the priority of all the other tickets in the queue.

But it never does, there's always some critical new feature sales wants, or something bigger on fire.

I still create the tickets, as a kind of cathartic process, a confession to the jira gods, I have sinned and half assed something. Please take this ticket as my penance.

Wanting SQLite in Go touches on something that I think is quite a waste in modern Go circles, but happens everywhere to varying degrees.

There's often (for instance, in Go projects wanting to avoid cgo) a desire for everything to be in the single source language - Go. In what resembles NIH syndrome, there will be clones of existing libraries, offering little over the original except being "Written in Go". From experience this often makes for more bugs, as the Go version is commonly much younger and lessor used than the existing non-Go library.

The Python world does it a lot less, perhaps the slowness of Python helps encourage using non-python libraries in Python modules. But that sure does making building and distributing Python projects "fun".

What I'm trying to say is that:

A world where every language community has it's own SQLite project because the communities shun code written in other languages just feels like a profound waste.

I'm going to mention my own tiny experience report as a frequent SQL user, of Go's simplicity pushing a lot of burden onto the user in the relatively simple task of querying a list of things from a SQL table:

http://go-database-sql.org/retrieving.html - lets pretend we return errors rather than dying with log.Fatals :)

There's a specific order of operations to be done here, and even a slight deviance could be a significant bug.

To start of with we:

  1. Do query
  2. Check err
  3. Defer close

  1 is straight forward.
  2 you can forget, then something bad may happen.
  3 you can forget, which will cause a resource leak.
  If you switch the ordering of 2 and 3 something bad may happen.
Instead of defer close(), a user might opt to just close() at the end of the function, but there's a reasonable chance they'll overlook the unhappy paths.

Next we have iterating over the results:

  1. For rows.next()
  2. Scan into a &var
  3. Check for scanning errors
  4. Exit for loop, check rows.Err

  1 is hard to mess up.
  2 has some potential to mess up if you're not clear on which bit of memory you're storing the result in.
  3 you can forget, which could cause you to get the previously scanned var show up multiple times, or zero values.
  4. you can forget, which will cause your results set to (I guess?) be incomplete.
There's a lot of different permutations in this code that will compile, and I think has a good chance of passing the average paid dev's test suite (it's a bit of work to exhaustively test the unhappy paths).

In my experience people are especially prone to messing up closing rows. I don't blame em, we know from decades of C that manually freeing resources, especially in the case of errors, is tricky.

If I've made any mistakes, please point them out, as it supports my stance ;)

(There's more fun to be had in SQL with Go, like that SQL has optional types, but Go doesn't, which leads us to sql.NullString et al).

your greater system model has to assume it can die at any instant for any reason

Correct. This is something I have to design for in the system anyway, because in practice anything can (and does!) die at unpredictable times. It's typically an inevitable fact of life that a machine/kernel/program will occasionally die, and your system has to survive that.

IRC's influx of new users has been dropping off for a long time.

Personally I started using IRC 20 years ago, there were a lot of new users then.

The big IRCnets were massive[a] compared to today[b]. Today libera.chat is the biggest, but slowly dropping.

End result? IRC provides me direct access to a community that's ancient, with a notable lack of less experienced users. This is exceptionally helpful, I don't need a giant community to engage with, a few users with decades of experience in the topic I'm interested in is enough to answer almost all my questions :).

As such I would be rather surprised if there was a better option for real time answers.

I imagine usenet is a similar experience. An even older community with little influx of new users, ergo an even higher median experience level.

I expect I'll use IRC until I die, I can't say that for many things in technology.

[a] https://netsplit.de/networks/top10.php?year=2003 [b] https://netsplit.de/networks/top10.php

Much like you I look forward to (mostly CPU) increases to get better arma3 performance!

We need all the performance we can get, because even if it was the worlds most optimized engine, we'd just create bigger scenarios. Who wouldn't find a 10,000 unit mission fun, even if it was only at 40fps? :)

Inutterably brilliant and a genre of 1, I couldn't agree more.

Is Rust Web Yet? 4 years ago

I'm not sure what you mean by manually manage.

I don't manually manage my memory anymore in Rust than I do in garbage collected languages (say Python or Go). (I do have to think about object lifetimes and whats pointing where in all three mentioned languages).

As an aside, I really like not having to manually free locks, close files, release connections back to pools, etc. It's one resource management paradigm that applies to everything - not just memory.

Software updates is one reason

For simpler userspace updates a restart of the relevant processes is easy enough, but it can be a bit more difficult when it comes to kernel updates.

(Updating a running kernel has been a thing in Linux for a number of years, but my systems don't do it.)

Programming is a vast field, "essentially never" is quite a strong statement.

For many errors, in many situations, terminating the process is quite reasonable.

In my particular situation, the greater system will restart failed processes, and retry failed tasks. I find this useful as in many cases my program can just die when something weird happens, simplifying it's own logic.

IMHO:

Rust integrates a bit better with existing software. Inclusion of Rust in Linux being an example. Go culture tends to value pure Go projects a bit more than Rust's, where Rust wrappers around C libs are more accepted and common.

Go is generally easier from a social point of view, there's not much to learn as it's largely a repeat of what people are familiar with. So introducing it in a workplace is easier as the on ramp is minor.

Ubiquitous greenthreading in Go seems to make the integration piece a bit harder, but the onramp a bit easier.