Embracing Innovation and Collaboration
Last month Bitrock had the pleasure of attending the Devoxx UK 2024 conference in London. This incredible event, organised by developers for developers, is renowned for its comprehensive agenda covering a wide range of topics from software development to the latest technological advancements.
This year’s conference featured 170 insightful sessions and 130 high-profile speakers, making it a must-attend event for anyone in the tech industry.
As part of a company committed to fostering innovation, some of our Bitrockers had the opportunity to engage with this dynamic community and learn from industry leaders.
With many talks taking place at the same time, here are some highlights from the talks they enjoyed the most.
Clean Modular Architecture
How many developers don’t know Victor Rentea? One could say very few. Those who know him are surely aware that his talks are a show: but, beyond the show, Victor is a strong advocate of clean code, refactoring, and unit testing. You may be wondering what these three things have to do with application architecture.
Spoiler: they have a lot in common. Warning, those who think automated testing is useless can skip to the next section!
Taking a step back, many developers tend to be cautious when writing new code. Senior developers blame juniors for abstracting code too early, or for over-engineering simple features (K.I.S.S.). Right? Wrong? As always, the answer is “it depends.” If you appreciate automated tests, you surely know the RED-GREEN-REFACTOR cycle made famous by Kent Beck. So, we write new code, exercise it with tests, and then make all the necessary changes since there will be tests to ensure functionality.
Speaking of architecture, the answer here is also “it depends.” A few years ago, monolithic applications were increasingly criticized for being problematic in terms of slowness and scalability, for example. The solution was to use microservices—lightweight, scalable, quick to develop by several small teams, the solution to all problems, right? Not so simple: microservices entail greater complexity in terms of management and orchestration. Companies have noticed this. Some have taken one or more steps back in search of alternatives.
What if one could create a modular monolith? A Modulith.
Nothing new. Nothing unseen before. Just a different way of looking at things. Taking a traditional web application written with Spring, the package structure would look something like this:
This is a functional grouping of the different components. However, if you try to group them by domain, the result might be:
Each of these packages should have the following characteristics:
- business features (user value)
- private implementation (domain model + logic)
- public API
- internal, for other modules (method calls or events)
- external, for other systems (REST, Kafka)
- private database tables
Each of these modules could then be managed by a single team. This structure would allow for the quick extraction of a module if necessary. Earlier, we talked about refactoring; this is refactoring applied to architecture.
We also talked about testing. Ever heard of ArchUnit? It’s a library that can be used to quickly run unit tests on the architecture. The characteristics of the modules described above can be defined using ArchUnit.
Now imagine:
- a single repository
- all teams working on the same repository but each on a dedicated domain/module
- zero integration time (it’s just refactoring of Java code)
- immediate communication between modules
- deployment of a single artifact
- tests that immediately show if a module no longer meets certain characteristics
- in case of necessity, a module can be easily extracted
If it seems very complex to achieve all this, it is not. It just requires the courage to try a different approach. Spring helps with the Spring Modulith project, which already provides all the ideas presented here, especially architectural tests. Implementing the same with other frameworks, such as Quarkus, is not complicated either.
GraalVM and native images
GraalVM and native images in general were the subject of some talks at Devoxx UK in which they tried to explain their pros and cons, some features to take into consideration and some successful use cases.
GraalVM is a high-performance runtime environment that executes applications written in Java, JavaScript, Python, R, Ruby, and other languages. It also includes a Just-In-Time (JIT) compiler to create a native image, a type of executable file that is created by ahead-of-time (AOT) compilation. This means that the code for the application is compiled into machine code before the application is run.
This is a very good choice for serverless functions where the startup time is very important.
Benefits of Combining Native image with Serverless functions are:
- Reduced Cold Starts: native images eliminate the need to launch the JVM, significantly reducing cold start times
- Native images are smaller than their JVM counterparts, leading to lower memory usage and potentially reduced costs
- Since the code is already compiled, execution becomes faster compared to running bytecode through the JVM.
Native images introduce also some limitations when dealing with frameworks and reflection:
- Closed World Assumption: operates under a closed-world assumption, meaning it needs to be explicitly informed about dynamic aspects of your code. This includes reflection, resources, serialization, and dynamic proxies.
- Application Classpath: the application classpath is fixed at build time. You cannot dynamically add or remove classes during runtime in a native image.
- Limited Debugging: debugging native images can be more challenging compared to traditional JVM applications.
- Framework Considerations: some frameworks, like Spring with profile-specific configurations using @Profile, might have limited functionality due to the closed-world assumption.
- 3rd party library: support for native images is not guaranteed
These limitations can impact the flexibility of frameworks when using GraalVM native images. However, there are techniques to mitigate these issues, such as using static reflection or providing explicit configuration for dynamic aspects of your application.
How To Not Strangle Your Coworkers: Resolving Conflict with Collaboration
Devoxx wasn’t only about coding and tech stuff. The conference also had talks on better communication, relationships, and becoming a good mentor. Arthur Doler‘s talk was really interesting. He gave useful tips and talked about the psychology behind dealing with workplace conflict.
Psychological Safety: The Secret Sauce
A key takeaway from Arthur’s talk was the importance of psychological safety, a concept developed by Harvard professor Amy Edmondson. This isn’t just a buzzword; it’s the bedrock of a thriving team. Psychological safety means everyone feels safe to speak up without fear of retribution or embarrassment. Imagine a workplace that encourages open dialogue and constructive conflict where ideas flow freely, mistakes are discussed, and learning is continuous.
Amy Edmondson‘s study on teams of doctors brings this to life. She discovered that teams with higher error rates often had better outcomes because they were more open about mistakes. This culture of transparency led to continuous improvement and outstanding performance. This is a powerful reminder that admitting errors isn’t a sign of weakness.
Emotional Management in Conflict
Arthur dismantled the common misconception that holding back emotions in conflict leads to better outcomes. Contrary to popular belief, it doesn’t help. In fact, it can make things worse. Instead, he urged us to bring emotions to the forefront and discuss them openly (e.g. “this release scares me”). This approach promotes understanding and defuses tension.
What’s Your Confrontational Style?
Exploration of conflict styles was eye-opening – introducing the Dual Concern Model, which maps out five styles based on concern for self and others: avoiding, yielding, fighting, cooperating, and conciliating.
- Avoiding – dodging the issue, hoping it resolves itself
- Yielding – giving in to others to keep the peace
- Fighting – is about winning at all costs
- Cooperating – seeks solutions that benefit everyone
- Conciliating – blends elements of fighting and yielding
Better understanding of these styles can help us identify our own tendencies, and adapt our approach based on the situation and the people involved in the conflict.
Power Moves for Everyone
Even if you’re not in a leadership role, you can make a huge impact. He emphasized that every voice matters. Persistently advocating for positive changes, even if you’re just an individual contributor, can shift team dynamics over time. The key is to remain a member in good standing within the team. Influence works best from within, so stay engaged and connected with your team.
Understanding power dynamics is crucial. Whether you have power or not, recognizing its influence helps you navigate conflicts more effectively. Arthur encouraged us to approach conflicts with curiosity and a collaborative mindset. Often, others will follow your lead when you demonstrate a commitment to mutual understanding.
Focusing on common objectives is essentia even in disagreements. However, it’s also important to pick your battles wisely, prioritizing conflicts that align with your values to ensure your efforts are impactful.
Wrapping up
Arthur Doler’s talk was an excellent reminder that conflict isn’t a villain to vanquish but an ally. By fostering psychological safety, embracing our emotions, and strategically navigating conflict, we can transform the core of our teams in terms of innovation and collaboration. Let’s embrace these insights and create a work environment where every voice is heard, every idea is valued, and every conflict is a little step to better understand each other.
Securing a Supply Chain
Security is an evergreen topic and surely couldn’t be missed at DevoxxUK 24! Security spans a large spectrum of our IT world, and some aspects are more complex than others because they involve more parts of our software. Supply chains are one of them.
A supply chain can be briefly described as a set of dependencies, procedures, tools and people that are needed to develop, build and deploy an application.
One of the first talks was about securing a supply chain, held by Thomas Vitale. The talk was very practical and cited some tools that can be used in each step of the supply chain to make it more secure:
- Source Code: as we may have noticed, git commits lack authentication so anyone can commit as anyone. There are lots of solutions such as gitsign (which supports OpenID) or just git, which allow optionally to sign commits with SSH or GPG.
- Dependency Management: injecting a malicious repository from which to include dependencies can be a way to introduce malicious code in our software. There are very subtle ways that permit this attack by abusing the repository discovery system of our dependency management tools (maven, gradle, etc). A solution to maintain our dependencies clean are SBOMs (Software Bill Of Materials) that can be the input of vulnerability scanners and address integrity issues too. CycloneDX is one of the most used tools for generating SBOMs.
- Build: going native, as mentioned in another chapter of this article, has lots of pros. One that is often overshadowed is that a native binary offers less surface to be attacked. A java jar includes all the dependencies code, even if not used that code is there and if it’s vulnerable code, ready to be exploitable. On the other hand, the native binary is obtained only by compiling the code reachable by your application. Obviously this can’t justify a migration to native, but it’s surely a “nice to have”! Buildpacks it’s a tool that can be used to manage the build of native images.
- Secure Artifacts to deploy: Cosign is a tool that allows to cryptographically sign any of the elements discussed above: SBOM files, images, binaries, etc. By validating these signatures we can be sure that the artifacts deployed is what we built previously and has not been replaced or tampered in any way.
As we can see, there are lots of tools at our disposal. The challenging part is, often, to instill this culture in our day-to-day procedures.
Understanding the Hype Around Rust
Rust has gained popularity for its innovative approach to memory management and its ability to provide both safety and performance. By eliminating common bugs such as null pointer dereferences and data races through its ownership system, Rust ensures memory safety without sacrificing speed. Let’s delve into Rust’s ownership model and some of its key features that make it both a powerful and secure language.
Ownership System
In Rust, each value has a single owner. When the owner goes out of scope, Rust automatically frees the associated memory. This ensures memory safety without a garbage collector.
Here’s a simple example:
In this snippet, s1 and s3 own their values. When these variables go out of scope, Rust frees their memory. If a variable’s ownership is transferred, as with s2, the original variable cannot be used unless the ownership is transferred back or cloned.
Handling References and Borrowing
Rust’s borrowing system allows for references to values without taking ownership. This ensures memory safety while allowing multiple references:
Here, calculate_length borrows s1 without taking ownership, allowing s1 to be used elsewhere.
Other Key Features
UTF-8 Encoded Strings: All strings in Rust are UTF-8 encoded by default, simplifying internationalization.
Enums and Pattern Matching: Rust’s enums can contain data and are used extensively with pattern matching, enabling clear and concise code:
Option and Result Types: Rust replaces nulls with the Option type and exceptions with the Result type, integrating these possibilities into the type system to ensure they are handled properly.
Traits and Structs: Rust uses traits for defining shared behavior and structs for creating complex data types. Traits can be implemented by multiple types, similar to interfaces in other languages.
Rust’s Adoption and Ecosystem
Rust has been the most loved language on Stack Overflow since 2016. It’s being adopted by major companies like Google, Apple, and Amazon, and is now supported in the Linux kernel. Despite its strengths, Rust has some drawbacks, such as a smaller standard library and longer compile times due to extensive safety checks.
Getting Started
For those interested in learning Rust, the official Rust book, available online for free, is an excellent starting point. Online platforms like Exorcism offer practical coding challenges, and joining Rust community Discords can provide additional support and resources.
To cut a long story short, Rust’s ownership system and modern features make it a compelling choice for building safe, efficient, and reliable software. Whether you’re developing web applications, embedded systems, or anything in between, Rust offers powerful tools to help you write high-quality code.
Conclusions
Devoxx UK 2024 was an event not to be missed: a goldmine for anyone wanting to stay at the forefront of technology. Top speakers from around the world delivered insightful talks on the latest advances. But Devoxx UK wasn’t just about lectures! It was a blast – a chance to connect with the UK’s incredible developer community. We look forward to Devoxx UK 2025!
Authors: Cristian Bertuccioli (Senior Software Engineer and Scrum Master Certified); Marco Righi (Scala Developer); Davide Pavan (Software Engineer); Carmelo Calabrò (Senior Developer); Gianluca Cavalli (Software Engineer) @ Bitrock