Quantcast
Channel: Andela
Viewing all 615 articles
Browse latest View live

How to Build a CRUD App in Vanilla PHP

$
0
0

Introduction

During a recent technical assessment, I was tasked to develop a simple CRUD events management system in PHP. I planned on using Laravel as I have always done, after all, it is really easy. However, I run into a few problems and was unable to proceed beyond creating a new Laravel project. My only other option was to do the app in vanilla PHP, however, given that I had been using Laravel for a long time, I had totally forgotten how to accomplish this simple task. For anyone else out there like me, here is a simple step by step way of developing a simple CRUD application without any frameworks.

What do I hope to achieve?

  • Follow the principle of separation of concerns as much as possible
  • Create a script to handle the database connection, another script for running all database migrations.
  • Have a class to handle all database transactions. For this case, we will limit this to inserting, viewing, updating and deleting items from the database.
  • Create a dynamic web app that will allow users to perform the CRUD operations

    Prerequisites

    • Basic knowledge of PHP, HTML, and CSS
    • A local PHP and MySQL develop environment eg  MAMP, vagrant.

    I will begin by taking you through what the file structure will look like. If you would like to look at the full project you can find it here

    File structure

    I will first show you what the file structure looks like:

    Events

    1. app
      • Models
      • event.php
      • Templates
      •  app.php
      •  create.php
      •  delete.php
      •  edit.php
      •  update.php
      •  index.php
      • View.php
    2.  database
      • migrations.php
    3. migrations (Folder containing the migration files)
    4. scripts
      • create_migration.php
      • migrate.php
    5. config.php
    6. Migrations_list.php

Connect to database

First, we need to create a connection to the database so we can be able to save the data. I will be using a MySQL database which I will call events.

We will do all the configurations in the config.php file.

PHP has an inbuilt class, PDO, for handling database connections.

<?php
class PDOConfig extends PDO {
 
   private $engine;
   private $host;
   private $database;
   private $user;
   private $pass;
   private $port;
   private $db;

 
   public function __construct(){
       $this->engine = 'mysql';
       $this->host = '127.0.0.1';
       $this->database = 'events';
       $this->user = 'root';
       $this->pass = 'root';
       $this->port = '8889';
       $dsn = $this->engine.':dbname='.$this->database.';host='.$this->host.';port='.$this->port;
       parent::__construct( $dsn, $this->user, $this->pass );  
   }
}
?>

It is, however, not advisable to pass in the database parameters as I did above, they should always be passed in as environment variables.

Database transactions

We will then define a class that will handle all the database transactions which means we only need to call the config.php in this one file, instead of every time

we need to interact with the database. I have defined INSERT, UPDATE, SELECT, and DELETE statements here. Notice that I make use of prepared statements to provide a level of security against SQL injection.

<?php
   require_once('../../config.php');

   class DatabaseTranscations extends PDOStatement {
       private $connection;

       public function __construct()
       {
       }

       private function connection() {
           $connection = new PDOConfig();
           if($connection === false){
               echo "ERROR: Could not connect. " . mysqli_connect_error();
           }
           return $connection;
       }

       public function insert($event_name, $description) {
           $sql = "INSERT INTO events(event_name, description) VALUES (?, ?)";
       try {
           $connection = $this->connection();
           $statement = $connection->prepare($sql);

           $statement->bindParam(1, $event_name, PDO::PARAM_STR);
           $statement->bindParam(2, $description, PDO::PARAM_STR);

           $statement->execute();
           $connection = null;
           return true;
       } catch (PDOException $e) {
           echo $e->getMessage();
           return false;
       }
       }

       public function select($id = null) {
           if (isset($id)) {
               $sql = "SELECT * FROM events WHERE id = :id";
           try {
               $connection = $this->connection();
               $statement = $connection->prepare($sql);
               $statement->bindValue(':id', $id);
               $statement->execute();
               $result = $statement->fetch(PDO::FETCH_ASSOC);
               $connection = null;
               return $result;
           } catch (PDOException $e) {
               echo $e->getMessage();
               return false;
           }
           } else {
               $sql =  "SELECT * FROM events";
               try {
                   $connection = $this->connection();
                   $statement = $connection->query($sql);
                   $result = $statement->fetchAll();
                   $connection = null;
                   return $result;
               } catch (PDOException $e) {
                   echo $e->getMessage();
                   return false;
               }
           }
       }

       public function update($event_name, $description, $id) {
           $sql = "UPDATE events set event_name = ?, description = ? WHERE id = ?";
           try {
               $connection = $this->connection();
               $statement = $connection->prepare($sql);
               $statement->bindParam(1, $event_name, PDO::PARAM_STR);
               $statement->bindParam(2, $description, PDO::PARAM_STR);
               $statement->bindParam(3, $id, PDO::PARAM_INT);
               $statement->execute();
               $connection = null;
               return true;
           } catch (PDOException $e) {
               echo $e->getMessage();
               return false;
       }
       }

       public function delete($id) {
           $sql = "DELETE FROM events WHERE id = ?";
           try {
               $connection = $this->connection();
               $statement = $connection->prepare($sql);
               $statement->bindParam(1, $id, PDO::PARAM_INT);
               $statement->execute();
               $connection = null;
               return true;
           } catch (PDOException $e) {
               echo $e->getMessage();
               return false;
           }
       }
   }

Create tables

I created a script, create_migration.php to generate the migration files. When this script is run with the table name, it generates the migration file for creating that table.

<?php

$opt = 't:';
$options = getopt($opt);
if (!$options) {
   echo "Migrations not created please provide a table name";
} else {
   $table_name = $options ? $options['t'] : "";

   $time = time();
   $date = date('Y_m_d');
   $time_stamp = $date . "_" . $time;
   $file_name = $time_stamp . "_create_" . $table_name . "_table.php";
   $table = ucwords($table_name);
   $migrate_table = "Create".$table."Table";
  
   $data =
       "
           <?php
           require_once(__DIR__.'/../config.php');\n
           class " . $migrate_table . " {\n
               private function connection() {\n
                   \$connection = new PDOConfig();\n
                   if (\$connection === false) {\n
                       echo 'ERROR: Could not connect. mysqli_connect_error()';\n
                   }\n
                   return \$connection;\n
               }
  
               public function createTable() {\n
                   \$table_name = ". "  '$table_name'  " .";
                   \$sql = 'CREATE TABLE `$table_name` (\n
                   id INT AUTO_INCREMENT PRIMARY KEY,\n
                   created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)';\n
                       try {\n
                           \$connection = \$this->connection();\n
                           \$statement = \$connection->prepare(\$sql);\n
                           \$statement->execute();\n
                           \$connection = null;\n
                           return true;
                       } catch (PDOException \$e) {\n
                           echo \$e->getMessage();\n
                           return false;
                       } 
                   }
  
               public function dropTable() {\n
                   \$table_name = ". "  '$table_name'  " .";
                   \$sql = 'DROP TABLE IF EXISTS `$table_name`';\n
                   try {\n
                       \$connection = \$this->connection();\n
                       \$statement = \$connection->prepare(\$sql);\n
                       \$statement->execute();\n
                       \$connection = null;\n
                       return true;
                   } catch (PDOException \$e) {\n
                       echo \$e->getMessage();\n
                       return false;
                   } 
               }
               }
           ?>
       "
   ;
   file_put_contents(__DIR__."/../migrations"."/".$file_name, $data);
}
?>

Migrations

To run my migrations, I run the script below, migrate.php.  If I want to run all migrations, I run it without any flags otherwise, I run it with the file name of the migration to run.

<?php
require __DIR__."/../database/migrations.php";
require __DIR__."../../migrations/2020_01_28_1580251805_create_venues_table.php";
require __DIR__."../../migrations/2020_01_29_1580256901_create_books_table.php";
require __DIR__."../../migrations/2020_01_28_1580250049_create_users_table.php";
require __DIR__."../../migrations/2020_01_29_1580262222_create_houses_table.php";
require __DIR__."../../migrations/2020_01_30_1580402897_create_teachers_table.php";
require __DIR__."../../migrations/2020_01_30_1580402811_create_subject_table.php";
require __DIR__."../../migrations/2020_01_30_1580418760_create_marks_table.php";

$opt = 'm:';
$options = getopt($opt);
$file_name = $options ? $options['m'] : "";
$migrations = [];
$hashed_migration = new HashMigrations();

if (!$options) {
   $migrations_files = array_diff(scandir((__DIR__."/../migrations")), ['..', '.']);
   foreach ($migrations_files as $migration_file) {
       $migration_file_path = __DIR__."../../migrations"."/".$migration_file;

       $file1 = preg_replace('/[0-9]/','',$migration_file);
       $file2 = explode("_", $file1);
       $file3 = implode(" ", $file2);
       $file4 = ucwords($file3);
       $file5 = str_replace(" ", "", $file4);
       $file6 = str_replace("php", "", $file5);
       $file7 = str_replace(".", "", $file6);
       $class_name = $file7;
       $class = new $class_name;
      
       if($hashed_migration->migrationExists($migration_file) && $hashed_migration->compareFileContents($migration_file)){
           continue;
       }
       elseif ($hashed_migration->migrationExists($migration_file) && !$hashed_migration->compareFileContents($migration_file)) {
           $created = $class->createTable();
           $hashed_migration->UpdateFileContentsHash($migration_file);
           echo "Migration ".$migration_file." has been run.";
           continue;
       }
       else{
           $created = $class->createTable();
           if ($created) {
               $hashed_migration->storeHash($migration_file_path);
               echo "Migration ".$migration_file." has been run.";
           } else {
               echo "Couldnot run migration". $migration_file ."";
           }
           continue;
       }
   }
} else {
   $migration_file = $file_name;
   $migration_file = __DIR__."../../migrations"."/".$migration_file;

   $file1 = preg_replace('/[0-9]/','',$migration_file);
   $file2 = explode("_", $file1);
   $file3 = implode(" ", $file2);
   $file4 = ucwords($file3);
   $file5 = str_replace(" ", "", $file4);
   $file6 = str_replace("php", "", $file5);
   $file7 = str_replace(".", "", $file6);
   $class_name = $file7;
   $class = new $class_name;

   if($hashed_migration->migrationExists($migration_file) && $hashed_migration->compareFileContents($migration_file)){
       return;
   }

   elseif ($hashed_migration->migrationExists($migration_file) && !$hashed_migration->compareFileContents($migration_file)) {
       $created = $class->createTable();
       $hashed_migration->UpdateFileContentsHash($migration_file);
       echo "Migration ".$migration_file." has been run.";
       return true;
   }

   else{
       $created = $class->createTable();
       if ($created) {
           $hashed_migration->storeHash($migration_file_path);
           echo "Migration ".$migration_file." has been run.";
           return true;
       } else {
           echo "Couldnot run migration". $migration_file ."";
       }
       return true;
   }
}

$hashed_migration->checkForUpdate();

A little a bit about this script, I have used the concept of the hash table to find which migrations have been run or have changed and which haven’t been run. Only the migrations that have either changed or not been run will run. To help with making this check and also running the migrations, I use the HashMigrations class in the hash_migrations.php file.

Within this class, I have methods which:

    • Create the hash for both the migrations file name and contents of the migrations file
    • Save the hashed migrations file contents in the associative array with the hashed migrations file name as the key. This array contains all the migrations that have been run.
    • Update the hashed migrations file contents
    • Check if the migrations file contents have changed so that the associative array can be updated according

Check if a migration has been run before.

<?php
require __DIR__."/migrations_list.php";
class HashMigrations {
   public $migrations_array;
   private $stored_migrations_array;

   private function getMigrationsArray() {
       $file_contents = file_get_contents(__DIR__."/../migrations_list.json");
       return json_decode($file_contents, true);
   }

   public function __construct() {
       $this->stored_migrations_array = $this->getMigrationsArray();
       $this->migrations_array = $this->getMigrationsArray();

   }

   private function updateMigrationsArray() {
       $migration_array = json_encode($this->migrations_array);
       $migrations = file_put_contents(__DIR__."/../migrations_list.json", $migration_array);
       if ($migrations) {
           return true;
       } else {
           return false;
       }
   }

   public function checkForUpdate() {
       if ($this->stored_migrations_array === $this->migrations_array) {
           return;
       } else {
           return $this->updateMigrationsArray();
       }
   }

   private function hashFileContents($file) {
       $hash = hash_file("sha1", $file);
       if (!$hash) {
           throw new \ErrorException("File does not exist");
       }
       return $hash;
   }

   private function hashFileName($name) {
       $hash = hash("sha1", $name);
       if (!$hash) {
           throw new \ErrorException("File does not exist");
       }
       return $hash;
   }

   public function storeHash($file) {
       $hash_file_name = $this->hashFileName($file);
       $hash_content = $this->hashFileContents($file);
       $this->migrations_array[$hash_file_name] = $hash_content;
   }

   public function migrationExists($hash) {
       if (isset($this->migrations_array[$hash])) {
           return true;
       } else {
           return false;
       }
   }

   public function compareFileContents ($file) {
       $hash = $this->hashFileName($file);

       if (!$this->migrationExists($hash)) {
           throw new \ErrorException("Migration does not exist");
       }
       $new_file_content_hash = $this->hashFileContents($file);
       $old_file_content_hash = $this->migrations_array[$hash];
       if ($new_file_content_hash == $old_file_content_hash) {
           return true;
       } else {
           return false;
       }
   }

   public function UpdateFileContentsHash($file) {
       $hashed_file_name = $this->hashFileName($file);
       $hash_content = $this->hashFileContents($file);
       $this->migrations_array[$hashed_file_name] = $hash_content;
       return true;
   }
}

When the migrations are run, we check if a particular migration has been run before, if yes we check if the contents of the migrations file have changed, if yes we run the migrations otherwise we skip that migration. If the migration has not been run before we run the migration, hash it and add it to the migrations_list.

Add the CRUD

Next, we will add the functionality for the CRUD. I have done this in the event.php.

<?php

require '../../database.php';

class Event {
   public $event_name;
   public $description;
   private $db;
   public function __construct() {
   }

   public function addEvent($event_name, $description) {
       $event_name = filter_var($event_name, FILTER_SANITIZE_STRING);
       $description = filter_var($description, FILTER_SANITIZE_STRING);

       $db = new DatabaseTranscations();
       $inserted = $db->insert($event_name, $description);
       if ($inserted) {
           return "Successfully inserted";
       } else {
           return "Something went wrong insertion didnot happen";
       }
   }

   public function viewEvents() {
       $db = new DatabaseTranscations();
       $result = $db->select();
       if ($result) {
           return $result;
       } else {
           return "No results returned";
       }
   }

   public function viewEvent($id) {
       $id = filter_var($id, FILTER_SANITIZE_NUMBER_INT);

       $db = new DatabaseTranscations();
       $result = $db->select($id);
       if ($result) {
           return $result;
       } else {
           return "No results returned";
       }
   }

   public function editEvent($id, $event_name, $description) {
       $event_name = filter_var($event_name, FILTER_SANITIZE_STRING);
       $description = filter_var($description, FILTER_SANITIZE_STRING);
       $id = filter_var($id, FILTER_SANITIZE_NUMBER_INT);

       $db = new DatabaseTranscations();
       $result = $db->update($event_name, $description, $id);
       if ($result) {
           return true;
       } else {
           return false;
       }
   }

   public function deleteEvent($id) {
       $id = filter_var($id, FILTER_SANITIZE_NUMBER_INT);
       $db = new DatabaseTranscations();
       $result = $db->delete($id);
       if ($result) {
           return "deleted";
       } else {
           return "Something happened event not deleted";
       }
   }
}
?>

Within this file, I have defined methods for creating, updating, viewing and deleting an event.

Templates

Landing page

This will be the index page. This page will display the events, and have a button for creating a new event.

<?php
require "../models/event.php";
?>
<body>
   <?php require "app.php"; ?>
   <div class="jumbotron">
       <?php
       $s = new Event();
       $result = $s->viewEvents();
       foreach ($result as $row) :
       ?>
           <div class="list-group">
               <a href="view.php?id=<?php echo $row['id']; ?>" class="list-group-item list-group-item-action">
                   <?php echo $row['event_name']; ?> <br />
               </a>
           </div>
       <?php endforeach; ?>
   </div>
</body>

Below is what the landing page would look like. I have made use of bootstrap in this project. Check out this link for more on bootstrap.

Each event item is clickable and when clicked, it should redirect to a page that shows the details of the event. To enable this, we pass the id of the event to the URL.

<a href="view.php?id=<?php echo $row['id']; ?>" class="list-group-item list-group-item-action">

View details of a single event

We will create a page that will display the details of a single event. When an event is clicked, it will redirect to this page.

if (isset($_GET['id'])) {
       $event = new Event();
       $result = $event->viewEvent($_GET['id']);
   }

The above line of code picks up the id which is passed in the URL and passes it along to the viewEvent method which then returns details of the selected event.

The page also has edit and delete buttons. The edit button when clicked also passes the id of the event to the URL.

<button class="card-link btn btn-primary" onclick="window.location.href = 'edit.php?id=<?php echo $result['id']; ?>'">Edit</button>

The delete button loads a popup a modal which asks the user to confirm if they would like to delete the selected event. The pop up looks like this

<?php require "../models/event.php";
require "app.php"; ?>

<body>
   <?php
   if (isset($_GET['id'])) {
       $event = new Event();
       $result = $event->viewEvent($_GET['id']);
   } else {
       echo "Something went wrong!";
       exit;
   } ?>
   <h1>Showing details for <?php echo $result['event_name']; ?> </h1>
   <div class="jumbotron text-center">
       <p>
           <strong>Event:</strong> <?php echo $result['event_name']; ?><br>

           <strong>Description:</strong> <?php echo $result['description']; ?><br>
       </p>
       <button class="btn btn-primary" onclick="window.location.href = 'edit.php?id=<?php echo $result['id']; ?>'">Edit</button>
       <!-- Button trigger modal -->
       <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalCenter">
           Delete
       </button>
   </div>
   <!-- Modal -->
   <div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
       <div class="modal-dialog modal-dialog-centered" role="document">
           <div class="modal-content">
               <div class="modal-header">
                   <h5 class="modal-title" id="exampleModalLongTitle">Delete event</h5>
                   <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                       <span aria-hidden="true">×</span>
                   </button>
               </div>
               <div class="modal-body">
                   Are you sure you want to delete the event <?php echo $result['event_name']; ?>?
               </div>
               <div class="modal-footer">
                   <button type="button" class="btn btn-secondary" data-dismiss="modal">No</button>
                   <button onclick="window.location.href = 'delete.php?id=<?php echo $result['id']; ?>'" class="btn btn-primary">Yes</button>
               </div>
           </div>
       </div>
   </div>
  
</body>

Create and Edit an event

The landing page has a link that allows a user to add an event. When clicked, the user is redirected to a page that loads a form so a user can enter details of the event to be created.

The user fills in the details in the form above when done, they hit the submit button, which submits the data.

<?php
require "../models/event.php";
session_start();
if (!isset($_SESSION['count'])) {
   $_SESSION['count'] = 0;
} else {
   $_SESSION['count']++;
}
if (isset($_POST['submit'])) {
   $event_name = $_POST['eventName'];
   $description = $_POST['description'];
   $insert = new Event();
   $insert->addEvent($event_name, $description);
   $_SESSION["flash"] = ["type" => "success", "message" => "Event successfully created"];
   header("Location:" . "index.php");
}
?>

This section of the code runs after the form is submitted. The $_POST  is a super PHP global variable that is used to collect form data.

<input name="eventName" type="text" class="form-control" id="eventName" placeholder="Enter event name">
               <input name="description" type="text" class="form-control" id="description" placeholder="Enter a description for your event">

As you can see the input elements have a name attribute, this attribute becomes the key of the associative $_POST array with the form input value becoming the value.

As you can see, once the entered values are picked from the array, they are passed to the addEvent method which then handles the data insert.

The edit works more or less the same as the create except that in the case of edit, the form is pre-populated.

Delete

When a user selects Yes from the modal that pops up when the delete button is clicked.

The id of the event is passed to the URL and delete.php is called where the id is picked from the URL and passed to the method deleteEvent which handles the delete. Upon delete, the user is redirected to the landing page where a success message is displayed.

This is achieved through the use of PHP’s super global variable $_SESSION. We add the message to be displayed to the session.

 $_SESSION["delete"] = ["type" => "danger", "message" => "Event successfully deleted"];

The above line of code is setting the message to display in the PHP $_SESSION global variable.

We then pick this message from the session variable and display on the landing page

if (isset($_SESSION["flash"])) {
       vprintf("<p class='flash %s btn btn-success'>%s</p>", $_SESSION["flash"]);
       unset($_SESSION["flash"]);
   }

   elseif (isset($_SESSION["delete"])) {
       vprintf("<p class='flash %s btn btn-danger'>%s</p>", $_SESSION["delete"]);
       unset($_SESSION["delete"]);
   }

The above code handles the display of the flash messages from the session variable.

Conclusion

And that marks the end of our very simple CRUD application in vanilla PHP without using any framework. I hope it has been helpful. If you have any comments or questions please do feel free to ask.

The post How to Build a CRUD App in Vanilla PHP appeared first on Andela.


Talks At Andela: Building Engineering Teams at Scale

$
0
0

What does “building engineering teams at scale” mean to you (as an engineer or team lead) and your organization? Is it about the infrastructure – connecting people at scale globally? Or is it the team – their interaction, culture? Or about the team’s environment — that allows them to learn, unlearn, relearn? Or maybe a healthy combination of all the above?

On Facebook’s 16th anniversary, we had the opportunity to host 240 engineers across Africa, and hangout with  Ziad Traboulsi, Director of Engineering at Facebook, as he shared and highlighted key lessons from approximately 20 years of being in the industry; having founded and sold his startup in the early 2000s, then at Facebook across various roles and teams for close to 10 years.

Here are some of the lessons he has picked up along the way in his dynamic career:

For Engineers:

A lesson of perseverance — it takes time and effort to learn and grow, and if you want something seen, start by building it yourself. Ziad mentions how, in his earlier years in coding, he wanted something very specific; he wanted to wake up every day and go to school with a specific MP3 playing – looks minor in retrospect, but you’ve got to remember that app stores, smart alarms, etc. were not prevalent back then! But this solution didn’t exist, so he decided to learn it himself; it took him ~1.5 months to write a few 100 lines of code, but remember → perseverance.

Tap into your passion — remember technology is simply a means to an end and not an end by itself. What’s at the core of what you are interested in technology? Is it in building solutions to local problems, in infrastructure, in understanding your consumer’s behavior? Ziad talks about his interest in understanding people’s behaviours, which is why studying behaviour and economics was important for him, because it made him better understand how people get to interact and draw value from tech-enabled solutions — he gives an example of a life-changing experience of man who had a heart condition, joined a Facebook Community group, which he was profoundly grateful for because of how much he had learned by being part of the group.

Have fun, but also remember to take on challenges — optimize for both! Don’t optimize to only have fun at something, take on (at least) 2 components 1) what you are good at and, 2) what you are passionate about (that’s where the challenge lies), and optimize for both.

Take ownership — nothing at Facebook is someone else’s problem, Ziad says. Be the change you want to see. A lot of power comes with a lot of responsibility too, so when you take ownership, you’ll be taking a lot of risks too, but don’t be afraid to fail!

For Engineering Organizations:

Promote “Openness and Transparency” — Do you have a culture that allows any engineer to check anyone’s code? Can any engineer review anyone’s code? It’s good to also note that a lot of power on engineers’ hands, with power comes responsibility.

Do you provide an environment that keeps questions flowing across all matters of the org? Ziad gives an example of an open Q&A at Facebook that allows questions and answers from and to anyone in the company including the CEO.

Do you have an infrastructure that promotes information flow internally amongst engineers? It could be an Intranet, or via Slack, Messenger, etc.

Create a decision-making environment that has minimal obstacles — empower engineers to make the right choices for themselves as this will also translate to the right choices for the company.

Can engineers make decisions without a lot of obstacles? For example, can they access all codebases in the organization, say, during the induction period? How smooth is the transition from one team to another if an engineer is looking for change within the organization?

Build a culture around “assuming good intent” — this ultimately brings engineering teams closer.

Empower engineers to not be afraid to fail — Ziad highlights an earlier motto that Facebook had “Move fast and break things” which has now evolved to “move fast with stable infrastructure” that adds to the confidence of engineers to not be afraid to fail and learn.

Scaling Challenges:

Ziad acknowledges that building engineering teams at scale also has its fair share of challenges; growth challenges, change challenges, product diversity challenges – he shares 2 key pieces of advice:

Re-invent as many times as you can to serve growing needs: Solutions from 10 years ago are quite different now. How you acquire talent, hire, onboard, etc has significantly changed. Strategy and tactic that got you to 100 users, will be different from what gets you to 1,000 then to 1M users; same to your employee growth, and storage, and servers and engineering team growth.

Iterate faster: Dependent on the user needs and the product, invest in infrastructure that allows for faster iteration towards an environment where code is compiled, built, tested, deployed in real-time.

In Conclusion…

Success in building engineering teams at scale is highly pegged on the company’s culture and the engineering team’s culture. So in conclusion, I will leave you with some of these questions to ponder on:

What is your company’s culture? Do you have a healthy culture? Is your culture working? Do you help advocate for it? Is it translated into concrete directives, privileges, and programs that the company supports? Has your culture helped in recruiting and retaining the right people into your company?

Notable quotes by Ziad Traboulsi:

“Code wins arguments, and metrics drive the team.”

“Connectivity cannot just be a privilege, it needs to be an opportunity for everyone to tap into.”

“Pay attention to your culture, it will be a catalyst to help achieve your goals.”


Ziad leads the Mobile & Connectivity Partner Engineering Team at Facebook, a dynamic team of Marketers, Designers, PMs, Data Analysts, Engineers. He is currently primarily working on an initiative to bring access to the Internet in the developing world, has been to >20 countries in the continent, and loves the energy, creativity, entrepreneurship and self-starter culture of technologists in Africa.

The post Talks At Andela: Building Engineering Teams at Scale appeared first on Andela.

The Brilliance of a Borderless Engineer: Remote Heroes Egypt Recap

$
0
0

The Remote Heroes event in Cairo, Egypt was held on Saturday the 22nd of February 2020 at the Greek Campus. The event was themed “The Brilliance of a Borderless Engineer”; fully inspired by the fact that, at Andela, brilliance is evenly distributed and that we are not bound by borders. Our guests started arriving at 5:00 p.m while our evening full of interesting talks kicked off at 6:00 p.m. with an introduction about Andela and a quick walk through the agenda.

The first talk of the evening was from our country Director, Rama ElSafty whose main message was to highlight what it means to be a borderless engineer, the brilliance of it highlighting the concept from an Andela EVP (Employee Value Proposition) perspective, with a special focus on the Engineering Framework deployed at Andela & how it ensures our hired engineers are benchmarked against global standards.

Engineering spotlight

Randa Fahmy, a Senior Software Engineer talked about her experience as an Andelan working remotely with her partner WEAVE. This session was very interesting to the audience because it was an honest experience that an engineer like them went through, they connected with her initial worries on how to remotely integrate with a customer from a culturally different background. Randa explained how the culture & process at Andela facilitated this integration and the support she received from the team. She also spoke about how this role has allowed her to develop her own skills, where initially she was only an Andriod developer, and how she was constantly encouraged to learn & become an IOS developer as well, till she finally nailed it. One must also mention that leveraging a video which was brilliantly directed & executed showcasing Randa’s daily lifestyle and how she manages her work-life balance through the flexibility she enjoys at Andela, had a great impact in establishing the connection with the audience.

ALC Spotlight

Sherif Olama, who leads Talent Partnerships, introduced the Andela Learning Community, highlighting how the program is designed to help engineers at different levels develop their skills and how the program opens up the market for those engineers; whereupon finishing it they could choose to apply to join Andela or any other employer of their choice.

Panel Discussion

The panel discussion was focused on exploring the different faces of Remote work. Along our Country Director, Rama El Safty we had two external Panelists: Tarek Zidan, who is the Chairman & CEO of Athear Marketing Services, and Ahmed Tolba, who is a Principal Engineering Manager at Microsoft and currently heads Bing Cairo, a remote Bing team and one of the main constituents of Microsoft’s Cairo Advanced Technology Lab.

Tarek, with his long experience, took us back to the origins, highlighting that back then “video conferencing was the crystal ball of the future” and right now there are more and more tools available to facilitate remote work.

“…the new generation is faster, smarter, more exposed to technologies we never had, you can basically google anything, nowadays data is on the cloud, we don’t have to meet face to face, as a business owner, we need remote work. For example, in order to reserve a seat for a single employee it costs at least 3K EGP per month, remote work is beneficial for everyone; it is a win-win as long as you are well connected. And It will allow us to get access to better calibers/diversity.”

Echoing what Tarek mentioned about how things worked back then & now, Ahmed also highlighted the importance of finding the right talent. “When I started my career, I didn’t have the same resources that the current generation has. Tooling isn’t an issue, finding the right person who can share knowledge & work with you is more important.”

Ahmed’s point on the higher importance of the person where he believes that the tools would just be a means to an end, resonated with Tarek’s strong opinion that it takes a highly disciplined person to work remotely. For engineers, specifically, Tarek mentioned that “The benefit of remote work is getting the experience and pay of an international engineer but with the local cost of being in Egypt and the added flexibility of being with your family.”

Q&A

The panel session was followed by a Q&A session, with the audience fielding questions to the panelists. A crucial question was raised around the concept of job stability in a remote work model. Our panelists were all aligned in their answer that in today’s evolving world, people create their own opportunities. As Tarek stated: “We need to change the definition of job stability; if you are good, you are stable.” Despite the fact that at Andela there are teams ensuring our engineers are placed, Rama highlighted that it holds true that one has to always work on developing their skills to cope with the fast pace of change.

The post The Brilliance of a Borderless Engineer: Remote Heroes Egypt Recap appeared first on Andela.

Engineering Team Forced to Work Remote? It Doesn’t Have to Slow You Down

$
0
0

The coronavirus outbreak is accelerating a trend: distributed engineering teams are becoming the norm rather than the exception. For businesses suddenly forced to contemplate 100% remote teamwork for the first time and on short notice, the idea can be daunting. This article shares three best practices to make a successful transition to all-distributed engineering:

• Communication

• Collaboration

• Culture

We’ll go into more detail in these best practices in the upcoming webinar, “Are You Ready for Remote Work? How Engineering Teams Can Thrive With or Without the Office,” March 19 at 1:00 PM EST/10:00 AM PST. Experts from Andela and GitHub VP of Engineering Sha Ma will share from their experiences managing successful all-distributed teams. 

Communication

Communication in this context is about how your team shares information. It is important to have ground rules for how the team communicates and for how communication tools are used. For example, many teams use a combination of email, instant messaging platforms like Slack, and video conferencing tools like Zoom. Guidelines about how to use them streamline expectations. For example, you can agree that different tools are used for different types of communication, like email for is only for non-urgent messages. That way all team members understand the expectations for responding.

Additional best practices apply to specific types of meetings like standups and all-hands—more on this in the webinar.

Collaboration

Collaboration has to do with how the tools and processes you use to work together. If your team is working across time zones, for example, Spacetime is an excellent calendar tool that makes it easy to view schedule overlaps and to schedule meetings without counting on your fingers to determine the time in other zones. Shared project management tools like Trello can also help teams stay on track when used properly.  It is vital to use tools in ways that are inclusive in planning and decision-making. One big challenge remote team members face is isolation. Over-inclusion should be the norm. 

GitHub is another critical collaboration tool for developer teams and Sha Ma will share best practices for using it in the webinar!

Culture

Culture is the shared values and team strength. This should be fun. You can replicate office culture- and team-building exercises online. Like having personal one-on-one’s with teammates, even sharing lunch and happy hours over Zoom. More seriously, it is important to establish a culture of transparency and accountability. This means, among other things, ensuring everyone has the resources they need to be successful, and that team members are empowered to and have the channels to speak up when they need something. There are ways to build transparency and accountability into your teamwork.

Another best practice is to recognize and reward great work just as you would in an office setting. One of Andela’s clients sent a remote engineer in Nigeria a Domino’s pizza, a 7,000 mile thank you! We’ll share more examples from Andela and GitHub in our March 19 webinar.

Hit the Ground Running

If your engineering team is forced into an all-remote mode, it doesn’t have to slow you down. Andela has trained and deployed hundreds of all-distributed groups, and GitHub is a pioneer in distributed engineering. We have found that these best practices apply to organizations of all sizes and in all types of industries. Across the board, high-performing distributed teams practice communication, collaboration, and culture that supports and empowers employees. Register for our webinar, where you can learn more about how to put these best practices to work now.

The post Engineering Team Forced to Work Remote? It Doesn’t Have to Slow You Down appeared first on Andela.

Seven Habits of Highly Effective Remote Engineering Team Leaders

$
0
0

As businesses scramble to respond to the coronavirus, many are asking their employees to work from home. For engineering teams to remain productive, team members need more than a computer and an internet connection. They need to implement tools, processes, and best practices to collaborate. 

Andela will hold a live webinar, “Are You Ready for Remote Work? How Engineering Teams Can Thrive With or Without the Office,” March 19 at 1:00 PM EST/10:00 AM PST to go in-depth about best practices for remote engineering teams. Sha Ma, VP of Engineering for distributed engineering pioneer GitHub will join Andela CTO David Blair to share best practices that will help you get through this difficult time.

In the meantime, here’s how you can build and manage a distributed team that continues to be productive and to deliver quality products. 

1. Take the time to onboard. A sudden shift from an all-office to an all-distributed one will require collaboration tools to be used differently and strategically. But first, make sure that team members have the tools that they need in the form of instant messaging and video conference accounts, an appropriate workspace, and high-quality audio equipment for communication. 

2. Set communication expectations. Collaboration tools may be used sparingly in an office and instructions for how to use them aren’t necessary. When everyone is remote, these tools become the online equivalent of things like talking across a desk or over a cube wall or jumping into a conference room for a few minutes. Establish best practices for keeping the team on the same page by using the right tool for the right task at the right time..

3. Check-in with your team members 2-3 times each day. This might sound like overkill, but it is important because silence can be difficult to interpret. You might think you are empowering your employees by leaving them alone, and they may believe that you don’t care. Always ask if they have everything they need or if they need additional support.

4. Assume positive intent. This gets easier with frequent one-on-one meetings. Like silence, written communication can also be challenging to interpret, and it is easy to assume someone is being critical or resistant to something if you’re not frequently in touch. Assume otherwise, and you will be right most of the time. If you really aren’t sure, schedule a quick video call to diffuse any tension. 

5. Give positive feedback about how team members are doing under the circumstances. Frequent praise and positive feedback about work deliverables energizes everyone and fosters a culture of high-performance.

6. Have daily standups with the team in the morning or afternoon or both. Standups can be the life-blood of engineering teams. It can easy for team members to be quiet during in-office standups when they sit next to each other and know that they can touch base later. Make sure everyone speaks.

7. Share documentation with your team and encourage collaboration–ask them to review your notes and tell you if you missed anything. It is also a good idea to make extra thorough notes on Jira or Trello cards or other project management tools as projects move through a sprint. If you’re not familiar with these tools, we will go over them in more detail in the webinar

If your team is forced to work remotely for an extended period, it doesn’t have to slow you down. In our webinar, we will share more about how to put these best practices to work–all based on the speakers’ experience helping hundreds of engineering teams thrive working with developers from around the world.

The post Seven Habits of Highly Effective Remote Engineering Team Leaders appeared first on Andela.

It’s Time To Change How You Hire Engineers

How To Scale Your Engineering Team With A Growth Framework

Making the shift: Experts share how to rapidly build and scale remote teams


Hundreds of engineering leaders signed up for a webinar on remote work. Here’s what they wanted to know.

$
0
0

More than 500 people signed up for the webinar held by Andela, “Best Practices for Remote Engineering Teams: How Teams Can Thrive Without the Office.”

The response is a sign of the times. Engineering teams around the world are now working without an office, many for the first time. They want help.

Andela CTO David Blair and GitHub VP of Engineering Sha Ma shared best practices around communication, collaboration, and culture. You can watch a recorded version of the webinar here

The questions came in immediately, highlighting the urgency of the situation. We thought you might want to know what your colleagues are most concerned about. Here is a brief summary.

Performance and Trust

The most common questions were about performance–how to hold people accountable without sowing fear. These came as Sha emphasized creating a culture of trust. Having daily stand-ups to check the team’s and individuals’ progress can help with this. David talked about using data to assess performance, measuring productivity by work completed not by the perception of hours logged.

If a manager is concerned that remote workers will really, well, work, Sha stressed communication and advised managers to allow developers to show “what they are working on and working through.”

There was also a good deal of discussion about the human side of creating trust in an office-less environment, especially in this time of uncertainty and stress. “It is important that people feel safe,” Sha said. “People can’t be productive when they are fearful for their jobs or their health.” Part of the culture of trust, she said, is sharing personal stories and practicing kindness. Her team has a weekly family photo-sharing session in its retros, and a Slack channel for pet pictures. 

David also emphasized trust, saying, “start with empathy.” If someone’s performance is suffering, look for hidden issues that might be impacting someone’s life outside of work. 

Tools and How to Use Them

There were also questions and comments about tool use, including some recommendations from the audience. Without guidelines, Slack use can be chaotic with simultaneous conversations, one attendee said. Andela’s best practice is if a topic requires multiple Slack messages, the discussion should move to a Zoom meeting. Some people mentioned using permanent Zoom links between sites so that people literally can “walk by and say hi.”

Some additional tools recommended by the presenters included Kudoboard, which David’s team uses to give each other virtual high-fives. His team also uses Slack bots to send alerts when people make pull requests from GitHub as a way to keep one another informed. Sha’s team uses a home-grown app that employees can use to add compliments to each other for work and personal strengths. An audience member recommended Status Hero for virtual stand-ups. 

Hiring and Onboarding

Another topic that drew a lot of discussion was onboarding. GitHub used to fly new employees to its San Francisco office for onboarding, which isn’t happening for the time being. Sha and David both recommended creating thorough wiki pages to empower new team members with self-service direction. Sha also recommended giving new employees “buddies”–teammates they can ping for help and not be afraid to “ask stupid questions.”

As the world adapts to a rapidly changing social and occupational landscape, the new normal may be that there is no new normal. Being able to flex with evolving restrictions on travel and in-person activities will require businesses to continually discover new ways to work together and grow. Hiring and onboarding in a remote-first environment are among the things that they will need to learn. This will be diving deeper into these topics in our next webinar. Stay tuned!

The post Hundreds of engineering leaders signed up for a webinar on remote work. Here’s what they wanted to know. appeared first on Andela.

An introduction to thinking in a functional way

$
0
0

The Porsche 911 Turbo S has a front spoiler called a pneumatically dropped front lip. It works by reclining into the front bumper when the car is moving at low speeds and automatically deploying at high speeds when more drag is required to keep the car on the ground. This is how the car achieves stability at high speeds. The benefit is that when it is out of the way, it lends itself to a clean design, and does not get in the way of the beautiful swooping lines on the front bumper. I find this brilliant from a design perspective.

I appreciate declarative programming in a similar manner, in what it affords the programmer: out of my way when not required, fully operational when it is required.

Mainstream programming languages have been adopting functional programming axioms faster than an associate developer can spell functional programming. Which is all well and good, but an astute software developer should pose and reflect on why this is the case. It is turtles all the way down to invoke map, reduce and filter after a cursory introduction to functional programming, however, the calculus of negligence would be high if the ethos of the axioms is not fully comprehended, as to appreciate them for what they bring to the table.

To understand the benefits, let’s contrast functional programming to the more commonly used Object-Oriented Programming paradigm. To grasp the differences, we have to inspect the schools of thought from which the paradigms originate. Object-oriented programming flows from the imperative school of thought, where the main method of computation is assigning values to variables and manipulating them until they achieve the desired form. Conversely, in functional programming, the main device of computation is passing values to functions.

To illustrate the concept, an example suffices:

Suppose we want to find the sum of numbers from 1 to 10. In the imperative school of thought, a programmer could start assigning values to variables, creating something close to this (assuming JavaScript as a language):

let total = 0;
for (let x = 0; x <= 10; x++) {
   total += x;
}

console.log(total) //55

Decomposed into pseudo-code, it would probably read like this:

1. Create a variable total

2. Assign 0 as the initial value

3. Compute the number using an iteration protocol of type for

4. In the for-loop, define a variable x and assign it an initial value of zero

5. On every subsequent iteration, check that the value of x does not exceed the max number

6. Increment the variable x on every iteration by 1

7. Increment the total by assigning x to the current value of total on every iteration

Notice that assignment is the main method of computation here, without which, it would be very hard to achieve effective computability. Furthermore, note that we not only specify the problem we want to solve (summing numbers 1 to 10), we also specify how we want the computer to do it (using assignment and iteration). This convulsion of problem and solution is the bane of software engineering because it introduces variables that can be modified while being accessed by other sects of the program. This can lead to all sorts of problems.

Now imagine that we want to solve the same problem using a functional mindset:

[...Array(11).keys()].reduce((a, b) => a + b, 0)

Notice how succinct that code is. More importantly, notice how declarative (how the code lends itself to problem definition and solution) it is. If we were to decompose this to pseudo-code, it would read like this:

1. Given a list of items 0 to 10 (I cheated because I am lazy to create the array values manually – blame it on being declarative)

2. Reduce the items by summing them

3. Start with an initial value of zero

In essence, we have composed the steps from 7 down to 3, which is a good thing since the fewer mental hoops a developer has to skip when writing code the better. And therein lies the allure of functional programming, or at least thinking about solutions in a functional way.

Benefits of Functional Programming

What then, is the craze about functional programming? Let’s examine some of the benefits that functional programming affords a programmer.

Immutability:

Remember we mentioned that the road of assignment is paved with gremlins all the way to hell (ok, I didn’t say that but you get the gist). The raison d’etre for functional programming is immutability. Mainstream functional programming languages avoid mutability or at least make it very hard to reassign variables, as the primary device of computation.

Immutability simply means that once a value comes into existence, it cannot be changed (modified or otherwise). This property is what functional programmers call immutability. Let’s illustrate with an example:

function duplicateBook(bookData, bookList) {
    let bookDataCopy = {
        fname: bookData.fname,
        lname: bookData.lname,
        dateCreated: Date.now(),
        metaData: bookData.metaData,
    }
    // modify name
    bookDataCopy.metaData.name = bookData.metaData.name + ' ' + Math.floor(Math.random() * (bookList.length + 1));
    return bookDataCopy;
}

I have used the above code in a recent project. To the untrained eye averse to immutability, this code is good to go. It will probably pass a PR review, especially if it is backed up with unit tests. However, this innocuous-looking code has a major gremlin in it. The fifth line in that example code inadvertently modifies the value of the name on the original book object. Why is this so? Because metaData is open to modification. Such subtle errors abound in code bases out there (it is a dangerous world after all), and they are hard to catch during a cursory code review.

In languages that do not support mutability via the assignment, this is not possible. At the very least, a new copy of metaData will be returned, and the original value will remain intact, unchanged.

This idea is an extension of arithmetic. When was the last time anyone fretted over adding 2 numbers? Human beings have not invented a test-driven approach to arithmetic because they are sure that the numbers do not change. When we add 2 to 3, the arithmetic values do not magically transmogrify into 5, however, a new value of 5 comes into existence. But we are fully aware that 2 and 3 are immutable values waiting to be summoned the next time you need an arithmetic fix.

Some programming languages like Clojure (a dialect of LISP) avoid the concept of assignment altogether by not even providing an assignment operator, the lack of which causes untold discomfort for imperative programmers when they encounter Clojure, but an immense joy to functional programmers since it helps them inadvertent modification changes. However, imperative programmers do not have to worry because the same results can technically be achieved by using hygienic devices like recursion or reduce.

To get around the warts of mutability, programming languages that support it differentiate between primitive types and mutable types. Usually, numbers, strings, and booleans are immutable, and all the other data types are mutable. Functional programming languages or at least the good ones treat values the same way. In that way, they conform to the human rights of values, in that they are all born equal. 🙂

Python and JavaScript have a freeze function that anesthetizes a mutable type and prevents further modifications to it. However, they also provide the functionality to hang yourself with by unfreezing the frozen value (clonig etc), in case you want to modify the data and lose all the benefits of immutability.

Working in an environment that does not support immutability from the get-go leads to a sequestered approach to programming (by separating state and value), forcing developers to rely on mutating state by updating values in place, sometimes globally, to design solutions for effective computability.

Pure Functions

The pièce de résistance of functional programming is the ability to define pure functions. A function is pure if it conforms to two properties:

1. Referential transparency: meaning that it returns the same result given the same arguments

2. Zero side effects: It does not cause observable side effects out of its current scope.

These two qualities make it a lot easier to reason about programs since they provide the machinery to isolate functions and their scope and make it hard for a function to do more than is necessary to achieve the desired result. The functions are stable and non-inscrutable, which is what programmers mean when they talk about code quality.

Referential Transparency

A function is referentially transparent when it returns the same result given the same arguments. It doesn’t rely on data outside the current function, and it doesn’t change data that exists outside the current function. Functional programming provides aids to support referential transparency. By only relying on function arguments and immutable values for computation, functions operate within a scope that guarantees that no observable unintentional side effects occur.

As a way of illustration, here is a function that is not referentially transparent:

const multiplier = 2; 
function multiply(x) {
   return x * multiplier;
}

The above function is not referentially transparent because it relies on a global variable multiplier to accomplish its work. That global variable could be changed by another function, which would technically affect the correctness of the function.

Modifying global variables also hurts purity:

const total = 0;
function sum(x, x) {
   total = x + x;
   return total;
}

This is a contrived example, but it illustrates the point. The function is modifying a global variable (or at least a variable outside of its scope) to accomplish its computational task. This side effect is observable outside of the function scope and thus hurts purity. This kind of programming should be avoided for pure functions like this:

function multiply(x, multiplier) {
   return x * multiplier;
}

This function only relies on its arguments, plus it is easier to test and reason about since we can always change the multiplier, or even extend it to support additional multipliers through currying (a functional programming technique):

function variableMultiplier(multiplier) {
   return function(x) {
       return x * multiplier
   }
}

let square = variableMultiplier(2);
console.log(square(2)) // 4

Using pure functions allows the programmer to rely on small isolated and contained functions that can be composed to create elegant solutions.

How to achieve mutability

This is where I sort of shot myself in the foot, but any sufficiently complex software program has to modify some data lest it is useless. In functional programming, this is achieved through recursion. Let’s look at an example:

let flights = [{
       passengers: 10,
       flight_number: 1
   }, {
       passengers: 210,
       flight_number: 1
   }, {
       passengers: 323,
       flight_number: 2
   },
];

Suppose we want to find the total number of passengers that have flown on a given flight number, the quintessential way to do it would be:

let total_passengers = 0;
const LEN = flights.length;
for (let x = 0; x <= LEN; x++) {
   let flight = flights[x];
   total_passengers += flight.passengers;
}

console.log(total_passengers(flights)) // 543

This works, but we are thinking imperatively, something we should avoid if we can help it. Instead of assigning values to variables, we can use the concealed scope of a function and achieve the same result using recursion:

const total_passengers = (flights, total = 0) => {
   if (flights.length === 0) {
 return total;
   }
   total += flights.shift().passengers;
   return total_passengers(flights, total);
}
console.log(total_passengers(flights)) // 543

Notice how recursion handles assignment, iteration and scoping of the value being incremented. It has the added benefit of being elegant. But as much as recursion is elegant, the idiomatic way of achieving this in functional programming is through folding, also called reducing in some languages. In JavaScript, the same computation can be achieved by this code:

const total_passengers = flights.reduce((total, flight) => {
   return total += flight.passengers;
}, 0)

console.log(total_passengers) // 543

By now, you notice that you do not need to mutate state, nor have global variables to achieve effective computability. Working with recursion or reduce makes the code easier to reason about because it is a self-contained unit that is pure. I admit that it takes getting used to, but once the mindset is set in, you will be reducing and recursing instead of iterating. There is the added benefit of your PRs looking cool.

Tail Recursion

Some people quip that you need tail recursion to achieve proper recursion. However, it is important to understand that tail recursion is an optimization technique (under Tail Call Optimization) achieved at the compiler level, not a construct that a developer needs to understand to use recursion. JavaScript, python and a slew of mainstream programming languages do not support tail recursion, but programmers can use recursion in those languages. ECMAScript 6 has a proposal to implement tail call recursion, but it has not yet been adopted by all browsers

As long as there is a terminating condition that avoids infinite recursion, the compiler is happy to recurse until it reduces the value to your heart’s desire. And that is how mutation is achieved in functional programming.

Why Functional Programming Got a Slow Start

It is usually mentioned that, if functional programming is the best thing since sliced bread (it really is), why is it not mainstream, or at least as prevalent as other software programming paradigms. Like time slippage, the answer to this question depends on your vantage point of view. There are many reasons why this is the case, and I am unashamed to add to the pile.

To understand why a historical perspective is in order:

Euclid (325-265 BCE), defined what a computer is (as a person who executes an algorithm) in his work on Euclid elements. But a formal mathematical definition of an algorithm did not suffice until the 20th century, when three eponymous scholars independently formulated formal definitions in three subsequent papers: Alonzo Church (An Unsolvable Problem of Elementary Number Theory, May 1935), Kurt Gödel (General Recursive Functions of Natural Numbers, July 1935) and Alan Turing (On Computable Numbers, with Application to the Entscheidungsproblem, May 1936).

For an algorithm to be valid in every structure satisfying the axioms, it has to decide whether a given statement is provable from the axioms. Thus, in 1928, David Hilbert and Wilhelm Ackermann defined the Entscheidungsproblem (Decision Problem), in which they sought an algorithm which when given a statement in formal logic will determine if the statement is true or false. Hilbert based his work on the assumption that logic is complete, meaning every provable statement is true and every true statement is provable.

As long as academia held that there was a solution to the Entscheidungsproblem problem (Hilbert believed that there would be no such thing as an unsolvable problem until 1930), a formal definition of algorithms was not necessary. But if the goal was to show the undecidedness of the Entscheidungsproblem, then a formal definition of an algorithm was required, since it had to filter out the algorithms that would not prove the validity of a statement from its axioms.

Kurt Gödel published his Incomplete Theorems that invalidated Hilbert’s premise by proving that any logic powerful enough to represent arithmetic encoded the statement: This statement is not provable. Gödel achieved this using a novel numbering scheme called Gödel numbering, which he used to encode statements and proofs as numbers. In essence, this was the world’s first functional program.

May 1935 to May 1936 provided the formal mathematical and philosophical research requisite for the adoption of functional programming. Alonzo Church proposed his solution to the Entscheidungsproblem, when he came up with Lambda Calculus in 1932, and showed that it can express algorithms and to an extent show that the Entscheidungsproblem is undecidable, in his work on the proof of the undecidability of a problem.

Lambda calculus provides the foundation for functional programming:

L, M, N ::= x
       |  (λx.N)
       |  (L M)

It has three constructs, variables (L, M, N), function definition and functional application. This was defined before computers became en vogue. Notice the structural similarity to functions in mainstream programming languages (or methods, for languages like Java). To date, lambdas have been added to python, Java and pretty much every mainstream programming language.

Kurt Gödel later countered that Church’s definition was unsatisfactory, and devised General Recursive functions as a rejoinder to Church. In doing so, Gödel inadvertently showed that both his definition and Church’s were identical. This impasse was finally resolved when Alan Turing, whose doctoral supervisor was Alonzo Church, put forth his work on Turing machines and showed that if a Turing machine was the definition of an algorithm, then the Entscheidungsproblem was undecidable.

Alan Turing provided the philosophical argument for adopting Kurt Gödel’s research, which had demonstrated the inherent limitations of formal axiomatic systems performing arithmetic, which had in turn provided the logical framework to reason about the research of Alonzo Church, who had discovered Lambda Calculus. In essence, Alan provided a philosophical framework (as opposed to mathematics) for reasoning about algorithms by showing that anything a computer can do (by a computer we mean a person following a sequence of instructions), could be done by a Turing machine.

Notice that three independent definitions (Kurt Gödel, Alonzo Church, and Alan Turing) of computing algorithms turned out to be equivalent, although they were put forth by different people. This is powerful evidence that good ideas are not invented, they are discovered, and the same applies to functional programming.

It certainly took a long time from Euclid to Alan Turing, but along the way, functional programming was born. And since it took that long to formalize functional programming through discovery, it is plausible to conclude functional programming had to follow a similar trajectory since it takes time to discover good ideas, as opposed to inventing them.

Invention versus Discovery

Is mathematics invented or discovered?

Paul Graham mentioned that good ideas take a long time to adopt (he suggests 30 years). For example, Paul McCarthy put forth the formalisms for garbage collection in his 1959 paper titled Recursive Functions Of Symbolic Expression and their Computation by Machine, as a way to automatically manage memory in LISP. However, it was not until 1996, when Java was released that garbage collection became a mainstream phenomenon. That is 37 years later for those counting. Almost all mainstream programming languages support garbage collection because it’s benefits are self-evident.

James Gosling did not invent garbage collection, rather, he discovered that John McCarthy had put forward a formal definition of the GC, and if implemented properly, could afford the John Doe programmer untold joys as they write code, as opposed to phantasms of calamity when they manage their own memory. It certainly eliminates the set of bugs that arise due to poor memory management.

The TL;DR version is that functional programming, like mathematics, is a discovered idea that flows from Lambda calculus. Many programmers use languages that are invented, consider this an invitation to consider languages that are discovered.

A developer could start by looking at the LISP family of languages like Scheme or Clojure, since they are not dissimilar to Alonzo’s lambda calculus.

The post An introduction to thinking in a functional way appeared first on Andela.

Andela’s Engineer Value Propositions: What to Expect When You Join Andela

$
0
0

Before anyone takes on a new role or job, they typically do some research on the role which helps them know what to look forward to from day one. Such research is crucial to succeeding in the said role.

Applying for a job can be an ordeal if candidates don’t have access to information that helps their process. Access to information relating to company culture and employee experience plays an important role in easing the experience. As the nature of work tilts more and more towards remote and distributed teams, such information needs to readily accessible.

The slug on our ad banners invites software engineers to come to do their best work at Andela. That line is anything but trivial. We acknowledge the fact that work takes a significant chunk of a person’s time and therefore needs to be meaningful at the very least. We want our people to know for a fact that the work they do matters.

Impact on customers and revenue aren’t the only parameters for measuring meaningful work. It is a conversation that begins with employee experience and culture. As Malcolm Gladwell stated in a 2008 interview, “Meaningful work is work that is autonomous. Work that is complex, that occupies your mind. And work where there is a relationship between effort and reward — for everything you put in, you get something out.”

At Andela, we have distilled a set of value propositions for every software engineer looking to join us. They offer clarity on everything from culture & experience to on-the-job growth.

1. Professional Growth and Learning

Engineers at Andela build solutions for hundreds of the world’s most respectable technology companies. It is challenging work that will occupy your mind and help you grow. Also, our community of 1000+ engineers is filled with people who are at the top of their field. That network offers opportunities for mentorship and continuous growth for all our engineers.

2. Interesting and Diverse Problems to Solve

Hundreds of the world’s most respectable companies depend on the work done by our engineers to build and ship products and solutions quicker. Being an Engineer at Andela offers you an opportunity to work on several interesting challenges and projects and clock in invaluable real-world experience. The work we do impacts on millions of people every day; it is important work.

3. Flexible and Remote Work

We’ve been on the frontlines of enabling remote and distributed work since we commenced operations. We believe that the quality of work a person does should not have to be sacrificed on the altar of geography or zip codes. We have teammates working from several different cities and locations around the world. Andelans have the option of working from anywhere and will have the support and access they require to do their best work, whether they’re in the office or remote.

4. Fun Culture

Andelans come from several different backgrounds and cultures to work together. Our company culture is carefully crafted to ensure everyone has an enjoyable experience working here. It’s not all work and deadlines; there’s a lot of fun too! Whether you’re in Lagos, Egypt, Nairobi, or anywhere else we have operations in, the experience is the same. We’ve built a home for talented people to come and do the work they love.

5. Elite Engineering Team

Engineers at Andela are masters at their craft. We hire the best people because that is what our mission and the work we have to do demand. We are building solutions for the world; it is serious work — 0ur engineers are working on some of the most challenging problems in software today, and are building solutions that will shape the future. If you want to put your skillset to great use and do work that matters, you should apply to join Andela.

Related: Check out our Engineering Framework.

The post Andela’s Engineer Value Propositions: What to Expect When You Join Andela appeared first on Andela.

10 Commandments for Remote Workers: Follow These to Crush the New Normal 

$
0
0

Fun fact: I’ve been a remote employee for my entire career.

I’ve never had an office to commute to each day and my manager and teams have always been in different cities and usually in different time-zones. With IBM I had an office I could work from in San Francisco, but spent most days at client sites, working from home and getting to the office 1-2 times a week. With Andela, I’ve always been remote from our main office in NYC.

Unfortunately, many companies are asking their employees to work from home due to current events. This is going to be a huge change of pace. The good news is remote work is not rocket science and if done right can increase your productivity as an individual and as a company.

If you’re working from home (WFH), these “Distributed Work 10 Commandments” are some words to live by and practices to put into place.

10 Commandments for Remote Work Andela

You can download the infographic here.

#1 Thou Shall Not Wear Pajamas

One of the most important parts of the workday is your morning routine before you go to the office! When you work from home, getting ready is just as important. It’s easy to open your laptop and all of a sudden, the day has passed and it’s 6pm and you’re still in PJs… Take the time to get ready and get in the zone for work!

Even when you are remote, dress for the job you want, not the job you have. If you look good, you’ll feel good, and you need to bring that energy every day when you WFH!

Warning: Don’t be that guy who is on a video call and accidentally stands up and forgets he’s still in pajamas… it’s been done many times before. Don’t be that guy!

#2 Thou Shall be Self-Accountable

This probably should have been #1. 

All the technology, tools, and tips in the world cannot replace trust and accountability. A manager’s biggest fear about remote work is that their teams will misuse their time and that work productivity will drop without in-office collaboration. The frank reality is that there will be people who take advantage of a work from home structure. DON’T be that guy that gets caught watching TV, not working, and slacking off — that will impact your whole team.

Working remote means that you need to be a respectful employee that hits targets, communicates effectively and is an active participant in meetings. In return, your company needs to trust and empower you to get your work done.

Simple ways to be self-accountable:

• Be responsive to your team in email, Slack, meetings, and phone calls. Prioritize your time with todo lists and time-block your calendar.

• Send your manager a stand-up/stand-down.

• Work where you can get work done (home office, coffee shops, co-working spaces).

• Ask for help when you are blocked on a task – public channels are the best because others are likely to have the same question.

• Take ownership, don’t make excuses, and get your work done.

• These daily updates can be sent via Slack, email, or preferred communication tool.

#3 Thou Shall Use Video 

This will be a monumental change for companies used to phone calls, but video calls are a GAME CHANGER for remote teams.

Simply, video calls are much closer to real-life communication and in 2020 video-technology is available to us all. You can observe people’s true reactions, ensure others are engaged and not distracted, and build genuine relationships.

According to Gong.io, you are 41% more likely to close a deal if your webcam is on.  The impact of video calls stretches beyond sales calls and can increase the quality of all your meetings because, “When you pair the sound of your voice with the sight of your face, your words come alive and create a totally different perception.” 

Eye Contact:

• Always look at the green dot/camera at the top of your screen, it’s the virtual equivalent of looking someone in the eye.

Background and Lighting:

 • Simple backgrounds are key. Ensure you have light in front of you, and not creating a silhouette.

Yes, a selfie light works wonders

• Your camera should be at eye-level.  Sometimes you need to find a box/books for extra height.

Adjustable laptop stand

Sound:

• When you’re not speaking, mute yourself.

 • Use headphones and a quality microphone.

We also LOVE Krisp.ai. It’s a tool for your laptop that minimizes background noise when you’re speaking and listening to a call.

• For important meetings, be at home or in a quiet space with strong internet. Avoid coffee shops.

#4 Thou Shall Have a Workspace that Works for You

We’ve spoken about not wearing pajamas, aka the equivalent of “getting ready to go into the office each day” for us remote folks, but now we need to talk about “going to work each day.”

This is where you should prioritize setting up a workspace that works for you. For today, let’s talk about your home office, but the rules would still apply if you went to a co-working space each day.

Rule 1: Set up your desk, ideally in a room where you can be alone, have quality lighting and can shut the door.

• I haven’t had the luxury of a dedicated office room. To hack the system, while in San Francisco, I set up a desk in my room and actually installed a curtain behind it so you couldn’t see the rest of my room. Here in Charlotte, I use the edge of my kitchen counter as a standing desk and have an office chair. I have it positioned so that I have a blank wall behind me with good lighting.

Rule 2: What do you need to be productive?

• Work with your company to ensure you have the tools at home to accomplish your job. I mostly use a laptop, but others may require 2-3 monitors, high-tech sketching tools, studio-quality microphones, etc.

Rule 3: Quality Internet.

• At Andela, I am on video calls all day every day. I wish I was exaggerating, BUT it has required me to invest in the top internet speed from my provider to ensure I have the best connectivity and don’t drop calls.

All in all, set up a workplace that works for you and figure out your rhythm. It might take a few days to get used to – that’s okay!

#5 Thou Shall Commit to Communication

Communication can have MANY meanings. I define communication as, “How your team shares information verbally, non-verbally, and written.”

The good news is that most companies already have the 4 basic tools that remote teams need to successfully communicate.

• Instant Message (Slack/Microsoft Teams)

• Email (Gmail/Outlook) 

• Calendar (Gmail/Outlook)

• Video (Zoom Video Communications/Google Meet)

The first step you should take with your team is to outline your communication process, policy, and guidelines. Share these guidelines with every employee. Streamlined communications will improve efficiency and productivity while having a documented path of decisions.

Here are some of the guidelines I’d suggest:

• Slack/IM is for real-time conversations with colleagues and teams. Leverage open channels whenever possible vs. direct messages.

• Email is for official decisions, announcements, and information that should be taken seriously and clearly documented.

• Leverage a call if your conversation will be more than 5 messages. Recap your discussion with key stakeholders who should be informed.

• Your calendar should be your source of truth for you and your team (we’ll talk about this more later).

• Acknowledge messages with a “Seen” emoji and set expectations when you’ll respond.

• If you feel like you’re overcommunicating, you’re doing it right!

#6 Thou Shall Foster Work Relationships

One of my remote work pet peeves is when someone says, “Let’s grab a coffee when you’re in town.” I appreciate the notion and believe the best-distributed teams collaborate in-person a few times a year. That said, let’s grab a coffee now.

You can 100% build relationships over video. When you have work friends, life is better, and work is enjoyable. Plus you need trusted friends you can vent to and get advice from.

Strong 1:1 relationships and team relationships are critical. Individuals and managers should prioritize time for culture-building and collaboration. A happy employee is a productive employee!

A few tactical tips:

• Building a relationship starts on Day 1. Welcome new employees by saying hello on Slack and find time to connect.

• Install Donut – a Slack app that randomly connects you with colleagues and empowers you to get to know each other.

• Set up recurring meetings with 3-4 colleagues every few weeks to chat about life – BYOB coffee, kombucha, or wine.

• Host a team happy hour! Some remote inspiration: Trivia, Cribs (MTV style), Teach Something (i.e., cooking, workouts, cocktails), Meet the Pet(s), Talent Show, or a Dance-Off.

#7 Thou Shall Create Inclusive Meetings

When speaking about tips for remote teams, I often say that “remote best practices are really business best practices.” At Andela we have a lot of conversations about how to ensure everyone has a fair and equitable voice.  It’s a business best practice to ensure that you set up your meetings to be inclusive to promote diversity of thought and avoid groupthink.

There are many techniques your team can leverage to set up meetings for success, but it’s equally important as a remote employee that you commit to being an active listener, speaking up, and sharing the floor with your colleagues. Don’t fall in the trap of being a silent observer sitting on mute.

Here are some ways to have an inclusive conversation:

• Share an agenda beforehand with prep materials to ensure everyone is on the same page.

• Decided who should be in the conversation, the purpose of the meeting, and the desired outcome. 

• Introduce everyone on the call and any context to why they’ve been included.

• As a rule of thumb, If one person is remote on video, everyone should be on video to have an equal conversation.

• Pay attention to conversation balance. Encourage or call on team members who may quiet or who could provide an informed opinion.

• If there is a talking order, post a list of names in the chat to prevent people from talking over each other

• Use the power of “YES, and…” Build upon people’s ideas, understand the meaning behind the meaning.

• Regularly ask, “Are there any questions?” or “Was that point clear, any clarification needed?

• Never interrupt and allow people to feel confident when they speak.

#8 Thou shall be a calendar superstar

As I’ve been writing my Distributed Work 10 Commandments and Andela has gone to a 100% remote company, I’ve noticed that our Google Calendar has become a super tool we all rely on. 

Here’s why your calendar is powerful:

• Your calendar is a real-time snapshot of your day.

At any given time, we ask that our team’s calendars are as up-to-date as possible. We ask our teams to put on the calendar and update their Slack status anytime they’ll be away from their desk for more than 30 minutes. This allows the team to have an expectation of response time and give empathy in scheduling other meetings around appointments, child care, and commutes.

Our most productive employees time-block their day. They’ll mark when they’ll be dedicating focus to certain tasks so that we can be considerate or ask for permission if we need to schedule a call.

Accept or decline meeting invites. Follow-up with invitations asap if you cannot make the time and need to reschedule.

• Your calendar is a meeting accelerator!

As a best practice, every meeting should have an agenda, key documents attached, prep questions, and the purpose and outcome.

Every meeting should have clear dial-in instructions for video and phone connection – the best meetings kickoff on time instead of wasting valuable time for set up. PRO TIP: If you use Zoom, add the Chrome Extension to make adding meet details simple.

The meeting coordinator should remember to send a prep note before to all attendees and a recap note afterward to attendees and key stakeholders. If relevant, the recap note should include the meeting notes and recording. 

• Your calendar is searchable. If you do a good job creating agendas and adding context to your calendar invites, you’ll have a documented record of past conversations and decisions that were made.

• Your calendar is a global team’s best friend for managing time zones.

○ Set work hours.  Most calendars allow you to set your work hours to ensure your team knows when you’ll be signing on each day and when you’ll be signing off. Your teammates will get a notification if they schedule a meeting outside of your work hours.

○ In Google Calendar go to (Calendar > Settings > General > Working Hours)

○ Use Time Zone and World Clock. You can set a primary and secondary time zone to display on your calendar at all times. Additionally, Google Calendar allows you to add 4 more timezones on the world clock so that you can click on any time of the day and it will auto-adjust.

○ In Google Calendar go to (Calendar > Settings > General >  Time Zone and World Clock)

#9: Thou Shall Leave the House

Make it a goal to get outside every day! (especially when you don’t have to social-distance!)

Once you get into the rhythm of remote work, you’re going to get more work done than ever, but all of a sudden you may find yourself forgetting to eat, working until 7 pm, and for me… I will forget to leave my apartment for days. It’s essential to establish work/life balance and to get your daily dose of oxygen.Some Simple Ideas:

• Take walking meetings via phone.

• Build-in your “commute” to catch up on news/podcasts -Most mornings, my dog and I take a 30-minute walk around the neighborhood while listening to The New York Times, The Daily and Robinhood Snacks.

• Attend local networking events online or in-person (when we’re back to “normal”).

• Set up bike rides/run clubs with friends (again, when it is allowed again).

• Commit to your work hours and sign-off for the day!

• Another technique is changing your environment throughout the day to be more productive. For example, I frequently split my time into thirds:

○ Mornings: Home office.

○ Mid-Day: Coffee shop (when it will be allowed).

○ Afternoon: Apartment lobby or my couch.

Find the rhythm that works for you. It may take some time to adjust, and that’s okay!

#10: Thou Shall Prioritize Team Culture

At the end of the day, we’re all human. We all have a life outside of work and other priorities. We all want to work for a company that is fun and has great people. 

It’s up to the leadership and every employee to contribute to the workplace culture and to ensure that people are working towards a common goal and maintaining company values. As a remote company, there are so many ways to share laughs, bond outside of the office, and celebrate wins.  The more employees can be themselves and let their personalities shine, the stronger your culture will be! A strong culture is one that’s built on trust and empowerment.

Here are some of my favorite remote-work culture examples.

At GitHub, they have over 2,000 remote employees and have subgroups for different peer groups. For example, they have employee resource groups (ERGs) set up for:

○ WomenOnboarding Classes

○ Managers

○ LGBTQ 

○ Disabilities

○ Employees of Color 

○ Co-located Employees (to meet up for lunch or team meetings

The peer groups are endless, but incredibly valuable

BleacherReport hosted a Hot Sauce Challenge. They sent a box to all of their employees with 5 different hot sauces and everyone on the call had to join a zoom call and try each of the sauces. If you made it through all 5 hot sauces you win. Ultimate Hot Sauce Party

At Andela, we hosted a Halloween Costume Party with our team based in our African offices in Nigeria, Uganda, Kenya, Rwanda, and Egypt. We encouraged everyone to dress up and had the team vote on a winner!

Other simple ideas:

Rotate teams hosting a company-wide remote happy hour to cheers-on wins for the week (celebrate), “day-in-the-life of that team” (learn something new about the teams) and have some fun activity (bond) such as a themed event (i.e. College Shirt Day), Bingo, Teammate Trivia, Family Feud, Cribs, Talent Show, Dance-Off, etc.

Have a public channel or weekly email thread centered around fun themes (#ThrowbackThursday Pictures, Weekend Plans in Emojis, Jokes, Trivia, etc).

Remote Best Practices are Business Best Practices

Time to come down from the mountain and put these commandments into practice! Let’s face it, it is easy to take teammates for granted when you know you will see them in the office every day. Remember–remote best practices are also business best practices, it’s not rocket science or something to fear. Don’t be surprised if you find that your team’s productivity increases, collaboration improves, and your culture is stronger.  Follow these commandments and you’ll be well on your way to being an ELITE remote team. Best of luck and don’t wear pajamas!

Engineering teams around the world are now working without an office, many for the first time. For more information about how to make the shift to all-remote teams, check out our recorded webinar, “Best Practices for Remote Engineering Teams: How Teams Can Thrive Without the Office.” Andela CTO David Blair and GitHub VP of Engineering Sha Ma shared best practices around communication, collaboration, and culture.

The post 10 Commandments for Remote Workers: Follow These to Crush the New Normal  appeared first on Andela.

Making the Shift to All-Remote Teams: It’s Not Just About the Tools

$
0
0

You’ve probably read a few articles recommending collaboration tools like instant messaging (Slack) and video conferencing (Zoom) for employees suddenly forced to work from home due to COVID-19. These are great tools. But it takes more than a Zoom account to remain productive while remote, during what Gartner called “the world’s largest work-from-home experiment.”

It doesn’t have to be an experiment. Many engineering companies have been working in remote mode for years. Success depends not just on getting the right tools; it depends on how teams use the tools to work together. As Gartner points out, it is a chance to “seize the opportunity to bolster your policies — and prepare for future workplace and employee needs.”

You can find more detail about how to implement this kind of policy boost in our new e-book, “Making the Shift: Experts Share How to Rapidly Build and Scale Distributed Teams.” In it, distributed engineering leaders from Andela, Blackboard Insurance, and Percolate share best practices and lessons learned for teams going remote for the first time or expanding remote teams. 

It Starts with Culture

For teams that going remote for the first time, it is important to establish consistent policies for communication and collaboration. It all starts with culture. “Generally, distributed employees don’t fail — the companies that hire them do,” says Christopher Jordan, Head of Engineering at Blackboard says in the e-book. “And most of the time, that comes down to culture and leadership. It’s important to have a culture that empowers teams and a willingness to change the way you operate.” 

Ground Rules for Collaboration

When it comes to the use of tools like Slack and Zoom, it important to establish policies that will enable your team to use them strategically and consistently. Andela CTO David Blair recommends that all remote employees be on video for every meeting. “It cuts out a lot of wasted time trying to figure out who’s dialed in to the meeting or whether everyone’s ready. With video, you can immediately see when everyone is ready and can dive right in.” More on this in the e-book

Continue to Build Culture and Relationships

Once your team is up and running, it is important to continue to build culture and strengthen relationships. This will be valuable when you begin to grow your team and add more engineers. The processes and traditions that you create will make onboarding new hires easier.

Creating and sustaining culture is not as difficult as you might think. You can replicate in-office rituals online. On-hands meetings can be more “face-to-face” when everyone is virtually facing each other on a screen rather than facing presenters in a theater-style office setting. 

You can also personalize team meetings by inviting people to share personal stories like they would in a breakroom in the office. Melanie Colton, VP of Talent at Andela, recommends using ice-breaker questions to start meetings, allowing people to show their personalities and backgrounds. “Non-work banter is so important but gets left out among remote teams.” There are more tips from Melanie in the e-book.

Process and Practice

As your team grows, the processes, policies, and guidelines you establish early on will become second nature. Some of the exercises may feel awkward or forced at first, and it may be helpful to perform some practice sessions and laugh a little at the gaffs. But as the team experiences the value of the trust and accountability you build, they will embrace them and the productivity they deliver. Download it here

The post Making the Shift to All-Remote Teams: It’s Not Just About the Tools appeared first on Andela.

On-Demand Webinar: Best Practices for Remote Engineering Teams

How to Build a Résumé Builder Using Angular Reactive Forms

$
0
0

In this post, I will demonstrate how to add input elements dynamically to a form while building a Résumé Builder form.

It is very common to find web apps that have an input form to be filled by users who want to build their CVs online. Therefore, it is quite important for the user to be able to add as many experience blocks as needed in a dynamic way. And here the power of Angular Reactive Forms appears.

This is how our form will look like:

Adding a new “Experience Block” dynamically when clicking the add button

If you want to check the full code, you can check this Github repo .

Here are the steps to implement this form:

1. Firstly, we need to import ReactiveFormsModule from @angular/forms and then add it to the imports array in our NgModule. Here our app is simple so we only have one module which is the AppModule.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ReactiveFormsModule } from '@angular/forms';
import { ResumeBuilderComponent } from './resume-builder/resume-builder.component';
@NgModule({
declarations: [AppComponent, ResumeBuilderComponent],
imports: [BrowserModule, ReactiveFormsModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}

2. We will implement our form in the “ResumeBuilderComponent”

  • Add the required imports from ‘@angular/forms’
  • Declare our FormGroup
  • We will generate the different form controls using the FormBuilder service because it makes the code simpler. We need to inject it into the constructor first and add the required import.
...
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
@Component({
     ...
})
export class ResumeBuilderComponent implements OnInit {
resumeBuilderForm: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit(): void {
this.resumeBuilderForm = this.formBuilder.group({
      firstName: ['', [Validators.required]],
      lastName: ['', [Validators.required]],
      email: ['', [Validators.required, Validators.email]],
      phone: '',
      experienceBlocks:this.formBuilder.array(
                       [this.buildExperienceBlock()])
});
}
buildExperienceBlock(): FormGroup {
return this.formBuilder.group({
   title: ['', [Validators.required]],
   company: ['', [Validators.required]],
   location: ['', [Validators.required]],
   startDate: ['', [Validators.required]],
   endDate: ['', [Validators.required]],
   description: ['', [Validators.required]]
});
}
...
  • As you can see from the code above, we generated a Form Group in the ngOnInit Life Cycle Hook, it consists of simple child Form Controls ( firstName , lastName, email, and phone). But it contains a more complex control at the end which is the “experienceBlocks” Form Array. The child of this Form Array is an array of Form Groups.
  • The creation of each inner Form Group is handled to the function buildExperienceBlock(). We called this function once during the initialization phase to initialize the experienceBlocks Form Array with one experience block as a start.

3. We can easily now add a new experience block when the user clicks the add experience button as follows:

addExperience() {
 this.experienceBlocks.insert(0, this.buildExperienceBlock()); 
}

4. Lastly, we should loop through the Form Array in our template using *ngFor directive as follows:

<form (ngSubmit)="save()" [formGroup]="resumeBuilderForm">
....
 <div formArrayName="experienceBlocks" *ngFor="let experience of
  experienceBlocks.controls; let i = index">
   <div [formGroupName]="i">
     <label attr.for="{{ 'titleId' + i }}">Title</label>
     <input 
        id="{{ 'titleId' + i }}" 
        type="text"
        placeholder="Ex: Software Engineer"
        formControlName="title"/>
        ....
   </div>
  </div>
...
</form>

I hope you found this article useful!

The post How to Build a Résumé Builder Using Angular Reactive Forms appeared first on Andela.


Human Factors: Managing Remote Teams in the New Normal

$
0
0

Technical expertise is a prized value on engineering teams. But when it comes to team leadership, summoning that expertise has as much to do with human factors as it does with technical acumen. As teams are forced into all-remote mode by the COVID-19 pandemic, these human factors are even more critical to fostering an environment that supports trust and accountability. This article shares best practices for leading remote engineering teams through the current crisis.

  1. Make sure people feel safe. This is a stressful time. There are health concerns, job concerns, and family concerns. Human beings have a hard time concentrating on work if they don’t feel safe. It is important to honor the work and flexibility that employees are demonstrating at this time.
  2. Let the personal in. By now you’ve probably seen clips of video meetings interrupted by children. It’s not only ok, but it’s also good. Now is not the time to separate work from family–ask people how they are doing.
  3. Offer frequent recognition. Some 82 percent of employed American workers don’t feel that their work is appreciated, and would put more energy into their work if it were recognized. And that’s when they are in the office. Recognition is even more powerful and important when people are isolated.
  4. Set clear goals based on output, not activity. The point of work is not to log hours, but to deliver results. Clear, measurable objectives, with daily and weekly check-ins using virtual standups and retrospectives. Make standups on video calls and set a policy that everyone comes on camera, even if kids or pets are running around in the background. This can build trust as teams have the opportunity to show one another empathy in the moment.
  5. Assume the best. If someone isn’t delivering the same quality of work as in the office, it’s ok to ask why. It may have to do with other pressures they are going through, especially during this unprecedented crisis. Have an honest conversation about what is getting in the way and how to remedy it. One productivity drag right now, for example, is that some people don’t have high-quality Internet access home. This can be addressed by upgrading connections or by buying data bundles.
  6. Use data to measure performance. If there is a genuine work problem, make the conversation about the work delivered, not the time spent or the perception of others.
  7. Communicate often. Silence breeds misunderstandings. Use instant messaging platforms like Slack to ask questions and help one another. Check-in once or twice a day to review the status of projects, identify obstacles, and discuss how to break through them.

The principles behind these best practices are not new or unique to remote work, save children crashing meetings. Communication, recognition, goal setting, and accountability take on a different form when the team is not in the same building. These practices require more intentionality and frequency for all-remote teams, especially in the midst of our current circumstances.

For more information and guidance about building and managing remote engineering teams, download the e-book, “Making the Shift: Experts Share How to Rapidly Build and Scale Remote Teams.”

The post Human Factors: Managing Remote Teams in the New Normal appeared first on Andela.

While Some Regions Struggle to Work Remotely, Andela Is Ready to Help

$
0
0

The massive shift to remote work caused by the coronavirus has exposed the limitations of some outsourced engineering businesses’ ability to cope with the change. There are reports that a lack of portable computing equipment, reliable internet access, and adequate security make it impossible for the employees of some firms to work from home under shelter in place conditions. 

“Millions of workers in India and the Philippines do everything from writing computer code to fielding customer calls for companies across the globe. Now, with the new coronavirus hitting, they have been sent home to work,” the Wall Street Journal reported. “Client contracts have to be revised or suspended to allow work to be done outside the office.” 

A study by analyst firm Gartner found that 54 percent of the companies in India do not have enough technology and resources for employees to work at home. “These companies seem helpless due to old desktop-laptops, poor network connectivity, and UPS backup.”

There have also been reports that some companies have been forcing employees to come to the office in violation of India’s mandated 21-day lockdown. 

We at Andela want to assure our partners that our engineering teams have all shifted to remote work in accordance with government requirements in the countries where we operate. This is in the best interests of our employees’ health and our partners’ business continuity.

The shift was seamless. Andela’s teams are fully prepared for this kind of event because distributed engineering is our business. All of our engineers are equipped to work from their homes at any time. The measures listed below are standard for our developer teams.

• All engineers work on Andela-provided MacBook pro laptops with remote wipe.
 

• Andela has dedicated IT Security Teams that support our engineering organizations 24/7.


• Because Andela teams are embedded within our partner organizations, our security team implements any partner-specific security measures to ensure compliance with internal policies.


• All Andela engineers are provided with a stipend to use as needed to ensure that they have the high-speed Internet, auxiliary power, or coworking space (when available again), and anything else they might need to work at home. 

• In addition to technical support, Andela has established best practices for distributed development. All of our employees are fluent in remote tools and communications practices, and U.S. businesses are guaranteed a minimum of five hours of overlap with the remote team regardless of the time zone. 

Andela’s business model is not that of traditional IT outsourcing that is largely based on low-cost labor.  Andela’s distributed engineering model emphasizes providing U.S. companies with access to talented engineers regardless of the employee’s location. Our engineers work directly with our partners as extensions of their internal development teams. We have invested in the infrastructure and business processes to make these relationships personal, seamless, and reliable. 

If your engineering projects have been impacted by the ability of outsourced engineers to work at home, Andela is available to support you for interim or long term projects. To learn more about Andela’s remote engineering model, download the e-book “How to Scale Your Engineering Team with a Growth Framework.”

The post While Some Regions Struggle to Work Remotely, Andela Is Ready to Help appeared first on Andela.

Shifting to Remote Onboarding of Engineers in the New Normal

$
0
0

With millions of tech businesses working in all-remote mode for the first time, companies are confronted with a new challenge–onboarding new employees without a physical office for the company or the employee.

“For some industries, hiring is absolutely essential right now,” Doodle CEO Renato Profico wrote in Fast Company. “Virtual recruiting and onboarding is a new way forward.” Even companies that are not hiring will likely face this remote onboarding challenge, as a Gartner report says that most CFOs plan to make many positions permanently remote post-COVID-19.

So, how do you onboard new engineers when they can’t come to an office?

We will take a detailed look at how to onboard remote engineers in a new webinar, “Thriving in the New Normal: Best Practices for Onboarding Remote Engineers,” on Thursday, April 23rd at 1 pm EST / 10 am PST, with Liz Ojukwu, Engineering Manager at InVision and Andela VP of Partner of Engineering Wambui Kinya.

Onboarding is not Orientation
According to a report from Kronos and The Human Capital Group, “Onboarding is critically important but fundamentally broken — Some 76 percent of HR leaders say onboarding practices are underutilized in their organization.”

For many businesses, onboarding is better described as orientation. It involves enrolling in benefits programs and training on company policies through an online employee handbook. This is often done in a self-service manner that leaves new employees on their own when it comes to figuring out how to do their jobs. This “sink or swim” approach that asks employees to fend for themselves risks leaving new hires frustrated and isolated–especially in a home office.

Structure Brings Retention and Flexibility
A more structured approach to onboarding is associated with higher employee retention and productivity, according to the Society for Human Resource Management (SHRM):

69 percent of employees are more likely to stay with a company for three years if they experienced great onboarding
New employees who went through a structured onboarding program were 58 percent more likely to be with the organization after three years
Organizations with a standard onboarding process experience 50 percent greater new-hire productivity

Get On Board
Good onboarding for remote engineers builds and connects teams. Think about the word, “onboarding.” It means helping people “get on board” with an organization, not just by getting an ID and a computer but by engaging them in the organization’s mission. This isn’t only a matter of getting the right information into new employees’ hands. It is a matter of deeply integrating them with the company, product, and team, including inspiring them to jump onboard your team’s best practices for development.

We will discuss how to do this remotely in the webinar.

The post Shifting to Remote Onboarding of Engineers in the New Normal appeared first on Andela.

How to Scan for Android Bluetooth Low Energy Devices Successfully

$
0
0

The Use Case

Scan for all available Android devices supporting BLE, Use any Android device with Android OS starting from 4 to 10 to Scan.

The Problem

1. Successful scanning has inconsistent development requirements over different Android OS

2. Official docs are outdated and don’t mention these inconsistencies explicitly, also samples accompanying the docs are using deprecated APIs

Article objectives

This is not a tutorial! this article covers the missing and confusing parts in the Android Developers overview article on Bluetooth Low Energy. It is highly recommended reading.

Technical Solution In Three Steps

1. The first problem I faced was that I needed to make sure that the device’s Bluetooth is not only On but also Visible. That was mentioned explicitly in the documentation but after thorough readings!

Findings: no need to request Bluetooth permission if discoverability is requested, also to stay discoverable infinitely through development set EXTRA_DISCOVERABLE_DURATION to 0, but that was not recommended in real use cases by docs

val discoverableIntent =Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)
discoverableIntent
  .putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,0/*set a duration, 0 is not recommended*/)
startActivity(discoverableIntent)

2. If your app targets Android 6+, you must not only declare ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION in the Manifest, but also request Runtime Permissions in your app, or while in development mode, set your location permissions on for your app explicitly. If you didn’t, it would never be discoverable or even discover other devices.

A- In development mode give permission manually through settings.

App permissions settings

B- or add Runtime Permissions to activate it momentarily once user asks for scanning

private fun allowLocationDetectionPermissions() {
     if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.ACCESS_FINE_LOCATION)
             == PackageManager.PERMISSION_DENIED) {
         ActivityCompat.requestPermissions(this@MainActivity,
                 arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), FINE_LOCATION_PERMISSION_REQUEST)
     }
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
     when (requestCode) {
         FINE_LOCATION_PERMISSION_REQUEST -> {
             if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                 scanLeDevice(true)
             } else {
                 //notify the user to allow location detection otherwise the scaning won't work
             }
             return
         }
     }
}

3. Please use latest BluetoothLeScanner API to start and end scanning instead of bluetoothAdapter instance, this was the outdated part in the docs

private fun scanLeDevice(enable: Boolean) {
        when (enable) {
            true -> {
                // Stops scanning after a pre-defined scan period.
                Handler().postDelayed({
                    mScanning = false
                    bluetoothAdapter?.bluetoothLeScanner?.stopScan(mLeScanCallback)
                }, 5000)
                mScanning = true
                bluetoothAdapter?.bluetoothLeScanner?.startScan(mLeScanCallback)
            }
            else -> {
                mScanning = false
                bluetoothAdapter?.bluetoothLeScanner?.stopScan(mLeScanCallback)
            }
        }

    }

 private var mLeScanCallback: ScanCallback =
            object : ScanCallback() {
                override fun onScanResult(callbackType: Int, result: ScanResult?) {
                    super.onScanResult(callbackType, result)
                    //Do your thing
                }

                override fun onBatchScanResults(results: List<ScanResult?>?) {
                    super.onBatchScanResults(results)
                    //Do your thing
                }

                override fun onScanFailed(errorCode: Int) {
                    super.onScanFailed(errorCode)
                    //Do your thing
                }
            }

Then voila! All devices from Android 4 to 10 will be scannable in your app.

Please, check the full sample app code here

The post How to Scan for Android Bluetooth Low Energy Devices Successfully appeared first on Andela.

Podcast: Building and Managing Fully Remote Teams with David Blair

Viewing all 615 articles
Browse latest View live