Categories
Software Technology

A guide to dependency injection in NestJS

Abstract

Dependency injection is one of the most popular patterns in software design. Particularly among developers who adhere to clean code principles. Yet, surprisingly, the differences and relations between the dependency inversion principle, inversion of control, and dependency injection are usually not clearly defined. Therefore, it results in a murky understanding of the subject.

The present blog post aims to clarify the boundaries between these terms. My aim is to present a practical guide on how dependency injection could be implemented and used. By the end of this post, you will know:

  • What is the difference between the dependency inversion principle, inversion of control, and dependency injection?
  • Why is dependency injection useful?
  • What are meta-programming, decorators, and Reflection API?
  • How is dependency injection implemented in NestJS?

Introduction 

Software design is a constantly developing discipline. Despite its tremendous practical implications, we still don’t understand how to differentiate between a great and a terrible code of an application. That seems to be a reason to discuss how to characterize great software code.

One of the most popular opinions claims that your code needs to be clean to be good.  

The mentioned school of thought is particularly dominant among developers using an object-oriented programming paradigm. Therefore, they propose to decompose a part of reality covered by the application into objects defined by classes. Consequently, group them into layers. Traditionally, we have distinguished three layers:

  • User interface (UI);
  • Business logic;
  • Implementation layer (databases, networking, and so on).

Advocates of clean code believe that these layers are not equal and there is a hierarchy among them. Namely, the implementation and UI layers should depend on the business logic. The dependency injection (DI) is a design pattern that helps to achieve this goal.

Before we move forward, we need to make some clarifications. Although we traditionally distinguish three application layers, their number could be greater. “Higher level” layers are more abstract and distant from the input/output operations. 

Let’s meet the dependency inversion principle (DIP)

Clean architecture advocates argue that good software architecture, can be described with the independence of the higher-level layers from the lower-level modules. It is called the dependency inversion principle (DIP). The word “inversion” stems from the inversion of the traditional flow of an application where UI depended on the business logic. In turn, business logic depended on the implementation layer (if three layers were defined). In architecture where software developers adhere to the DIP, the UI and implementation layers depend on the business logic.

A bunch of programming techniques, were invented to achieve DIP. Accordingly, they are referred to together under the umbrella term: inversion of control (IoC). The dependency injection pattern helps to invert the control of the program in object creation. So, IoC is not limited to the DI pattern. Please find below some other use cases of IoC:

  • Changing algorithms for a specific procedure on the fly (strategy pattern), 
  • Updating the object during the runtime (decorator pattern),
  •  Informing subscribed objects about a state change (observer pattern).

The goals and pros of dependency injection

If you use techniques that invert the flow of the application comes with the burden of writing/using additional components. Unfortunately, it increases the cost of maintainability. Indeed, by extending the code base in this manner, we also increase the system’s complexity. As a result, the entry barrier for new developers is higher. That’s why it is worth discussing the potential benefits of IoC and when it makes sense to use it.

To describe the dependency injection, we separate the initialization of the objects the class uses from the class itself.

In other words, we decouple the class configuration from its concern. The class dependencies are usually called – the services. Meanwhile, the class is described – the client.

I assume the DI pattern is based on putting the initialized services as arguments to the client constructor. Yet, other forms of this pattern exist. For example, setter or interface injection. Nevertheless, I’m describing only the most popular constructor injection.

Overall, DI enables applications to become: 

  • More resilient to change. Therefore, if the details of the service change, the client code stays the same. So, dependency injects by code and outside of the client. 
  • More testable.  Injected dependencies could be derided. Finally, it results in a decrease in the cost of writing application tests.

When are these benefits worth the developers’ effort? The answer is simple! When the system is supposed to be long-lived and encompasses a large domain, which results in a complex dependencies graph.

Technical frames of implementing Dependency Injection

First, you should consider and understand the pros and cons of the DI. Does your system is large enough to benefit from this pattern? If so, it’s a good moment to think about implementation. This topic will embark us on a meta-programming journey. Thus, we will see how to create a program scanning the code and then performing on its result.

What do we need to create a framework performing the DI? Let’s list some design points that our specification. 

  • First, we need a place to store the information about the dependencies. This place is usually called the container.
  • Then, our system needs an injector. So, we need to initialize the service and inject the dependency into the client.
  • Next, we need a scanner. The ability to go through all the system modules and put their dependencies into the container is essential. 
  • Finally, we will need a way to annotate classes with metadata. It allows the system to identify which classes should be injected and which are going to be the recipient of the injection.

TypeScript, decorators, and reflection API

Specifically, regarding the general points mentioned above, we should focus on the terms of data structures that could help us to implement the specification. 

Within the TypeScript realm, we could easily use:

  • Reflection API. This API is a collection of tools to handle metadata (e.g., add it, get it, remove it, and so on). 
  • Decorators. These data structures are functions to run during the code analysis. The API can be used to run the reflection. Then, the classes will get annotated with metadata. 

Implementation of dependency injection is NESTJS

That was a long journey! Finally, we collected all the pieces to understand how to implement the dependency injection in one of the most popular NodeJS frameworks – NestJS.

Let’s look at the source code of the framework. Please, check the link: nest/packages/common/decorators/core/. Here, there are two definitions of decorators that interest us.

Both of these files export functions adding metadata to the object. The method is running the defined metadata function from the reflection API. 

In the first case (injectable decorator), we are tagging classes as providers. Consequently, they could be injected by the NestJS dependency injection system. The latter case (inject decorator) is different. We are informing the DI system that it needs to provide a particular constructor parameter from the class.

NestJS is grouping providers and other classes into higher architecture groups called: modules. As you probably have foreseen, we use decorators located in nest/packages/common/decorators/modules, as module.decorator.ts

Similarly to decorators defined above, the meat and potatoes of this code are to export a function that runs reflection API. Also, add meta-data that this class is a module. Inside the module, we need to answer two essential questions. 

  • Which classes are controllers?
  • Which are providers? 

Then DI system can know how to instantiate the dependencies.  

The NestJS adds the metadata that helps to organize the code into logical units:

– Units of injectable providers.

– Parameters of the constructors needed to inject. 

– Modules structuring the dependency graph of the project.

Step by step implementation in NESTJS

How is NestJS using this information? Every NestJS project starts with a more or less similar statement:

const app = await NestFactory.create()

This line runs the create function from the NestFactoryStatic class, which runs the initialize function (among others).

What is the job of the initialize function? 

  • It creates the dependency scanner, which scans modules for dependencies.
  • During the scanForModules, we add modules to the container, which is a Map between a string and a Module.
  • Then, scanModulesForDependencies is run, which in essence is running 4 functions: reflectImports, reflectProviders, reflectControllers, and reflectExports.
  • These functions have a similar goal: get metadata annotated by the decorators and perform specific actions.
  • After, this instanceLoader initializes the dependencies by running the function createInstancesOfDependencies, which creates and loads the proper object.

The described picture is less complex than the complete code of the system. It has to handle edge cases of circular dependencies, exceptions, and so on, yet it conveys the gist of it.  

Conclusion

To summarize, we have embarked on a long journey! First, we learned that classes are grouped into layers. Also, they are not equal. To maintain the proper hierarchy among them, we must invert the control. In other words, we need to standardize the flow of the application.

In the case of object creation, we can invert the control by using the dependency injection system. A great example is NestJS. Here, the system works by utilizing decorators and reflection API. Therefore, it enables to transformation metaprogramming in TypeScript.

Briefly all this jazz is worth the effort for complex and long-lived applications.

References 

Categories
Software Technology

Micronaut vs SpringBoot: which one is better?

Some time ago, I attended the Devoxx Conference in Kraków, the biggest Java conference in Poland. I searched for inspiration and wanted to hear about the newest trends in the industry. Among many great lectures, one topic left me with a feeling that I should give it more attention – the Micronaut framework and GraalVM native image.

Conference specification

Conference speeches are time limited so they usually don’t give you a ready solution which you can just grab and use in your projects. They show you only some aspects, highlighting the best features. A closer look and a real-life application is necessary if you want to actually use it. The most popular framework for creating Java applications is currently Spring with Spring Boot. It is very powerful and easy to start using it. Many features work out of the box and you can start a local development with just adding a single dependency to the application.

However, Spring heavily depends on reflection and proxy objects. For this reason, Spring Boot applications need some time to start. On the other hand, Micronaut is designed to use AOT (Ahead Of Time) compilation and avoid reflection. It should make it easier to use GraalVM and native image. We may ask a question if startup time is really important for Java applications. The answer is not very obvious. If we have an application running all the time, the startup time is not crucial.

The situation changes on Serverless environments, where applications are started to handle the incoming request and closed afterwards. Our application may prepare a response within milliseconds but if it needs a couple of seconds to start, it may become a serious problem if we are billed for each minute of running our application.

Applications used for testing

To make a comparison, I decided to write two simple CRUD applications (CRUD stands for Create, Retrieve, Update, Delete and represents the set of most common actions on various entities). 

One application was created using Spring Boot 2.7.1, the second one using Micronaut Framework 3.5.3. Both used Java 17 and Gradle as a build tool. I wanted to compare the following aspects:

  • application startup time;
  • how easy is to write the application;
  • how easy is to test the application;
  • how easy is to prepare the native image.

To look more like a real application, I defined three entities: Order, Buyer, and Product.

Example: 3 entities of model application

Each entity is persisted in a database, has its own business logic and is exposed through REST API. As a result each application has 9 beans (3 REST controllers, 3 domain services and 3 database repositories).

Example entity structure

Startup time and memory consumption

* all measurements done on MacBook Air M1

We can see that even without GraalVM, Micronaut gets better startup times and less memory consumption. Combining the applications with GraalVM gets a huge performance boost. In both scenarios Micronaut gives us better numbers.

Micronaut from the Spring developer perspective

I work with Spring on a daily basis. When I thought about writing a new application, the Spring Boot was my first choice. When I heard about Micronaut for the first time I was afraid that I would need to learn everything from scratch and writing applications wouldn’t be as easy as using Spring. Now, I can confidently say that the use of Micronaut is just as easy as writing a Spring Boot application.

Production code

Here we have mainly similarities:

  • Both have a nice starting page (https://start.spring.io/ and https://micronaut.io/launch/) where you can choose the basic configuration (Java version, built tool, testing framework) , add some dependencies and generate a project. Both are well integrated with IntelliJ IDEA.
Spring perspective
Micronaut perspective
  • Database entities and domain classes are just identical
  • DB repositories also looks identical – the only difference is in the imports
package eu.espeo.springdemo.db;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

import org.springframework.data.repository.CrudRepository;
import
org.springframework.stereotype.Repository;


@Repository
public interface ProductRepository extends CrudRepository<Product,Integer> {
  @Override
  List<Product> findAll();

  Optional<Product> findByBusinessId(UUID businessId);

  void deleteByBusinessId(UUID businessId);
}
package eu.espeo.micronautdemo.db;

import java.util.List;
import java.util.Optional;
import java.util.UUID;


import io.micronaut.data.annotation.Repository;
import io.micronaut.data.repository.CrudRepository
;

@Repository
public interface ProductRepository extends CrudRepository<Product,Integer> {
  @Override
  List<Product> findAll();

  Optional<Product> findByBusinessId(UUID businessId);

  void deleteByBusinessId(UUID businessId);
}
  • REST controllers are very similar
package eu.espeo.springdemo.rest;

import static java.util.stream.Collectors.toList;

import java.util.List;
import java.util.UUID;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


import eu.espeo.springdemo.domain.ProductService;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping(value = “/products”, produces = MediaType.APPLICATION_JSON_VALUE)

@RequiredArgsConstructor
public class ProductController {

  private final ProductService productService;

  @GetMapping
  public List<ProductDto> listProducts() {
    return productService.findAll().stream()
          .map(ProductDto::fromProduct)
          .collect(toList());
  }

  @GetMapping(value = “/{productId}”)
  public ProductDto getProduct(@PathVariable(“productId”) String productId) {
    return ProductDto.fromProduct(productService.findByBusinessId(UUID.fromString(productId)));
  }

  (…}
}

package eu.espeo.micronautdemo.rest;

import static java.util.stream.Collectors.toList;

import java.util.List;
import java.util.UUID;

import eu.espeo.micronautdemo.domain.ProductService;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Delete;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.http.annotation.Post;

import lombok.RequiredArgsConstructor;

@Controller(value = “/products”, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
@RequiredArgsConstructor
public class ProductController {

  private final ProductService productService;

  @Get
  public List<ProductDto> listProducts() {
    return productService.findAll().stream()
        .map(ProductDto::fromProduct)
        .collect(toList());
  }

 @Get(value = “/{productId}”)
  public ProductDto getProduct(@PathVariable(“productId”) String productId) {
    return ProductDto.fromProduct(productService.findByBusinessId(UUID.fromString(productId)));
  }

  (…)
}










,

Basically that’s it. There are no other differences in production code. 

The advantage of Micronaut

However, there is one big advantage of Micronaut. It checks many things at compile time instead of at runtime. Let’s see the following repository method: findByName. We used the wrong return type because we return String instead of Product. How will both frameworks behave?

package eu.espeo.micronautdemo.db;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

import io.micronaut.data.annotation.Repository;
import io.micronaut.data.repository.CrudRepository;

@Repository
public interface ProductRepository extends CrudRepository<Product,Integer> {
(…)
String findByName(String name);
}

Micronaut will fail during project compilation with the following failure:

error: Unable to implement Repository method: ProductRepository.findByName(String name). Query results in a type [eu.espeo.micronautdemo.db.Product] whilst method returns an incompatible type: java.lang.String

String findByName(String name);

Very clear. And how about Spring? It will compile successfully and everything will be fine until we try to call this method:

java.lang.ClassCastException: class eu.espeo.springdemo.db.Product cannot be cast to class java.lang.String (eu.espeo.springdemo.db.Product is in unnamed module of loader ‘app’; java.lang.String is in module java.base of loader ‘bootstrap’)

Let’s hope everyone writes tests. Otherwise such an error will be thrown on production.

Spring Boot vs Micronaut 0:1

Test code for the REST controller

For Spring we can write:

  • An integration @SpringBootTest with TestRestTemplate injected. This test starts the Web server. We can easily send some requests to our application.
  • An integration @SpringBootTest using MockMvc. This test doesn’t start the Web server so it is faster, but sending requests and parsing responses are not as easy as when using TestRestTemplate.
  • For more specific scenarios you can mock some classes using @MockBean annotation.

For Micronaut you can write:

  • An integration @MicronautTest with HttpClient injected. This test starts the Netty server. As easy to use as SpringBoot test with TestRestTemplate.
  • For more specific scenarios you can mock some classes using @MockBean annotation.
package eu.espeo.springdemo.rest;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;

import java.math.BigDecimal;
import java.util.UUID;

import static org.assertj.core.api.BDDAssertions.then;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ProductControllerWebIntegrationTest {

  @LocalServerPort
  private int port;

  @Autowired
  private TestRestTemplate restTemplate;


  @Test
  void shouldSaveAndRetrieveProduct() {
    // given
    var productBusinessId = UUID.randomUUID();
    var productName = “Apple MacBook”;
    var price = BigDecimal.valueOf(11499.90);

    // when
    var createResponse = restTemplate
        .postForEntity(“http://localhost:” + port + “/products”,
            new ProductDto(productBusinessId, productName, price), ProductDto.class)
;
    then(createResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
    var product = restTemplate.getForObject(
        “http://localhost:” + port + “/products/” + productBusinessId, ProductDto.class);
;

    // then
    then(product).isNotNull();
    then(product.businessId()).isEqualTo(productBusinessId);
    then(product.name()).isEqualTo(productName);
    then(product.price()).isEqualByComparingTo(price);
  }
}


package eu.espeo.micronautdemo.rest;

import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.UUID;

import static org.assertj.core.api.BDDAssertions.then;

@MicronautTest
class ProductControllerWebIntegrationTest {

  @Inject
  @Client(“/”)
  private HttpClient client;


  @Test
  void shouldSaveAndRetrieveProduct() {
    // given
    var productBusinessId = UUID.randomUUID();
    var productName = “Apple MacBook”;
    var price = BigDecimal.valueOf(11499.90);

    // when
    var createResponse = client.toBlocking()
        .exchange(HttpRequest.POST(“/products”, new ProductDto(productBusinessId, productName, price)))
;
    then((CharSequence) createResponse.getStatus()).isEqualTo(HttpStatus.OK);
    var product = client.toBlocking()
        .retrieve(HttpRequest.GET(“/products/” + productBusinessId), ProductDto.class)
;

    // then
    then(product).isNotNull();
    then(product.businessId()).isEqualTo(productBusinessId);
    then(product.name()).isEqualTo(productName);
    then(product.price()).isEqualByComparingTo(price);
  }
}








,

Generally, there is no big difference. Good thing for Micronaut is that it provides the default configuration of a database using TestContainers, so we can just start writing tests and everything should just work. On the other hand, Spring provides no test configuration so we need to remember to configure a database. This gives us a slight advantage over Spring Boot.

Spring Boot vs Micronaut 0:2

Native image (GraalVM)

Both frameworks support compilation to a native image. We can produce either a native application or a docker image containing a native application. Micronaut already uses AOT compilation so creation of native image should be easier. To be able to do it, I needed only 3 steps:

  • install GraalVM (if not already installed) and native-image tool
    • sdk install java 22.1.0.r17-grl
    • gu install native-image
  • Add Gradle dependency
    • compileOnly(“org.graalvm.nativeimage:svm”)
  • Annotate DTO classes used by REST API with @Introspected to generate BeanIntrospection metadata at compilation time. This information can be used, for example, to render the POJO as JSON using Jackson without using reflection.
package eu.espeo.micronautdemo.rest;

import java.math.BigDecimal;
import java.util.UUID;

import eu.espeo.micronautdemo.domain.Product;
import io.micronaut.core.annotation.Introspected;

@Introspected

public record ProductDto(
UUID businessId,
String name,
BigDecimal price
) {
(…some methods mapping DTO to domain model…)
}

That’s it. Now you can just execute ./gradlew nativeCompile (to build just an application) or ./gradlew dockerBuildNative (to build a Docker image – but currently it does not work on Macs with M1 chip), wait a couple of minutes (native compilation takes longer than standard build) and here you go.

I was really curious if Spring Boot applications will be as easy to convert as Micronaut applications. There is a spring-native project which has currently a beta support (it means that breaking changes may happen). The changes I needed to make was slightly different but still not complicated:

  • install GraalVM (if not already installed) and native-image tool
  • add a Spring AOT Gradle plugin
    • id ‘org.springframework.experimental.aot’ version ‘0.12.1’
  • add a spring-native dependency (but when using Gradle you can skip it because Spring AOT plugin will add this dependency automatically)
  • configure the build to use the release repository of spring-native (both for dependencies and plugins)
    • maven { url ‘https://repo.spring.io/release’ }

Now you can just execute ./gradlew nativeCompile (to build just an application) or ./gradlew bootBuildImage (to build a Docker image – but for some reason the process is stuck on my Mac with M1 chip), wait a couple of minutes (native compilation takes longer than standard build) and here you go.

As we can see, both frameworks compile well to the native image and both have some problems with generating Docker images on M1 Macs 🙂 None of them is perfect yet.

Spring Boot vs Micronaut 1:3

Summary

It’s great to have a choice. My test confirmed that Micronaut can be a good alternative to Spring Boot. It has some advantages but Spring is still very strong. I will keep an eye on both.

Categories
Entrepreneurship Software

The future of staff development. Business benefits of developing the staff’s soft skills

Soft skills are becoming increasingly important within the future looking companies around the world. Why is that? In what ways does developing the soft skills of employees benefit the organization? In the article below, I’ll try to answer these questions while giving a detailed insight into soft skills and emotional intelligence.

Finding my calling. How did I become a Chief of Staff

My background is quite unusual for a Chief of Staff. I come from an academic environment with which I have been bound for a few years after my initial studies. During my doctorate, I decided I wanted to gain new experiences and skills. This is when I joined Espeo Software. After around 3 years in the company, my focus pivoted towards people in the organization.

I took up Business Psychology studies at the SWPS university in Poznań during which I could broaden my knowledge in terms of internal communication. Alongside the SWPS studies, I also took a coaching course in IBD Business School Warsaw and graduated from the School of Transactional Analysis in Poznań. I gained a great deal of insight into healthy communication methods as a result of this experience. People usually communicate with each other on a subconscious level and not on a conscious one. As a result, in stressful situations, people usually fall into patterns (by taking on the role of either a parent or a child). During my studies, I learned how to communicate from an adult’s perspective and how to help others do the same.

Communicating efficiently requires letting go of unproductive subconscious patterns. Managers can easily assume the role of parents in a company environment, while employees can easily assume the role of children. Taking this approach leads you out of the professional realm and into the emotional one, which isn’t recommended in a work setting.

After a couple of years at Espeo, I got offered the role of the Chief of Staff. This has been a natural progression for me as I have already been doing more than Office Manager and with my experience and knowledge, I was qualified to take over the internal communication of the organization. Working closely with people is something I have always been passionate about, which is why I enjoy being a liaison between various departments and integrating internal processes. After I took up my current role, I started MBA studies in order to embed my soft skills in the demanding business setting. Since graduating in March this year, I have been applying the knowledge and experience I gained while studying over the last 1,5 years to my daily work.

My work gives me a lot of satisfaction, however, it doesn’t come without its challenges. When it comes to communicating, it is necessary to remember that every employee in a company is unique. As such, the messages that are shared with them must be tailored to their individual needs. Additionally, there are times when I have to stop internal initiatives if they are not supporting the company’s business strategy. All internal actions should have their justification and be embedded in the quarterly company goals. It is only this way that a coherent business development plan can be achieved.

The areas of soft skills development. Why is this topic important?

There are a couple of important areas when it comes to soft skills development, especially in the IT industry. First of all, software house employees very often are points of contact with clients. As a result, each employee has a direct impact on the company image that is communicated to the client. In general, communication while working on software development is crucial. All team members should know how to form their messages in a polite, respectful way. Such messages are categorized as open messages.

Often, however, technical experts form their messages in a closed manner, leaving little room for questions or discussion. If the interlocutor on the client’s side happens to be compliant with such communication, they might feel overwhelmed. Efficient communication is also key within the teams. The structure of software houses requires a great deal of cooperation between different departments. It’s important to adjust the level of a statement according to the person you’re talking to to ensure that everyone is on the same page. Here, showing the employees that their messages can be received differently depending on the recipient is crucial both in internal and external communication.

Secondly, IT requires a high level of problem-solving skills. While developing software, problems occur frequently. Therefore, a problem solving attitude should be cultivated among the employees. Only then can a great digital product be delivered. The ability to organize work efficiently is another soft skill that is required in a modern business (time and material), especially while working with external partners. Since people are not lonely islands, the skill to work with others is also quite major and should be continuously developed in the organization. The reason for this is that teamwork involves not only cooperation on a project but also sharing knowledge, developing competencies and skills between its members, and being able to replace each other. Last but not least, emotional intelligence is a soft skill that is extremely important from a manager’s perspective but is often overlooked.

The ability to empathize with people with whom you work with is crucial in order to develop yourself in the role of a manager. Personally, emotional intelligence is the reason why I am where I am professionally. As with anything, moderation is key – it’s not appropriate to be over-exuberant in the workplace. That being said, empathy is helpful not only in a day-to-day job but also in negotiating, establishing partnerships, or recognizing the intentions of subcontractors and partners.

The future of staff development. Business benefits of developing the staff's soft skills

The business benefits of developing the staff’s soft skills

There are many business objectives for which the companies should focus on developing their staff’s soft skills. In the first place, every employee is a representative of the company in some way. After all, it is the staff’s behavior that demonstrates the company culture while working with clients or external partners. Thus, it is crucial that that behavior be enriched with high soft skills and respect, as well as strong negotiation skills. Only then can the employee be a valuable representative of the brand. In our industry, technical experts usually focus on developing their tech skills. However, because of the value that soft skills bring, any organization should encourage the development especially of the soft competences among its employees.

Developing soft skills plays a vital role in maintaining high company culture and communication flow. It is especially valuable in the IT industry, where the success of the projects depends on effective cooperation between team members. In the end, eliminating communication barriers can help avoid issues that may arise during software production. At Espeo, we happen to work with people who have both extraordinary interpersonal and technical skills. Some of these people became mentors in our latest edition of Espeo Junior Academy. The mentor role required impeccable soft skills as well as vast technical experience.

High interpersonal skills have an impact on the general growth of the business as well. When technical experts have great soft skills, they are more likely to increase the clients’ trust and satisfaction, which leads to the acquisition of new projects or the extension of existing collaborations. The development of soft skills can also lead to reduced employee turnover as the bond between team members is stronger.

The current situation and trends of staff development across different organizations

From my perspective, the focus on staff development can be especially observed in the IT and creative industry. Particularly in software houses such as Espeo or digital agencies where the employee is in the company center and where the HR departments care about the staff’s satisfaction. Currently, a big trend for companies like these is to offer e.g. sponsoring personality tests in addition to organizing other actions to develop the staff’s soft skills.

Those employed by public companies, on the other hand, don’t have access to such commodities – there, the development of soft skills and employee benefits are very often left unconsidered.

So what will the development of soft skills look like in the future? Will more companies see its benefits and decide to invest in it?

The popularity of developing soft skills will continue to grow among future-looking organizations. However, the growth won’t be as significant in companies where the organizational culture is low and where there is not an individual approach towards the employees. The last two years of the employee market showed how important building the compatibility between the organizational culture and its external image is. Applicants were equally concerned about the culture of the company as about the job responsibilities. As a result, companies that failed to deliver what they promised lost a lot of external credibility.

What is more, I predict that in five to ten years the soft skills (such as flexibility, problem solving and sensing the needs of team members and business partners) will be on par with technical skills. Companies that will understand the need to develop those skills will thrive, whereas businesses that won’t, will become less competitive.

In general, companies will put even a greater focus on aligning the cultural fit of candidates before starting the cooperation. Departments such as Human Resources will likely draw more and more from the psychology field to improve the recruitment processes and the day-to-day work. Initiatives like Employee Advocacy will gain more traction within businesses.

Sign up for our newsletter to be the first to receive news about the FutureTalk series and other valuable materials.

Categories
Entrepreneurship Software

Espeo Junior Academy: insights from the people behind its success

One of the main goals of cooperation with our clients is to always provide the best and the most experienced developer teams for the purpose of delivering high-quality solutions and results. However, while building the teams, we don’t only focus on high technical skills.

At Espeo Software, we know that well-developed soft skills are on par with technical excellence in a software development process.

Consequently, Espeo Junior Academy is designed to strengthen both technical and soft skills of academics and young professionals who wish to develop their careers with us. At the end of Espeo Junior Academy, its graduates will be well-prepared, experienced and independent developers, ready to join commercial projects.

A strong focus on the learning and development process. Julia Kachlicka, the L&D Coordinator

While structuring the Academy, we firstly designed its learning and development process. Junior developers are given new challenges, encouraged to learn, find new solutions, and test their ideas. On one hand, each of them has support from an experienced Mentor and the possibility to discuss issues. On the other hand, they receive feedback about their technical and soft skills, which enables them to improve their skills constantly. Moreover, junior developers gain real life experiences. As part of the Academy, they take part in an international, non-profit project in cooperation with a Norwegian foundation The Human Aspect. Our team is responsible for developing The Human Aspect’s platform and building a new one from scratch – a platform supporting the mental-health of refugees and people helping them.

Finding a tech partner that connects with our vision and shows true passion to join us in building it. Jimmy Westerheim, CEO and Founder of The Human Aspect

We are a foundation that has a global vision and felt that involving an external software house would help challenge us to have an even better result. Especially the engagement Espeo offered into this partnership with a combination of junior devs, senior mentors, and sr. capacity made us confident it would help us to reach the best product.

For us, the most significant thing is that our partner connects with our vision and shows true passion to join us in building it. Secondly, it is essential to any cooperation that the communication is open, clear, and constructive. Thirdly, the technical and soft skill competency is essential to ensure a professional and fruitful cooperation where synergies are achieved to the best result.

In terms of the junior developers, our expectations were overshot by a mile! Their skills, engagement, ability to challenge us, but also learn and commit to the vision fast impressed us. We all brought our full heart into this project and felt the junior developers did the same, to join us in what feels like a dream team. Together, we have already created something meaningful to the world, and we look forward to creating even more.

“We are working on transforming our current simple video library into an interactive tool including several types of resources. The video library called “The Life Experience Library” is already the largest free digital resources within mental health in the world. With this upgrade, it will be able to give the users around the world a much more therapeutic and useful experience.”

Jimmy Westerheim, The Human Aspect’s Founder & CEO

Making sure all client and technical requirements are met. Adrian Warkocz, Tech Lead

In the project, I am responsible for technical support for the team, code reviews, and recommending as well as discussing the best solutions and technical aspects of the development process. The main technologies used in the projects are React, Next, Typescript, Scss. Basically, Typescript is used in every project realized by Espeo Software. Scss and Next were technologies recommended by the client. However, using React wasn’t an obvious decision. At the beginning of the project, the client asked about recommended frontend technology. Our recommendation was React as the most popular and developed technology in advanced frontend development. Therefore, the client decided to rewrite the existing platform from Vue to React. It has begun the first stage of our cooperation.

Developing the soft skills of the Academy’s participants to fit modern software development. Jacek Malinowski, Delivery Manager

As a Delivery Manager in The Human Aspect project, I manage the team, solve problems and coach the participants of the Academy. My responsibilities include being a proxy between the team and the client, maintaining high communication quality, and transparency.

When it comes to project management in this case, we are using Kanban. It allows us to be more agile and focus more on keeping team skills in the upraise trend. What is more, thanks to Kanban, we are focused more on product and development than on process. I am an Agile Leader. I am transparent, open and client-oriented. Furthermore, I am showing direction rather than micromanage.

I am trying to implement and maintain a good vibe in the team and show them the best practices. In that case, We have great cooperation between Espeo and The Human Aspect. Likewise, we are aware of The Human Aspect’s needs, and they are aware of ours. Our main goal is to help people, create great products, and develop our team. Both The Human Aspect and Espeo Software are fully transparent, which allows our cooperation to flourish.

Read also: Espeo Junior Academy. Our solution to the developer shortage