What Can Men Do

So, I wrote a long email to the London Java Community in answer to an excellent question: “What can men do to support Women in Technology?".

It’s a bit of a brain dump, by no means comprehensive, and is in answer to a specific question in a specific context, but I’ve been asked to make the information public so it can be useful in a broader context. So here it is.

Continue reading "What Can Men Do"

IntelliJ IDEA for Eclipse Users

List of resources for those trying to make the switch from Eclipse to IntelliJ IDEA:

In the slides above, there’s a section “The Power of IntelliJ IDEA” with no content - that’s because that’s a place for a live demo of working with IntelliJ IDEA. To create that demo, I jotted down some topics that I think are interesting in IntelliJ IDEA, which are worth making a note of here:

JavaZone 2016

It’s been a while since I wrote a conference write up. The short version of “why” is because I got a bit bored of doing it. Plus, I found I was attending conferences as a speaker “on the circuit”, and my experience of hanging out, catching up with my friends, chatting to other attendees to see what they’re up to and so forth, didn’t seem as useful to share with people who might want to find out whether a conference is worth attending from a content or atmosphere point of view.

But I feel compelled to blog about JavaZone. I presented there back in 2013, but every year since then haven’t made it for one reason or another (the fact that it’s near my birthday in no way impacts my scheduling…). I made the effort this year, and I’m so pleased. Now I’ve been to many more conferences, of various sizes, various themes, all around the world, and I can definitely state that JavaZone is up there as one of the best conferences around.


  • The content is great, JavaZone manages to attract a lot of great speakers who can present on topics that range from deeply technical to more theoretical to concepts beyond just code and syntax. They also really make an effort to encourage local presenters, and to offer the option of lightning talks. I love this from the point of view of encouraging more from the community to get involved and present themselves, but also because you get more novel content - experience reports from developers deep in the trenches; teams who can tell you what they’ve found trying to implement things that we hear about at conferences; and other things from the point of view of real developers.

![Food and fantastic coffee](/static/images/javazone-2016/2016-09-08 15.45.36-coffee.jpg “Food and fantastic coffee”)

  • The food is fantastic, and available all day. I made half of a promise to myself not to rate conferences on the quality of the food after I had a glimpse at how insanely hard it is for conference organisers to balance the requirements of keeping ticket costs low, using an adequate venue in an accessible location, and providing some sort of catering through the day. Especially when venues themselves often restrict this. I don’t know how JavaZone do it, but now I’m aware of all these issues, I’m even more impressed at the variety and quality of their food.

![Robots](/static/images/javazone-2016/2016-09-08 15.46.02-robots.jpg “Robots”)

  • The venue. The location in the centre of Oslo is nice, often conference venues are out of town, making them hard to get to or, if you’re staying near there, terribly isolated. One of the reasons to travel to a conference is to see the city, and you get a chance to do that at JavaZone. So it’s central, easy to get to, with plenty of great hotels nearby. The venue itself also nicely laid out, with presentation rooms circling a central exhibition space. Which leads me to…

![Exhibition](/static/images/javazone-2016/2016-09-08 09.46.18-exhibition.jpg “The Exhibition”)

  • The exhibition space is brilliant. Because it’s central, most people spend their time between sessions in the exhibition hall. As an exhibitor (JetBrains had a stand there), this is obviously useful to us, but as an attendee it’s nice to know there’s a place to go to hang out where other people will also be hanging out. Especially when the vibe of the hall was so much fun, so energetic. And the stands themselves were impressive: some bribing us with excellent coffee; several with lego areas inviting you to sit down and play; interactive VR headsets; modern and retro gaming centres (curses, I forgot to take a photo); interactive quizzes and games… As for us, we had a sofa, and I loved that, it felt welcoming and relaxed.

![Games](/static/images/javazone-2016/2016-09-08 15.45.20-games.jpg “Exhibition”)

  • Everyone is really friendly. The crew and JUG people were easy to spot and friendly if you needed help. All attendees and speakers were happy to strike up conversations short and long, on a variety of topics. People smiled.
  • It’s a big conference, there are a lot of attendees, but it doesn’t feel big and daunting. Instead, you get the benefit of 8 tracks of varied content, but don’t feel lost in the crowd.

![Overflow Room](/static/images/javazone-2016/2016-09-08 09.39.20-overflow.jpg “Overflow Room”)

  • The overflow room is the best thing I’ve ever seen at a conference, and I’m seriously wondering if I can set up something similar at home (on a much smaller scale!) to let me skim content from multiple talks when I’m doing research, or maybe just something to have half an eye on while I’m entertaining the minion.
  • It was, from my point of view as an attendee and speaker, incredibly well organised. It felt smooth, and touches like the big monitors flashing up relevant information was really nice. I also loved that the video production quality and presentation of the stages and so forth was really professional.

![Plenty of caffeine for the developers](/static/images/javazone-2016/2016-09-08 15.46.36-stacks-coffee.jpg “Plenty of caffeine for the developers”)

  • I personally think it’s brilliant that the videos are online really soon after you’ve presented. Sometimes as a speaker you might want a delay on the video - conferences may be more likely to accept your talk if it’s not already widely available. For me though, especially when giving a new talk like we did here, it’s nice to be able to see the video so soon afterwards, to see how it went and learn from it. For speakers just starting on their presenting career, it’s also great - you have a video to use in your “portfolio” to help you get your talk(s) accepted at other conferences.
  • And I can’t leave this without mentioning diversity. Now that I’m a world-weary veteran of conferences, I’m fairly blind to gender balance unless I specifically look, or something out of the ordinary catches my attention. I don’t know what the percentages were, but I noticed so many women at the conference, women who were clearly professionals attending the conference and not hired booth babes or staff of some other kind. It was obvious and pleasing. I’m not sure how the other women attendees felt, if it was their first conference maybe they still noticed there were fewer women than men, but the difference to me was that whichever direction I looked in, there was at least one woman, usually more. I don’t know if there are more women developers in Up North, or if it’s just a conference that somehow appeals more to women than other conferences. I’d be interested to find out if any special measures were taken by the conference organisers.

Now I know a bit more about conferences and how they work behind the scenes, I’m astounded at JavaZone. It feels like a lot of money has been spent getting it really right, and/or they’ve worked really hard to get the absolute most out of what budget they have.

If I had to really hunt for a downside, it’s that all the free alcohol was beer and not wine. Yep, a complaint about free beer. But knowing how expensive wine is in Norway, I’m not at all surprised. Plus, moaning about the exact type of free alcohol available seems churlish at best.

![The JatBrains stand](/static/images/javazone-2016/2016-09-08 16.28.07-jetbrains.jpg “The JetBrains stand”)

If you do get a chance to go to JavaZone as an attendee or speaker, I highly recommend it. I hope to be going again.

PS In case you’re interested, we were presenting a new talk, Code Review Matters and Manners

Code Review Matters and Manners

Content and resources for the Code Review Matters and Manners talk, including links to additional information and supporting material.


A code review is basically a technical discussion which should lead to improvements in the code and/or sharing knowledge in a team. As with any conversation, it should have substance and form.

What’s involved in a good code review? What kind of problems do we want to spot and address? Trisha Gee will talk about things a reviewer may consider when looking at changes: what potential issues to look for; why certain patterns may be harmful; and, of course, what NOT to look at.

But when it comes to commenting on someone’s work, it may be hard to find the right words to convey a useful message without offending the authors - after all, this is something that they worked hard on. Maria Khalusova will share some observations, thoughts and practical tricks on how to give and receive feedback without turning a code review into a battlefield.

The talk

More Information



And, of course…

A Year? Really?

So I came to the blog to update my upcoming events (at least something stays up to date) only to find it’s been nearly a year since I last blogged! This is terrible!

It’s not that I haven’t written anything in a year, it’s that a lot of my writing energy goes into stuff for the actual day job. Which is good, because that’s pretty much what I wanted from the day job, but the blog makes it look like I don’t write any more.

So I’m going to cheat. Here’s the stuff I’ve written in the last 12 months.

I’ve also done a bunch of screencasts & webinars for IntelliJ IDEA, Upsource and Team City.

Oh yeah, and I had a baby. I’m contemplating blogging about being a working parent, but I’m a bit concerned that Of Course a woman is going to blog about Being A Mother, when previously I just blogged about… well, come to think about it I blogged about all sorts of things, including haircuts and [hangovers] (/post/what_my_hangovers_can_teach_you_about_agile/), so I guess I could probably get away with it.

Applying Java 8 Idioms to Existing Code

  • Understand how to improve performance with your Java code using Java 8 language features.
  • Learn hands on techniques to discover and implement common Java 8 refactorings.
  • Understand when you should and should not apply key refactorings in Java 8.


While we’re drawing ever closer to Java 9, and even hearing about features in Java 10, many of us are still working with an older version. Even if your project has technically adopted Java 8, and even if you’re using it when coding new features, it’s likely that the majority of your code base is still not making the most of what’s available in Java 8 - features like Lambda Expressions, the Streams API, and new Date/Time. And this is a shame, since Java 8 provides not only nicer syntax for developers, but (usually) better application performance.

In this presentation, Trisha will:

  • Highlight the performance benefits of using Java 8 - after all, you’ll probably have to persuade “The Management” that tampering with existing code is worthwhile
  • Demonstrate how to identify areas of code that can be updated to use Java 8 features, and how to pick which changes will give you the most benefit
  • Demonstrate how to automatically refactor your code to make use of features like lambdas and streams
  • Cover some of the pros and cons of using the new features - including suggestions of when refactoring may NOT be the best idea.

The talk

This is the most complete version of the talk, containing as many different refactorings as I could squeeze in, and updated performance analysis.

Other versions include:

You can purchase a more in-depth tutorial on informIT, and is also available via Safari Books Online.

The IntelliJ-specific features of some of the refactoring shown are covered in my Migrating to Java 8 tutorial.


Article: Why Java 8
Article: Five Java 8 Features You Won’t Be Able to Live Without
Video and Research: Building a Java 8 Application


The project we’re refactoring is Morphia. You can see the “after” of the chosen refactorings on the r2j8 branch.

The performance tests that were written and run specifically for this talk are in the j8-morphia-perf-tests repository


Lambda Expressions

Video: Lambda Performance and [talk slides](http://www.oracle .com/technetwork/java/jvmls2013kuksen-2014088.pdf)
Article: Java 8 Lambdas - A Peek Under the Hood
Video: Lambdas in Java: A Peek under the Hood - Brian Goetz


Video: Let’s Get to the Rapids: Java 8 Stream Performance
Article: [Java performance tutorial: How fast are the Java 8 streams? - Angelika Langer](https://jaxenter .com/java-performance-tutorial-how-fast-are-the-java-8-streams-118830.html) Notable Quotes:

Again, the for-loop is faster that the sequential stream operation, but the difference on an ArrayList is not nearly as significant as it was on an array.


You will find that there is no measurable difference any more between for-loop and sequential stream if the functionality is heavily cpu bound.


The point to take home is that sequential streams are no faster than loops. If you use sequential streams then you don’t do it for performance reasons; you do it because you like the functional programming style.


The reality check via our benchmark yields a ratio (sequential / parallel) of only 1.6 instead of 2.0, which illustrates the amount of overhead that is involved in going parallel and how (well or poorly) it is overcompensated (on this particular platform).


With this in mind it is fair to say that the performance model of streams is not a trivial one


…you need to benchmark a lot in order to find out for a given context whether going parallel is worth doing or not.


The realisation is: Yes, parallel stream operations are easy to use and often they run faster than sequential operations, but don’t expect miracles. Also, don’t guess; instead, benchmark a lot.

Article: [Benchmark: How Misusing Streams Can Make Your Code 5 Times Slower](http://blog.takipi .com/benchmark-how-java-8-lambdas-and-streams-can-make-your-code-5-times-slower/) - interesting comparison of different iteration styles. Also shows that things like boxing might add more cost than streams (but that you don’t realise you’re boxing)

Article: Stream Performance - some interesting benchmarks based on Angelika Langer’s article
Article: Follow up on Stream Performance

Date and Time

Article: JSR 310 – Java 8 Date/Time library performance (as well as Joda Time 2.3 and j.u.Calendar)


I used a bunch of techniques to produce the benchmarks on the talk. I’d like to summarise them more thoroughly when I get a chance, but for now here’s my background reading:

Article: Avoiding Benchmarking Pitfalls on the JVM

Tool: JMH
Tool: IntelliJ JMH Plugin
Article: Introduction to JMH

“Best Practice”

I dislike the term “Best Practice” as it implies a “one size fits all” approach, and I believe that our job is to make difficult decisions based on various pros and cons and differing situations. However, here I will collect resources that may help us make some of those decisions

Article: Refactoring with Loops and Collection Pipelines - Martin Fowler
Slides: Workflows of Refactoring - Martin Fowler
Book: Refactoring: Improving the Design of Existing Code - Martin Fowler

Article: Using Optional in Java SE 8 - Stephen Colebourne
Article: Java 8 Best Practices Cheat Sheet - ZeroTurnaround

Java 8 MOOC – Session 3 Summary

Last night was the final get-together to discuss the Java 8 MOOC. Any event hosted in August in a city that is regularly over 40°C is going to face challenges, so it was great that we had attendees from earlier sessions plus new people too.


The aim of this session was to talk about Lesson 3, but also to wrap up the course as a whole: to talk about what we liked and what we would have improved (about both the course itself and our user group events).

As in the previous two posts, let’s outline our discussion areas:

findAny() vs findFirst(): Why do we need both of these methods, and when would you use them?

Well, findFirst() is the deterministic version, which will return you the first element in the Stream (according to encounter order - see the section on Ordering in the documentation). So, regardless of whether you run the operation in parallel or serial, if you’re looking for “A” and use findFirst with this list:

["B", "Z", "C", "A", "L", "K", "A", "H"] 

you’ll get the element at index 3 - the first “A” in the list.

But findAny() is non-deterministic, so will return you any element that matches your criteria - it could return the element at index 3, or the one at position 6. Realistically, if the stream is on an ordered collection like a list, when you run findAny on a sequential stream, I expect it will return the same result as findFirst. The real use-case for findAny is when you’re running this on a parallel stream. Let’s take the above list, and assume that when you run this on a parallel stream it’s processed by two separate threads:

["B", "Z", "C", "A",    // processed by thread 1   "L", "K", "A", "H"]     // processed by thread 2 

It’s possible that thread 2 finds its “A” (the one at position 6) before thread 1 finds the one at position 3, so this will be value that’s returned. By configuring the Stream to return any one of the values that matches the criteria, you can potentially execute the operation faster when running in parallel.

If findAny is (potentially) faster in parallel and (probably) returns the same value as findFirst when running in serial, why not use that all the time? Well, there are times when you really do want the first item. If you have a list of DVDs ordered by year the film was released, and you want to find the original “King Kong” (for example), you’ll want findFirst to find the one released in 1933, not the one that was released in 1976 or the one from 2005.

Plus, findFirst is not always going to be slower than findAny, even in parallel. Going back to our list:

["B", "Z", "C", "A", "L", "K", "A", "H"] 

Trying to findFirst or findAny for “H” could be the same performance for both methods.

Collectors: Maybe it’s just me who doesn’t really see the big picture for collectors. I’m perfectly content with the built in collectors like:




It’s easy to see what they do, and work out when you need to use them.

I’m also very happy to have discovered joining:


a super-useful way to create Comma Separated Values (CSVs) that I use in my Java 8 demo.

Where things get a bit murky for me is where we start chaining up collectors:


(it should be obvious from my lack of clear example that I’m not 100% certain under which circumstances these are useful).

As a group, we think the chained collectors are kinda ugly - not because we’re against chaining (we like Streams), but maybe because it’s another chain inside a param to a chain.

We think this is an area where some good, solid examples and a bit of daily use will make it much clearer to developers. We hope.

Related to this, the course didn’t go into creating your own collectors at all. My personal (under-informed) opinion is that I guess most developers should be able to use either the out-of-the-box collectors (toList etc) or use the collector chaining to build what they need. If you need a custom collector, perhaps you haven’t considered everything that’s already available to you. But as a group, we decided we would have liked to see this topic anyway so that we could get a deeper understanding of what collectors are and how they work.

Exercises for lesson 3: Well. What can we say? I really hope there are people reading this who haven’t finished the course yet, because the Sevilla Java User group would like to say to you: don’t despair, the lesson 3 exercises are substantially harder than those for lessons 1 and 2. Honestly, the whole group considered it less of a learning curve and more of a massive cliff to climb.

![I have no idea what I am doing](http://herbookthoughts.reads-it.com/wp-content/uploads/2014/06/d6a1143f571184db25f94613edd43b40af6d3a629221aba00d9efdcfef5efd84.jpg “I have no idea what I am doing”)

I mean, it was great to have something so challenging to end on, but it probably would have been less ego-destroying if we could have got up to that level gradually instead of having it sprung on us.

The good thing about Part 2 of the lesson 3 exercises was that we had three very different answers to discuss in the group. None of us were super happy with any of them, but we could see definite pros and cons of each approach, and that’s something you really want to learn in a course like this.

It was also really great to have a rough performance test to run on your own computer, so that you could really see the impact of your choices on the performance of the stream.

For more info
I’m going to add a shameless plug to a friend’s book here. I’ve been reading a lot about Java 8 for this course, for my Java 8 demo, and to generally get up to speed. My favourite book for getting to grips with lambdas and streams is Java 8 Lambdas: Pragmatic Functional Programming"" by Richard Warburton. This book also contains more info about collectors too, so maybe some of our questions around how to use these in more complex situation are answered in here.

In Summary
We really enjoyed the MOOC, and the sessions to get together to discuss it. We particularly liked that the meetups were a safe place to ask questions and discuss alternative solutions, and that we weren’t expected to be genius-level experts in order to participate fully.

If/when Oracle re-runs the MOOC, if you didn’t get a chance to take part this time I highly recommend signing up. And if you can find (or run) a local meetup to discuss it, it makes the experience much more fun.

Java 8 MOOC – Session 2 Summary

As I mentioned last week, the Sevilla Java User Group is working towards completing the Java 8 MOOC on lambdas and streams. We’re running three sessions to share knowledge between people who are doing the course.

The second week’s lesson was about Streams - how you can use the new stream API to transform data. There was also a whole section on Optional, which initially seemed like rather a lot, but it turns out that Optional can do rather more than I originally thought.

In the meetup session, we talked about:
Optional: we were pretty comfortable, I think, with using Optional to prevent a NullPointerException. What we weren’t so clear on were the examples of filter() and map() - if you were getting your Optional values from a stream, why wouldn’t you do the map and the filter on the stream first? For example, why do this:

list.stream()     .findFirst()     .map(String::trim)     .filter(s -> s.length() > 0)     .ifPresent(System.out::println); 

when you could map and filter in the stream to get the first non-empty value? That certainly seems like an interesting question in relation to streams.

I can see Optional being more useful when other APIs fully support Java 8 and return Optional values, then you can perform additional operations on return values.

That terminal operation’s not actually terminal??: We ran into this a couple of times in our examples in the session, one example is the code above (let’s copy it down here so we can look at it more closely):

list.stream()     .findFirst()     .map(String::trim)     .filter(s1 -> s1.length() > 0)     .ifPresent(System.out::println); 

Isn’t findFirst() a terminal operation? How can you carry on doing more operations on that?

The answer is, of course, that the return type of the terminal operation can also lead to further operations. The above is actually:

Optional<String> result = list.stream()                               .findFirst(); result.map(String::trim)       .filter(s1 -> s1.length() > 0)       .ifPresent(System.out::println); 

Our terminal operation returns an optional, which allows you to do further operations. Another example of this confusion:

list.stream()     .map(String::toLowerCase)     .collect(toList())     .forEach(System.out::println); 

Here, collect() is a terminal operation, but it returns a list, which also allows forEach():

List<String> results = list.stream()                            .map(String::toLowerCase)                            .collect(toList()); results.forEach(System.out::println); 

So be aware that just because it’s called a terminal operation, doesn’t mean you can’t perform other operations on the returned value.

Parallel/sequential/parallel: there had been a question in the previous week about why you could write code like this:

list.stream()     .parallel()     .map(String::trim)     .sequential()     .filter(s1 -> s1.length() > 0)     .parallel()     .forEach(System.out::println); 

and whether that would let you dictate which sections of the stream were parallel and which were to be processed in serial. Lesson two set the lesson straight, declaring “the last operator wins” - meaning all of the above code will be run as a parallel stream. I can’t find any documentation for this, I’ll edit this post if I locate it.

Unordered: “Why would you ever want your stream to be unordered?” - the answer is that unordered() doesn’t turn your sorted collection into one with no order, it just says that when this code is executed, the order of elements doesn’t matter. This might make processing faster on a parallel stream, but as a group we figured it would probably be pointless on a sequential stream.

Efficiency optimisations and order of stream operations: We had a long conversation about the order in which you perform operations in a stream. The MOOC (in fact, most documentation around Streams) tells us that a) streams are lazy, and not evaluated until a terminal operator is encountered and b) this enables optimisation of the operations in the stream. That lead to a discussion about the following code:

list.stream()     .map(String::toLowerCase)     .filter(s -> s.length() % 2 == 1)     .collect(toList()); 

The filter operation should result in less items to process in the stream. Given that the map() operation doesn’t change anything that filter() relies on, will this code be optimised somehow under the covers so that the filter is actually executed first? Or are optimisations still going to respect the order of operations on a stream?

Our case is actually a very specific case, because a) the map() returns the same type as the params passed in (i.e. it doesn’t map a String to an int) and b) the map() doesn’t change the characteristic the filter() is looking at (i.e. length). But generally speaking, you can’t expect these conditions to be true - in fact I bet in a large number of cases they are not true. So pipeline operations are performed in the order in which they are written, meaning that our map and filter will not be re-ordered into a more efficient order.

A good rule of thumb seems to be to do filtering as early in the stream as possible - that way you can potentially cut down the number of items you process in each step of the stream. Therefore our code would probably be better as:

list.stream()     .filter(s -> s.length() % 2 == 1)     .map(String::toLowerCase)     .collect(toList()); 

**Flat Map**: what...? [`flatMap()`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#flatMap-java.util.function.Function-) is one of those methods that makes total sense once you get the hang of it, and you don't understand why it was so confusing. But the first time you encounter it, it's confusing - how is `flatMap()` different to `map()`?

Well, flatMap is used to squish (for example) a stream of streams into just a simple stream. It’s like turning a 2-dimensional array into a single dimension so that you can iterate over all the items without needing nested for-loops. There’s an example on StackOverflow, and some more examples in answer to this question.

Comparators: We’ve probably all written comparators at some point, it’s probably one of those examples where we really did use anonymous inner classes “in the olden days” and were looking forward to replacing them with lambdas.

reader.lines()       .sorted(new Comparator<String>() {           @Override           public int compare(String o1, String o2) {               return ???;           }       })       .collect(toList()); 

Sadly, using a lambda still doesn’t answer the question “do I minus o1 from o2, or o2 from o1?":

reader.lines()       .sorted((o1, o2) -> ??? )       .collect(toList()); 

But there’s yet another new method in Java 8 here that can save us, one that is not nearly as well publicised as it should be. There’s a Comparator.comparing() that you can use to really easily define what to compare on. The JavaDoc and signature looks kinda confusing, but this is one of those places where method references suddenly make loads of sense:

reader.lines()       .sorted(comparingInt(String::length))       .collect(toList()); 

(Here we’re actually using the comparingInt method as we’re going to compare on a primitive value). Personally this is one of my favourite new features in Java 8.

Join us next week for the [last session on Java 8 - Lambdas and Streams](http://www.meetup.com/SVQJUG/events/223910762/).

The Extraordinary Team Of Developers

Daniel Bryant and I did a keynote at Devoxx UK about how individuals can add something to a team to make the team more productive, and overall more awesome.

We mention a number of books, so I’ve made a list of them here:

Drive: The Surprising Truth About What Motivates Us""
Badass: Making Users Awesome""
The Tipping Point: How Little Things Can Make a Big Difference""
Effective Java (2nd Edition)""
The Servant as Leader""
The Back of the Napkin: Solving Problems and Selling Ideas with Pictures""


Rock stars are dead. Ninjas are banished. There are simply too many trashed hotel rooms, dead bodies and failed projects. The age of the individual superhero coder is over.

But if we’re still striving for excellence, what’s replaced the rock-star-ninja-hero programmer?

The team. The team that’s greater than the sum of its parts. Like The Avengers, but with less latex.

In the same way those without super powers, genius levels of intelligence and pots of money were vital to The Avengers, every developer, no matter how much or how little experience they have, brings something important to the team and has the potential to make it better: a nicer place to work, an openness to learning, a focus on clean code or a deeper understanding of the business’ needs.

How can a collection of good developers become a super-performing business-impact-delivering team? What do you, as an individual, add to the mix?

Daniel and Trisha will share stories of individuals and teams who have made an impact (both good and bad!) and offer suggestions for steps we, as individuals, can take to level up our teams.