Ir al contenido principal

Entradas

Unique bucket names in Google Cloud Storage

One interesting thing about Google Cloud Storage buckets, that maybe not all people is aware of, is that their name is unique at Google Cloud Storage level (and not at project level, as most of us would assume). That means that a bucket name must be unique at global level, and that is a problem as some of the names we choose may already exist. The way Google Cloud recommends is creating the names of the buckets as subdomains of an owned domain. Google ensures that it will verify the domain property before creating the bucket. In that way nobody will be able to create buckets using our domain and, therefore, our buckets will become unique at Google Cloud level. For multisite projects, it is also a good idea to add the bucket location to the name, so equivalent buckets could coexist in different locations. Examples of that exposed would be: mybucket.mydomain.net for a global "mybucket" bucket associated to our domain "mydomain.net" mybucke...

Go: Calculating the MD5 hash of a struct

In some scenarios, calculating the hash of a piece of data is useful, for instance when you only need to know that something in the dataset has changed, no matter what. Calculating a hash is moderately computing consuming but has some advantadges: Avoids checking the changes field by field of the dataset Allows storing only the data hash instead of the whole dataset In Golang, calculating MD5 hashes of structs can be achieved by using a code piece as this: import ( "bytes" "crypto/md5" "encoding/gob" "encoding/hex" "fmt" ) // Random struct, just for demo purposes type MySubStruct struct { Zaz *bool } type MyStruct struct { Foo int Bar []string Baz MySubStruct } func main() { // Hasheable struct myBool := false myStruct := MyStruct{ Foo: 67372388, Bar: []string{"b", "ar", ""}, Baz: MySubStruct{ Zaz: &myBool, }, } // Crea...

Concurrency in Go: Wait groups

This is the second article of a series analyzing Go concurrency, ie, parallel execution of different threads using Go. The series is composed of these articles: The Go concurrency foundation: goroutines . This one, in which synchronization between subprocesses, specifically by using Go waitgroups , is analyzed. Data exchange between subprocesses: Go channels Why synchronization between subprocesses The first article of the series exposed an example that clearly demonstrated why the subprocess synchronization is needed specifically in go: package main import ( "fmt" "time" ) // mySubprocess sleeps for a second func mySubprocess() { fmt.Println("Entering to mySubprocess") time.Sleep(1 * time.Second) fmt.Println("Exiting from mySubprocess") } // main program process func main() { fmt.Println("Calling mySubprocess from main()...") go mySubprocess() fmt.Println("mySubprocess finished!...

Concurrency in Go: Goroutines

This is the first article of a series analyzing Go concurrency, ie, parallel execution of different threads using Go. The series is composed of these articles: This one in which the Go concurrency foundation, the goroutines , are analyzed. Synchronization between subprocesses: Go waitgroups Data exchange between subprocesses: Go channels Goroutines In brief, a goroutine is a standard Go function that is processed in parallel (concurrently) to the main Go process. Let's see an example. The execution of the next code is quite predictible: The main Go process (that code in the main() function) will execute, then it will pause while the function mySubprocess() is running and then it will finish. Just one process, no concurrent execution. package main import ( "fmt" "time" ) // mySubprocess sleeps for a second func mySubprocess() { fmt.Println("Entering to mySubprocess") time.Sleep(1 * time.Second) fmt.Pr...

Install mongosh in Linux Debian

mongosh , the MongoDB Shell, is a JavaScript and Node.js REPL environment for interacting with MongoDB deployments in Atlas, locally, or on another remote host. It is a really productive tool that, by the time of writing this article, is not yet included in the Debian distributions. Does that mean that it cannot be installed on Debian? The response is yes, it can be installed on Debian , since MongoDB publishes the .deb packages for different Debian distribution on its own repository. The steps are described below. 1. Check the Debian distribution name This section deals with the steps needed to determine the Debian distribution name ( wheezy , stretch , jessie , buster , bullseye , bookworm ,...) of the system where mongosh is being installed. In case you know it, this step can be omitted. Install the latest version of lsb-release: sudo apt-get update sudo apt-get install lsb-release Once installed, run the command: lsb-release -a 2. Import ...

Defining Google Cloud IAM conditions for Secret Manager roles

Defining conditions for the permissions granted to a Google Cloud service account helps to enforce our security policy. By defining conditions we can, for instance, specify not just that a given account can access to secrets, but also to what secrets. This is really important since, in case an attacker could take control of a compute resource associated to an account with read access to secrets, he would literally be able to read all our secrets. However, if a condition is applied to that permission, just the secrets matching the condition would be exposed. In order to define an IAM permission condition, it is necessary to access to the Google Cloud IAM administration console and editing the principal (service account) whose permissions must be conditioned. Then by clicking the "ADD CONDITION" label of the role whose permissions must be conditioned, we access to the condition definition view, that contains both the Condition Builder that allows us defining c...

Debugging Google Cloud Functions with event signature in Node

In the article Debugging Google Cloud Functions in Node we exposed a first approach of what Google Functions Framework was and how could it be used. The article was mainly focused on debugging Google Cloud Function with HTTP signature, ie, those functions intended to be triggered by an HTTP request. There are however other ways of triggering the execution of a Google Cloud Function, as for instance Cloud Storage , Firestore or, more commonly, by forwarding a Pub/Sub message . This article covers how to debug Google Cloud functions intended to be triggered by a Pub/Sub message. Google Cloud functions with cloud event signature Let's assume we have a function that must be triggered by a Pub/Sub message. To do that, we need to perform two actions: Properly configuring Google Cloud to specify that our function will be triggered by a given kind of Pub/Sub message. This part is described in the official documentation and it's out of the scope of this article...

Using Bitbucket app passwords with git on MacOS (OSX)

Learn how Bitbucket passwords are stored by git on MacOS.

Tests coverage in Typescript

Learn how to apply test coverage to your Typescripts projects.

ESlint: Ignore unused underscore variables

Some naming conventions promote the use of the underscore character (" _ ") for those variables that must be declared but are not being used. One common case is that in which a function signature contains some variables that will not be used, as for instance the Express error handlers: app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Something broke!'); }); In the above example only the arguments err and res are being used, though all four must be defined in the handler signature. Thus, following the naming convention of using underscores for those unused variables, we could recode it as: app.use(function(err, _, res, __) { console.error(err.stack); res.status(500).send('Something broke!'); }); Though it makes the function more readable, it comes with a problem if using ESlint: it will blame by declaring unused variables. error '_' is defined but never used error '__' is define...

Understanding Google Cloud Tasks Timing

Google Cloud Tasks offer a good solution for controlling workflows in our backend infastructure, increasing load peaks resilency while keeping costs controlled. Such a powerful solution requires a careful configuration to properly work, specially when dealing with task retrying policy. This feature is basically controlled by a set of properties described in the Google Cloud documentation and quickly described here: minBackoff : Elapsed time in seconds, from the initial task execution, that defines the lower limit of the incremental retry time window. The first retry will occur minBackoff seconds after the initial task execution. maxBackoff : Elapsed time in seconds, from the initial task execution, that defines the higher limit of the incremental retry time window. After reaching maxBackoff the retry time will not increment, and retries will occur every maxBackoff seconds. maxDoublings : Number of times that minBackoff will be doubled (multiplied by two) in order to ...

Linting and formatting in Typescript

Linting and formatting tools are common in the Javascript/Typescript (JS/TS) scene, and their benefits are out of discussion: linters allows applying a set of coding style rules, whereas formatters apply a set of not coding but format style rules. Used in a development team scenario, its usage allows unifying the codebase by applying a common set of coding and formatting rules, no matter who the coder was. However, if not properly configured, these tools can collide in their functions, being the most common case the linter formatting code, a task that might be performed by the formatter. This article exposes the way of proceeding in order to allow both tools living in armony. Install and configure a linter The most common linter in the JS/TS scene is ESLint since TSLint , in the moment of writing this article, has been deprecated in favour of the first one. To install ESLint run these commands: $ npm install eslint --save-dev $ npx eslint --init Once installed you c...

Node process.env always returns strings

In Node, process.env property gives you access to the user environmental variables. Opposite to what you could think, these variables are always treated as strings , no matter the nature of your environment or the way you defined them. Misunderstanding of that said above can give you unpredictible behaviours, as that shown in the next code snippet regarding the usage of a presumably boolean env variable: process.env.FALSY = false; let evaluation = process.env.FALSY ? "This is imposible" : "This is the expected result"; // Since process.env.FALSY is returned as string, // and the bool value of a non empty string is true // it is evaluated not as falsy but as truthy The problem is not just related to boolean values, but also to numeric values, as shown the next code snippet: process.env.ONE = 1; let mustBeSix = process.env.ONE + 5; // Though you could expect mustBeSix being 6 // its result is the string concatenation // of '1' and '5' ie, ...

GCloud: Changing the default project (in a nutshell)

gcloud command line tool allow us managing a list of Google Cloud projects, one of which is considered as the default project, so all the operations we perform via gcloud are performed on it. Available projects To check what projects are available via gcloud , run the command: $ gcloud projects list This command drops an output similar to this example: PROJECT_ID NAME PROJECT_NUMBER fooOrg-pr01 Project Bar 239785793387 fooOrg-pr02 Project Zaz 348328582382 ... You can check the available options in the GCloud SDK reference . Current default project As you can see, that output doesn't set what is the default project. To get it run this command: $ gcloud config get-value project The command output will show the ID of the default project. Following the above example, the output of the command could be fooOrg-pr01 to state that the default project is our Project Bar. Changing the current default project To change the default project, run this comman...

Using paths in tsconfig.json

How frustrating can be managing a big Typescript project in which all the module paths are relative to the importing file, as the next example. Every time we move a file, and therefore its relative path changes regarding its imported modules, we must sacrifice time and patience fixing a train of dots and slashes that too many times are fixed by trial and error. import {Request} from "express"; import {foo} from "../../../../types"; import {bar, baz} from "../../../../../myModules/bax"; Hopefully Typescript's tsconfig.json file allows specifying path aliases by setting the paths option. This option, together with the use of the npm package module-alias allows converting the previous mess into a piece of fine art: import {Request} from "express"; import {foo} from "@types"; import {bar, baz} from "@myModules/bax"; As said the process implies not just configuring tsconfig.json but also using the package...

Delete Redis keys matching a pattern

Though Redis allows searching entries based on a key pattern (command KEYS ), it doesn't allow bulk deleting entries based on a key pattern, what can be useful in many scenarios, as that in which you need to refresh part of your cache and don't want to entirely drop it. However, we can do it by using the redis-cli pipe mode, that allows redis-cli executing a list of commands received by the standard input. Let's see how to delete a set of entries based on a key pattern: redis-cli --raw KEYS mykeyprefix* | awk '{print "DEL "$0}' | redis-cli --pipe As can be seen, three commands are used: The first command, redis-cli --raw KEYS mykeyprefix* , executes the Redis command KEYS mykeyprefix* for getting all the keys starting by "mykeyprefix", and sends the raw result to the standard output. awk '{print "DEL "$0}' basically transforms the previous command output by prefixing every line with DEL , ...

Useful redis commands (in a nutshell)

redis-cli , the Redis command line tool, is a quick shortcut for running the most common operations that require our everyday job. Let's review them in a nutshell: To open a server session, run the console command: shell> redis-cli -h <hostname> The password can be specified in the above command by setting the -a <password> argument, but for security reasons it's better to authenticate once in the redis-cli console: redis> AUTH [username] password Again from the console, to check if one ore more keys exist: redis> EXISTS <key> [<key> ...] To search keys matching a given pattern: redis> KEYS <pattern> To get an entry value given its key: redis> GET <key> To delete an entry given its key: redis> DEL <key> To quit the redis-cli session: redis> EXIT Lastly, to access to the redis-cli command reference click here .

Linting C# in Visual Studio Code

Though very usual in programming environments as Javascript/Typescript, linting , or analyzing code for enforcing a set of coding style rules, is not usually present in the .NET based environments. Rule enforcing is really useful when working on team shared codebases in order to keep them coherent, what in last term reduces both development times and coding errors. A linting example Maybe a practical example would be helpful for explaining what  linting  is to the newcomers (feel free to go on if you aren't). Let's imagine you are a new member in a C# development team that has well established set of coding style rules. Instead (or apart) of putting them in a document, they've adopted a tool that checks these rules during the code building process. Your first code is such ambitious as this: namespace HelloWorld {      using System;      public class Program      {           p...

Update NPM to the latest version (in a nutshell)

To update npm itself to its latest version, run the command: npm install -g npm@latest If working on Linux/Mac, chances are that you need superuser rights, so prefix the above command with sudo : sudo npm install -g npm@latest Finally, to check the version before and after updating, run the command npm -v

Be Agile with Codetags

To put it simple, Agile methodology is based on quick iterations. That approach implies that:  We must be fast coders to complete each iteration in the scheduled time Soon or later we'll go back to that code we quickly wrote in the past If we only focus in the first statement ( be faster, my friend ), codebase quality tends to degrade, code entropy -or the codebase maintenance complexity- increases, bugs start to consume more and more time in every sprint and, in last term, software components must be fully re-coded, what can consume great part of the benefits we got by becoming agile. However if we have in mind that, in coming iterations, we'll have to refactor the code we are working on right now, we can document the technical debt we intentionally create with the purpose of fixing it in the future. In that way, when planning every iteration (or sprint) we can schedule a percentage of the coding effort to fix that debt we left, theref...