CV writing tips for Tech Professionals

We are hiring

When it comes to landing your dream job as an engineer in a cold market, a well-crafted CV can make all the difference. Drawing from my experience as a hiring manager for over 100 roles throughout my career at companies such as Twiga, Wasoko, Shara, and currently Meta, I have gained valuable insights into what makes a CV stand out. In this blog post, I will combine my experiences with essential strategies for writing a CV that captures attention and increases your chances of securing an interview.

Prioritize Achievements:

In my experience, prioritizing achievements is crucial. Numbers are particularly powerful in showcasing measurable results and setting goals without sounding self-aggrandizing. Highlight specific accomplishments with quantifiable outcomes, whether it’s exceeding performance targets, reducing project timelines, or driving revenue growth. These numbers provide concrete evidence of your capabilities and showcase your ability to deliver tangible results.

Trim Unnecessary Details:

Keep your CV concise (1 page ideally) and focused on relevant information. For example, while including your educational background is important, prioritize qualifications and experiences that are directly related to the job you are applying for. Minimize extraneous personal details and hobbies unless they significantly contribute to your engineering qualifications.

Also, please don’t put your picture, it’s just a distraction.

Show, Don’t Tell:

Go beyond listing technical skills in your CV. Showcase how you have applied those skills in real-world scenarios. Describe projects where you utilized your skills to solve complex problems or achieve noteworthy outcomes. By providing examples of practical application, you demonstrate your problem-solving abilities and capacity to contribute effectively. You can not achieve the same effect with a list like: MySQL, Python, Java blah blah blah.

Highlight Relevant Soft Skills:

Employers value candidates who possess not only technical skills but also relevant soft skills. Instead of simply stating desirable qualities, provide concrete examples of how you have demonstrated them in a professional setting. Share specific scenarios where your communication skills, teamwork abilities, or adaptability were essential to successful outcomes. These examples provide valuable insights into your fit within the company culture and your potential contributions. For example, did you need to work with stakeholders from different countries? Or launch a project on tight timeline

Remember, point of CV is to get an interview, the point of the interview is to get you the job:
An engaging CV quickly captures the attention of hiring managers. Use bullet points, concise language, and a simple format (only use bold, H2 headers and italics) to make your CV easy to scan. Tailor the content to align with the specific job you are applying for, emphasizing the skills and experiences most relevant to the position. Highlight your ability to align with the company’s goals and contribute to its success to increase your chances of securing an interview.

What is your own experience in writing a CV for engineers? Talk to me on my Twitter @jchex


What is Inversion of control?

Inversion of Control (IoC) is a powerful concept that allows us to decouple the flow of control from the flow of dependency in software systems. By understanding and leveraging IoC, we can achieve more flexible and maintainable code.

It took me a while to understand this concept because I only viewed it from the lens of interfaces as a tool in statically typed languages.

In this article, we’ll explore the problem solved by IoC using a simple example of a login system, and discuss how to separate the concepts of flow of control and flow of dependency for improved code organization.

What does it mean to be Tightly Coupled?

Consider a scenario where we have a basic login system. In this system, we typically have a main file, a database driver, and the actual database. The flow of control occurs when a user logs in and an endpoint is hit, triggering the processing of the login request. The response, using the POST HTTP verb, involves fetching the user’s information from the database and validating it.

In this simple system, the flow of control and the flow of dependency are tightly coupled. The login file, responsible for the flow of control, directly imports and depends on the database driver file. This direct coupling poses challenges when changes to the database or dependencies are required. For instance, if we were to switch from MySQL to Postgres, we would need to modify both the login file and the driver file, introducing unnecessary complexities.

Separating Flow of Control and Dependency with Interfaces

To address the tightly coupled flow of control and dependency, we introduce the concept of interfaces or contracts. Instead of directly importing and depending on specific files, the login file will utilize an interface as a contract for its required functionalities. This way, the flow of control can remain unchanged while the flow of dependency becomes more flexible.

Here’s how the solution unfolds:

1. Defining an Interface:
We create an interface that represents the required functionality for the database driver. This interface acts as a contract that the driver must implement. It defines the methods and behaviors needed by the login file.

interface DatabaseDriver {
function fetchUserDetails(username: string): User;
// Other required methods...

2. Implementing the Interface:
The driver file, responsible for interacting with the actual database, implements the interface defined earlier. It ensures that the required functionality is available to fulfill the contract.

class MySQLDriver implements DatabaseDriver {
function fetchUserDetails(username: string): User {
// Implementation specific to MySQL
// Other methods implementation...

3. Utilizing the Interface:
In the login file, instead of importing the actual driver file, we import the interface or pass it as a parameter. This way, the login file doesn’t depend on the specific implementation but relies on the contract defined by the interface.

function loginUser(driver: DatabaseDriver, username: string, password: string) {
const userDetails = driver.fetchUserDetails(username);
// Validate user details...
// Perform login operations...

While we introduced a simple example of a login system, the principles of IoC and interface-based development apply to more complex scenarios.

Did this help you understand the concept a bit more? Talk to me in the comment section below, or on my twitter @jchex