Two C# idioms

This post is part of the series "C# idioms"

  1. Two C# idioms This post
  2. Another two C# idioms
  3. Two C# idioms: On Dictionaries
  4. Two C# idioms: On defaults and switch

You have heard about Pythonic code? Languages have an expressive or “native” way of doing things. But, what about C#? Is there C-Sharpic code?

In this series of posts, I will attempt to present some idioms or “expressions” to write more expressive C# code. I collected these idioms after reviewing code and getting mine reviewed too.

In this first part, you have two useful C# idioms on conditionals and its alternative solutions.

Instead of lots of or’s, use an array of possible values

Use an array of known or valid options, instead of a bunch of comparison inside an if statement.

Use this idiom when checking preconditions or validating objects.

Before, we used comparison with || inside an if statement.

if (myVar == 2 || myVar == 5 || myVar == 10)
{
    DoSomeOperation();
}

After, we can use an array of valid options.

var allowedValues = new int[] { 2, 5, 10 };
if (allowedValues.Any(t => myVar == t))
{
    DoSomeOperations();
}

If you need to check for a new value, you add it in the array instead of adding a new condition in the if statement.

Instead of lots of if’s to find a value, use an array of Func

Replace consecutive if statements to find a value with an array of Func or small choice functions. Then, pick the first result different from a default value or null.

Use this idiom when finding a value among multiple choices.

Before, we used consecutive if statements.

var someKey = FindKey();
if (someKey == null)
    someKey = FindAlternateKey();
if (someKey == null)
    someKey = FindDefaultKey();

After, we use a list of Func.

var fallback = new List<Func<SomeObject>>
{
    FindKey(),
    FindAlternateKey(),
    FindDefaultKey()
};
var someKey = fallback.FirstOrDefault(t => t != null);

You can take advantage of the Null-coalescing operator (??) if these choice functions return null when a value isn’t found.

The Null-coalescing operator returns the expression on the left it it isn’t null. Otherwise, it evaluates the expression on the right.

var someKey = FindKey() ?? FindAlternateKey() ?? FindDefaultKey();

Similarly, if you need to add a new alternative, either you add it in the array or nest it instead of adding the new alternative in the if statement.

Validate a complex object with an array of Func

Also, this last idiom is useful when validating an object against a list of rules or conditions. Create a function for every rule, then use All() LINQ method to find if the input object or value satisfy all required rules.

var toValidate = new ComplexObject();

Func<ComplexObject, bool> Validation = (obj) => /* Validate something here...*/;
Func<ComplexObject, bool> AnotherValidation = (obj) => /* Validate something else here...*/;

var validations = new List<Func<ComplexObject, bool>>
{
    Validation,
    AnotherValidation
}
var isValid = validations.All(validation => validation(toValidate));

Voilà! These are our first two idioms on conditionals. I have found these two idioms more readable in some scenarios. But, don’t start to rewrite or refactor your code to follow any convention you find online. Make sure to follow the conventions in your own codebase, first.

These two first idioms rely on Func and LINQ, if you need to learn more on these subjects, check What the Func, Action! and Quick Guide to LINQ.

Happy coding!

Git guide for TFS users

Dear developer, you’re working in a project that uses Team Foundation Server, TFS. You’re used to check-out and check-in your files. Now you have to use Git. Do you know how the two relate to each other? This is what makes TFS and Git different.

Team Foundation Server (TFS) and Git belong to two different types of Version Control Systems. TFS is centralized and Git is distributed. This distinction makes collaborating with others, syncing changes and branching different.

Centralized vs Distributed

Centralized version control systems need a server in place to operate. To version control a file, view the history of a file or perform any other operation you need to communicate to a server.

But, distributed version control systems don’t need a server. Each operation is performed in a local copy of the project. You could choose to sync your local copy with a server later on.

TFS is a centralized version control system and Git a distributed one.

TFS vs Git

This distinction between Centralized and Distributed Version Control Systems brings some differences between TFS and Git. These are some of them.

Exclusive checkout

Have you ever needed to modify a file and you couldn’t because a co-worker was working on that file too? That’s Exclusive Checkout.

Exclusive Checkout is a feature you can turn on or off in TFS. But, it isn’t available in Git. Because, there is no lock on files to have only one user working in a file at a time.

With Git, each developer works in his own copy of the project.

No mappings

Before starting to work with a project under TFS, you need some “mappings”. A place where the files in TFS server will be in your computer.

With Git, you can clone and keep a project anywhere in your computer. There’s no such a thing as mappings.

Checking and Pushing

After modifying some files, you want to version control them. With TFS you “check-in” your files. This means, those files are kept in the history of the project and synced with the server.

With Git, you don’t “check-in” your files, you “commit” them. And, your committed files live only in your local copy of the project, until you sync or push them to a server.

Branching

With Git, branches have a new meaning. You could have lots of light-weight and short-lived branches to try things out, solve bugs or do your everyday work. By convention, all Git repositories start with a branch called master.

Starting from Git 2.28, Git will use the configuration value init.defaultBranch to name the default branch. Other alternatives for master are: main, primary or default.

Gitflow, a branching model

Maybe, you have worked with one branch per environment: Dev, QA, Beta and Production. You start every new task directly on the Dev branch.

There is another branch model: Gitflow.

Gitflow suggests that the master branch mirrors the Production environment. The develop branch is where everyday work happens. But, every new task starts in a new branch taken from develop. Once you’re done with your task, you merge this branch back to develop.

In case of bugs or issues in Production, you create a new branch from master. And you merge it back to master and develop once you’re done fixing the issue.

Every release has a separate branch, too. This release branch is also merged to master and develop. For more details, see Introducing GitFlow.

Pull or Merge Requests

Some projects adopt another convention. Nobody pushes or syncs directly to the master or develop branch.

Instead, every new task goes through a code review phase using a pull or merge request. During code review, your code is examined to find bugs and to stick to coding conventions.

A pull or merge request means that “the author of the task asks to merge his changes from a branch into the current codebase”.

Most of the time, this code review is done through a web tool or web interface. After one or two team members review your changes, the same tool will allow the reviewer to merge the changes to the destination branch.

If you're interested in the code review process, check my post on Tips and Tricks for Better Code Reviews. It contains tips for everyone involved in the code review process.

Reference

This is how TFS and Git actions relate to each other.

Changesets = Commits

In TFS, a changeset is a set of changes that have been version-controled and synced to the server.

With Git, you have commits. Your commits can live only on your local copy, until you upload them to a server.

If you want to collaborate with others or host your code somewhere else, you can use a server as a single point of authority.

Have you ever heard about GitHub, GitLab or Bitbucket? These are third-party hosting solutions for Git.

Check-in = Commit + Push

With TFS, you “check-in” your files. But, with Git, from the command line, you need three commands: add, commit and push.

$ git add .
$ git commit -m 'A beatiful commit message'
$ git push origin my-branch

Get latest version = Pull

To get the most recent changes from a server, with TFS, you “get latest version”.

With Git, you need to “pull” from a remote branch on a server. Use git pull origin my-branch.

By convention, the name associated to the sync server is origin. You can add other remotes if needed.

Branch = Branch + Checkout

With TFS, you create a new branch from the source branch using the “Branch” option. If you have a large project, this could take a while.

With Git, you need to create a branch and switch to it. Use the commands: branch and checkout, respectively. But, you can combine these two actions into a single one with checkout and the -b flag.

$ git checkout -b a-new-branch

Shelve = stash

If you want to temporary suspend your work and resume it later, you use a shelve in TFS or an stash with Git.

With Git, to create an stash, use git stash -u. And, git stash apply to bring back your changes.

Integration

Please, do not be afraid of using the command line and memorizing lots of commands. There are Git clients and out-of-the-box integrations (or plugins) for Git in most popular IDE’s. For example, Visual Studio and Visual Studio Code support Git out-of-the-box, and SourceTree is a Git client you can download for free.

Voilà! That’s what makes Git and TFS different. Now you know where your changesets are, how to check-out to files and why you don’t need any mappings with Git.

For a more in-depth guide to Git, read my beginner’s guide to Git and GitHub. If you’re interested in code reviews, check my post on Better Code Reviews.

Happy Git time!

Remote interview: Here I go (interview types and tips)

Are you applying for a remote position? For a on-site position but the interviewer is on another branch outside your city? Are preparing yourself for future interviews? Let’s see 4 types of interview and tips to prepare for them.

There are four types of interviews you can find while applying for a new job.

1. Conversation

In conversational interviews, the interviewer will start a casual conversation about your experience, your past positions and your skills. Be ready to describe one or two past projects.

When describing your projects, make sure to include:

  • Name of the project
  • Purpose and Market
  • Duration: How long did it take to finish it? or how long were you in it?
  • Tech Stack: what frameworks and tools did you use on the front-end and the back-end?
  • Team Size: Did you have a QA team? designers?
  • Role and areas in charge: What did you do inside the project? What were you responsible for?
  • Biggest challenge you faced in the project: a new tech stack? changing requirements? short duration?

2. Interrogation

In interrogational interviews, the interviewer will have a list of predefined questions to test your knowledge on the skills required for the position.

Be ready to answer questions of the type:

3. Programming exercise

In exercise-type interviews, the interviewer will ask you to open a text editor to solve one or two exercises to test algorithms and data structures. Have a development environment ready!

In the past, I’ve been asked to evaluate postfix expressions, solve two-sum problem and shift an array elements to the right.

4. Homework

In homework interviews, the interviewer will ask you to solve a medium-size coding challenge in a couple of hours or even days.

Use Git and write good commit messages. Follow best practices and code as clean as possible! It’s time to show off your coding skills.

Dont’ forget to add a README file to your solution. Include features you implemented, libraries you used, major design decisions you made and how to install your solution.

If you’re asked to solve a coding challenge, check these ten tips to solve your next interview coding challenge. I will give you more tips on naming and documentation.

Tips for your next remote interview
Photo by Daniel McCullough on Unsplash

Before, during and after the interview day

Now you know the interview types, it’s time to move on to the interview preparation.

  1. Check the date and time. Make sure you have the time in your own timezone. Don’t show up the wrong time.
  2. Install and setup the software needed. Is it Skype, Zoom or Hangouts? Did you receive an invitation link? Do you need a password to use the link?
  3. Do not answer the videocall using your cellphone. Do you remember the type of interviews? It isn’t that comfortable to solve an exercise using the phone. You will inspire more trust turning on your camera.
  4. Use video only if the interviewer uses it. Online etiquette.
  5. Reduce background noise. Do not answer the videocall from a cafe, a shopping mall or a public hotspot. If you are staying at home, ask the people around you not to disturb you while in the interview.
  6. Show up 10 minutes earlier. Don’t be late.
  7. Be ready to introduce yourself using an elevator pitch. You will have less than 30 seconds to say who you are and what you have done professionally. Make sure to include in your pitch:
    • Years of experience
    • Education
    • Type of projects you have worked with: banking, marketing, etc
    • Specialty: fullstack, backend, fronted, mobile, etc
    • Languages, frameworks and tools you know
    • A hobby. Be memorable
  8. Be precise. Answer within 60 seconds. Don’t talk too much.
  9. Summarize all your skills and strengths, before finishing the meeting. Give a good last impression.

Final tips

Voila! Now, you know the type of interviews you will find. Be prepared for them! Practice your elevator pitch and your project descriptions. Have a printed copy of them next to you during the interview, in case of panic attack. Be enthusiast and precise.

For more resources on interviews, check these two online resources: 7 Interview Tips That Will Help You Get Hired and 60 seconds and you are hired

This post was inspired by all the tips I have received from colleagues, managers and the Internet while preparing for remote interviews

Happy interviewing!

How to Shift Array Elements in C# (Space Complexity)

Here you are in another interview. You start to feel confident from your last interview. You have already evaluated postfix expressions and solved the two-number sum problem. Now, the interviewer challenges you with a new exercise: How to shift arrays elements to the right. Let’s solve it.

Given an array of integers and an integer k, rotate all elements k positions to the right. For example: After rotating [1,2,3,4,5,6] two positions to the right is [5,6,1,2,3,4]

Obivous solution: loop and bound checking

Your first approach is to roll a loop through the array and put in a second array each element shifted to the right.

You have to take care of elements near the end of the array. Otherwise, you will get outside of the array and an exception will be thrown. So, you add an if to check you keep it inside the bounds.

Something like this:

static int[] Shift(int[] array, int k)
{
    var result = new int[array.Length];
    for (int i = 0; i < array.Length; i++)
    {
      if ((i + k) >= array.Length)
        result[(i + k) - array.Length] = array[i];
      else
        result[i + k] = array[i];
    }
    return result;
}

Modulus operator without bound checking

You can do better. Can you remove the bound checking?–the interviewer says.

Now, you start to use an example. If array=[1,2,3,4,5,6], k=1 and i=5, the last element must be the first one and so on and so forth. It reminds you the modulus operator (%).

The modulus operator, instead of dividing two numbers, calculates the remainder of dividing those two numbers.

Since the remainder is less than the divisor, you will always be inside the size of the array, if you use the modulus with the array length. So, you modify your previous solution.

static int[] Shift(int[] array, int k)
{
    var result = new int[array.Length];
    for (int i = 0; i < array.Length; i++)
    {
      result[(i + k) % array.Length] = array[i];
    }
    return result;
}

What is Space complexity?

What is the space complexity of this solution?–the interviewer asks.

Space complexity is a metric to compare the amount of memory required to run an algorithm in relation to its input size. If the input gets bigger, how much storage the algorithm requires?

Since you are using a temporay array, the storage will be proportional to the size of the array. So, it’s linear!

Right!–the interviewer replies. Can you come up with a constant solution?–he suggests.

You have to get rid of the temporary array! What if you shift one element at a time and the repeat the process as many times as needed? This solution isn’t the most performant, but it uses constant space.

This time you have to shift the array backwards to only keep one element of the array in a temporary variable.

static int[] Shift(int[] array, int k)
{ 
    for (int times = 0; times < k; times++)
    {
      int tmp = array[array.Length - 1];
      for (int i = array.Length - 1; i > 0; i--)
      {
          array[i] = array[i - 1];
      }
      array[0] = tmp;
    }
        
    return array;
}

What about if you would’ve started with a one-line declarative LINQ solution? The interview could go in a different direction?

static int[] Shift(int[] array, int k)
    => array.Skip(array.Length - k)
        .Concat(array.Take(array.Length - k))
        .ToArray();

Voilà! Another happy interview! That’s how to shift the elements of an array and what space complexity is. For more interview preparation posts, check interview types and tips for your next interview and ten tips to solve your next interview coding challenge.

Happy coding!

How to Solve The Two-Sum Problem in C# (Time Complexity)

You nailed it at evaluating postfix expressions. You impressed the interviewer with your solution. Now, you’re asked about the time complexity of finding the sum of two elements in two arrays.

Time complexity is a mechanism to compare the performance of two algorithms as the input size grows. Time complexity measures the number of operations instead of execution time.

Time complexity and Big-O Notation

Well-known algorithms and common patterns of code have already a time complexity associated to it.

For example, performing an assignment or checking if a dictionary contains a key have constant time. It means, it will always take the same amount of operations to check if a dictionary contains a key, not matter the size of the dictionary.

Looping through the elements of an array has linear time. Dealing with matrices using two nested loops has quadratic time. Dividing an array into halves each time has logarithmic time. Do you remember binary search? It has logarithmic time.

Time complexity uses a mathematical notation to describe the complexity of an algorithm, called Big-O notation.

Big-O notation assigns a function to the complexity of an algorithm. Do you remember functions from Math class, right? So, constant time is O(1), linear time is O(n), quadratic time is O(n^2) and logarithmic time is O(logn).

You could use this Big-O cheatsheet to find the complexity and BigO notation of well-know algorithms.

Time complexity: An interview exercise
Photo by Aron Visuals on Unsplash

Remember time complexity measures number of operations, not execution time. An algorithm with smaller number of operations has better time complexity than another one with a larger amount of operations.

Two Sum Problem in C#

The interview goes like this. The interviewer asks you to introduce yourself. You answer using the elevator pitch you prepared. Then, he suggests to start a whiteboard exercise. You open Notepad++, Visual Studio Code or your favorite editor. And, there you go.

Given two array of integers, find a pair of elements, one from each array, that adds up to zero. The size and the order of the elements aren’t specified. They may be sorted or not

First approach: Nested loops

Your first and obvious approach is to roll two loops and check every pair of elements in the two arrays. If the two arrays contain lots of elements, it would be slow. But it will get the task done.

for (int i = 0; i < a.Length; i++)
{
    for (int j = 0; j < b.Length; j++)
    {
        if (a[i] + b[j] == 0)
        {
            Console.WriteLine("Found");
        }
    }
}

The interviewer asks you about the time complexity of this solution. Since, you have to traverse the second array per every element in the first array, you will end up with n x m operations. With n and m the lengths of each array. So, you answer your solution has quadratic time or O(n^2). Right!

Better approach: Dictionary or set

Then, he asks you to do better. He asks for a linear solution.

To have a linear solution, you will have to get rid of traversing the second array. The problem will be solved if you know if any element in the first array has its inverse in the second array.

With a dictionary or a set with the elements of the second array, you can only traverse the first array and check for its inverse in the dictionary. Since, checking if a dictionary or a set contains a key has constant time, you will have a linear solution. It will loop through the first array only once.

var set = new HashSet<int>(b);
for (int i = 0; i < a.Length; i++)
{
    if (set.Contains(-a[i]))
    {
        Console.WriteLine("Found");
    }
}

Voilà! That’s how we can find the sum of two elements in linear time. Another happy interview! This time, you have in your toolbox time complexity. Not only for next interviews, but for everyday programming.

If you’re getting ready for your next interview, check these remote interviews types and tips and follow these ten tips to solve your next interview coding challenge.

Happy coding!