On the other day, I was reading a post on a social network
where a person who went to an interview for the position of (junior)
developer asked a question at the end of it: how one can become a senior developer. He was very impressed by the answer of the interviewer. The answer was,
Being a senior developer is about how to handle people, how to
teach them, how to guide and mentor them. You’ll have a group of juniors
under you with different mindsets. You need to know their mindset and
behave accordingly…
…blah blah blah. This answer may look good. You may be impressed by
the answer. But wait! Does that mean if you are good at people
management and can mentor them, then you’re a senior developer? I mean,
where is the point of being very good or an expert at development to
become a senior developer? Where is the point where you need to be good
at estimation, implementation planning, knowing risks in the technical
decisions, business values, etc.? Aren’t those needed to become a senior
developer, or is just people management and mentoring enough?
On the pretense of saying something that looks catchy, they’re ignoring the base.
Or are they assuming the base when giving a shining opinion to impress
people? Like, being good at development is the base to become a senior
developer, isn’t it?
I remember watching an interview where the interviewer mentioned that
focus was the reason for Bill Gate’s success. Then someone suggested
that curiosity was the reason why he was successful. These are
absolutely correct reasons to be successful. But, does that means if I
sharpen my focus on something for half an hour every day, that I’ll
become successful? No. One must need to work hard as the base. Focusing
on one thing is very important, but hard work is essential. Why are
people not talking about hard work nowadays? Is it because talking about
hard work is boring? I don’t know.
Go or Golang is a static, inferred,
structural programming language created by Robert Griesemer, Rob Pike,
and Ken Thompson initially at Google. It has built-in support for
concurrency, testing, and has rich standard library.
Go is extremely easy to dive into. There are a minimal number of
fundamental language concepts and the syntax is clean and designed to be
clear and unambiguous. - Dave Astels.
As I’m using GNU/Linux system, I need to follow these steps. The
steps for the GNU/Linux are written so clearly that I follow these steps
even I want to install something else from given .tar.gz file.
# unzip the .tar.gz file at /usr/localtar-C /usr/local -xzf go1.24.1.linux-amd64.tar.gz
# Add the bin path to access go commandexport PATH=$PATH:/usr/local/go/bin
# Test
go version
Let’s write the hello, world program. Create a file with name hello.go and write the following code.
Run the following command in the terminal to run this program.
go run hello.go
hello, world
Explanation of the hello, world Program
You can package your code by any name you want to arrange your code logically. But, package main is the special package that should contain main() function. We’ll talk about package stuff in future if it looks confusing to you. For now, just add package main at the top of the file. We we write something else as name of the package than main, you’ll know the meaning of it.
import is used to import the library or package. Here, we are importing fmt standard library to access the Println() function.
Execution of the program starts from main() function. func keyword is used to define function.
Println() function is used to print text in the terminal. Println() is part of fmt. Remember that P is capital in Println() function.
Variables
There are multiple ways to define variables and assign values to
them. As Go is static programming language, type is bound to the
variable than the value. What value a variable can accept is depends on
type it bound to.
To define a variable following syntax is used. var keyword, followed by name of the variable, and finally the type of the variable.
varxint
As the type of x is int, it can only accept valid integer values. Assigning floating number of string results in error.
Boring = or assignment operator is used to assign value to the variable.
varxint=42
If you are assigning the value to the variable at the time of
defining it, you can drop the type from the syntax as Go will inter the
type based on initial value.
varx=42
Even further, replace boring= with interesting:= operator and you don’t have to write var keyword.
x:=42
And now you know couple of ways to define variable in Go. Use the
syntax that make more sense to you in terms of program context and
usage.
Go is rich in types. Following are some the basic data types Go has supports for.
boolstringintint8int16int32int64uintuint8uint16uint32uint64uintptrbyte// alias for uint8rune// alias for int32// represents a Unicode code pointfloat32float64complex64complex128nil
You don’t have to remember all these types! You’ll get to know and use these types as you get more experience with Go.
Here is an example program that demonstrate the usage of some of the types from above list.
In Go, variables can be reassigned and are mutable by default. Unlike current tend, Go doesn’t enforce immutability by default.
age:=32age=42fmt.Println(age)
Output is:
42
In Go, if you declare a variable but don’t use it, the compiler will
give an error. To ignore values and fix the compiler error, use the
blank identifier _:
_=12result:=12+10_=result// If you're not going to use result
String Interpolation and Concatenation
Go uses the fmt package for string formatting and the + operator for concatenation. Go use Printf() function with format specifier to do the string interpolation.
packagemainimport"fmt"funcmain(){name:="Bruce"age:=32fmt.Printf("I am %s and %d years old\n",name,age)fmt.Println("But my real name is "+"Batman ЁЯжЗ")}
Output is:
I am Bruce and 32 years old
But my real name is Batman ЁЯжЗ
Finally, following are the list of popular projects created in Golang.
viewpoint may be largely unrelated to its usefulness. Many if not most of the software we use is probably obsolete according to the latest design criteria. Most users could probably care less if the internals of the operating system they use is obsolete. They are rightly more interested in its performance and capabilities at the user level. - Ken Thompson, The Tanenbaum-Torvalds Debate
At the moment when you start using cutting-edge technology, it quickly
becomes outdated. At the same time, someone is fixing a bug, making your
cutting-edge technology one patch version old. Someone else might be
adding a new feature, making your cutting-edge technology one minor
version old. Or, someone could have a grand plan to improve it, making
your cutting-edge technology one major version old, or even deprecated!
In other words, as soon as you use a particular technology, it is
already old. What I’m saying is, you’re always using old technology.
The first two lines define the tuples tuple1 and tuple2, each containing values of different types. Even further, tuple2 contains a tuple!
Finally, as we know, we cannot use the IO.puts function to print the composite data type values. Instead, we have used the same IO.inspect function to inspect and print the values of tuple1 and tuple2.
---
From a user’s (or developer’s) perspective, both lists and tuples
store the same types of values (though not internally in the same way).
However, if you want to save a small number of values, such as two,
three, or five, use tuples. For all other scenarios, use lists.
Now, you know a few primitive data types such as Integer,
Floating-point numbers, Boolean, and String. Let’s move on and talk
about a few composite data types, starting with Lists.
Lists are defined using [] and can hold any type of value.
Go ahead and create a file named list.ex. Open this file in your favorite text editor and write the following code in it:
The first two lines define the lists list1 and list2, each containing values of different types. Even further, list2 contains a list!
Here, we also define true and 5.0. These are examples of the Boolean and Floating-point data types in Elixir.
Finally, we cannot directly print the List data type values using the IO.puts function. That’s why we use a specialized function IO.inspect to inspect and print the values of list1 and list2.
Elixir is a dynamic programming language. Assign the value to a variable, and you’re good to go.
Go ahead and create a new file named var.ex and write the following code in it:
name = "Bruce"
age = 26IO.puts("Hi " <> name <> ".")
IO.puts("You're " <> Integer.to_string(age) <> " years old.")
Let’s run this program, and then I’ll explain. Use the following command to run the program:
$ elixir var.ex
Hi Bruce.You're 26 years old.
Explanation
We’ve defined two variables, name and age, with initial values of Bruce and 26, respectively.
Bruce is string in Elixir and due to this, all the functions associated with type String are applicable to name variable.
26 is integer in Elixir and due to this, all the the functions associated with type Integer are applicable to age variable.
In the last two lines, we’re printing text to the terminal.
In the first printing line, we’re greeting Bruce with “Hi Bruce.”. The <> is a binary concatenation operator used to combine strings.
In the second printing line, we’re printing the age message as “You’re 26 years old.”. Since age is an integer, we need to convert the number into a string. To do this, we use the to_string function from the Integer module.
---
Finally, there are two other primitive data types that I haven’t
covered in this article which are Boolean and floating point numbers.
Boolean has true and false value and floating numbers are numbers with decimal points.
Elixir is a dynamic, functional programming language designed
for building scalable and maintainable applications. It runs on the
Erlang VM (BEAM), known for its low-latency, distributed, and
fault-tolerant capabilities.
puts is the function responsible for outputting the string.
Elixir is a functional programming language that organizes code into
modules, and functions are defined inside these modules. In this case,
IO is the module, and puts is the function that performs the printing.
JavaScript object is a powerful data structure that contains both data and methods. Consider the following example.
constperson={firstName:"Kiran",lastName:"Chauhan",greet:function (){console.log("Hello from Kiran Chauhan");},};
Here, person object contains firstName and lastName as data and greet() as method.
We use dot notation(.) or array notation([]) to access the data or call methods.
// Dot notationperson.firstName;// 'Kiran'person.lastName;// 'Chauhan'person.greet();// Hello from Kiran Chauhan// Array notationperson["firstName"];// 'Kiran'person["lastName"];// 'Chauhan'person["greet"]();// Hello from Kiran Chauhan
Most of the time, dot notation is enough to access data or call the methods unless we have more specific scenarios to work with.
Now, pay attention to the body of the greet() method.
constperson={firstName:"Kiran",lastName:"Chauhan",greet:function (){console.log("Hello from Kiran Chauhan");},};
Console message contains “Kiran” and “Chauhan” as hard-coded values. We can easily replace these hard-coded values with firstName and lastName. But, firstName and lastName are not variables. Instead, they are the properties of the person object. So that, we can’t directly access them like variables. Even if we try to do so, JavaScript will throw errors.
To use the properties of the object within object, we need to use this keyword. this means this object or object at the hand or self or etc. In other words, if we want to use properties of the object within object, then we need to write this.firstName instead of firstName and this.lastName instead of lastName.
constperson={firstName:"Kiran",lastName:"Chauhan",greet:function (){console.log(`Hello from ${this.firstName}${this.lastName}`);},};
The output remains the same. But, we removed the hard-coded values and replaced by the appropriate properties.
person.firstName;// 'Kiran'person.lastName;// 'Chauhan'person.greet();// Hello from Kiran Chauhan
In conclusion, this in greet() method refers to the current object or the object on the method is called upon(person). In simple words, whatever is on the left-side of the dot operator, this refers to it. In case of greet() method call, it is person object. So, this refers to the person.
In this example, we do not have dot at all. Then the question is what this refers to in the magicSum() function? The answer is the global window object. When you define a normal function outside of anything, the function is attached to the window object and because of that you can call this function as magicSum() or window.magicSum(). Both calls are identical.
magicSum();// NaNwindow.magicSum();// NaN
As a side note, when you define variables with var keyword, they are also attached to the global window object whereas let and const don’t.
Continuing with the magicSum() function, this refers to the global window object. But, in the window object, we don’t have a and b. Due to this, we get NaN as a result. But, if we define variables a and b using the var keyword, then this.a and this.b resolve from the window object and we will get the current result as a sum than NaN.
vara=40;varb=2;
Re-define this magicSum() function after these variables.
Now, calling this function as magicSum() or this.magicSum() returns the correct result 42. this refers to the window object and resolve the values of this.a to 40 and this.b to 2 resulting 42 in magicSum() as sum.
The conclusion is, the value of this can be different based on how the function or method is called. If the function is called directly, this refers to the window object. But, if the method is called on the object, this refers to that object.
Things are not done here. We are halfway through. Based on the context, this can have three different sets of values and we can also set the value of this based on our requirements. So, this can have four different types of value based on context.
Do you know what a constructor function is? Consider the following example.
functionPoint(){this.x=2;this.y=4;}
Note: Don’t worry about this in this example. We are going to cover it soon. That’s the main topic of this ongoing explanation.
This is the constructor function. Ok, this can be a constructor
function. Ok, ok, this is not a constructor function. Actually, there is
no unique syntax to define the constructor function. Instead, how the
function is called, makes it a constructor function. When you use the new keyword to construct the copy of it, then it becomes the constructor function. When you make a copy of it using the new
keyword, it will create an object. But, by convention, developers make
the first letter capital to differentiate it from the normal function.
Going back to the example,
functionPoint(){this.x=2;this.y=4;}
We can create as many copies or the objects of this function we want using the new keyword.
Now, these p1, p2, and p3 refer to the different objects with different values.
p1;// Point {x: 2, y: 2}p2;// Point {x: 3, y: 4}p3;// Point {x: 7, y: 3}
With this explanation, you know what the constructor function is,
right? A function is usually defined with first-letter capital and you
call it using the new keyword that creates a new object. But, what does it has to do with this? The answer is this plays an important role when you have the methods in it.
One more time, let’s define the same Point constructor function but with an add method.
You can access the values x and y and the method add().
p1.x;// 2p1.y;// 2p1.add();// 4
In p1.x, the left-side of the x is p1. So, this refers to the p1 object. That’s why you get 2. In p1.y, the left-side of the y is p1. So, this refers to the p1 object. That’s why you get 2. Finally, in p1.add(), the left-side of the add() method call is p1. That’s why this.x and this.y correctly resolve to x and y values of the p1 object and that’s why you get 4.
The conclusion is, if you’re using a constructor function, then this refers to the object that you created. Now, you know that based on the context, this can have three different values.
Within an object, this refers to that object.
In global scope, this refers to a window object.
In case of the copy of the constructor function, this refers to the object that is created.
Finally, in JavaScript, we have flexibility to set the this to whatever object that we are interested in!
Consider the example, where I have the following two objects.
constperson1={firstName:"Kiran",lastName:"Chauhan",greet:function (a,b){console.log(a+b);console.log(`Hello from ${this.firstName}${this.lastName}`);},};
constperson2={firstName:"Punit",lastName:"Tewani",bye:function (a,b){console.log(a-b);console.log(`Goodbye from ${this.firstName}${this.lastName}`);},};
Notice, person1 has greet() method whereas person2 has bye() method. We can easily call these methods from respected objects.
person1.greet(2,2);// 4 Hello from Kiran Chauhanperson2.bye(2,2);// 0 Goodbye from Punit Tewani
But, what I want to do is, I want to call the bye() method on person1 and greet() method on person2 as Kiran wants to say Goodbye and Punit wants to say Hello.
You can do it using call() or apply() methods. Both methods are almost the same except how they accept the arguments is different in terms of syntax.
The first argument to the call() method is this
that you want to make as an object and remaining arguments are the
arguments that the method that you’re calling needs separated by commas
which are a and b.
call()
method is called. In other words, you need to chain this method on the
method that you’re interested in calling. In our case, the method is, greet(). So, we need to write,
person1.greet.call();// This is partial code. Won't run.
Yup, we don’t have to write () after greet as it is call()’s responsibility to call this greet() method.
As mentioned previously, The first argument to call() method is the object that you want to make this which is in our case, person2 as Punit wants to say Hello even though he doesn’t have greet() method.
person1.greet.call(person2,2,2);// 4 Hello from Punit Tewani
this.firstName and this.lastName within the greet method are resolved against the values from person2 object using the call method.
If you use, apply()
method instead of a call, you’ll get the same result. But, instead of
passing arguments as comma separated values, we need to pass within a
single array.
person1.greet.apply(person2,[2,2]);// 0 Hello from Punit Tewani
The difference between call() and apply() is how you pass the argument to the method greet(). In case, if you have a method that doesn’t accept any argument. Then both call() and apply() methods serve the same purpose.
Because of the call() and apply() methods, Kiran can say Goodbye even though he doesn’t have bye() method.
// You can read the following as _call person2's bye method on person1_.person2.bye.call(person1,2,2);// 0 Goodbye from Kiran Chauhan// You can read the following as _apply person1 object in person2's bye method_.person2.bye.apply(person1,[2,2]);// 0 Goodbye from Kiran Chauhan
Let’s define the following callTwice() function.
functioncallTwice(cb){cb();cb();}
This function accepts the callback and calls the callback twice. If we do,
Note: For a moment, I’m not worried about passing values of a and b.
callTwice(person1.greet);// NaN Hello from undefined undefined x2callTwice(person2.bye);// NaN Goodbye from undefined undefined x2
Even though person1 and person2 are clearly mentioned for greet and bye method, this.firstName and this.lastName are not correctly resolved. Things are tricky in callbacks. To resolve this, we need to use the .bind() method. This .bind() method correctly binds the scope of this and returns a new method. This method accepts an object that you want to makethis. In the case of person1.greet we need to call the bind method and pass person1 as an object to correctly bind the person1 object. Same is true for person2.
As the adjustment for the credentials are done in the
previous article, we are now ready to create the CRUD end-points for the
Contact resource. But, before that, I would like to cover a few methods
that are needed in CRUD end-points such as fetching value(s) from
dynamic params, reading request body, fetching value(s) from query
string, and so on.
Let’s start with the dynamic params for this end-point: /contacts/:id. To fetch the id, we need to use c.req.param() method. This method returns a param object that we can de-structure to get id.
const { id } = c.req.param();
// ORconst id = c.req.param('id');
Next, to read the request body, c.req.json()
method is used. Again, this method returns a request body object that
we can de-structure to get the given field. In the case of contacts
end-point, it might be firstName and lastName.
c.req.json() method is useful when you’re reading a request body with type application/json. But, if the request is in plaintext as text/plain type, then need to use c.req.text() or if request body type is blob, then need to use c.req.blob(). There are a couple of methods available within the c.req object based on the type of data you get in the request body. Refer the HonoRequest documentation for the more details.
Finally, to read the data from the querystring, c.req.query() method is used. This method returns a querystring object that we can de-structure to get the given querystring.
Although, there are many possible ways you can use styles in
React application, following are the general categories to choose from.
Default: React supports the default styling via class. Actually, via className.
Or you can write the inline styles. But, you need to define it as an
object and kebab-case converted to camelCase for the CSS properties
whereas values must be defined as string. Event further you can use
framework classes such as from Bootstrap or Tailwind. Some frameworks have React component wrapper around it such as react-bootstrap. But, still internally they use className.
// React component with class/className // (true for Bootstrap or Tailwind).constComponent=()=>{return (<h1className="title">Header</h1>)};
// React component with inline styles.constComponent=()=>{return (<h1style={{fontSize:"14px",paddingTop:"14px"}}> Header
</h1>)}
// React component with inline styles as style object.constheaderStyles={fontSize:"14px",paddingTop:"14px",};constComponent=()=>{return (<h1style={headerStyles}>Header</h1>)}
CSS Modules: This is not the default one that you
can write within normal HTML/CSS. But, React provide the supports for
it when you create an application using create-react-app. If you have a
component in Component.jsx then you can define a styles for it in
Component.module.css (here .module.css is important) and then you can
import whole styles as JavaScript object and use the classes defined
within this Component.module.css. This make sure that styles don’t have
the side-effect on other components and correctly scoped.
CSS-in-JS: People like the idea of inline style
in React as you can define it as an object and you have autocomplete and
suggestion for it. So, developers extend it further and make some good
changes on top of it by making a style as component. Examples are styled-components, Emotion, etc.
This article assumes that you already know Elixir programming language. Further, following are the software you have on your computer.
Elixir 1.14 or later
Erlang 24 or later.
PostgreSQL
If you do not have Elixir and do not know Elixir programming language, please refer the official website to install the Elixir language on your computer and go through this very well written Getting Started
docs on Elixir language. This Getting Started covers Elixir in detail
and that is what you need before jumping into this series on Phoenix framework. I will explain some Elixir concepts but those will be brief and specific within the context of framework only.
If you do not have Phoenix framework on you computer, please follow this excellent Installation
guide. Please install all the suggested software written on this
Installation guide. Please also confirm the version of these software as
stated above.
-–
Open terminal and run the following command.
mix phx.new hello
This command will scaffold the application with default files and
folders. Then it will ask you to install dependencies or not. Press Y or y and wait for the dependencies to be installed.
Once the dependencies are installed, you will get further
instructions on what to do next. For example, the first thing to do is
to cd into the created hello application/folder.
Next, open the application or hello folder into your favorite text-editor. For example, I am using Visual Studio Code.
code .
Then as suggested in further instructions, open config/dev.exs file. In this file, we are going to adjust the database connection config. Following is a part of the code copied from the config/dev.exs file that we need to adjust for the same.
# Configure your databaseconfig:hello,Hello.Repo,username:"postgres",password:"postgres",hostname:"localhost",database:"hello_dev",stacktrace:true,show_sensitive_data_on_connection_error:true,pool_size:10
As the database is now configured, we can follow the command to create the database and associated tables in it.
mix ecto.create
The stage is set up. Run the application using the following command.
mix phx.server
The application is up and running at http://localhost:4000.
Open this URL in the web browser and you should see a landing page with
text “Peace of mind from prototype to production.” I like this phrase!
Congratulations! You have just created an application in the Phoenix framework.
Before we go further and learn more about the Hono framework,
the one thing that is bothering me is database credentials written in
code. We should adjust the existing code by removing the credentials
from the code and put it within the .env file. We should never hard-code the secret(s) as per 12factor app.
Go ahead and create a .env file in the root of the project.
touch .env
Let’s define the following environment variables within this created .env file.
We should not commit this file in the Git. The file should be added within .gitignore file. But, to give and idea about the existence of the .env file, we should have the .env.example file in the repo with same content as we have in .env file but with dummy environment variables or env vars.
cp .env .env.example
Hono has an adapter to read the env vars from the .env file. But, unfortunately it is not working for the Node and outside of c or context. For now, we are going to use the dotenv package. Let’s first install the dotenv package.
npm i -E dotenv
Import dotenv/config in app.js and we are good to go.
With these changes, we have removed the hard-coded secrets from our
code. These changes should not effect the output. Run the application
to confirm the same!
npm run devListening on http://localhost:3000
Visit the http://localhost:3000 in the web browser and you should see the following output in terminal while displaying Hello! in the browser.
Result(1) [ { '?column?': 2 } ]
Note
The code is available at GitHub. Checkout chapter03 branch for the code of this chapter.
In this article, we are going to connect the database in Hono
application. For the purpose of demonstration, we are going to use
PostgreSQL database and postgres
as npm package. You are free to use any other package and database as
steps will be similar except you need to consult the respected
documentation for initial setup.
Let’s install a postgres package.
npm i -E postgres
As per postgres package documentation, we first need to import the postgres function. This function accepts the connection options, and we can save the connection within sql variable as follows.
You need to adjust the connection options to the postgres() function based on your PostgreSQL setup. Once done, you now have the active connection within sql variable.
Let’s execute the simple SELECT 1 + 1
query within root route and print the result of it. The query returns
the promise, and due to this we need to update the signature of the
callback function to async/await.
That’s it! Run the application using the following command.
npm run dev
Visit http://localhost:3000 in the browser and check the terminal. You should see the following console message.
Result(1) [ { '?column?': 2 } ]
We got the result 2 as 1+1 and when you don’t define the column name in SELECT clause in PostgreSQL, PostgreSQL by default gives ?column? as column name.
With these changes, our Hono application is connected with database.
You might say that this is boring and nothing specific to Hono. That is
right! As Hono doesn’t re-invent wheel in every aspect of the web
development and database connection is one such a case!
Note: The code is available at GitHub. Checkout chapter02 branch for the code of this chapter.