The intersection of technology and leadership

Category: Development (Page 1 of 18)

Using different SSH keys for different hosts

When I’m setting up a new computer, one of the tasks I need to do is set up new SSH keys to access different servers. It’s good practice not to use the same key for different services. Keys are useful so you don’t need to type your credentials in all the time when working on a trusted PC.

Instead of typing something like: ssh thekua@github.com I can just simply type ssh github without being prompted for credentials. Less typing. Win!

After you generate several different keys, you can either add them to the command line when using ssh, but it’s easier just to use the config file (typically found at ~/.ssh/config).

Here’s an example config file you might have assuming you have three different projects:

Host github
    HostName github.com
    User git
    AddKeysToAgent yes
    UseKeychain yes
    IdentityFile ~/.ssh/github_rsa
Host gitlab
    HostName gitlab.com
    User git
    AddKeysToAgent yes
    UseKeychain yes
    IdentityFile ~/.ssh/gitlab_rsa
Host ossproject
    Hostname myossproject.someserver.com
    User thekua
    AddKeysToAgent yes
    UseKeychain yes
    IdentityFile ~/.ssh/myossprojectcreds_rsa

If you have properly installed all of your public keys on the appropriate server, then you should now be able to use the following commands:

ssh github
ssh gitlab
ssh ossproject

Each of these will use different credentials and not know about each other – w00t!

The Trident Model of Career Development

Careers ladders are all the rage in software firms. They create structure and shared expectations around different levels. Like any model, career ladders have pros and cons. Career ladders are a starting point for shared expectations across an organisation. However career ladders cannot be comprehensive, as people are unique, like snowflakes. People bring their different strengths and experiences to what they do. Everyone will do this differently. As a result, I like to explain that levels in a career ladder do not represent a checklist. Rather, levels reflect how people can have a different impact in an organisation in different ways.

In my most recent talk, “Talking with Tech Leads,” I explain how, some companies have a two-track career model. Two tracks are great, as they allow for more development and growth in different areas. Most of the research I did seemed to focus on two main tracks. In Silicon Valley they refer to these as Individual Contributor (IC) and Management tracks. I actually don’t think a two-track ladder is enough. This is why I present you the Trident Career Model below.

The Trident Model of Career Development

The Trident Career Model has three tracks. Each track represents where people spend most of their time or energy.

The Management Track

In this track, people spend a majority of their time (70-80%) on management activities. This still includes leading people, supporting people, managing structures & processes and organising. People in this track must still have some background in the topic they are managing.

Most importantly, their main value add is not necessarily through making decisions related to the specialist field (e.g. system architecture). Instead, they manage the surrounding system & structure to ensure people closest to the work have the best context and information to make better decisions. They provide enough support, time and/or budget to enable others to do what they do best.

Example roles in this track: Engineering Manager, VP Engineering, IT Manager

The Technical Leadership Track

In this track, people spend a majority of their time (70-80%) leading people on a technical topic. People in this track must have relevant hands-on technical skills and experience. They should have good but not necessarily the best skills in the team they are leading. People in this track draw heavily on refined leadership skills to be successful. Classic activities for this role (in the field of software) include:

  • Establishing a Technical Vision
  • Managing technical risks
  • Clarifying/uncovering technical requirements
  • Ensuring non-technical stakeholders understand technical constraints, trade-offs or important decisions
  • Growing technical knowledge and cultivating knowledge sharing in and across teams

Example roles in this track: Lead Developer, Tech Lead, Principal Engineer, Software Architect

The True Individual Contributor (IC) Track

In this track, people spend a majority of they time (70-80%) focused on “Executing/Doing”. Software engineers early in their career reflect this very well. This track still requires people to have excellent communication and collaboration skills. People in this track have impact through the deep/detailed knowledge or skills they offer. Most small companies do not need a deep IC track, as there is no need for specialisation. As an organisation grows, they may need more of these roles. The number of these roles will always be smaller than the other two tracks in a well-functioning organisation.

Example roles in this track: DB Specialist, Performing Tuning Specialist, Domain Specialist.

Conclusion

This model is indeed a simplification. In real life, the Management and the Technical Leadership tracks are not always so clearly separate. I know some companies where Engineering Managers also take Technical Leadership responsibilities, or where Tech Leads or Lead Developers are also expected to take on Management responsibilities. This is not necessarily wrong.

I have personally found that, at scale, it is often hard to find people who have deep skills and experiences at both of these areas, and that it can be useful to have a discussion around where someone’s focus, passion or development progression lies.

As the famous quote goes:

All models are wrong, some are useful.

George EP Box

I have found this Trident Model a useful starting point to contrast differences in roles or expectations. Considering using this model:

  • To develop skills in an area you may want to work
  • When building out your own company’s Career Ladder
  • To explain differences/focuses on existing roles and responsibilities

Looking for an example of this in the wild? This post, Engineering Levels at Carta, isn’t as visually deliberate, but points out “Senior software engineer II (L5) is the second of Carta’s two senior levels, our first terminal level.” This is made more explicit in this post about Staff Engineering at Carta, which says, “For those who wish to pursue it, our first level beyond “senior” and into focused technical leadership is staff engineer.”

I hope you found this post interesting. Please leave a comment about your thoughts of the Trident Model of Career Development.

Learning about More with LeSS

Background

I took part in a three day course before Christmas to better understand Large Scale Scrum (LeSS). LeSS’ tagline is “More with LeSS”. I’m pessimistic about most “Scaling Agile Frameworks.” Many give organisations an excuse to relabel their existing practices as “agile.” Not to fundamentally change them. Bas Vodde (one of the founders of LeSS’) invited me to take part in a course just before Christmas. I took him up on the offer to hear it “From the horse’s mouth.”

This article summarises my notes, learnings and reflections from the three day course. There may be errors and would encourage you to read about it yourself on their LeSS website, or post a comment at the end of this article.

About the Trainer

I met Bas Vodde about a decade ago. We met at one of the Retrospective Facilitator’s gathering. He is someone who, I believe, lives the agile values and principles and has been in the community for a long time. He still writes code, pair programming with teams he works with. He has had a long and successful coaching history with many companies. He worked with huge organisations where many people build a single product together. Think of a telecommunications product, for example. Through his shared experiences with his co-founder, Craig Larman, they distilled these ideas into what is now called LeSS.

What I understood about LeSS?

LeSS evolved from using basic Scrum in a context with many many teams. I took away there are three common uses of the term LeSS.

  • LeSS (The Complete Picture) – The overview of LeSS including the experimental mindset, guides, rules/framework, and principles. See the the main website, Less.
  • LeSS (The Rules/Framework) – The specifics of how you operate LeSS. See LeSS Rules (April 2018).
  • LeSS (for 2-8 teams) – Basic LeSS is abbreviated to LeSS and is optimised for 2-8 teams. They have LeSS Huge for 8+ teams, and modifications to the rules. See LeSS Huge.

Practices & Rituals in LeSS

LeSS has a number of practices and rituals as part of its starting set of rules. Some of these include:

  • A single prioritised Backlog – All teams share a single backlog with a priority managed by the Product Owner.
  • Sprint Planning 1 – At the end of this, teams have picked which Backlog Items they work on during a sprint.
  • Sprint Planning 2 – All teams do this separately. Like in Scrum, Sprint Planning 2 focuses on the design and creation of tasks for their Sprint.
  • Daily Scrum – Each team runs their own Daily scrum as per standard Scrum.
  • Backlog Refinement – Teams clarify what customers/stakeholders need. Good outcomes include Backlog Items refined into sizes where teams can take 4/5 into a Sprint. LeSS encourages groups, made up of different team members, to refine Backlog Items. This maximises knowledge sharing, learning and opportunities to collaborate.
  • Sprint Review – Teams showcase their work to customers/stakeholders for feedback. The Product Owner works to gather feedback and reflect this in the overall Backlog. Sprint Reviews should not be treated as an approval gate. It’s about getting more input or ideas.
  • Sprint Retrospective – Each team runs their own retrospective. As per standard Scrum.
  • Overall Retrospective – Members from every team plus management hold a retrospective. This retrospective focuses on the system and improving the overall system.
  • Shared Definition of Done – All teams share an overall Definition of Done, which they can also update. Teams can build on the basis of the shared Definition of Done.
  • Sprint – There is only one sprint in LeSS, so by definition all teams synchronise on the same sprint cadence.

Roles in LeSS

  • Scrum Master – Like in Scrum, LeSS has the Scrum Master whose goal is to coach, enable and help LeSS run effectively. The Scrum Master is a full time role up of up to 3 teams.
  • Product Owner – The Product Owner is the role responsibility for the overall Backlog prioritisation
  • Area Product Owner – In LeSS (Huge), Area Product Owners manage the priority of a subsection of the Backlog. They also align with the Product Owner on overall priorities.
  • Team – There are no explicit specialist roles in LeSS, other than the team (and its members).

Principles of LeSS

A key part of LeSS is the principles that guide decisions and behaviours in the organisation. People can make better decisions when taking these principles into account. You can read more about LeSS’ principles here. Like many other agile ways of working, Transparency is a key principle. Unlike other agile methods, LeSS calls upon both System Thinking and Queuing Theory as principles. Both are useful bodies of knowledge that create more effective organisations.

Another explicit difference is the principle of the Whole Product Focus. This reminds me very much of Lean Software Development’s Optimise the Whole principle. I also like very much the description of More with LeSS principle. This principle challenges adding more roles, rules and artefacts. So think carefully about these!

Overall observations

  • In LeSS, having LeSS specialisations is a good thing. This encourages more distributed knowledge sharing.
  • LeSS explicitly priorities feature teams over component teams to maximise the delivery of end to end value. Both have trade-offs.
  • LeSS doesn’t explicitly include technical practices in it’s rules. It assumes organisations adopt modern engineering practices. To quote their website, “Organizational Agility is constrained by Technical Agility.”
  • A lot of LeSS has big implications about organisational design. Agile teams showed how cross-functional teams reduce waste by removing hand-off. LeSS will be even more demanding on organisations and their structure.

LeSS Huge

The creators of LeSS made LeSS Huge because they found a Product Owner was often a constraint. Since Product Owner’s focus on prioritisation, it’s hard to keep an overview and manage the priority of 100+ Backlog Items. (Note that teams still do the clarification, not the Product Owner). With 8+ teams, they found even good Product Owners could not keep on top of the ~100+ refined Backlog Items (which normally covers the next 3+ sprints).

LeSS Huge addresses this by introducing Categories (aka an Area). Each Backlog Item has its own category, and each category then has an Area Product Owner to manage the overview and prioritisation of Backlog Items in that category.

Guidelines for creating an area:

  • This should be purely customer centric
  • Often grouped by stakeholder, or certain processes
  • Could be organised by a certain market or product variant
  • No area in LeSS Huge should have less than 4 teams

Conclusions

After taking the course, I have a much stronger understanding of LeSS’ origins and how it works. After the course, it feels much LeSS complex than when I first read about it on their website. It includes many principles which I run software teams by. I can also see many parallels to what I have done with larger organisations and LeSS. I can also see how LeSS is a challenging framework for many organisations. I would definitely recommend larger product organisations draw inspiration from LeSS. I know I will after this course.

Thanks Jerry Weinberg

If you have worked in IT for some time, you will have come across the name Jerry Weinberg (Gerald M Weinberg). I first came across Jerry when I first read his book, “The Secrets of Consulting.” Jerry impacts great wisdom through his use of stories. He shared his knowledge generously with our industry and set a great example.

He was a prolific writer and I was lucky to inherit many of his books when a contact moved house. I devoured them rapidly, learning much in the process. As a proud Systems Thinker, I enjoyed “An Introduction to General Systems Thinking.” As someone passionate Technical Leadership, I inhaled, “Becoming a Technical Leader.” I refer and recommend many of his books time and time again.

I never had the opportunity to meet Jerry but I met many people who he had personally influenced. I heard amazing things about the “Amplify Your Effective (AYE)” conference. I felt people who frequented the AYE conference came away with more drive to have a greater impact. I regret not taking the one opportunity I had to take part, given the wrong timing and place in my life.

As someone who believes in agile values, I was lucky to meet Norm Kerth. I forgot he co-authored the “Project Retrospectives” book with Jerry Weinberg. Continuous improvement is the basis for better organisations, teams and processes. Call it retrospectives, kaizen or some other name. I count myself lucky for reading this early on in my career.

We stand on the shoulders of giants. Jerry was definitely a giant among giants. In the world of software we often have a negative association with the word, “legacy.” We forget that sometimes that legacy can be a good thing. I am particularly grateful for the legacy Jerry left behind. 

Book Review: Accelerate

I first heard about this book when I saw Jez Humble (@jezhumble) keynote at OOP earlier this year. You will get significant value from this book. Jez has already made many contributions to our industry. He introduced Continuous Delivery (CD) and the Lean Enterprise. He also helped shape the field of DevOps, as we know it today.

The Science of DevOps: Accelerate Book

Think about this book as a very readable academic paper, based on the long-running State of DevOps report.

Rigour in its research method

The book describes how the authors gathered vast data and their research methods. They discuss their observations and lead you to their conclusions, with concrete examples. The author shared how some of their assumptions turned out false. An example is the study showing how there is a positive correlation with Trunk-Based Development (TBD) and quality. This technical book is a rare gem based on rigorous research methods. Nicole Forsgren obviously had a large impact on the book

I’m amazed at how rich their raw dataset is. The authors draw on four years of data from many responses around the world. Their sample size towers over many academic studies. Many academics rely on student control groups instead of real industry data. Rarely academics also get to study a few companies or teams within a single company. The wealth of the raw data gives more weight to the report’s authenticity and credibility.

Martin Fowler highlights one point in the Foreword which I agree with. Even though the survey raw data comes from many sources, it is still self-assessed. Self-assessments are naturally biased by Dunning-Kruger effects.

Strong guidance and good advice

Our industry struggles with useful performance measures in IT. Metrics are either irrelevant or drive poor behaviours. This book debunks false prophets like Gartner’s Bi-Modal IT. Spoiler: You can got fast AND have quality, unlike normal assumptions. The book, Accelerate, gives strong suggestions for useful KPI measures. The authors present convincing conclusions that any modern technology firm should take on. This book gives many ideas to improve software and organisational architectures, and processes.

Many studies such as this focus only on the technical practices (such as CD or TBD). Many experience people realise a focus on technical practices is not enough. They realise organisational processes or structures constrain the value technical practices bring. To make the most of technical practices, management must look at their processes and structures. (Disclaimer: We address this topic in our book about Building Evolutionary Architectures). Maybe it’s confirmation bias, but the chapter on Transformational Leadership is super important.

Here’s an simple example why. Imagine you have an organisation with a Head of Development and Head of Operations. Each have hundreds of people with different reporting structures and processes. If the Heads do not support new initiative like DevOps, collaboration won’t move very far.

Conclusion

I found this book extremely easy to digest. I wanted to read more about their research methods. The authors convinced me of their conclusions and made them come to life with concrete examples. I highly recommend this book for any technology executive in the modern world. Accelerate sets the standards for measuring the performance of technology firms in 2018.

5 Tips for Being an Effective Tech Lead

Becoming a Tech Lead is a tough transition for any developer, because only part of the skills and experience you had as a developer prepares you for the expectations of a new role. Instead of simply designing and writing code, a Tech Lead is suddenly responsible for an entire development team – and this means dealing with people, both technical and non-technical.

The time a developer spent focusing on writing well-designed code does not translate into the skills necessary for understanding people, resolving conflict, or suddenly having to juggle more tasks than they can possibly achieve by themselves.

Tech Lead Dilemma

I present 5 tips for being an effective Tech Lead.

1. Learn to Delegate

As a developer, you get a kick from working out what the hard, technical problem is to solve. You research different ways to solve the problem, seek the most simple solution and celebrate a victory when you want that red, failing test going green.

As a Tech Lead, you cannot take on all the coding tasks, and cannot take on all the hard or interesting problems, regardless of your experience. You have many more responsibilities that need time and attention, and if you are focused solely on a single task, those other responsibilities will fail to be fulfilled. When you take on the harder problems, it also misses opportunities for other developers to grow and problem solve, which will lead to frustration and potentially people leaving your team!

Of course, there are some problems when your experience and knowledge are important, but you do not want to be a bottleneck in solving problems, so you want to find a way to delegate and still be involved. Solutions might include kicking off a design session with developers to talk about general approaches, and reviewing progress with the developer on a regular basis to see if things are on track.

As you and the developer build trust with each other, you can be less involved and fully delegate an activity to let you focus on more important tasks.

2. Find Time to Code

The role is called “Tech Lead” for a reason, and it is essential that you find some time to spend in the codebase. Being involved in the code helps you build respect with the rest of the team, but it also helps keep your knowledge up to date and current with constraints, problems and the “shape” of the current codebase.

If you do not spend time with the code, you run the risk of invoking the “Ivory Tower Architect” anti-pattern, leading technical decisions without understanding their real implications for implementation or maintenance. This anti-pattern has numerous side effects including destroying trust with developers, increasing the development time of new features, and increasing the accidental complexity of your software systems.

There are many different ways a Tech Lead can find time to code, but it is essential that you make it a priority. This often means making difficult choices about where you spend your time. Tip #1 should help increase the amount of available time you have. I know some Tech Leads who will block out time in their calendar to ensure that there is always time during the week to write or review code with the other developers. I know of other Tech Leads who review commit logs, and provide feedback to developers – similar to a loose pair-programming style.

3. Visualise Your Architecture

I have worked in several teams where developers had no idea how their task fit into a bigger picture. A small technical decision made by a developer might have a wider architectural impact, but is impossible to prevent if developers do not understand the broader picture.

An effective Tech Lead often has a visual representation of their system architecture on-hand and uses it to have discussions with developers. There will often be different views of the architecture (logical, deployment, etc) and each diagram helps developers see how their task fits into a broader system architecture.

A whole-team whiteboard session is often a useful exercise for reviewing the overall architecture, as it evolves over time to meet differing requirements and the discussion during the session is even more important than the diagram. Focus on key quality attributes that drive out your architectural vision (scalability, performance, usability concerns, etc) and how they have shaped your architecture. Call out assumptions and the historical context to help developers guide their everyday decisions.

4. Spend Time 1-on-1 With Team Members

An effective Tech Lead will not be measured with how many coding tasks they complete. They are measured by how effective their software team is. Anything that a Tech Lead can do to make each person on their team better, makes the overall team better. Sit down with members on your team to understand their backgrounds, their strengths, their interests and their goals to understand how the people in your team fit together as a group. Connect developers with opportunities for them to grow. This means allowing them to take risks so they can learn and grow, but also contribute to the team. Encourage people sharing knowledge across the team and find ways to help each team member connect with each other.

5. Learn to Speak the Language of the Business

To be an effective Tech Lead, you will need a great relationship with people outside of the development team including people like Product Managers, Marketing, Sales and CxOs. They will not understand the vocabulary you accumulated as a developer, and talking to them in terms of frameworks, technical tools and platforms will only confuse them.

An effective Tech Lead finds ways for non-technical people to understand technical concepts, and the best way to do that is to find the terms that business people use and find ways to explain tasks in those terms. Use visual models, whiteboard sessions and metaphors to help business people understand technical concepts and their implications. You might rehearse on friends or relatives who don’t work in technology to see if you can succinctly explain an idea.

Minimize the translation layer as much as possible by bringing business terms into the development team and encouraging their use as much as possible. The better the developer team uses these domain terms, the better their understanding and empathy with business stakeholders will be.

This is a repost of an old blog post I published while I worked at ThoughtWorks and wanted to recapture it here. See the original here.

Just Published: Building Evolutionary Architectures

I’m very proud to announce the release of a new book that I co-authored with Neal Ford and Rebecca Parsons whilst I was at ThoughtWorks. Martin Fowler writes the Foreword (snippet below):

While I’m sure we have much to learn about doing software architecture in an evolutionary style, this book marks an essential road map on the current state of understanding

Building Evolutionary Architectures

It marks the end of a very long project that I hope will have a positive impact on the way that developers and architects consider building and designing software. We will also post related news to our accompanying website evolutionaryarchitecture.com

You can find the book available on:

Enjoy!

Three ways to handle CFRs

Cross-Functional Requirements (CFRs) are some of the key system characteristics that are important to design and account for. Internally we refer to these as CFRs, although classically they might be called Non-Functional Requirements (NFRs) or System Quality Attributes, however their cross-cutting nature means you always need to consider the impact of CFRs on new or existing functionality.

In the Tech Lead courses that I run, we discuss how it’s important that the Tech Lead ensures that the relevant CFRs are identified and accounted for either in design or development. Here are three ways I have seen some CFRs accounted handled.

1. CFRs satisfied via user stories and acceptance criteria

Security, authentication and authorisation stories are CFRs that naturally lend themselves to actually building out testable functionality. It’s important to consider the effort the risk and, in my experience, is important to start implementing these early to make sure they meet the needs and can evolve.

For these sorts of CFRs, it’s useful to identify these as natural user stories, and once implemented become acceptance criteria on future user stories that touch that area of the system.

As as example, authorisation can be dealt with by introducing a new persona role and what they might do (or not do) that others can have:

As an administrator, I would like to change the email server settings via a user interface, so that I do not need to raise an IT change request for it.

If this is the first time that this user story is implemented, then some acceptance criteria might look like:

  • Only a user with an administrator role can access this page
  • Only a user with an administrator role can successfully update the email setting (check the API)
  • Users with no administrator access receive a 403 or equivalent

This new role addition often means considering new acceptance criteria for every story going forward (if it should be accessible only by administrators or by all.

2. CFRs satisfied through architectural design

Scalability and durability are often CFRs that require upfront thinking about the architectural design, and perhaps planning for redundancy in the form of additional hardware, network, or bandwidth capacity. A web-based solution that needs to be scalable might draw upon the 12-factor application principles, as well as considering the underlying hardware. Failing to think about the architectural patterns that enable scalability and start coding will lead to additional rework later, or make it even impossible to scale.

3. CFRs satisfied via the development process

User experience is a CFR which often requires people, making automated testing much more difficult. An application where a high level of user experience is best dealt with by ensuring that a person with a background in UX is involved and that certain activities and feedback cycles are planned into the software development process to continually fine-tune the user experience as an application evolves.

Changes to the development process might include explicit user research activities, continuous user testing activities, the addition of an A/B capability and some training for product people and the development team to ensure that the developed software meets the desired level of user experience.

Conclusion

Every system has their own set of Cross-Functional Requirements (CFRs) and it is essential that teams focus on identifying the relevant and important CFRs and find ways to ensure they are met. In this article, I shared three typical ways that CFRs might be met.

How else have you seen these handled?

Automated Tests for Asynchronous Processes

It’s been a while since I’ve worked on a server-side application that had asynchronous behaviour that wasn’t already an event-driven system. Asynchronous behaviour is always an interesting challenge to design and test. In general, asynchronous behaviour should not be hard to unit test – after all, the behaviour of an action shouldn’t necessarily be coupled temporally (see forms of coupling).

TIP: If you are finding the need for async testing in your unit tests, you’re probably doing something wrong and need to redesign your code to decouple these concerns.

If your testing strategy only includes unit testing, you will miss a whole bunch of behaviour which are often caught at high level of testing like integration, functional or system tests – which is where I need asynchronous testing.

Asychronous testing, conceptually, is actually pretty easy. Like synchronous testing, you take an action and then look for a desired result. However unlike synchronous testing, your test cannot guarantee that the action has completed before you check for the side-effect or result.

There are generally two approaches to testing asynchronous behaviour:

  1. Remove the asynchronous behaviour
  2. Poll until you have the desired state

Remove the asynchronous behaviour

I used this approach when TDD-ing a thick client application many years ago, when writing applications in swing applications was still a common approach. Doing this required isolating the action invoking behaviour into a single place, that, instead of it occurring in a different thread would, during the testing process, occur in the same thread as the test. I even gave a presentation on it in 2006, and wrote this cheatsheet talking about the process.

This approach required a disciplined approach to design where toggling this behaviour was isolated in a single place.

Poll until you have the desired state

Polling is a much more common approach to this problem however this involves the common problem of waiting and timeouts. Waiting too long increases your overall test time and extends the feedback loop. Waiting too short might also be quite costly depending on the operation you have (e.g. hammering some integration point unnecessarily).

Timeouts are another curse of asynchronous behaviour because you don’t really know when an action is going to take place, but you don’t really want a test going forever.

The last time I had to do something, we would often end up writing our own polling and timeout hook, while relatively simple is now available as a very simple library. Fortunately other people have also encountered this problem in java-land and contributed a library to help make testing this easier in the form of Awaitility.

Here is a simple test that demonstrates how easy the library can make testing asynchronous behaviour:

package com.thekua.spikes.aysnc.testing;

import com.thekua.spikes.aysnc.testing.FileGenerator;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;

public class FileGeneratorTest {

    private static final String RESULT_FILE = "target/test/resultFile.txt";
    private static final String STEP_1_LOG = "target/test/step1.log";
    private static final String STEP_2_LOG = "target/test/step2.log";
    private static final String STEP_3_LOG = "target/test/step3.log";

    private static final List<String> FILES_TO_CLEAN_UP = Arrays.asList(STEP_1_LOG, STEP_2_LOG, STEP_3_LOG, RESULT_FILE);


    @Before
    public void setUp() {
        for (String fileToCleanUp : FILES_TO_CLEAN_UP) {
            File file = new File(fileToCleanUp);
            if (file.exists()) {
                file.delete();
            }
        }
    }


    @Test
    public void shouldWaitForAFileToBeCreated() throws Exception {
        // Given I have an aysnc process to run
        String expectedFile = RESULT_FILE;

        List<FileGenerator> fileGenerators = Arrays.asList(
                new FileGenerator(STEP_1_LOG, 1, "Step 1 is complete"),
                new FileGenerator(STEP_2_LOG, 3, "Step 2 is complete"),
                new FileGenerator(STEP_3_LOG, 4, "Step 3 is complete"),
                new FileGenerator(expectedFile, 7, "Process is now complete")
        );

        // when it is busy doing its work
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (final FileGenerator fileGenerator : fileGenerators) {
            executorService.execute(new Runnable() {
                public void run() {
                    fileGenerator.generate();
                }
            });
        }

        // then I get some log outputs
        await().atMost(2, SECONDS).until(testFileFound(STEP_1_LOG));
        await().until(testFileFound(STEP_2_LOG));
        await().until(testFileFound(STEP_3_LOG));

        // and I should have my final result with the output I expect
        await().atMost(10, SECONDS).until(testFileFound(expectedFile));
        String fileContents = readFile(expectedFile);
        assertThat(fileContents, startsWith("Process"));

        // Cleanup
        executorService.shutdown();
    }

    private String readFile(String expectedFile) throws IOException {
        return new String(Files.readAllBytes(Paths.get(expectedFile)));

    }


    private Callable<Boolean> testFileFound(final String file) {
        return new Callable<Boolean>() {
            public Boolean call() throws Exception {
                return new File(file).exists();
            }
        };
    }
}

You can explore the full demo code on this public git repository.

Fixing ssh on Mac Sierra 10.12.1

I recently upgraded my mac to the latest OS only to find out that my ssh command wasn’t working.

>ssh <strong>servername</strong>

resulted in:

> .ssh/config: line 18: Bad configuration option: useroaming
> .ssh/config: terminating, 1 bad configuration options

which looks like because I added in the following entry to my

.ssh/config

file in response to a previous SSH vulnerability:

UseRoaming no

This vulnerability looks like it’s been fixed: https://www.solved.tips/sshconfig-line-7-bad-configuration-option-useroaming-macos-10-12-sierra/

« Older posts

© 2024 patkua@work

Theme by Anders NorenUp ↑