Logo

TODAY I LEARNED

1da8dc585e837af36ae8288940f98773

12 posts by kevin-perez

Tell apt to keep the current version of a package

If you ever need apt to keep the current version of a package, use hold:

sudo apt-mark hold <package>

This will prevent apt from upgrading the package. You can always unhold it back when you want to upgrade it.

Learned by kevin-perez on Aug 22, 2022

973983 adforcodereview v3 0211021 c02 021121

Always use retry inside rescue blocks

Ruby includes a retry keyword that would bring execution back to the start of the current method while preserving scope. But what if you do this?

def my_method
  my_var = 1
  retry
end

That would fail with an Invalid retry, which is one of the few illegal statements in Ruby.

retry is only allowed inside rescue blocks.

def my_method
  my_var = 1
  raise Exception
rescue Exception
  retry
end

Learned by kevin-perez on Aug 16, 2022

973983 adforcodereview v3 0211021 c02 021121

Always check ACLs if something is fishy!

If you ever encounter a Linux dir in which you cannot write even when you're sure you have write permissions on it, check the ACLs. You may find someone doesn't particularly like you. 😞

-> getfacl /tmp 
# file: tmp
# owner: root
# group: root
# flags: --t
user::rwx
group::rwx
other::rwx
user:my_user:--- # this means "screw u and only u"

Learned by kevin-perez on Mar 11, 2022

973983 adforcodereview v3 0211021 c02 021121

Defining classes using full name vs wrapping them inside modules

In Ruby, we can write classes inside modules. We usually do this to have classes namespaced to the module, so we don't risk two different classes having the same name. This is important since Ruby won't complain about re-defining a class, it would just open it and add new methods to it.

We could write classes using their full name, like this:

class Pokemon::Game::SpecialAttack < Pokemon::Game::Attack
  # ...
end

or, we could wrap the whole thing using modules, like this:

module Pokemon
  module Game
    class SpecialAttack < Attack # Ruby looks for SpecialAttack inside Pokemon::Game automatically!
      # ...
    end
  end
end

Both methods work the same, except the one above can only reference Attack using its whole name. On the other hand, it looks somewhat easier to read than nesting modules inside other modules. Which style do you prefer?

Learned by kevin-perez on Mar 4, 2022

973983 adforcodereview v3 0211021 c02 021121

Upgrade your SSH keys from RSA to ED25519

ssh-rsa is the most common public/private key type, but is widely considered insecure with key lengths lower than 2048 bits. If you created your SSH key using ssh-keygen with default options a while ago, chances are you're using an unsafe key. Furthermore, support for RSA host keys (keys that identify the server you're trying to connect to) is disabled by default since OpenSSH 8.8 and they may consider disabling the algorithm altogether in the future.

But don't worry! Just create a new key for yourself using the most recommended key type available today: ED25519.

ssh-keygen -t ED25519 -a 100 -C "myemail@email.com"

Just make sure you got OpenSSH 6.5 or greater on both ends. Don't forget to install your new key and remove the old one!

Learned by kevin-perez on Mar 4, 2022

973983 adforcodereview v3 0211021 c02 021121

Underscores are not allowed as part of domain names

According to rfc1035, underscores (_) are not allowed as part of domain names.

The labels must follow the rules for ARPANET host names. They must start with a letter, end with a letter or digit, and have as interior characters only letters, digits, and hyphen (-). There are also some restrictions on the length. Labels must be 63 characters or less.

This means domain names like my_domain.com or sub_domain.main-domain.com are invalid.

Special thanks to @jclopezdev for finding this out.

Learned by kevin-perez on Sep 28, 2021

973983 adforcodereview v3 0211021 c02 021121

ON DUPLICATE KEY UPDATE

When you're doing an INSERT query, you could be trying to insert a row containing a primary key that already exists in the table. Instead of doing a previous query to see if the key exists or not, you could try ON DUPLICATE KEY UPDATE.

INSERT INTO table (
  field1, 
  field2
) 
VALUES (
  "foo", 
  "bar"
) 
ON DUPLICATE KEY UPDATE 
  field1="foo", 
  field2="bar"

Learned by kevin-perez on Jul 6, 2021

973983 adforcodereview v3 0211021 c02 021121

You can forward/reverse ports on Android device using adb

I'm developing an Android app as a side project and today I learned about adb forward and adb reverse. Basically, they allow you to forward or reverse traffic to specific ports between an Android device and your development machine.

Let's say I need my app to fetch something from http://localhost:3000/some-data. When the app is running on the phone localhost refers to the phone itself, and my server is running in my dev machine. So, if I do this:

adb reverse tcp:3000 tcp:3000

Now when the app tries to access localhost:3000 it will actually reach out to my dev machine's 3000 port. Very useful if you're developing the app's backend as well (as I am).

Similarly, if I wanted to access a server inside the phone from my dev machine, I could run:

adb forward tcp:5000 tcp:5000

And now if I run curl http://localhost:5000 in my dev machine it will hit the server running on the phone. Pretty neat!

Learned by kevin-perez on Jun 30, 2021

973983 adforcodereview v3 0211021 c02 021121

Ruby 2.7 introduced numbered parameters for blocks

Since Ruby 2.7, it is possible to use numbered parameters in blocks additionally to named parameters.

This is an example of a block with named parameters:

my_array.each { |element| element.do_something }

And this is the same line with numbered parameters:

my_array.each { _1.do_something }

This works with multiple parameters too:

# named parameters
my_hash.each_pair { |key, value| puts "#{key}: #{value}" }

# numered parameters
my_hash.each_pair { puts "#{_1}: #{_2}" }

Learned by kevin-perez on Mar 30, 2021

973983 adforcodereview v3 0211021 c02 021121

If you're having issues installing gems...

...try running rm -rf vendor/cache inside your app's root directory. Looks like sometimes cache can cause compilation issues while building gem extensions so getting rid of it fixes the issue. I can't guarantee this works 100% of the time, but it's worth giving a try if it can help you avoid a headache.

Learned by kevin-perez on Mar 29, 2021

973983 adforcodereview v3 0211021 c02 021121

Testing and sharing simple SQL queries online

If you want to test and share a simple SQL query, take a look at http://sqlize.com. Keep in mind you'll need to create the tables you need in the same script and you're only allowed to create TEMPORARY tables. You can run your query and see the results below it right away. Then, you can generate a permalink and share your query with everyone!

Learned by kevin-perez on Mar 10, 2021

973983 adforcodereview v3 0211021 c02 021121

Beware of calling #count on Active Record relations!

Given code like this:

records = Record.includes(:related).all # Eager-loads to prevent N+1 queries...
records.each do |record|
  puts record.related.count # => ... but this produces N+1 queries anyway!
end

If you run this, you'll notice you get an N+1 queries problem, even though we're using #includes. This happens because of record.related.count. Remember, records.related here is not an Array but an instance of CollectionProxy and its #count method always reaches out to the database. Use #length or #size instead to solve this issue.

records = Record.includes(:related).all
records.each do |record|
  puts record.related.length # Problem solved!
end

Learned by kevin-perez on Feb 18, 2021

973983 adforcodereview v3 0211021 c02 021121