martes, 28 de septiembre de 2021

The “Two-And-Done” Rule

This one is something that depending on the moment your think about this you might agree or disagree, and it's like those optical illusions that when you think "right" the images rotates to the right, and when you think "left", it does to the left.

The principle of "two and done" is a guiding tenet to keep yourself sane, on your toes, and put things on perspective to not give an unwarranted amount of importance to things that do not have them. 

Even is "someone is wrong on the internet", knowing when to stop arguing can feel like "not driven enough" on my side, but it can feel also like a liberating proactive empathic way to problem solving.

So the Two-And-Done rule was born, wherein I will state my case the first time, and if whoever is arguing to the contrary does not agree after hearing my position, I’ll let it go. But the next time the opportunity comes up, I will argue my point again. Maybe allowing for a gap of time for people to consider my original point, or maybe allowing me time to refine and rephrase my ideas to be more convincing.

If I fail to get my way after the second time though, I am done. I will even say as much to whomever I am debating if they are the final decision-maker. I will say something like, “OK, let’s go your way then. I still don’t completely agree with everything proposed here, but I think I’ve made my case, and we need to move on.”

Yielding in an argument like this has some weird, powerful effects. One is, it kind of releases you from responsibility if things should go wrong. And if a truly bad decision has been made, it is actually pretty likely that things will start going wrong. (Important Note: If you fail to convince people after two tries, you really do have to get behind the decision, and not try to sabotage or undermine it)

 

The pretty important part is that you have to get behind the decision.

 

jueves, 23 de septiembre de 2021

Good Job Aaron

Today I read this HN thread about YJit and Tenderjit that is a great lesson, and there's a comment there, someone describing some traits of his. I'm quoting it here just to read it from time to time when I review my posts:

I've had the pleasure of meeting Aaron at a number of ruby confs. He's supportive from the largest all the way to the smallest.

My personal favorite thing he'll do is ask conference speakers questions that make the speaker look good/best-light-possible. Something slightly technical/challenging, not fully covered in the talk but definitely something the speaker can handle.

To be able to do this consistently means he knows the topic better than the speaker themselves (at least this has been true when I've been there).

This is in contrast to people who ask "gotcha" questions. Spend 3-4 minutes showing off their knowledge and then finally getting to the question which is to stump the speaker. I hate these kinds of people at conferences the most.

 

Shouldn't be hard, right? supporting people and trying to make them feel engaged and well about what they do, let people shine without having to point out that "actually,....", or "as I said in an earlier thread....", or ... you know.... 


miércoles, 22 de septiembre de 2021

Caught by a regex

I'm a big fan of regexes. 

I've not found yet a DSL that has proved so useful in so many situations (text handling, really).

But today, I got caught by something I didn't know, and that totally escaped me. It's not even in the sense of "now you have 2 problems". Because the problem at hand was perfectly suited for regular expressions. no capturing, no grouping, no back references, no (negative)?look(ahead|behind). A typo gone wild.

It's about `]`, and the fact that if it's paired with an earlier `[`, the regexp matches any character inbetween them. That's known, and what's also known is that escaping characters inside works a bit different, and also that `-` means "range", UNLESS it's in the first or last position.

But, What caught me today is that `]` (without escaping) works as a literal if there's no pairing `[`. 

  • /(/ -> invalid regexp
  • /)/ -> invalid regexp
  • /[/ -> invalid regexp
  • /]/ -> fine. O_O

This is so foreign and arbitrary I couldn't really believe it. I don't know if there's a deeper reason for this being this way, but I can't find a reason why it couldn't behave the same way as grouping parenthesis.

This was cascading from a regex like /[`~! @#$%\^&*()_+={\[}]|:;\"'<,>.?\/-]/ .

It is intended to check that there's at least 1 symbol in a string.

If you notice there no escaping for the ] in the middle, the regexp is still valid, but the bracketed part is smaller than what you'd think.  And it doesn't fail to compile the regex.

But to make things worse, just after the ']', there's a pipe symbol (because they are close in the keyboard). and now, this symbol is not treated specially anymore, but it counts as an alternative.

With this, what do we got here? 

the regexp matches either one of [`~! @#$%\^&*()_+={\[}] bracket, or the string ':;\"'<,>.?\/-'. This made it even more difficult to find, because some validations passed, while some didn't. If it wouldn't be for the '|' being just after ']', all validations would have failed from the beginning.

Well... 2 level fuckup from a single regexp due to an missing backslash and the US keyboard layout.

How many problems do I have now?

martes, 21 de septiembre de 2021

7GUIs examples

I discovered 7GUIs from a guy in HN that posted his plain vanilla html/js/css implementations https://news.ycombinator.com/item?id=28600804


The HN comments have some good insights on when DIY is no longer sustainable. And in the case of web development, it falls appart pretty early.


On my personal front end adventures, I'm trying material-ui, which I think combining react with that might actually alleviate a lot of the pains when developing a frontend as an "I-dont-care-much-how-it-looks-like-as-long-as-it-looks-okish".

I also liked tailwind a lot, but it's lower level, and really, I-dont-care-much-how-it-looks-like-as-long-as-it-looks-okish.

 

 Also, Look at the Red implementations of the GUIs. Amazing

jueves, 16 de septiembre de 2021

Small little grep+edit trick

This is so small, but so huge....

It's like many other finders you find in your editor of choice, but because it's such a generic and minimalistic tool, I keep up using it tenths of times a week.

Idk, this is more composable and functional and succinct than many things I find in the wild that claim to be so. 

And it is damn useful!

Also, even it's 4 lines of code, there's probably a thing or two you can probably learn from those. Here are some things I like and why I think it's High Quality Shit:

- It's short, you can inspect the words  it contains, and if you get more or less the programs it calls, it can only do one thing.

- It solves a real problem

- It has high density. All words there mean something, there's 0 boilerplate

- It is composed of smaller parts. It feels Forth-y

- The way it's composed is subtly nice (the existence of "e" function is needed to compose it that way)

- It's as configurable as the program it uses to grep. It inherits its flags

- It inherits its auto-completions

- You can learn a bunch of things from it

- It fits in your head

- It has that Iversonian "suggestivity"

- I wrote it, so it has that IKEA effect on me


Many more things like that in https://raimonster.com/scripting-field-guide/


Oh! I found https://github.com/junegunn/fzf/blob/master/ADVANCED.md#ripgrep-integration which is an even more advanced version of it. Not as cute though

miércoles, 15 de septiembre de 2021

Oh Yes You Can Use Regexes to Parse HTML!

This is Perl, and regexes, and parsing, so if you enjoy those kinds of things, you'll love the comment on this HN Thread. that points to this insane "oh yes, you can use regexes to parse HTML" .


Wow. We've seen all the "you can't parse html with regexes",  and if you were into Perl and knew about the superpowered regexes, you knew it was possible. 

And you might even remember that Damian Conway's Regex::Grammars was some amazing weird Conway thing that twisted regexes just to test their limits.  

Or, my Meta-II compiler implemented in a Perl regex...

 

But it's great to see all those twistings of the common tools. 

viernes, 3 de septiembre de 2021

Get Github Actions' container logs

 If you happen to use github actions AND you use service containers, you might want to show their logs, and GH doesn't do it (at least in some cases).


So, according to  https://github.community/t/how-do-i-get-the-logs-for-a-service/16422/2 , you can create a later step that prints the container logs:

docker logs "${{ job.services.mysql.id }}"

miércoles, 25 de agosto de 2021

A couple of jq tricks

 There's 2 jq functions I'm using a lot, and I don't see many people using: "join" and "fromjson".

The first one, is join, which joins arrays into a single string. I shared it in a HN thread about jq. That thread has some nice tricks, check it out if you do that kind of json parsing in the CLI.

The other one is "fromjson", and you use it like this:  

     echo '"{\"a\":1}"' | jq fromjson.a      # 1


A concrete practical example is in when fetching secrets from aws secretsmanager. A secret's content is a string, that is really a json.

     aws secretsmanager get-secret-value --secret-id  <secret-key> | jq '.SecretString| fromjson.key_of_the_json' -r

miércoles, 28 de julio de 2021

More on Writing, Notation, Symbols, and Emoji

Since My "On Writing" post, a few posts came through HN that touched somehow on the communication styles, context, and missconceptions on sharing knowledge.

- What happened when I stopped using emojis. That reasonates with my thinking a lot. I'm trying to use only the modern version of '+1' and simple ':)'. The other ones dumb down the expressivity to a baseline that brings nearly 0 info. On the other hand, knowing that old reddit's '/s' has its own family of symbols and meanings made me think that well used, a short symbol can convey the a lot of info (https://toneindicators.carrd.co/). On Context and the power of understanding "where that person is coming from", there's this great example on Greg Wilson's talk What Everoyone in Thech Should Know About Teaching and Learning where it explains how in examining the novice's mistakes, you can infer what he/she didn't understand, and what's the best explanation or example to give in order to solve the enigma and make it 'click'. (As an aside: I think it's a great example of why human interactivity is not redundant once you have docs and wikis.)

Which brings us to APL (again), and its notation. I've been more and more excited by APL, and I'm following now some APLers on youtube, for example Rodrigo Girao which does great short beginner videos on APL solving leetcode problems. Also, subscribed to the shakti mailing list, and reading 'mastering dyalog' when I have some time.

 

On the strict writing side, I found a couple of courses and docs in https://developers.google.com/tech-writing and https://developers.google.com/style/highlights that deserve a good read. I just skimmed them, but well.... something >> nothing.

sábado, 24 de julio de 2021

Cypress, React and Emacs backup/lock files

 So I'm dealing with some javascript lately, and it took me a while to figure out that some of the javascript tooling ("cypress open", or "yarn start" a react app) fails to refresh correctly (in fact exits with an exception) every time you modify a file that it is watching.


So, if autorefresh is "on", you can't touch any file.  Not good.

Found out that the cause of those failures are both emacs lockfiles and backup files. They are created in the source directories, and then, js tries to load them, or to examine them somehow, and js falls flat on its face.

(setq make-backup-files nil  

         create-lockfiles nil)  

That should do it.



domingo, 11 de julio de 2021

Deploy and SPA and getting 404 errors? WTFs that become normal

So, deploying an SPA to an S3 bucket, or github pages involves hacking your way around 404's.  

I did not know this one previously, but once you understand what happens under the hood, it makes sense, the web file server can't understand about any kind of paths besides index.html.  What feels strange is that the "official" ways of deploying such "modern" apps feels like it's using a hack, relying on this catch-all solution of overwriting the 404 page to serve index.html (and potentially hacking it's router), or create an ad-hoc 404.html page and put the hack there.  

Finding all info in random blogposts, stackoverflow threads, gists.... The whole thing seems so fishy... but I've come assume that it's just the way it is. That's the full story. Accept it and move on to more interesting things (like fighting CORS or Same-Site Cookies on buggy browsers)

  • https://github.com/rafgraph/spa-github-pages
  • https://medium.com/swlh/how-to-host-your-angular-reactjs-vuejs-spa-on-github-pages-2d9ab102ac7b
  • https://dev.to/alexeyromanchenko/how-to-deploy-spa-as-a-static-website-using-aws-s3-1adg
  • https://gist.github.com/bradwestfall/b5b0e450015dbc9b4e56e5f398df48ff
  • https://johnlouros.com/blog/using-CloudFront-to-serve-an-SPA-from-S3



sábado, 10 de julio de 2021

viernes, 9 de julio de 2021

Show other revisions of a file with magit

Magit proper offers magit-find-file and magit-find-file-other-window, that ask you for both revision and file. At least they autocomplete with sane defaults. 

The thing is my usecase is 99% "current-file in previous-branch in a split window".

As easy as

(defun rgc/magit-find-file-dwim ()
  (interactive)
  (magit-find-file-other-window (magit-get-previous-branch) (buffer-file-name)))

You get a nice command to open the current file from the previous branch you visited in your repo. 

Often, next immediate  command is m-x ediff-buffers RET. (yeah, maybe adding that would make it even more dwim).

If you'd want to do it in the command line, something like 

    git show branch:file

Would do, but you'd have to type both branch and filename.

 

domingo, 4 de julio de 2021

Taming Zoom with Ratpoison, part 2

 It's been already 2 years since the last zoom hack, and it worked fine for some time, but since January 2021, Zoom was behaving even worse on my ratpoison setup. Hijacks of popup windows left me without being able to join zoom with any sort of confidence.

A temporary solution is to use ratpoison's tmpwm, but there's another wrinkle there. In the latest official ratpoison release (1.4.9, from 2017), there's a bug that makes ratpoison not be able to go back from a tmpwm if you have multiple screens. It is fixed in the git version, but having to compile your own WM is yet another yak to shave. (Even more when using nixos). 

So I spoke to a coworker who's a StumpWM user and asked if stump had those issues.

So, it turns his hack worked, and it consists of changing the .config/zoomus.conf. Changing config files on proprietary applications reminds me of my reverse-engineer times on Windows 98.


Anyway:

sed -i 's/enableMiniWindow=true/enableMiniWindow=false/' ~/.config/zoomus.conf


Thanks, Tim and good luck!

sábado, 3 de julio de 2021

Anomalies and Resilience in software

A great read of a mars story and great lessons on software design, systems thinking, and probably resilient software.

https://mars.nasa.gov/technology/helicopter/status/305/surviving-an-in-flight-anomaly-what-happened-on-ingenuitys-sixth-flight/

 

 

If you want to really go into detail in the greatest space story ever, dont' miss this one from the Moon landing: https://www.youtube.com/watch?v=B1J2RMorJXM

domingo, 6 de junio de 2021

Patching via AST in python

Even though I'm lately 75% Clojure and 25% apl/j/k, there's always a spot for a nice python article about patching thousands of lines of code via converting the source code to AST and back to text:

https://engineering.soroco.com/abstract-syntax-tree-for-patching-code-and-assessing-code-quality/ . The corresponding HN thread: https://news.ycombinator.com/item?id=27419237

Reminds me of https://www.debuggingbook.org/ .


Which also reminds me of this clojure https://github.com/bfontaine/grape and https://github.com/borkdude/grasp, that allow you to search clojure code not just by text but by patterns of code, without taking spacing or variable names into account.

And segway to clojure here's some sophisticated clojure codebase walkthrough: https://news.ycombinator.com/item?id=27385208

And last, some good food for thought on leveling up the engineering skillset: https://skamille.medium.com/an-incomplete-list-of-skills-senior-engineers-need-beyond-coding-8ed4a521b29f . Although each one of those make sense, the environment in which one works makes them easier to realize/work.

jueves, 20 de mayo de 2021

The Array Cast

There's a new podcast about array programming languages!

https://www.arraycast.com/

In the first chapter, they mention Richard Park's articles and videos porting perlweekly challenges to APL.

https://perlweekly.com/a/richard-park.html and https://www.youtube.com/channel/UCOx-h5m9MeV14rG4PicRB7g . Very very cool stuff around this magical programming language style

domingo, 16 de mayo de 2021

Current file name on emacs's shell-command

When I came from vim to emacs, I wanted to get my ":!perl %" command in emacs. I found that by default, there was no symbol bound to current-file-name in the shell-command minibuffer.

One of my first emacs hacks was this snippet (git blame says I added it in 2013)



The other day, in some reddit thread, I found shell-command+, which does this and a bit more. Super cool that it also uses '%', inheriting the vi tradition. And I can retire now my old code.


Speaking of '%', did you know that typing '%' in your firefox address bar will narrow the completions to currently open tabs?  A-MA-ZING. More cool shortcuts here.

sábado, 1 de mayo de 2021

Wait a sec..., did I just ask for paredit-convolute-sexp?

So, After years of lisping, and using paredit (feeling that paredit is not for me, and realizing that "if paredit is not for you, you have to become the person who paredit is for", and becoming that person), I found a need for a command I wish it existed, and turns out it did.

After getting used to paredit, you just love it and miss it in non-lisps. But there is this paredit command that is basically a big question mark. You read about it when you were learning paredit, it didn't make sense then, and you moved on with your life, barfing, raising, and splicing sexps.

So it just clicked today, (now that I'm back to lisp (clojure)). I was thinking "there should be a way to do this", and then remembered there are a few paredit commands that I didn't find use for when I learned about them. And Bingo! It's just one of them!: paredit-convolute-sexp.

So the situation where it's useful is when you want to "swap" 2 "wrapping macros".  By "wrapping macros" I mean any macro or special form that expects a body. Such forms are "let", "binding", "with-redefs", "db/transaction"... you know, all those.

And by "swapping", I mean changing who wraps who. Here's a before/after 


See? Instead of a "let" wrapping a "binding", we get "binding" wrapping a "let".

If the binding forms (the pairs in square brackets) live in the same line as the special form function (like the previous example), and if you would be using evil, you would just swap the lines with ddp and reindent. 

But if the binding forms live in different lines, it's not as straightforward anymore.   I hope you know where I'm going now...

Well, paredit-convolute-sexp helps in those situations. Your only task is to put the cursor in inner expression, exactly in the place where you want the split to happen: before the first form that belongs to the &body. Then you press M-? (now, I think I even "see" why the shortcut). And magic happens.

The movement and the results are weird to explain, but with proper examples, it is easier to get a feel for it. Just try it in different positions with code with lots of nesting.

sábado, 24 de abril de 2021

Fast feedback loop with emacs (Lua)

Here's a long overdue post about emacs fiddling. All this belongs to my previous job time, during the past 3 years doing Lua.

One of the major test frameworks in Lua is Busted. It uses an rspec-inspired syntax and the cli accepts flags to filter the tests you want to run, by file and regular expression.

To iterate as fast as I could, I'd want to lock on a particular test, and be able to run that same test for a while. That's super useful while hacking on a feature or fixing a single test.

So the solution I came with was to use our beloved emacs, to find the current test the cursor is on, and remember it in a global variable. Of course, I want it in the most dwim-y way, so the same binding does "the right thing" most of the times.

Here's the decision making proces, that starts calling rgc-run-test (bound to f7):

rgc-run-test

If I'm in a *_spec.lua file, the process sets a global var with the current file path. The process also looks for the closest previous line to my cursor that looks like a test definition and sets another variable with the string of the test. To recognize the test definition, I match the lines against "it(", "describe(", or "it_content_types(". I use 'rx' library for that, which is pretty cool, check that out if you're doing complex regexes in elisp.

rgc-test-shell

After that, we find a buffer with a shell.

If there's none currently open, I create one, using the right parameters (so it lands on the correct directory).

An extra nicety is that I call 'highlight-regexp' with a string that will highlight any debug line.

You can enable (add-hook 'shell-mode-hook 'compilation-shell-minor-mode), making all shell buffers to run compilation-shell-minor-mode. That means that every line that looks like a path/to/source.file:line becomes clickable. That means that you can navigate to the source:line from a stacktrace.

With this, you can press F7 in a test file, and this snippet will make sure that a shell is in the right place (opening an existing one if it's already there) and will run the current test. 

But, many times, you are not just editing the test, but you're touching the code. No problem. F7 remembers the latest test you run when you were in a test file, so it will run that same test in case you're not in a test file.

When things seem to be solved, you then want to run the tests in that same file, but not restricting it to that single test, but run the whole file, to make sure you didn't mess up anything else. C-u F7 will do just that.

rgc-test-flags

Last cool thing. Sometimes I want to lock extra flags for the tests, rgc-test-flags is a quick way to overload the flags and keep them around for the next runs also.

ffap

Also, sometimes, the test errors in lua are marked like 'path/to/file @ 98'.  This makes find-file-at-point miss the line number.  But yeah, emacs. you defadvice find-file-at-point, with an extra case and off you go.

 That's it

I know this whole thing is quite hackish, and there's a lot to chew in just 50 lines, but this was so useful to me that I wanted to share before I forgot about it (changed job recently so I'm not using this snippet anymore)

It's this kind of workflows that the holistic approach of emacs allow for. And we love it so much :)

Here's the gist of it:


 

miércoles, 31 de marzo de 2021

Interesting new-old takes on git

It seems there are a few things going on lately on the git subspace.

For one, ppl are talking about the mail flow vs Pull Request flow. It's interesting how people go back and forth on those: https://blog.brixit.nl/git-email-flow-versus-github-flow/

 Here's an interesting take at git flows again. Git plan focuses on writing the commit message before doing the commits. Maybe it's something to fix the issue/pr dicothomy?: https://github.com/synek/git-plan

And an experience report of using squash+merge for couple of years. That's interesting because it's what we are using at work, and even though I'm skeptical about its advantages, it's nice to see how people perceive the effects of squash+merge: https://blog.dnsimple.com/2019/01/two-years-of-squash-merge/

And a bonus of HN thread with some git helpers using fzf: https://news.ycombinator.com/item?id=26634419


jueves, 4 de marzo de 2021

a few cli tools

 New job, new tooling, and reinventing the same trick again and again :)


This time, a few things on console stuff:

  • https://github.com/okbob/pspg
  • https://github.com/rcoh/angle-grinder
  • https://github.com/jpmens/jo


domingo, 21 de febrero de 2021

2 emacs lisp curiosities

So some guy wrote a story about emacs being used in some air traffic control system, because elisp. :) And another user (unrelated) showed off this amazing cl-loop in emacs. 

 2 elispy things that got me smiling this weekend :)


"When all you have is a Lisp ...

...everything looks like a recursive merge of trees"


It's been a little more than a month at Metabase, and doing Clojure is giving me again those deep recursive thoughts of seeing every problem as a recursive merge of trees.


I've looked at this python deep merge of dictionaries I used for some project at my previous $JOB.

And there are DSLs everywhere (sometimes, more than I think are needed).

And there's Specter, and Meander (https://www.reddit.com/r/Clojure/comments/loz77v/just_came_across_specter_mind_blown/ ) that use the code-is-data approach.

And just getting familiar with edn, that even it is very simple and minimal. It is malleable enough to be processed. 

I'm also working on a clojure version of gojira, that of course uses some tree merging.

sábado, 30 de enero de 2021

Shell Oneliner Compression

I'm back to Lisp. Now, Clojure. For real. But this post is about zsh

Part of my relearning of clojure is to read and watch everything clojure that crosses my path. And I discovered https://github.com/clojure-cookbook/clojure-cookbook , which seems super useful.  But I have too many open tabs and books already. So I thought I'd do a 'Tip Of The Day' like thing, and I'd pop a different page every day.

 Relevant files have .asciidoc  extension. And the ones with content start with a number. The other ones are index pages or headers/footers.

Here's a version of what I typed. and it worked (at the second try!)


random-clojure() {
   e $(ls ~/clojure-cookbook/**/*asciidoc(.) | awk -F/ '$NF ~ /^[0-9]/' | shuf -n1 | xargs realpath)
}

Quite a lot of things going on there, so I'm gonna explain the oneliner, because there's a lot of compression there.


  • e. e is my shellscript that opens files in emacs, moving to the line, and massaging input. in this case, it's the same as emacs, vi, $EDITOR.
  • ~/clojure-cookbook/**/*asciidoc(.). This one expands recursively files that contain 'asciidoc'. excluding directories. '**/' means 'recursively' in zsh, and the '(.)' globbing is for files only.
  • awk. '-F/' makes slash a field separator. Then, we pick the latest field, and we regex match it with '/^[0-9]/', beginning with a number. Cool!
  • shuf -n1 picks a line at random
  • xargs realpath. As we'll be running this function from all kinds of directories, expand the file path to an absolute path. as realpath asks for a parameter, we either nest the whole thing or use the xargs trick.

 

While writing this, I noticed that the whole thing is much simpler than that:

 e $(ls ~/clojure-cookbook/**/[0-9]*asciidoc(.)|shuf -n1| xargs realpath)

Master-ing git