Hacker News

New stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. Uber to pay $40M to parents of woman fatally struck after being left on freeway(abcnews.com ↗)
    discuss
  2. Show HN: LiteLLM sends AI requests.Conduct decides which ones shouldn't be sent(pypi.org ↗)
    discuss
  3. Show HN: I forked JetBrains' new agent IDE to host Claude Code(github.com/commandertvis ↗)
    discuss
  4. Nerra – a company context engine that powers agents with live business context(nerra.ai ↗)
    discuss
  5. Maximizing TPU interactivity with automated full stack performance optimization(makora.com ↗)
    discuss
  6. Show HN: Reintroducing Micro: A Personal Assistant(micro.mu ↗)
    discuss
  7. Show HN: Video uploader for React/RN – drop in or headless UI, any back end(github.com/hyper-serve ↗)
    discuss
  8. PS5 Linux dev quits after "the only hypervisor bug left" was reported to Sony(gamingonlinux.com ↗)
    discuss
  9. A Windows terminal built on the Ghostty core(wintty.io ↗)
    1comments
  10. Castla: Android Auto alternative for Tesla (2024)(github.com/suprhimp ↗)
    discuss
  11. VA Claims Guide – exact CFR rating thresholds for 15 conditions(outset-solutions.com ↗)
    discuss
  12. Quantum computing's flagship chemistry results don't say which state they found(purestatelabs.com ↗)
    1comments
  13. Thomas Silverstein(wikipedia.org ↗)
    discuss
  14. OpenAI flags new concerning AI behavior, to track model misalignment regularly(npr.org ↗)
    discuss
  15. What are you guys building? Especially in Fintech
    discuss
  16. Show HN: Live honeypot telemetry – 941K attack events, 160 countries(lurescope.com ↗)
    discuss
  17. Inside OpenAI's Project Lily(youtube.com ↗)
    discuss
  18. Venus Has Been Waiting 40 Years(blue-continuum.com ↗)
    discuss
  19. The AI graveyard: a running list of projects and startups that didn't make it(techcrunch.com ↗)
    1comments
  20. Valve open-sources Lepton, its Android compatibility layer for SteamOS(steamos.cloud ↗)
    discuss
  21. NASA spacecraft discovers a new 2-year-old crater on the moon(apnews.com ↗)
    discuss
  22. Why are APRs on secured credit cards so high?(unbreakfinance.com ↗)
    discuss
  23. Sharing My Secret for Fast, Security-First VM Deployment on AWS. Save This Post(idlefy.medium.com ↗)
    discuss
  24. Show HN: I build unprompted speaking app to improve speaking(speechio.app ↗)
    discuss
  25. What Is Happening with PostgreSQL 19?(snowflake.com ↗)
    discuss
  26. Reverse Engineering ChatGPT Web: How OpenAI Built for a Billion Users(performance.dev ↗)
    discuss
  27. OpenAI reports new misalignment incidents(openai.com ↗)
    discuss
  28. Show HN: Calmscroll – a reader that shows the current paragraph in the library(calmscroll.com ↗)
    discuss
  29. Is the phrase "master bedroom" harmful? A new psychology study says no(psypost.org ↗)
    2comments
  30. Olympiad Man has displaced Davos Man(economist.com ↗)
    discuss

Small programming tricks

600 pointsby 23h agowill-keleher.com
264 comments
22h agoHN ↗

This reminded me to ask: To what extent are people still coding by hand these days? In my profession (academia), literally no one codes anymore. On one hand, it sucks because the joy and fun of programming has been replaced by constant agent orchestration tasks, but on the other hand, it's hard to go back to the way things were before because the productivity gain is so good.

I remember learning a lot of these programming tricks over the years. They would give me happiness: learning something new about nvim, or some new shortcut in the Fish shell, or a new Vim macro, or the difference between 1 bracket or 2 brackets in Bash scripts, etc. But now it seems like all of them are irrelevant, and I wanted to see how others think about the situation.

22h agoHN ↗

Also in academia but I'm old and my real work is done withy students. I'm coding by hand much less than I used to (boo) but solving more problems with code myself than I used to (yay). Having an llm do things turns out to be similar to having a student do them but with fast turnaround and it's fine to have them work on your home automation system. ;)

22h agoHN ↗

Another academic. LLMs are great for opening searches. I state what I would like to get into and let it get some initial paper recommendations. It seems to solves a hard problem: discoverability. Maybe I'm just getting subjected to more subtle bias but it is extremely easy and fast now to get a nice selection of relevant literature to review.

Analysis and any artifacts are all handcrafted by me. I mean, that is the work. I have never seen papers or code as an outcome. What I want is to learn and enable other to learn. That I can only get from doing the work myself.

22h agoHN ↗

I do hand-code for the most part. I will use LLMs as a "smart reference" when I can't recall how to do something or maybe to scaffold out a starting point if I'm working in a less familiar language or framework. I use them as a better search engine, where I would have probably have looked at Stack Overflow, mdn, or online docs in the past.

I'm fortunate I guess in that most of my work tasks have very loosely defined deadlines, if any at all.

22h agoHN ↗

I hand code entirely at work still, while almost all of my colleagues do not and I am still able to keep up. I do use coding agents on personal projects, but have not felt the impetus to switch to agent based coding at work.

I don’t mean this to brag, mostly to point out that in my line of work, actually writing the code is not the biggest bottleneck.

For context I work on greenfield network security appliances

22h agoHN ↗

My coding by hand is always exploratory. Either I’m getting familiar with a new library/platform or I’m sizing up the architecture of the software. Then it’s a heavy dose of copy/pasting, snippets, and emacs-fu. What I spend most time on is reading docs. Apart from that, it’s thinking (mostly away from the computer).

22h agoHN ↗

I still hand code backends and frontends. I also review code by reading it manually, and ideally running it and then screenshot'ing receipts of it working and attaching those in my PR approval.

22h agoHN ↗

Im not TYPING a lot of code by hand anymore (still some, inference is slower than typing in a few cases) but im still in the shell zipping around doing other stuff like i always have, the LLM is helpful in a lot of ways but it in no way shape or form is the ideal way to interact with a computer.

So i still get daily use out of these tricks.

Are there people that are literally ONLY interacting with a computer via an LLM? thats crazy if its true

22h agoHN ↗

While I mostly just do AI-assisted coding at work nowadays, after a long time yesterday I did some scripting in a python REPL on a remote server which didn't have any AI tooling. It felt rewarding. I was also surprised my programming muscle memory was still alive and kicking.

21h agoHN ↗

To what extent are people still coding by hand these days?

I write everything myself. After 41 years of coding, I think in code — code flows from my brain through my fingers effortlessly: translating my thoughts to English for an LLM to then translate back to code is much, much slower than me. And once my hyperfocus kicks in, the last thing I need is to be jolted out of it by an LLM prompting loop.

JetBrains Rider has an AI auto-complete which I do use for the 5-10% of the time that it can predict what I’m going to write next. But even the next-word/next-block-of-code prediction seems so hopelessly out of its depth (which is supposed to be LLM’s party piece), it’s genuinely shocking how wrong it is most of the time.

Disclaimer: I’m not writing vanilla line-of-business code or bog standard web apps, so I suspect I’m just not in the training data.

20h agoHN ↗

what are you writing? like - what type of programs?

19h agoHN ↗

Well, there's my super-secret future-of-software-development-and-data-autonomy project, but we're not to talk about that, so shhh! (basically my next startup idea, once I've finished inventing it).

Then, there's language-ext [1], which is my large open-source functional-programming framework for C#. And although this isn't beyond the realms of an LLM: they know FP and they know C# and even my library has been around for more than a decade, so it'll be in the training data, when it comes to bending C# to my whims or to trying to eek out exceptional performance, they're all at sea.

A good example would be what I am working on at the moment, which I have in a standalone prototyping repo [2]. Basically I have introduced functional traits to C#, like `Functor<F>`, `Applicative<F>`, `Monad<M>`, etc. This brings more rigour to things like LINQ comprehensions and allows for the building of truly generic trait-based behaviours. Something that just doesn't really exist in C#.

In language-ext today I have `Foldable<F>`, which is a little bit like `IEnumerable`, but pure. I want to be able to provide a super efficient set of default implementations for any `Foldable` (or enumerable/iterable). For this I need an efficient lazy-stream or co-routine system. The one built-in to C# (`IEnumerable` and `IEnumerator`) is impure (it mutates as it enumerates), so I am trying to build an efficient iterator/enumerator that:

* Takes around 0.25 nanoseconds per-iteration-step for its housekeeping (this speed is then on a par with the mutable IEnumerators that are a core part of C#).

* Doesn't allocate any memory

* Is immutable

* Is lazy

* Can be stopped at any point and the iterator reference be passed around (because it's immutable)

* Can be composed with standard functional operators (functor map, applicative apply, monad bind, etc.) without performance degradation and without a large memory-allocation cost.

I've been building several prototypes to try different ways of bending C# to my whims. I've managed all but the last item on that list.

Not allocating memory means using value-types (stack allocated types), but that also means the entire state of the co-routine needs to be stored in the value-type as each value is yielded (because control needs to be given back to whatever code is processing the values). To solve it, I'm pretty much building my own runtime, stack-machine, and memory manager on top of the .NET CLR so that I don't have to submit to its rules. I'm trying to apply as many of my old-skool low-level engineering chops as I can (without making it brittle); but to do the last item on that list needs more space in a value-type than would be reasonable (to avoid copying costs), so I'm looking at other pooling strategies and into building lots of bespoke to-the-metal memory managers.

After all of that, it may be a fools errand, and not doable. The LLM wouldn't understand, and that's for just one feature! Also, it must be stated, I just love doing this shit, it's brain fuel. The idea of having this conversation endlessly with an LLM as it continuously gets it wrong is nightmare fuel.

I'm not anti-AI, I love the fact that people who can't, now can. But, at this point in my journey with code, I think quicker and can produce quicker than an LLM. I think it's akin to a virtuoso piano player. If the piano player had to describe what they wanted to an LLM, the magic would go, the enjoyment would go, and potentially the quality would go. It would it also take much longer than if they had just played.

That's how I feel with code. An LLM can maybe churn out more code than me, but I can build more value and I can invent. And when in my flow state, nothing can stop me.

I will certainly keep checking in though, I'm sure there'll be a point where I feel like it augments me rather than hinders. It's just not there for me yet.

Too much information? :D

[1] https://github.com/louthy/language-ext

[2] https://github.com/louthy/iterator-prototype (this is messy prototype code, don't hate me).

21h agoHN ↗

I write code by hand because LLMs do not provide any significant productivity gains. They turn out code fast, but then I have to review it to make sure the code is correct. That takes me about as long as it would to write the code myself in the first place, so I continue to write the code myself.

20h agoHN ↗

People in academia generally doesn't code much. So I am not surprised.

LLM's have not affected us in the slightest when it comes to coding. Maybe we write a snippet, post it for llm to scrutinize, and usually LLMs spout bullshit and wrong suggestions and after enough verbal abuse it points to some issues with the code.

But I don't get this delegation to LLM's for your entire coding. I hope everyone delegates to LLM :) (sarcasm)

5h agoHN ↗

so are you a time traveller from like, 2023 or something?

20h agoHN ↗

To what extent are people still coding by hand these days?

That's basically I all do. I might ask a few questions to LLMs here and there like Google/StackOverflow in the days of yore.

Still, every line in all my codebases are still hand-typed. I get everything I need out of the chatbots, and I cannot use any kind of agentic coding tools at work, oddly enough. Trust me, I'd love to have access to something like Codex at work. That way I could save my mental bandwidth for personal projects that I find interesting and enjoying.

2h agoHN ↗

The code I check in at work is nearly all hand-written. I'll often send files and functions and snippets and questions and `git diff`'s to an LLM. In particular the code review is very helpful for catching silly mistakes. But if it generates code, even if it looks fine, I always end up manually moving it around and rewriting and renaming things. I need to understand the code I maintain, and those "prosaic" changes and refactorings that I do while incorporating the code help ground me deeply in how it works.

Also, I'm mostly not very happy with the architectural choices the LLM makes. It can be good at little details, and sometimes I learn about language features or idioms or libraries by reading its code, but I find it often uses wrong patterns. E.g. just this week I saw it creating two huge intermediate data structures for parsing something in a "cleaner" way, completely missing how the library it had suggested actually had something builtin (and prominently featured in the tutorial) that obviated the need for those intermediate structures and was both safer and more readable.

When I've tried full agent coding, I kept getting distracted while waiting. I also have the feeling that my questions to the LLM were getting "dumber" as I lost contact with the code. And I don't have the hardware for local LLM's, so giving full repo access is out of the question for work.

Altogether I feel like I've found a fairly good balance in how to use them in such a way that I can avoid a lot of the downsides and still have a tool that gives me much value that I didn't have before: I check in fewer bugs, I waste less time picking libraries/methods, I have a better rubber duck, I learn little tricks all the time, I never send LLM-generated text to humans.

22h agoHN ↗

I would probably retitle this less as "programming tricks" rather instead make it "bash/zsh CLI tricks" as this only really tangentially refers to programming.

22h agoHN ↗

Only a few of these are actual programming tricks. The problem with sharing them is that they'll typically seem obvious to you, since you know them. It's difficult to know what is actually unknown to other people, and if you share stuff everybody knows you risk coming off as arrogant.

Here's one that I think more people should know: avoid branches. If I can do the same thing without an if statement and even a logical expression, the code typically both becomes easier to understand for people and easier to run for the CPU.

22h agoHN ↗

I'm struggling to comprehend how branches can be avoided (or why one would want to, as they are the cornerstone of programming). I can only think how to obfuscate them, which is rarely useful.

21h agoHN ↗

OK, but the code with the branch is easier to understand.

21h agoHN ↗

Generally agree. As with many optimisations, branchless code can easily be less obvious than the branchy equivalent.

21h agoHN ↗

Yeah, I don't buy the premise that branchless code is intrinsically easier to understand. Maybe OP's point is that adding unnecessary branches makes code harder to read? But that's generally the case for any unnecessary code.

20h agoHN ↗

I see stuff along the lines of:

  if (x == 0) {
      return y;
  }
  
  y += 25*x;
  return y;

and skipping the if just makes the function shorter and simpler, while also not involving the CPU branch prediction. Another one that doesn't necessarily skip all branching but at least drops one - and more importantly makes the code simpler and easy to verify, is removing the if statement in code like

  if (count == 0) {
      return;
  }

  for (int i = 0; i != count; i++) {
    puts("hello");
  }
15h agoHN ↗

Both of your examples are optimized by the compiler (gcc 16.1 -O3).

In the first case, the compiler removes the first if/return

In the second case, if you don't have the first if/return the compiler will add it. That's because it will actually convert your loop into a do/while, with the test in the end, because it is more efficient. But it has to handle the count == 0 special case first, so it will do that early return even if it is not explicitly there.

That's the kind of optimization modern compilers are good at.

21h agoHN ↗

From the article:

=====

Should you go branchless?

Most of the time, no. Branchless code is harder to read and easier to get wrong. Besides, compilers know a lot of tricks and already do a lot of this work for us.

Only when a profiler points at a hot loop, and the loop contains a branch on unpredictable data this technique can pay off big.

22h agoHN ↗

Maybe they mean rather than:

if (thingThatIsTrue):

  // a bunch of logic here...

else:

  // different logic here...

they mean:

if (thingThatIsTrue):

  return doThisWhenTrue()

return dothisWhenFalse()

Just a simple example. I'm not sure if this is what you consider "obfuscating" the branches. Logically the same, but a bit more linear to understand?

Edit: I am bad at formatting comments here.

20h agoHN ↗

Putting two spaces before the line formats is as code.

Example:

No space before start of line.

One space before start of line.

  Two spaces before start of line.

Thus, you can put multiple lines of code with indentation as well as long as you put two spaces at the start of the line:

int main() { return 0; }

  int main() {
    return 0;
  }

See https://news.ycombinator.com/formatdoc

21h agoHN ↗

Flow control is not always necessary. Other times it can be minimized. The point is not to never branch, but to avoid unnecessary ones.

It's not applicable to every situation, but one way to do this is some very basic fuzzy logic. You do a little math and then either choose a single branch at the end, or sometimes avoid a branch altogether. https://www.geeksforgeeks.org/artificial-intelligence/fuzzy-...

Another way to avoid some branches is to have specialized routines, maybe with multiple dispatch, rather than more general methods with a bunch of checks within them for slightly different situations.

A classic performance hack for critical sections is loop unrolling.

21h agoHN ↗

well here is a branching strategy I often see, pseudocode, and often this is a really stupid example as I do not have the time to come up with a good one:

if Val === "A" then Do funcA() else if Val === "B" then

and so forth for lots of values, or using a switch statement or similar branching instead of

Object functions = { "A": funcA() {does what funcA does}, "B": funcB() {does what funcB does} etc. etc.

}

runnableFunction = functions[val]; runnableFunction();

Actually writing it I remember now someone who did this, a junior who had to update a validation function for XML invoices based on their root namespaces, which there could be a large number of these, and so she wrote out

switch namespace == "somenamespace" { validatingscheme = "someschema"; doPreliminaryFunctionToDetermineifshouldvalidate(); }

I can't remember all the details as this was almost 20 years ago, however while it was true that one branched on the schema, it made much more sense to look up what one was supposed to do based on the rule for branching and then just execute that one action rather than writing a bunch of branching logic.

So to make it more concrete: Once branching rules becomes sufficiently complex prefer query for what you should do rather than branching

on edit: note again, not real code, but should be understandable and translatable into real code to understand what is being said easily enough.

on 2nd edit: this is also just basically one of the things I prefer instead of getting a lot of branching logic. I have never seen any stats on any benefit to this model than just having a bunch of branching statements, but I feel that the benefit is there nonetheless.

21h agoHN ↗

There's stuff like the "Command Pattern"/dispatching/subclasses etc that can make this nice, although it's not always a good fit.

Like imagine you have a few different classes of things A,B,C so instead of checking if the thing you're handling is an A,B,C you have like a shared interface across all and can call Thing.do_it or whatever.

Still branching conditionally but it's passing it off to language features instead of code you have to write.

21h agoHN ↗

There are multiple ways to avoid branches. An early return, a lookup table are two that I use regularly and consider a code smell when the AI uses many if clauses or switches.

20h agoHN ↗

What people refer to when they say "branchless code" is something very particular, and it refers to not triggering the CPU's branch prediction. That is, don't make the CPU have to guess which fork in the code you're going to take. This is usually accomplished in one of two ways: either bit twiddling hacks or specialized instructions that do not affect the CPU's branch prediction, such as the 'cmov' family in x86. If you search for `examples of branchless code using conditional moves` using your search engine of choice, you'll find numerous examples.

A trivial example is actually written with a branch in C/C++, but relies on compiler optimizations to kick in. If you compile a ternary operator in C/C++ (and probably rust, C# and other languages) such as in:

   int min_branchless(int a, int b) {
        return a < b ? a : b; // Often emits cmov with -O2
   }

With gcc/clang a -O2, one would expect the compiler to emit the following assembly:

    cmp edi, esi
    cmovle eax, edi   ; select a if a <= b
    ret

There's numerical tricks for other operations/comparisons, and compilers know a lot of them. But, I just suggest compiling your code and configuring your compiler to emit the generated assembly with references to the code it was generated from (you should be able to get it to emit source line references in the assembly). You'll likely be surprised at the optimizations applied at -02, and utterly confused by what you find at -03.

edit: Also, it doesn't mean to never branch, but to minimize branching, especially in tight loops. Branch outside loops, not inside, for instance.

e.g. don't do:

    for (...) {
        if (condition independent of loop variable) { 
          ...
        } else {
          ...
        }
    }

do:

    if (condition independent of loop variable) { 
        for (...) {
          ...
        }
    } else {
        for (...) {
          ...
        }
    }
18h agoHN ↗

The latter example, sounds like something trivially done by the compiler. I mean I would sometimes, adhere to it, but only if the loops afterwards become substantially different. If I would just repeat most of the loop body, I would prefer the former.

14h agoHN ↗

Rust is an expression language and so it doesn't have "the ternary operator"† you can use conditionals like if anywhere in your expression anyway.

If you want to tell the Rust compiler that you're certain a branch predictor can't help here [be very sure, most often humans are wrong which is why historically these "I know better than the branch predictor" features get ignored by optimisers] you can core::hint::select_unpredictable(condition, a, b) rather than using a dedicated operator.

† That's not its actual name, some languages have an operator with three operands which does something else, such as fused multiply-add so in a multi-lingual context better to say explicitly you mean the ternary conditional operator.

8h agoHN ↗

Yes, and back when hand-writing vectorized kernels via intrinsics, one learned to do the equivalent of (pseudocode here - picture SSE, AltiVec, NEON, etc.):

    vector conditionmask = <some computation...>; // E.g., 11111111 00000000 00000000 11111111
    vector truebranch = <some computation...>;
    vector falsebranch = <some computation...>;
    vector result = (truebranch & conditionmask) | (falsebranch & ~conditionmask);

where each lane of the conditionmask has either all bits set or all bits clear, depending on the outcome of the conditional test for that lane.

The processor obviously does execute both branches here, so there's going to be wasted work. But since it's just a linear sequence of operations it can often schedule them independently and run them out-of-order and in parallel. And of course, if there's any shared computation between the two branches, the compiler can do common subexpression elimination.

That said, that sort of approach where you go ahead and do both and then blend them was definitely the kind of optimization where you'd want to profile rather than doing it blindly. But it was a pretty common thing to do when hand-vectorizing code. (Thankfully, auto-vectorizers are pretty good at doing this sort of optimization for you these days. It's been a very long time now since I've had to hand-write vector intrinsics.)

20h agoHN ↗

Probably by using various convenience functions.

A common pattern in an old C++ job I had: People writing for loops, coupled with if conditionals, for things that could just be done by chaining functions in the algorithm library.

Don't do a for loop, check for a condition, and break. Use find_if.

22h agoHN ↗

if you share stuff everybody knows you risk coming off as arrogant.

Or stupid, like all those vloggers posting "ZOMG! Go all in with these secret hidden weird trick iPhone life hacks to level up!" that are just regurgitating what's in the manual.

As we used to say, RTFM: https://support.apple.com/en-us/docs/iphone

22h agoHN ↗

A (hopefully interesting) aside about avoiding branches is if you don't need an exact answer but need your code to make a decision based on an approximation over some known range, you can employ a basic fuzzy logic method. Serially add, subtract, or multiply to adjust a value by a handful of weighted inputs then use that value instead of branching repeatedly to choose the right action. You might branch once based on the final value where it would have otherwise been a larger tree of decisions. In fortuitous situations, you may avoid branching altogether.

21h agoHN ↗

Maybe something (contrived) like this providing no-op defaults?

  total = calculateOrderTotal(user.order);
  if (user.isPremiumMember) {
    total = total * 0.9;        // 10% discount

versus

  total = calculateOrderTotal(user.order);
  discount = calculateDiscount(user);  // Returns 0.9 or 1.0
  total = total * discount;
21h agoHN ↗

OK, or maybe...

  total = calculateOrderTotal(user.order);
  total = total * user.discount;
18h agoHN ↗

Or:

  total = calculateOrderTotal(user.order);
  total *= user.discount;

or:

  return 
         calculateOrderTotal(user.order)
       * user.discount;
21h agoHN ↗

Didn't you just shift the branch to the calculateDiscount() function?

18h agoHN ↗

Not necessarily.

   return 1 - user.isPremiumMember * 0.1;

would also cut it.

19h agoHN ↗

some initial function like

  v = setup()
  if v == 1:
    side_effect_1()
  elif v > 1:
    side_effect_1()
    side_effect_2(v)
  else:
    raise Exception()

then we can "refactor"

  v = setup()
  if v < 1:
    raise Exception()
  
  side_effect_1()
  if v > 1:
    side_effect_2(v)

i know that this might seem "dumb" that the code was ever setup the first way but code can grow into that shape pretty easily. this refactor "removes" the v==1 branch. this new code also follows the "early return" pattern, which improves readability.

21h agoHN ↗

if you share stuff everybody knows you risk coming off as arrogant

I have always felt like my bar for publishing something (even just to internal wikis/channels) is too high due to being overly self-conscious. I think we should try not to validate that feeling by implying that there is a non-negligible number of readers who will think you have a personality flaw because you wrote down your personal collection of tips in a public place, or that those people deserve consideration in the first place.

There is no such thing as "the things everybody knows". There are just too many things. Even a list of basic tips is probably going to contain one thing I didn't know or perhaps forgot. Write-ups like this are where most of my practical knowledge comes from, not RTFM (which I do).

22h agoHN ↗

If you want to level up your Zsh history experience, I built zhist[1] specifically for that. It uses fzf underneath, but provides considerably more context than simply using fzf. There's a demo video in the README.

[1] https://github.com/overflowy/zhist

22h agoHN ↗

I would love for someone to package up some kind of script or AI skill that evaluates your current terminal config/set-up and applies all of these tips and tricks. For instance, it might detect that you currently use ag, install ripgrep, and offer a short tutorial on how users accustomed to ag should use it. Or it might look at the history of git commands you've run and offer tips on efficiency improvements.

22h agoHN ↗

I think it's a great way to stop understanding what's going on in your terminal.

IMHO the value of these nuggets is that you understand what you're doing and why; opening yourself to large amounts of non-default behavior likely will end up in a less than pleasant setup.

Not taking into account that different users might disagree on what is convenient and what is not, which is basically the point of making things configurable.

22h agoHN ↗

I doubt you need a full script or skill for that. I would try something like this straight in Claude Code (and will as soon as my 5 hour quota resets :-): Review this page: https://will-keleher.com/posts/small-programming-tricks-matt... Then, review my shell init scripts (both bash and fish) and shell history. Make recommendations based on the tips and tricks from the page.

22h agoHN ↗

Going from ag to ripgrep is not unequivocally better. Sure ripgrep is faster, but its file filtering using -g is so much more cumbersome than -G in ag. The latter uses a regex and the former uses glob. I type many more characters to do the same search, and the same search is maybe 0.1s faster for a medium codebase. So no for me. Maybe it’s worth it for a larger codebase that isn’t large enough to require indexing.

20h agoHN ↗

ag is also a little more ergonomic with its default flex casing: your query is case-sensitive if it has any uppercase letters, otherwise case-INsensitive. rg defaults to case-sensitive (but does have flags for insensitive and flex casing)

8h agoHN ↗

A lot of this kind of choices are rather opinionated and personal preferences. But anyway, I think the closets thing I can think of is oh-my-zsh.

22h agoHN ↗

At a previous company, I shared a trick on slack every day with the engineering team, both technical and company-specific, and folks found them pretty useful.

I would find that annoying, however to not be seen as a jerk I wouldn't say anything.

22h agoHN ↗

I think I would prefer an optional separate channel specifically for people to share such things with each other who wanted to see that exact sorta thing. Then nobody gets bothered by it who's not interested in such things, and people who are have a place that's dedicated to exactly that.

22h agoHN ↗

I think that "everyday" would be a stretch, but i dont understand why youd think thats annoying, someone took the time to consider helping the rest of the engineering team grow, by posting something useful.

I frequently do the same, but not everyday; only when i think its something actually useful/helpful beyond the everyday crap. Most recently, we have had a huge push to use ai (just like everywhere else), ive been getting pretty creative with it, and at this point have a well polished setup that i can give a shitty sentence on a problem, not only does it understand the task, but theres a full ticket->branch->work->pr review->ready comment flow that it uses. My team also uses ai but they havent quite wrapped their head on ways to really work with it. I have built and shared a number of helpful things with the team to try and help them grow. One such thing was a doc i had my ai instance write, based on how ive been using my setup. This alone has started to get the rest of the team up to where i am.

My team doesnt share the same types of things i do, but they still share helpful things.

Call it what you will; I think if youre not helping your team grow by providing insights and helpful things, then youre not the kind of person i want to work with.

22h agoHN ↗

I think there's a fine line between helping your team grow and the sorta annoying self promotion I've seen people do in overly broad slack channels.

One is actually helping and the other is making yourself more visible to mgmt for promotions.

21h agoHN ↗

I rather think the opposite. People who share tips and hacks are genuinely trying to help others, while people who hoard information are competing on an individual basis without regard for team.

21h agoHN ↗

Please take this in good faith, as I hope your own post is, but I interpret the thread you're replying to as focusing on the "everyday' part.

Share knowledge? I don't think anyone here is arguing against that in any way (or conversely arguing for hoarding knowledge).

The concern, one I share, is where the sharing has to happen publicly "every day" - so no matter how trivial, useless, niche, overly-specific the tip is (whatever, the list isn't exclusive), someone shares it.

That's the part that's not sharing knowledge for the benefit of others, but rather self-serving. I might even go so far as to say self-serving doesn't even need to be selfish; the person might genuinely believe they're doing good, but even there, self-serving.

TLDR: Share your knowledge, don't make sharing something every day, even when you don't have something valuable to share, your target.

PS - if this note irks anyone (are routine maxxers a thing?), make the goal to learn something every day, then share where appropriate.

20h agoHN ↗

Yep, crop dusting knowledge in a public space without at least tying it to something relevant is a faux pas in my book.

Offering to teach someone something proactively? Sure, go ahead.

Sharing stuff freely when asked and arming someone with the tools to investigate further? Amazing!

Treating a public channel like ye olde facebok wall? Mildly annoying.

20h agoHN ↗

Treating a public channel like ye olde facebok wall? Mildly annoying.

Every team/department/org/whatever should have channels everyone should subscribe to, and channels individuals set up that are optional for everyone. The appropriate way to handle this is for the OP to write a few tips once in a while in the public channel, and if people seem to like it, announce that all future tips will be in that channel.

20h agoHN ↗

We work in very different places. Wherever I've worked, the guy who knows all these tricks is not the guy getting promoted. Senior management doesn't care about your shell or scripting skills. Sure - they make you more productive, but at a very local level (may be good for a single promotion early in your career).

Most senior engineers I've worked with have forgotten all these tricks, and they actively tell you that while you should try to get better at these things, career gains lie elsewhere. Focus on things with higher impact.

21h agoHN ↗

Why just one each day then? Why not a shared knowledge base? Do you start with a "bag of tricks" and then hand them out one by one each day to remind people you're the guy with the bag of tricks?

"Oh, yeah, I know a cool trick, but y'all have to wait until tomorrow to find out what it is."

"Look! It's a way to evaluate SQL expressions with a select with a from! Oh, you already knew about it?"

I have nothing against sharing knowledge, especially when seeing someone else do something that can be done better. But just leaving daily breadcrumbs to remind people you're the guy that teaches random trivia feels like attention seeking.

20h agoHN ↗

I don't think that's a generous way to interpret it.

I see it more as: every day they will go on the slack channel and pause, wondering "Is there a neat trick I've learned or used recently?" then they share it. It's like a ritual to remember that you can share things because it's easy to forget other people don't work the same way you do. Writing it all at once is difficult (you have to remember a lot of stuff at once) and it tends to go unread.

I also think every single day is a stretch, but it's nice to pause once in a while to think about how you could help other people with something you've learned.

20h agoHN ↗

You’re right, a centralized repository would be good too.

Both a centralized repository AND a daily message, especially for new employees, would be ideal, imo!

Normalize chatting and sharing stuff in slack!

15h agoHN ↗

Because it's about the journey and not just the artefact. If you're not thinking of something that's useful and preparing snippets to share every day you are not practising it. Having to come up with something stretches your imagination and critical thinking skills. What's true for the writer is true for the reader - if you just shared a simple repository with tricks, exceedingly few are going to read that, and the ones who do will forget it. Daily practise is important.

2h agoHN ↗

Sharing an hundred tips one tip a day has certainly more chance to be shared correctly than pointing to a page containing those hundred tips.

Personally I don't care if the guy looks for attention or not. IMO people that do care have likely some jealousy issues ("I don't want other to get more attention than I do"). Lose-lose attitude.

22h agoHN ↗

s/seen as//

Annoyance is a clue; not about them, but about you.

22h agoHN ↗

Weird personal attack, thanks.

What I'm saying is I am not a jerk and actually do care about my coworkers, however I also don't want a bunch of noise in a chat app I have to use to do my job.

21h agoHN ↗

You can mute the channel. Why would you want your teammates to communicate less ?

21h agoHN ↗

I think that it would be unwise to mute #engineering or whatever the main eng channel is

I shared a trick on slack every day with the engineering team

20h agoHN ↗

An engineering team may have multiple channels.

21h agoHN ↗

The post writer is also a person that you attacked for no reason even tho he's not your coworker.

21h agoHN ↗

I thought it sounded like a nice gesture of trying to be helpful and making a small connection with their coworkers. One message a day is hardly "a bunch of noise". Even though you say you wouldn't have said anything at the company, you said something here, and that has a similar chilling effect on other people who might have been inspired by the OP to share their tips and tricks with their coworkers.

Sorry for the "personal attack" but my point stands, you may not think of yourself as a jerk, but I saw your comment and thought "this guy imagining himself being annoyed at a coworker for a daily message with a helpful tip might be more of a jerk than he realizes". As a jerk myself I judged myself qualified to make that assessment and commented accordingly.

12h agoHN ↗

As long as they do that in separate channel and don't tag all, i'm fine with it.

22h agoHN ↗

My favorite is generating a sequential resultset of the numbers 1-4096 in SQL Server with this simple query:

;with [[[]][[[](_)as(select 1 union select 0),[[]][]][](_)as(select 1 from [[[]][[[] []]]][]]],[[[]][[[] _),[]][]][[](_)as(select 1 from [[]][]][] []]]][]]],[[]][]][] _),[[[[[]][](_)as(select 1 from []][]][[] []]]][]]],[]][]][[] _),[[[]][]]](_)as(select 1 from [[[[[]][] []]]][]]],[[[[[]][] _)select _ from(select row_number()over (order by _)from [[[]][]]])[[[]][[[](_);

/s

22h agoHN ↗

Additional tip:

In the macOS terminal you can...

  Ctrl + Option + -

...and it'll undo your typing.

Dunno about other OS keys!

17h agoHN ↗

Didn’t know about that one, and can’t find any references, but works in my fish

I’ve always used Ctrl+U, it’s an Emacs shortcut, so it works in many shells and other prompts (especially since readline supports it) by default.

(For example Ctrl+Opt+- doesn’t seem to work in the Python REPL whereas Ctrl+U does.)

22h agoHN ↗

Wrote "script" by accident once in my terminal. Turns out the unfortunate naming of that gnu tool from unix days makes it rather unknown.

Record a debugging terminal session including output to a file. Its pretty great.

22h agoHN ↗

These bash commands along with similiar others makes a developer so productive.

For me, I personally use nothing fancy other than normal KDE Kate for backend development.

Function and variable names are chosen after putting a lot of thought into it which also includes being amenable to grep and sed.

22h agoHN ↗

+1 for git log -S. Two I use daily: rg --hidden -g '!*.lock' to skip noise, and python3 -m json.tool to pretty-print API responses.

22h agoHN ↗

I find myself using ctrl-r less and less as I make sure that anything of value that I work out goes into a Makefile or the app tooling, for me this is the basis of the dev-ops approach to work (make sure everything is scripted, not worked out on the fly).

22h agoHN ↗

Ctrl+r is great, sometimes. History saving sucks which can make using it difficult, but i usually use it out of laziness than trying to recall a command, especially with ssh or repeated iterations requiring flipping between two settings/states. Its hard to rely on it for other things, but its still super useful.

20h agoHN ↗

I use history | grep quite a lot, because of the non-fuzziness with default ctrl+r. If I know exactly what the substring is, then that's great, but sometimes I also want to see the sequence around the command too (e.g. two step processes like eval ssh agent + ssh add key)

22h agoHN ↗

I’m lazy so With fish, I just type a part of the command and press up few times to get to where I want. There’s also fish-fzf.

18h agoHN ↗

I've relied on this so much that I copy my entire history between machines...

15h agoHN ↗

Self hosted Atuin would do this for you too. Unless you don't want the added tooling/complexity

8h agoHN ↗

Ahh I only do this when reinstalling or moving to a new laptop but it's good to know about Atuin for the future!

21h agoHN ↗

ctrl+r still great for targeting your make targets :)

21h agoHN ↗

Ctrl + R is great, you don't have to type out --dangerously-skip-permissions

20h agoHN ↗

I do that too. I am trying to use Mise. (Getting interested in Maak. Haven't done anything with it yet. My Scheme is pretty rusty)

Still, Zsh history with fzf fuzzy searching is fantastic. I have years of history I can recall commands with a few keystrokes.

Truly a second-brain.

20h agoHN ↗

Yes, but how do I know what should go in the justfile? When I've realized I've used Ctrl-r for the same thing a few times :-)

And as another commenter said, you often forget the target, and use Ctrl-r to find it. Although just does support fzf...

2h agoHN ↗

atuin for me has replaced ctrl-r.

well not specificlly but its bound to it. Having durable history stored in an SQL database (with secrets filtering and option syncing) you can search global history, or local. (as in if you have two terminals open, you can just search the commands you've typed in one terminal for that session, that session plus history or that session plus what you've just typed in any other session. )

Its awesome

22h agoHN ↗

Almost all of these are irrelevant in the age of AI, except for the logarithm thing

20h agoHN ↗

Using a computer is irrelevant in the age of AI, you should stop doing that.

20h agoHN ↗

I have the same feeling, there are new approaches and tricks to get things done, mainly from how to work with AI more efficiently. But the human brain still needs to be trained and learn new things to not get rotted

20h agoHN ↗

Can you explain that one (the logarithm trick)? I have no idea what it's trying do to. Is it saying that it's convenient or useful to know the order of magnitude of a number rather than its value?

22h agoHN ↗

You might not need find due to advanced globs, but it's too easy to run into expansion limits when you match hundreds or thousands of files, so you're back to find for that.

6h agoHN ↗

Something about the find syntax never sat well with me, and I don't search often enough that I feel I need to learn it.

My "find" is almost always

    tree -if | grep "<whatever-pattern>$" | head -1

head, of course, being optional

The tradeoff is needing to learn regex, which is not any easier to learn than find arguments.

22h agoHN ↗

Another one I use often is <command returning output > | pbcopy on macOS. Pipes the the result directly into your clipboard

20h agoHN ↗

Definitely. The whole Unix philosophy of each command doing one thing and being easily composable always seemed to break down in my mind when it came to find. find does a lot.

similar to ripgrep, though, fd is a modern replacement that’s a bit friendlier to use.

12h agoHN ↗

find is absolute agony once you get a taste of fd.

2h agoHN ↗

I tried fd but it seems to ignore so much that it's basically useless. If I wanted `git ls-files|grep` I would `git ls-files|grep`

yells at cloud

..it's probably ok actually and I should give it a real go, but I'm too used to find and even have a keybinding in my ~/.inputrc to insert a find + where loop

    "\e\C-f": "find . -type f -print0|while read -rd '' f; do ; done\e-b\C-b\C-b\C-b\C-b\C-b\C-b"

(yes I know about -exec; I find the loop easier to work with)

18h agoHN ↗

`find` does a lot more things than that.

And I don't think that's a good thing. Especially because AI coding agents use it a lot. They only need to hallucinate a little to destroy your filesystem.

18h agoHN ↗

It is just a query language for the filesystem, which is what "finding" means.

It's essentially like the SQL SELECT expression.

10h agoHN ↗

I'd wager that most people just don't get that the second "arg" (composed of multiple args) to find is an expression. Expressions are, somewhat unfortunately, code, so there's essentially a mini DSL there.

  find -name '*.md' -and -not -type d

Of course, then it becomes more obvious why there are parens, why those parens must be escaped for the shell, etc. E.g.,

  find '(' -name '*.md' -and -not -type d ')' -or '(' [...] ')'

I think once someone groks the nature of the expression args, then find becomes easier to start working with.

The most messed up part in my mind though is that while most things in find are clearly helping the expression towards its goal of "true" or "false" on whether to include the file or not in the results, some, like -prune or -exec do so but with side-effects. And since they're usually invoked primarily for their side-effect, it isn't immediately obvious that they even return a value, or are participating in the expression itself. (-prune is true, and -exec depends.) And this is where it becomes important that `find`'s -and & -or are short-circuiting, too. (In a purely logical expression, it wouldn't really matter except as an optimization.)

People also sometimes omit -and, which I'm not a huge fan of the legibility of. (But using -and makes it not POSIX; you can do -a but ew. which brings me to the last bit…)

macOS: the find there requires the starting-point arg; so my examples above, on macOS, would all need to be,

  find . [expression args...]

… which is lame. Brew install GNU find and be done with that.

While I agree with globbing (or fd) for interactive use, I think for scripting I'd still say "you might want find"; there are limits to arg list lengths (see xargs) that (esp. recursive) globs can exceed; unless you know you'll never glob the world, find might be appropriate. Also:

  echo *nope*

Globs will betray you on the zero-match case. (`man bash` & cf. `nullglob`.)

22h agoHN ↗

A lot more tricks can be learned from just watching AI work. Instead of allowing AI to work autonomously, go back to the old days where you manually approve every command the AI runs. Just recently while doing performance optimization work, I found Opus using the `perf` command in ways I didn’t know possible. Just give AI a real task and carefully read what commands are used by the AI to solve the problem; most likely the AI uses a trick or two that you didn’t know existed.

22h agoHN ↗

This is interesting, I also do this, it will not let me remember the commands, but, I will learn what is possible and roughly how. And in this day and age that is more important. Just like stamping knowledge into your head also became less important (but not 0 important) with books and the internet.

21h agoHN ↗

“the old days”

Is this just plain old rage baiting? I literally can’t tell any more.

21h agoHN ↗

It’s a figure of speech. I use that phrase for anything older than three months.

5h agoHN ↗

I find it a valid statement.

IT was always fast, and I explained my students what IDE cable was and they don't even knew about SWAP because they never had memory issues.

21h agoHN ↗

go back to the old days where you manually approve every command the AI runs

Those are also the current days if you have any sense. It's a bad idea to run an LLM with access to your machine at all, but if you absolutely must, you better review everything it does to make sure it doesn't run anything insane.

21h agoHN ↗

They run in a container with no network access, no data access other than the project folder.

19h agoHN ↗

So say people so afraid of LLMs they don't even use them :).

The rest of us picks a level between "approve some" and "YOLO" depending on how much they worry about having to clean up the workspace afterwards. Encouraging using the repo and some dedicated per-session storage, while discouraging changes to global state (like installing packages system-wide) reduces cleanup problem to "every now and then `rm -rf` some agent session dirs".

37m agoHN ↗

The last time I did this, the AI was markedly worse and it took a few days of development time to undo it. Then Claude blamed me for it when asking about the root cause in a retrospective.

20h agoHN ↗

There are several keyboard shortcuts that you would never find out from watching an agent, but are mindblowing to new Linux users. I suck at remembering vim keybindings, but I have ingrained ctrl+a ctrl+e for jumping to the start/end of a string (which also works all over OS X). I had been a developer for an embarassing amount of time before I discovered those.

There are other terminal specific shortcuts for removing last word (ctrl+w) but they don't seem to be as portable.

20h agoHN ↗

Another one, not quite as handy but still awesome: ctrl s / ctrl-q. This freezes/unfreezes the terminal output so you can read it, without interrupting your program. Useful for very fast walls of text.

19h agoHN ↗

Oh so that is what this is for. I thought ctrl-q / ctrl-s are there as a nasty way to screw with users, who every now and then accidentally press one of these, and find their terminal frozen and no longer visibly reacting to input, for no apparent reason.

15h agoHN ↗

there was an old riddle I saw on usenet, "there is a key I use for one of its intended purposes several times a day, but when it stopped working I never missed it. what key was that?". the answer was the caps lock key, one of whose intended purposes was reverting back to normal after accidentally pressing it to go into caps mode.

3h agoHN ↗

I rebind capslock on all my new computers, usually to ctrl or cmd.

45m agoHN ↗

Mine is usually Esc or, when it’s an option, “Esc when pressed, Ctrl when held”.

11h agoHN ↗

You can disable this misbegotten feature with

stty -ixon

9h agoHN ↗

Ah this is also a fun default feature of Powershell, except it works on mouse click.

7h agoHN ↗

That's actually XON/XOFF - in the old days when computers could send serial data to your VT100 or whatever faster than it could handle it (and we're talking 9600 baud here), the terminal would send XOFF (ctrl-S) telling the computer to stop sending - then, when the terminal caught up, it would send XON (ctrl-Q) to let the system know it could resume sending.

The advantage of doing it this way ('software flow control') is it worked with just TX and RX lines, rather than having to connect up additional wires to indicate when the terminal was busy ('hardware flow control').

18h agoHN ↗

It can’t always not interrupt your program. Think about it: after you press Control S to trigger XOFF, the fast output has to be buffered in memory. That memory is certainly not unlimited. There’s no way for the program to keep outputting text. Indeed some programs (including Claude Code, at least a while ago) really don’t like it when you press Control S and let the terminal be frozen for a very long time.

11h agoHN ↗

Interesting; I assumed the write to stdout would just hang for the writing program.

17h agoHN ↗

I remember when the Pause key did that! It's long enough ago that I don't remember which systems did so, and most laptops don't even have a Pause key any more, but it was often very handy for reading fast-moving console output.

19h agoHN ↗

The OS-wide Emacs bindings are one of the main things still keeping me on macOS; in editors like Helix (or Zed with Helix mode) I invoke these really cursed combinations of the Helix(vim-like) shortcuts in the editor with the Emacs ones from the OS and it feels really natural as a means of moving around text.

I haven't put in enough effort to replicate the experience on GNOME but once I jump ship from Apple I'll have to.

The way macOS treats shortcuts thanks to the separation of Command and Control is great. It even makes Google Docs pretty painless to use because it's mostly like Emacs. Word still tries to hijack the shortcuts so that's suboptimal.

18h agoHN ↗

I think gnome just had this as an option somewhere. Asking chatgpt says that this was removed in GTK4, so maybe it's no longer a thing?

7h agoHN ↗

I can still do everything in gnome with a shortcut, but not in vim style.

15h agoHN ↗

ctrl+u and ctrl+k (to delete the line forward/backward from the cursor) are super useful too

5h agoHN ↗

ctrl+u generally works for lots of password prompts to reset/remove what was typed, wherever you come across a password prompt and a keyboard including those two keys.

10h agoHN ↗

This makes me think of something I hate about how LLMs write CLI scripts. Even with the same model on the same day, there's never any consistency with the way CLI arguments are written or handled. Sometimes they want to split on an equal sign, and specifically write that into the code. Other times they write code to pair keys and values based on spacing and order, even and odd.

--date=2026-09-16

--date 20260916

and all variations thereof. It's annoying enough to have to check which script expects what format that I probably should've wasted some time or tokens to align them all, or at least put it into an MD file. But it's just an illustration of how LLMs can make CLI commands more obscure than they need to be.

3h agoHN ↗

Eh sometimes it overcomplicates things. I have seen Opus 5 do mad shell gymnastics for something that could have been a simple `jq`.

2h agoHN ↗

That is indeed a good way to pick up new tricks with AI! But I'm afraid a lot of us will just end up mindlessly pressing "Approve". I doubt people will have the energy to pause and look at the reasoning behind each output when they're overwhelmed by the sheer volume and speed of AI output. And more fundamentally, I know it can be fun to learn new tricks, but I agree with phforms that if you don’t use them often enough, the novelty wears off quickly. And with AI taking over more of the work that used to help us learn by doing, we may end up with even fewer chances to actually internalize those skills.

19h agoHN ↗

While AI has made my life as a developer worse in many, many ways, I am conversely really glad the conversation has shifted past these types of tricks, framework wars, etc.

21h agoHN ↗

The most useful shell trick I've used to date is mapping the 'cd' command to 'zoxide', which is a more powerful version of cd that remembers folders you've been to.

20h agoHN ↗

yes! zoxide is also probably my most used tool. I did not map it to cd yet, but I use the z command to jump into directories indexed by zoxide.

20h agoHN ↗

I go a step further. When I press Alt + j, it sends all the directories in zoxide to fzf (in order of frequency), and I quickly choose the directory and jump to it.

I rarely type "cd" anymore. A huge quality of life improvement!

16h agoHN ↗

You don't need to use fzf. Zoxide has an interactive function too.

17h agoHN ↗

Yes, because you don't have to pop in order. "zoxide <subpath>" is "search the history of working directories for a path ending in <subpath> and cd to that".

21h agoHN ↗

After 24 years and it is still useful. I would add Sed and Awk books as well.

21h agoHN ↗

These bits of knowledge are becoming less useful to me now that AI is doing a lot of the work.

21h agoHN ↗

The thing with a lot of these tricks is that you have to get into the habit of using them. I knew `Ctrl+r` for history since I learned about the command line. I even have a nice shell integration with fzf. But I still used the up/down arrow keys for years or scrolled up when I was looking for a previous command, because I never remembered the shortcut and just took the path of least resistance to find something.

Usually what I do is writing these tricks down to a document that is easily accessible at a place where I know that I will look for when failing to remember them. I have a directory of docs where I write stuff like this down by language/tool/etc., so I can quickly look it up without having to search the internet. But I also have to actively remind myself that these things exist whenever I have a problem, stop me from just doing the inefficient thing.

20h agoHN ↗

But I still used the up/down arrow keys for years or scrolled up when I was looking for a previous command

It's not even that bad of a habit with zsh either where it will only scroll through history matching a substring in your history, for instance if I type "rg -i" and then start pressing up arrow, it will only cycle through history entries starting with "rg -i".

20h agoHN ↗

if you enable history substring search in zsh you can get that feature anywhere in the command and not just the start. it's very useful if you remember some snippet of the command like it had the word debug in it etc. in fish that is built in and on by default.

though one function that i recently added will narrow your history down based on a space separated set of filters which i found useful

    function hgrep
        set -l cmd history
        for pattern in $argv
            set cmd "$cmd | grep -- "(string escape "$pattern")
        end
        eval $cmd | cat
    end

use `hgrep ruby debug foo` would filter for a line that contained all the words ruby, debug and foo.

19h agoHN ↗

Clearly I am missing some setting. On zsh on macOS and I tried what you just said and it doesn't work like this

18h agoHN ↗

FWIW I'm also on macos 15.7.9, zsh 5.9, oh-my-zsh - and I do get this behavior (TIL).

type eg "rg" then up or down arrow, and the history shown is filtered by that rg prefix.

13h agoHN ↗

Isn't oh-my-zsh one of those batteries-included distributions? It sounds like that's just one of the configurations that it provides.

17h agoHN ↗

I was missing it too. Google says it's a builtin zsh feature but mac doesn't turn it on by default, so you add these to `~/.zshrc`

    bindkey '^[[A' history-search-backward
    bindkey '^[[B' history-search-forward

So far it works. Thank you diath.

12h agoHN ↗

I'm not really sure what "turn it on by default" even means in the context of a shell. I've had that manually in my config for years.

11h agoHN ↗

This is a readline feature. You can enable it in bash (and other shells?) with:

bind '"\e[A": history-search-backward'

bind '"\e[B": history-search-forward'

20h agoHN ↗

atuin kind of fixes this habit, when you click up you get a list of the latest commands, and you can just start typing to search. It's extremely natural.

20h agoHN ↗

I found atuin way too hard/slow to use, I think I went two days before I nuked it and went back to pure omzsh. Has it gotten any better in the past 2ish years?

20h agoHN ↗

(hi! I work on atuin!)

yes, it's improved a lot in the last couple of years! what in particular bothered you?

12h agoHN ↗

Not the parent commenter, but I also tried it a year or two ago and my recollection is that I had a similar experience. I have a really long history file that dates back like a decade and if remembering correctly I tried to import it, and it made using my shell very laggy so I ended up removing it. I'm not 100% positive that I'm remembering the exact way that I started experiencing the lag though, so if I have time tomorrow I'll try it out again and see if it's still something I encounter.

11h agoHN ↗

Ahh yes, we’ve done a lot of performance optimisation since then. We regularly test on >1m records and have no issues

Make sure you’re using the daemon (the install script will handle this) and you should be good to go

Very happy to help if you have any problems. Ellie at Atuin dot sh

11h agoHN ↗

Good to hear! Sounds like my history file might not even be that large compared to your tests now

15h agoHN ↗

I've been using it happily for longer than that! I do remember having to tweak the default search behaviours when I first installed it but it's been largely problem free ever since.

18h agoHN ↗

Or you can start typing and press up arrow to search with that. Atuin (or some Zsh extensions, etc.) fix the bad UI of having to remember a different key for "search history by order and text" and "search history by order".

19h agoHN ↗

I was my most effective when I had a bunch of cheat sheets taped up in my workspace.

18h agoHN ↗

Hot-desking killed this practice. I now get desk anxiety on my in-office days

17h agoHN ↗

Have an AI agent compile the cheat sheets into a searchable website hosted on Github for your own personal reference.

17h agoHN ↗

and hook up a Bluetooth sensor so when you walk into the office it prints them off in individual sticky notes and assigns one of the humanoid robots to collect them and stick them on the monitor or cubicle walls of your chosen work desk.

what a time to be alive.

16h agoHN ↗

The printed copy lets you build a spatial association with the command. You are more likely to be able to look up and have your eyes settle roughly where it is than write a query on a custom site.

I think for a digital solution to come close you need it permanently present on a nth monitor

16h agoHN ↗

I am young enough that my entire career has been markdown files, screenshots, and photos on my phone. I (a)sync everywhere by pushing git lfs commits to my home server.

Seems like overkill until it saves my ass. It continues to do so almost half a decade into all the LLM hype. It hits the sweet spot between simplicity, convenience, reliability, and precision.

People strongly underestimate how good the git life can be, especially with all the blogspam on here trying to dethrone it lately.

6h agoHN ↗

I (a)sync everywhere by pushing git lfs commits to my home server.

Don't let IT hear that unless you work on FOSS.

58m agoHN ↗

That's a funny (bad faith) angle you took it. I thought were talking about personal cheat sheets for general programming and tools, not work and proprietary stuff.

The alternative and typical options that nobody bats an eye at for doing this kind of thing (3rd-party big tech cloud) are much worse from a data hygiene perspective. If you're going to be that distrustful of personal phone usage by employees, you're running a prison instead of a workplace and replacing all thought with pointless checklists. That slippery slope never ends.

From your perspective, the best security posture is for employees to return to the office without any personal belongings so we can be extra super secure? It's too bad we can't erase their memories while we're at it since being a programmer is knowledge work.

16h agoHN ↗

reminds me of the time when you got strips of fn key binding cheat sheets for various popular software packages like lotus 123 and wordperfect, and keyboards came with a space to hold them.

19h agoHN ↗

Usually what I do is writing these tricks down to a document that is easily accessible at a place where I know that I will look for when failing to remember them.

People had this same problem last century. They would use templates that fit over their keyboards with all the common shortcuts and commands printed on them. Sometimes they were for a specific program, but you could buy blank ones to write your own notes.

Today, "keyboard templates" have an entirely different meaning, so the best thing for this is paper. Print your shortcuts out on a piece of paper and put it near your monitor. You could even categorize them by writing them on different-colored Post-Its.

18h agoHN ↗

It's quite true. Years ago, after `git switch` was released, I wanted to try to switch from `git checkout` to `git switch`. Ultimately I had to set up some bash nastiness to error and "scold" me when I typed `git checkout` from memory, while still allowing shell scripts to call `git checkout` just fine. It was a fun exercise, and at least now I know how I could do it again: https://github.com/lelandbatey/dotfiles/blob/99c08f81fc89710...

17h agoHN ↗

Your beef is with git, which is terrible, not a shell.

16h agoHN ↗

What's the point of switching to switch? I've only ever used checkout and not sure what I am missing out on.

17h agoHN ↗

You just have to do it so often that you’re annoyed by it and then you learn the shortcut and then you force yourself to always do the shortcut.

9h agoHN ↗

being annoyed and forcing yourself is how everyone learns Emacs

14h agoHN ↗

I’ve read that if you’re trying to overturn a habit with a new habit, it’s best to undo whatever it is you did the old way, then redo it the new way.

So if you want to use ctrl-r, but you’re using the up key, use the down key to navigate back to a clear line, then use ctrl-r. Do it enough times and your brain will work overtime to find a shortcut (aka just doing it the new way).

9h agoHN ↗

Temporarily binding the up arrow in the shell to echo "Use Ctrl-R" is probably the quickest way to un-/re-learn

9h agoHN ↗

I’ve done this, nowadays asking Claude to rebind things so that I’m forced to learn. It comes with interesting side effects!

7h agoHN ↗

I learned to type `ls` properly the first time, every time, shortly after installing `sl`.

2h agoHN ↗

ive just done this, thanks for the suggestion:

"Use Ctrl-R for fuzzy history, or Ctrl-P/Ctrl-N for history entries"

(I have those bound to bindkey '^P' up-history and bindkey '^N' down-history instead of up and down arrow's "up-line-or-history" which is really annoying with multiline commands)

11h agoHN ↗

Bonus: if you write all your tricks in a document, people will love your document. Whenever I offer a new student my CHEATSHEET.md file, their eyes absolutely light up.

9h agoHN ↗

You have a link? :-) (Still a student)

1h agoHN ↗

Mine is unfortunately pretty specific to the HPC clusters we use. Maybe I should pick out the more general bits and make them public some day...

2h agoHN ↗

I've found Spaced Repetition (via Anki etc) to be great for remembering these things.

Was originally turned on to this by Derek Sivers: https://sive.rs/srs

1h agoHN ↗

I have following lines

  "\e[A": history-search-backward
  "\e[B": history-search-forward

in my .inputrc for years. I think, this is how command line worked in tcsh.

It changes unconditional prev/next to prefix search. With empty command line it is the same as the old behavior. But if you enter "ls" and then press up-arrow, it will scroll through all commands in history that have "ls" as a prefix. I use it much more often than C-r.

6m agoHN ↗

on fish shell i never felt the need for any of this, since pressing up does a history search on what you have typed

21h agoHN ↗

the biggest trick I have is to learn to use curl properly

21h agoHN ↗

You can SELECT without a FROM

welllll that depends entirely on the DB Software you're using. A certain IBM product certainly has opinions on this.

20h agoHN ↗

git log -S pattern (”git pickaxe”)

Another option is to do a ‘git log -p’ followed by a string search ‘/‘. It can give more context and let you browse more easily, especially if the project has small commits. It won’t work well for every project or search though.

20h agoHN ↗

I keep a ~/scratch.txt file and a bash alias "scratch" that will just grep it. Then I put a lot of relatively infrequently-used but often-forgetten command recipes in there, so that I can just do "scratch keygen" or whatever and it will find it. It persists longer than bash history.

If anything, I wish I had paid a lot more attention to this in the early days and made a nicer shell environment full of my own utilities, as I felt my skills just kind of slowly erode over the years with each migration. Make a nice little nest for yourself and curate those tools as your own (text) UI.

20h agoHN ↗

Was not expecting to see my per-directory-history project mentioned in this, glad the author found it useful!

19h agoHN ↗

I've noticed the same thing with AI coding tools. Sometimes I learn more from the commands they use along the way than from the actual solution.

19h agoHN ↗

Simple trick I use almost daily for navigating backwards to an exact directory:

https://gist.github.com/GNOMES/6bf65926648e260d8023aebb9ede9...

I use this often instead of chaining together multiple '../..'.

Also nice for when I use Zoxide to CD into a deep nested directory. I quickly found out unless you manually CD each hop, the different parent directories aren't added to your Zoxide DB. (I have come across snippits to recursively CD into all directories in a path to "prepopulate" Zoxide).

I made this to jump directly from say `/foo/bar/batz/abc/123` to `/foo/bar/batz`.

18h agoHN ↗

This is a neat and useful trick, and I will be borrowing it. Thanks!

15h agoHN ↗

Abbreviate moving up in the directory hierarchy:

  alias ..="cd .."
  alias ...="cd ../.."
  alias ....="cd ../../.."

Just keep typing period and hitting enter until you get where you want according to your prompt. I haven't found much use for more than four periods. One period would be well-defined but useless.

3h agoHN ↗

I have a shell function called "up" that finds a project root and jumps back to it (e.g. a dir containing something like .git)

Now I have these to complement - thanks!

7h agoHN ↗

Somewhat along the same lines, as I regularly SSH to other hosts with the same network filesystem mounts, 'scd' starts an SSH session on a remote host in the same directory.

  #!/bin/bash
  # SSH to remote system and change into same (current) directory
  DIR=$(pwd)
  ssh -t $1 "cd $DIR; bash -l -i"
6h agoHN ↗

For fish shell users, you get chronological directory traversal with Alt-Left Arrow and Alt-Right Arrow.

19h agoHN ↗

Aside from the NodeJS "trick", these seem like system administration "tricks" not programming "tricks"

Of course shell scripting is programming according to some HN commenters

Perhaps others would call SQL a programming language

18h agoHN ↗

In NodeJS, you can keep a connection open to an external resource by creating an https.Agent and then providing it to your http requests: fetch(url, {method, agent}). This can have a dramatic impact on latency.

Is it true that you can pass a nodejs agent to fetch ? I don't think so

15h agoHN ↗

No. Node's built-in fetch uses Undici. The custom hook is dispatcher, with an Undici-compatible dispatcher: fetch(url, { dispatcher })

18h agoHN ↗

You probably don’t need find

I think for most cases `git ls-files` does this job quite well. If you provide pathspecs, this can be very powerful!

18h agoHN ↗

Those were not programming tricks, but computing tricks or command line/sql tricks.

Anyways I find it mind boggling how many useful actions are not known by „normal people”. Most people are really using computers in a very inefficient way.

My idea is if we would spend time making people learn computers or software they use daily better - we wouldn’t need AI agents and we would triple GDP.

17h agoHN ↗

Maybe, but there's all sorts of habits and skills that would make us enormously more productive/healthy/etc. if only the masses would learn them. This is a very old problem.

11h agoHN ↗

For sure! It was on Hacker News too that I learned not that long ago via this thread[1] how to tie my shoes in such a way that the knot won't come undone by itself. It has definitely saved some time with some shoes with laces that would always undo themselves on their own with my old method.

[1]: https://news.ycombinator.com/item?id=48397028

9h agoHN ↗

if we would spend time making people learn computers or software they use daily better - we wouldn’t need AI agents

There's no amount of skill/efficiency/productivity a human worker can reach that will make employers give up on the dream of one day replacing them with software. The AI companies looking to profit from renting out the collected works and creativity of humanity certainly wouldn't shut down if the GDP tripled either.

People should still take time to learn how to use computers though. As long as they're going to use computers they can save themselves a lot of trouble and anxiety by investing some time in learning about them a little. Same with many other things people use and depend on.

5h agoHN ↗

There's no amount of skill/efficiency/productivity a human worker can reach that will make employers give up on the dream of one day replacing them with software.

I agree... but also this is so wrong it's painful. If you do have a good worker, they don't cost money, they MAKE money. Of course if you as the CEO think you are smart enough to cover everything and anybody but you is just wasting money, then that doesn't work and optimizing makes sense. Corporations have grown in size to be mindless heartless engine, literally, and that comes at the heavy price of ... not thinking, just an automaton with a single goal, growing profit, leading to an even more inhumane setup within which removing costly humans makes perfect sense.

17h agoHN ↗

In Jetbrains I do secondary shortcuts and I name them as what they are in my hand:

Alt M + V = Move Alt E + C = Extract Component Alt S + E = Search Everywhere _ many more.

Or just vim combos.. with ideavim

16h agoHN ↗

A small side note I want to raise:

Folks need to be sufficiently motivated to learn it. All hell break loose when `RTFM` becomes taken offensively; What do I know - I am just a weird guy with a beard.

And folks always wanted to type the commands without RTFM'ing - now we have two problems instead of one.

Also, these were hard learned tricks YOLO'ing until 3.30AM debugging a failed DNS clusters or why the HSM suddenly decided to trip up at 5AM! Nobody even cares about the things we learn these days - Google and then your AI agent already does 98% of what I know already. So, let them blow up the clusters and the racks - your pal AI agent knows. Go ask them instead.

16h agoHN ↗

“Small programming tricks for webdev” - title

16h agoHN ↗

I switched from vi readline mode to emacs recently primarily for Ctrl-r and Alt-. (insert the argument from the last command). I love how interactive they feel.

You can accomplish the same things in vi editing mode (with ? and !!) but they’re not as interactive.

15h agoHN ↗

It’s sad, I used to love little tricks like this: optimizing my workflow, learning the keyboard shortcuts, reading the manual. But now I just prompt codex or cc. The appeal of “sharpening the axe” is greatly diminished. I fear much of this type of knowledge will soon be lost to time.

15h agoHN ↗

I prompt a lot, but I also still run a lot of commands and do quick edits with vim myself, not gonna prompt "increase X to Y" when it takes ~3 seconds to do myself vs ~30 seconds for even a fast model to do it.

14h agoHN ↗

My main trick is to use fish and enable vi key bindings. Especially on mac where there is no Home And End functionality.

6h agoHN ↗

Can't say enough good things about fish from a UI/UX experience. There's a reason Shell Bling Ubuntu [0] swaps out your underlying shell to fish. Unless you need a terminal up ASAP for scripting purposes or shelling out (in which case dash is still much faster than bash) it's just such a better experience.

[0]: https://hiandrewquinn.github.io/shell-bling-ubuntu/

6h agoHN ↗

I do this all the time with Vim. To the point that it astonishes me that this isn't like the third or fourth thing people learn about Vim.

You can just record and play back your exact keystrokes like a _Super Smash Melee_ game plays back your inputs to replay matches. If you can figure out how to do any mildly complex action once you can literally replay it a thousand times. Just like AutoHotKey! To my that's the essence of citizen programming!

11h agoHN ↗

Not exactly programming tricks, but there's also stuff you just recognize quickly because it's a pattern you've encountered before. Like yesterday I had to diagnose a bug where some newly deployed and barely tested software hung while generating a gift certificate. Customer's name was O'Brien. Anyone wanna guess the bug?

10h agoHN ↗

A few tidbits I wish I had known about sooner:

bash: Ctrl-L to clear the screen

VSCodium: Shift+Alt+[arrows|mouse click] to select a rectangular block

scp for moving files (instead of ftp)

9h agoHN ↗

Yes, but try rsync instead of scp. Mind the slash though!

Both rsync -avz /path/to/file user@server:/another/path/to/ or rsync -avz /path/to/file/ user@server:/another/path/to/file

Will create directory named /another/path/to/file which will contain all contents of the original directory (/path/to/file/*).

Basically, if you include the trailing slash in the source path, only contents of the directory will be copied (useful when you need to rename it).

    rsync -avz path/to/old_dir/ user@server:/path/to/new_dir

If you omit the trailing slash in the source path, rsync will create the target directory for you. See man rsync for more info.

6h agoHN ↗

Ctrl-lpj is ingrained in my fingers.

Ctrl-l to clear the screen, Ctrl-p to select previous command, Ctrl-j to enter it again. I don't even use Enter key when in terminal anymore.

When you want to pause entering a command for a moment do Ctrl-a to go to the start of the line, and type # to comment out. Then Ctrl-j. You can return to that later with Ctrl-p, then Ctrl-a again and Ctrl-d to remove that comment.

To edit complex commands you might want to use Alt-e to enter $EDITOR.

8h agoHN ↗

I remember when I was using JetBrains IDE they had this feature that would list all shortcuts and IDE features and how frequently I use them. This was excellent for feature discovery. I would regularly check it out and scroll to the list of features I never used and try them.

I always wanted the same for Vim, zsh, etc.

8h agoHN ↗

Do they still do this? I'm using PyCharm daily but have never seen it. Would indeed be pretty cool!

6h agoHN ↗

Ha! I just checked it out (had to install IntelliJ for this!) and it is still there!!! "Help" -> "My productivity".

8h agoHN ↗

I am so proud of this (I'm sure others came up with it way before me, but I still came up with it all by myself!)

    //*
        normal path
    /*/
        debug path
    //*/

take away the the first slash to toggle the debug zone ON!

7h agoHN ↗

It's awesome in both senses! How readable has it become for you over time? Because on first glance and without syntax highlighting it's a head-scratcher.

5h agoHN ↗

With syntax highlighting I instantly know what it is :) But to be honest it's just for when I find myself toggling something a lot during development.. but still am too lazy to make a variable.

6h agoHN ↗

  #if 0
    // Normal path
  #else
    // Debug path
  #endif

Only works with C and C++, though.

7m agoHN ↗

C#:

#if DEBUG

    Console.WriteLine("This only compiles and runs in Debug mode.");

#else

    Console.WriteLine("This only compiles and runs in Release mode.");

#endif

3h agoHN ↗

I once took the time to figure these out for all the languages I use

here's python:

    #'''
      normal path
    '''
      debug path
    #'''

when I comment out python code I do it with ''' ... #''' so I can uncomment it with 1 keystroke

7h agoHN ↗

Programming? You mean that clever trick people do to make progress on a code base slowly while Claude is down?

6h agoHN ↗

A lot of these tricks come down to knowing there is a better alternative program somewhere out there in the universe, and then installing it. I happen to keep a shell script handy for these situations, which automatically installs most of the options listed here:

https://github.com/hiAndrewQuinn/shell-bling-ubuntu

More readable presentation: https://hiandrewquinn.github.io/shell-bling-ubuntu/

Among other things, fzf gets installed with all the proper key bindings, ripgrep, fdfind... basically every papercut I could find between going from a vanilla Ubuntu or Debian box to a configured one is handled in this shell script.

5h agoHN ↗

My bash terminal starts with my own shortcuts and

     ^a         ^e       \
  <-------   -------->    } Moving
    alt-b    alt-f       /
     <----   --->       /
       ^b    ^f        /
         <- ->z 

$ cp monfi[c]hier dir/

     <----   --->
     ^w     alt-d       \
  <-------   -------->   } Erasing
     ^u         ^k      /

precisely because combinatorial mindset and efficient navigation are so important to my workflow.

PS: visual adapted from https://gist.github.com/tuxfight3r/60051ac67c5f0445efee

4h agoHN ↗

I think it's wise to be a bit deliberate when turning on globstar in bash. The main cost is occasional slowness on big trees. It's OK to turn it on for general purpose things, but for scripts the bigger concerns are portability and the possibility of unexpectedly broad expansion.

4h agoHN ↗

In case you were confused about the logarithm trick, here's what I think it's trying to say.

This hypothetical system has a bunch of users, belonging to groups. A possibility is that most groups have a only handful of users, but a few famous group might have disproportionate amount of users say 500,000.

If you wanted to put these groups in buckets, you can create linear buckets of fixed size based on number of users like

    bucket 1: 0 to 100 users
    bucket 2: 101 to 200 users
    bucket 3: 201 to 300 users
    ...
    bucket 600000: 599001 to 600000 users

Now the problem is you have way too many buckets, and most of them are probably empty. In situations these "buckets" actually cost you money, you might want to optimise the number of buckets.

So the code converts the user distribution to logarithmic scale:

    const bucket = Math.floor(Math.log10(userInGroupCount))

This essentially creates buckets as number of digits:

   bucket 1: 0 to 9 users
   bucket 2: 10 to 99 users
   bucket 3: 100 to 999 users
   bucket 4: 1000 to 9999 users
   bucket 5: 10000 to 99999 users
   bucket 6: 100000 to 999999 users

With this, you have needed only 6 buckets. Moreover, this probably maps to the real life distribution, so your charts read cleanly.

4h agoHN ↗

(you'll have to handle the case where `userInGroupCount == 0` in the code given)

3h agoHN ↗

Honestly, a lot of programming is just knowing the right little trick at the right moment. You don't need to know everything, you just need to know where to look.

2h agoHN ↗

For people asking "do these small tricks/trivia really matter??" I have an example of when they do:

- having strange networking issues on the blue side of a blue/green deployment

- networking engineers are involved

- nobody seems to be able to figure out what's going on despite LOTS of tcpdump/wireshark etc

- I suggest tcpflow[0] (which I used for protocol analysis of chat services etc)

- (there is some skepticism as I was SRE and not networking)

- Turns out that the TCP messages were getting truncated on the problem side

- Networking guys realize the config issue and fix it

I have other examples but this is why it's always good to learn new commands/tools etc.

This, in turn, reminds me of a quote from an army jungle survival expert: "People ask me if it's a good idea to read survival books. I say: 100%. You would be surprised how many people survive an emergency situation because their brain pops out some critical piece of information from a book or article they read 10 years ago."

0 - https://linux.die.net/man/1/tcpflow

1h agoHN ↗

Good post. +1 for Julia Evans mention. Her work and vibes are worth anyone's time

46m agoHN ↗

This will probably seem to obvious to mention to many, but it took me a few years to realise that you could replicate the "BREAK XYZ" from languages of yesteryear:

   FOR I = 1 TO 10
       FOR J = 1 TO 10
           FOR K = 1 TO 10
               DOSOMETHING I, J, K
               REM Breaks out of the middle loop, continues next I iteration
               IF SOMECONDITION(I, J, K) THEN BREAK J
           NEXT K
       NEXT J
   NEXT I

in modern languages by refactoring the loop you want to break out of into a function and using return instead:

   def inner_loops(i):
       for j in range(10):
           for k in range(10):
               do_something(i, j, k)
               if some_condition(i, j, k):
                   return
   
   def fn():
       for i in range(10):
           inner_loops(i)
32m agoHN ↗

Ugh, TIL that Python doesn’t have labeled breaks. Now I’m wondering what other languages in current use don’t have this functionality.

11m agoHN ↗

I was about to mention C#, but I just checked and it’s coming to C# 15 in a couple of months.