Hacker Newsnew | past | comments | ask | show | jobs | submit | retrodaredevil's commentslogin

NullAway with JSpecify annotations are a really good way to add null safety to Java applications. Even enforces nullability at the generic level.

The elephant in the room is the standard library (collections). It isn't even type safe yet, because some methods were around before generics were added. And collections are too core for anyone to be able to agree on a 3rd party standard.

I mean, I guess you could say stuff like get(Object) and contains(Object) aren't type safe, but I've never seen that as an issue in practice. Plus there are some ErrorProne checks that'll tell you if you're doing something wrong in regards to calling contains(Object) with the wrong type.

They accept Object not because they're not type safe. They accept Object because key `equals` method might return `true` for unrelated classes by design, and collections interfaces have to accommodate for that. In other words, you might put key of class C1 into the map, and later use `get` with key of class C2. And if these classes happen to implement `equals` accepting each other, the collections are supposed to work.

So the core issue is that `Object.equals` method isn't type safe. Collections API just follow that.


The design of error handling in Go is interesting because they wanted to force people to actually handle errors by returning them as values, but then you as the programmer have to decide whether an error should be returned or a panic should be used.

It reminds me of the original intention of checked exceptions in Java: checked exceptions are for things you force the caller to handle, unchecked exceptions are for "you the programmer messed up". In reality checked exceptions are pretty unpopular and can't be used in many situations, so people fall back to unchecked exceptions.

If we equate unchecked exceptions with panics in Go, falling back to panics would be an anti-pattern in many cases.

NPEs in Java have become rarer and rarer recently with the introduction of records (to easily create immutable classes, which are easier to validate for null against). Plus JSpecify annotations get you null denotation that's almost as good as Kotlin's. Combine that with NullAway are you have compile time null safety. Go has nilaway [0]. One interesting thing about nilaway is that you don't null-annotate your code, it just detects nilness when you run nilaway. That makes nilaway a decent tool to get feedback right away, but it doesn't force you to document the intention behind parameters and fields for whether they are nullable or not, which I would argue is one of the advantages to null-annotating Java code with JSpecify.

[0] https://github.com/uber-go/nilaway


But you don't have to handle errors in Go. With multi-return you just don't bother with the "err" value and happily proceed with whatever is in the first return position.

IMHO, only languages with exceptions or Sum types that encode that a return is either a value or an Err (but not both) actually do what Golang says it does (make you handle errors).


> NPEs in Java have become rarer and rarer recently with the introduction of records

While this is true, I think it goes back farther than that. NPEs became rarer since java.util.Optional and people taking the time to use JSR 305 nullability annotations. I do this on regular basis and haven’t seen NPEs in my work for ages now.

Because I’ve taken on projects with large Java codebases often written by people with poor code-design skills, I can say the single most frequent NPE offender I’ve seen was method bodies wrapped in: try { } catch {} return null.

Modern language features like Kotlin’s non-null fields are nice, but I hold self-discipline just as important.


Oh yeah, I agree with you on all those points. I guess what I'm trying to say is I feel like modern Java pushes you towards writing null-safer code than something like Go. I don't see the same push in modern Go.

This blog post is a great reference for "when to actually handle the nil case in Go" (and I think these ideas can even be applied to other languages), but there's nothing pushing anyone towards doing it the correct way in Go other than a documented team coding standard or an AGENTS.md/SKILL.md file.

In older Java applications there's also nothing pushing developers towards "correct null handling." A legacy Java application has a bunch of POJOs with getters and setters where all the fields start as null. That's why I think using records+JSpecify+NullAway is incredibly powerful in a Java project. NullAway really forces you to correctly and fully null annotate your code.

Self-discipline is great but static analysis tools actually enforce doing something "the right way." Things slip through code review, but a failing pipeline has to be fixed before the merge can happen.


Kotlins nice, mutability in the collections and nullable types are nice but they still lack some form of checked error handling. I really wish they would have taken checked errors exceptions further and made them usable.


The thing is, the EU needs to be able to not only sell that the regulation they propose is good to the public, but also not piss off the US administration.

Most people are too non-technical to understand why this is a bad thing even when it's explained to them. Plus, whatever administration is in power in the US has a lot of influence.

Trump has already said that he wouldn't tolerate regulation that affects American companies [1], painting regulation that happens in another country as something that will affect US citizens. (I mean if you use the GDPR as an example, it's not wrong. Think of cookie pop ups while browsing the web in the US)

I would like the the EU would go harder with their regulations, because it usually results in other countries or states following their lead, but I dont see that happening. Regulation has been painted as "bad", and we have at least 3 more years until that changes.

[1] https://www.cnn.com/2026/01/12/tech/us-eu-tech-regulation-fi...


> rump has already said that he wouldn't tolerate regulation that affects American companies

This lays bare the stupidity of applying the pay-or-consent law to only Facebook and not everyone. Every important newspaper in Europe has pay-or-consent. It does not matter that each one individually is smaller, the effect is the same.

The law was carefully crafted to ensure European businesses (newspapers) are not "gatekeepers" while ensuring American businesses (social networks) are. That fact did not go unnoticed in the rest of the world.


So? There is a fundamental difference. The app stores have effectively become utility companies through the Android-iOS duopoly and it is neigh-impossible to make a new competitive ecosystem. Utility companies are regulated because they can distort the market with their power otherwise. E.g. if the power lines are owned my a single company (which is the case in many countries), if they were not regulated, they could pretty much ask any price. What are you going to do to compete? Roll out a completely new power grid? The Android/iOS duopoly is the same, the fact that they could ask for an insane 30% (!) of every transaction before the regulatory squeeze started should tell you enough.

The newspaper market is very different, because there are many players and you can always go to a competitor. There are even newspapers that make all content available and ask an optional donation (e.g. Taz in Germany or to some extend The Guardian, who do not seem actively block ad blockers).


Adding null checks where they aren't needed means adding branching complexity. It means handling cases that may never need to be handled. Doing all that makes it harder to understand "could this variable ever be null?" If you can't answer that question, it is now harder to write code in the future, often leading to even more unnecessary null checks.

I've seen legacy code bases during code review where someone will ask "should we have a null check there?" and often no-one knows the answer. The solution is to use nullability annotations IMO.

It's easy to just say "oh this is just something a junior would say", but come on, have an actual discussion about it rather than implying anyone who has that opinion is inexperienced.


No, the branching complexity exists anyway. You've just made it clearly visible by adding a null check or accept that the computational may fail if violated.

You never know what changes are being done in the future, while today the variable may not be nullable in the scenario you're up-to-date on, that doesn't necessarily mean it'll stay like that in the future.

Ultimately, there is a cost associated with null checks everywhere and another by omitting them. The person I responded to just insinuated that people which introduce copious amounts of null checks are inept and lazy.

In response to that I pointed out that that's literally one of the core tenets of defensive programming, and people that make such sweeping statements about other people's capabilities in this way are very often juniors. I stand by this opinion. You can disagree on specific places were a null check may have been placed unnecessary, but that's always a discussion about a specific field and cannot be generalized like he did there.


The big news here is that you now need a premium subscription to use any of Spotify's APIs. This means that if you wish to use Spotify's APIs to more easily share music with others, you must have a premium subscription.

What's gross to me is the language:

> all newly created Development Mode Client IDs will be created under the updated Development Mode rules and will have the following restrictions applied by default > Development Mode use will require a Spotify Premium account

The language acts as if it's possible to have some sort of non-development mode application. If you look further, you'll see that a non-development mode application must be owned by an organization with more than 250k users.


This is a well put together list. One thing that frustrates me is that not all tooling respects mailmap. IntelliJ has an open feature/bug request for integrating mailmap into its git functionality. Additionally, the .git-blame-ignore-revs is more of a convention because you still have to manually configure that to be the file name to use.


I think tooling that can modify your source code to make it more modern is really cool stuff. OpenRewrite comes to mind for Java, but nothing comes to the top of my mind for other languages. And heck, I into recently learned about OpenRewrite and I've been writing Java for a long time.

Even though I don't like Go, I acknowledge that tooling like this built right into the language is a huge deal for language popularity and maturity. Other languages just aren't this opinionated about build tools, testing frameworks, etc.

I suspect that as newer languages emerge over the years, they'll take notes from Go and how well it integrates stuff like this.


Coccinelle for C, used by Linux kernel devs for decades, here's an article from 2009:

https://lwn.net/Articles/315686

Also IDE tooling for C#, Java, and many other languages; JetBrains' IDEs can do massive refactorings and code fixes across millions of lines of code (I use them all the time), including automatically upgrading your code to new language features. The sibling comment is slightly "wrong" — they've been available for decades, not mere years.

Here's a random example:

https://www.jetbrains.com/help/rider/ConvertToPrimaryConstru...

These can be applied across the whole project with one command, rewriting however many problems there are.

Also JetBrains has "structural search and replace" which takes language syntax into account, it works on a higher level than just text like what you'd see in text editors and pseudo-IDEs (like vscode):

https://www.jetbrains.com/help/idea/structural-search-and-re...

https://www.jetbrains.com/help/idea/tutorial-work-with-struc...

For modern .NET you have Roslyn analyzers built in to the C# compiler which often have associated code fixes, but they can only be driven from the IDE AFAIK. Here's a tutorial on writing one:

https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/t...


Rust has clippy nagging you with a bunch of modernity fixes, and sometimes it can autofix them. I learned about a lot of small new features that make the code cleaner through clippy.


In PHP you can use Rector[1]

It's used a lot to migrate old codebases. The tool is using itself to downgrade[2] it so that it can run on older PHP versions to help upgrades.

[1] https://getrector.com

[2] https://github.com/rectorphp/rector-downgrade-php


Does anyone have experience transforming a typescript codebase this way? Typescript's LSP server is not powerful enough and doesn't support basic things like removing a positional argument from a function (and all call sites).

Would jscodeshift work for this? Maybe in conjunction with claude?


jscodeshift supports ts as a parser, so it should work.

If you want to also remove argument from call sites, you'll likely need to create your own tool that integrates TS Language Service data and jscodeshift.

LLMs definitely help with these codemods quite a bit -- you don't need to manually figure out the details in manipulating AST. But make sure to write tests -- a lot of them -- and come up with a way to quickly fix bugs, revert your change and then iterate. If you have set up the workflow, you may be able to just let LLM automate this for you in a loop until all issues are fixed.


ESLint (and typescript-eslint) has the concept of fixers, which updates the source code.


Try ast-grep


python has a number of these via pyupgrade, which are also included in ruff: https://docs.astral.sh/ruff/rules/#pyupgrade-up


Haskell has had hlint for a very long time. Things like rewriting chained calls of `concat` and `map` into `concatMap`, or just rewriting your boolean expressions like `if a then b else False`.


> but nothing comes to the top of my mind for other languages

"cargo clippy --fix" for Rust, essentially integrated with its linter. It doesn't fix all lints, however.


Java and .NET IDEs have had this capabilities for years now, even when Eclipse was the most used one there were the tips from Checkstyle, and other similar plugins.


Yeah I've noticed the IDEs have this ability, but I think tooling outside of IDEs that can be applied in a repeatable way is much better than doing a bunch of mouse clicks in an IDE to change something.

I think the two things that make this a big deal are: callable from the command line (which means it can integrate with CI/CD or AI tools) and like I mentioned, the fact this is built into Go itself.


eslint had `--fix` since like 10 years, so this is not exactly new.



I can’t find where in the article the author claims it is new (as in original).

In fact, the author shows that this is an evolution of go vet and others.

What’s new, however, is the framework that allows home-grown add ons, which doesn’t have to do everything from scratch.


I work full time as a software engineer, and I also spend time writing code on side projects. I love working on my side projects because it means I get to spend a bunch of time learning the quirks of whatever tooling and frameworks I decide to use. I often develop opinions and personal standards that I bring with me to future side projects (and sometimes $dayjob), although I've never quite stood up all the components of one of my projects "quickly". I'll always find something to tinker with and learn about, which I think is acceptable for my personal projects, desirable even.

As I get more personal projects under my belt, I believe I'll be able to stand up projects more and more quickly, although it's never perfect. Even though I've been using a similar stack among my side projects for a couple of years now, dependencies get outdated. Sometimes you gotta jump to a new major version. Sometimes you wanna try out the "new way".

I like the idea of building up my own personal stack of tooling, frameworks, and patterns that I use, and could even encourage the use of at $dayjob, but for the reasons outlined above, I agree with the conclusion of the article, which is that an "IKEA of software" doesn't exist currently.

For now I'll keep happily tinkering in my side projects. This article was a good read.


That's simply not true. If you scratch a vinyl record, you've introduced a defect to it. If you scratch a CD, it's probably fine. Some CD players don't like scratched CDs, but for the most part CDs are very durable.

Plus if you damage a CD, simply rip it and burn it to a CDr. (did I mention that ripping a damaged CD usually works?)

You are right about vinyl sleeves being more attractive, though. I think that's its main selling point.


You can usually polish scratches out of CDs as well.

Where they’re actually much more vulnerable is on the printed side because the data layer sits just beneath that. Still more resilient than vinyl though, unless/until they get the dreaded rot.

They can also crack if dropped but that’s just as true of vinyl, if not moreso.


I don't really like that "enshittified" is being used here. You could argue that Plex, MinIO or Mattermost is being enshittified, but definitely not self hosting as a whole.

Enshittification also usually implies that switching to an alternative is difficult (usually because creating a competing service is near impossible because you'd have to get users on it). That flaw doesn't really apply to self hosting like it does with centralized social media. You can just switch to Jellyfin or Garage or Zulip. Migration might be a pain, but it's doable.

You can't as easily stop using LinkedIn or GitHub or Facebook, etc.


Ctrl+F "jellyfin" to find this excellent comment.


Same. I have been using Plex for 15 years. For my personal use case, it has not changed, ever. I don't encounter any "enshittification". For my purposes it continues to be exactly what I want, just as it always was.


> You could argue that Plex, MinIO or Mattermost is being enshittified, but definitely not self hosting as a whole.

That's probably not how you should interpret it. Self hosting as a whole is still a vastly better option. But if there is a significant enough public movement towards it, you can expect it to be targeted for enshittification too. The incidents related to Plex, MinIO and Mattermost should be taken as warning signals about what this may escalate into in the future. Here are the possible problems I foresee.

1. The situation with Plex, MinIO and Mattermost can be expected to happen more frequently. After a limit, the pain of frequent migration will become untenable. MinIO is a great example. Even the crowd on HN hadn't considered an alternative until then. Some of us learned about Garage, RustFS and Ceph S3 for the first time and we were debating about each of their pros and cons. It's very telling that that discussion was very lengthy.

2. There is a gradual nudge to move everything to the cloud and then monetize it. Mandatory online account for Win11, monetization of GH self-hosted runner (now suspended after backlash, I think) and cloudification of MS Office are good examples. You can expect a similar attempt on self hosted applications. Of course, most of our self-hosted software is currently open source. But if these big companies decide to embrace, extend and extinguish it, I'm not sure that the market will be prudent enough to stick with the FOSS options. Half of HN was fighting me a few days back when I suggested that we should strive to push the market towards serviceable modular hardware.

3. FOSS projects developed under companies are always at a higher risk of being hijacked or going rogue. To be clear, I'm not against that model. For example, I'm happy with Zulip's development and monetization model - ethical, generous and not too pushy. But mattermost shows where that can go wrong. Sure, they're are open source. But there are practical difficulties in easily overriding such issues.

4. At one time, we were expecting small form-factor headless computers (Plug computers [1]) like SheevaPlug and FreedomBox to become ubiquitous. That should still be an option, though I'm not sure where it's headed, given the current RAM situation. But even if they make a come back, it's very likely that OEMs will lock it down like smartphones today and make it difficult for you to exercise your choices of servers, if not outright restrict them. (If anybody wants to argue that normal people will never consider it, remember how smartphones were, before iPhone. We had a blackberry that was used only by a niche crowd.)

[1] https://en.wikipedia.org/wiki/Plug_computer


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

Search: