Mr. Right 

I want to tell you about working remotely. But before we break down the concept of remote work into smaller chunks, I’ll first lay out why I’m the right person to do this.

I’ve been working remotely for Scalac for two and a half years. This has given me enough time to experience all the pros and cons of working from home. This includes figuring out how to behave when a problem is escalating on the other side of the screen, how to manage formal and informal communication and keep my work-life balance healthy. After this time, I can tell you with certainty that it’s possible to connect with and efficiently motivate remote coworkers enough to keep a project up and running. However, for some, breaking free from strict corporate rules and meme-communication might be a challenge.

In my case, remote work was the natural result of my personal development process. I started to experiment with my work environment long before I was fetching project repos on my home network. For me, remote work has been an opportunity to discover the perfect workplace in the sense described below.

What working remotely really means

So, what exactly is remote work? Your first guess is probably  you’d take laptop and stuff from the office and, instead of traveling through a city to your “9–5 building”, move through your living space to the area you’ve assigned to be your “home office.” I know that’s how working remotely might seem from the outside, but this point of view is totally wrong. It’s not just about changing your place of work. It also involves changing your mindset on both your personal and professional life. Communicating screen to screen is different; self-organization in the era of distractions is different; even your working hours and work-life balance might look different at home. As I mentioned before, I’d like to break it all down for you, step by step, and show you how working from home changes your perspective when it comes to:

  • work ergonomics
  • work-life balance
  • self-organization
  • communication

I would also like to emphasize that this guide is based on my own personal experience and discussions with coworkers. Working from home is a journey on which I have discovered what suits me best. What follows shouldn’t be treated as a set of rules, but rather as advice.

Romove Tech Debt with Scalac

Work ergonomics

This might not be the most obvious aspect of working from home. You might remember the “perfect” work position, described in terms of angles for your legs, arms, neck, chair, and monitor to ensure the “correct” posture in front of the computer. I certainly don’t, but I do remember the pain in my neck and lower back caused by uncomfortable chairs and small desks ( which remain too small even after six months processing corporate paperwork for a replacement desk).

At home, you can place your monitor on the wall, have it standing, or use a holding arm to find a position that is comfortable for your neck. You can buy any chair you find comfortable (in my case, a relatively cheap chair from the furniture store was much more convenient than an expensive gaming chair). At the office, your employer takes care of the equipment, but at home, it’s up to you – this can be one of the biggest cons of building your own home office. On the other hand, it can also be one of the biggest pros, because you aren’t limited by health and safety regulations. You can buy the furniture and hardware that suits you best and personalize it as you wish. You don’t have to use 2×17″ monitors; you can use a 34″ one instead. You don’t have to stay sitting all day.

You can split up your workday by:

  • sitting
  • standing
  • standing on a balance board
  • half-lying on a sunbed
  • lying down
  • sitting on a gym ball
  • or any other way you can think up
Ergonomics for Remote Workers
Change your positions during the day

Pose!

Bear in mind that standing might be healthier than sitting, but it’s also more exhausting—meaning that you can lose focus after some time. The same with a balance board—it requires some practice, but once you get used to standing on the board, you can work and work out at the same time (after a few hours, it feels like taking a long walk). Lying down can be refreshing, and it might boost your creativity (for example, I often work 2–3 hours a day in the park lying on a lazy bag or hammock in the summertime).

One of the enormous benefits of working at home is the friendly, informal, and peaceful environment. Researchers at Cornell University point out that Even low-level office noise can increase health risks and lower task motivation for workers. The home environment also makes it more convenient to maintain healthy behavior between work sessions; for example, by exercising during breaks. Which leads us to the next subject.

Work-life balance

By this I mean:

  1. Keeping a healthy balance between time spent at work and time spent on other activities.
  2. Actively avoiding work burnout.
  3. Relaxing your mind after work and releasing work-related stress.
  4. Maintaining a healthy relationship with your body.

While many people are too shy to do even quick workouts at the office, home is a much nicer environment where you can do some sit-ups, deadlifts, pull-ups or stretch. Our bodies play an important role in our lives and keeping them healthy will positively influence your frame of mind as well as improve productivity and focus throughout the workday.

Working remotely saves you approximately 250 hours a year on commuting

Commuting

Another advantage of remote work is avoiding all the disadvantages that relate to commuting. In the USA, the  Average Commute to Work time is around 1h (in Poland, where I live, it’s around 1.3h). That’s a lot of time that you can spend in better ways. It’s literally like leaving work an hour (or more) earlier. It’s an extra hour that you can use for your favorite activities or for spending time with your family. That’s 5 hours a week, about 21 hours a month and 250 hours a year! Not to mention your whole life.

The point is, you can manage your time better because if you don’t have to leave your home; you have more time as well as the space to be yourself.

I usually do 5-minute workouts during every break and meditate for 10 minutes every 4 hours. It helps me to stay fresh and focused during the whole day. It also boosts my ability to focus on problems rather than worry about expectations. Breaks are beneficial ( New Study Shows Correlation Between Employee Engagement And The Long-Lost Lunch Break) and it’s vital that you use them mindfully! 

Working 9 to 5? 

Working at home might be better, but it can also be a nightmare when it comes to your work-life scheduling. Does that sound confusing and scary? Let me explain! At home, you don’t have to stick to traditional 9–5 work hours. You can book calls with coworkers and clients at more convenient times and fit-in your responsibilities at the times that suit you best.

Furthermore, it means you can be more flexible when working with people in different timezones. However, it also means that if you’re not assertive, you can end up working at times that don’t suit you.

Consider trying out some different workday schedules:

  • Fitting most of your work into the first half of the day.
  • Fitting most of your work into the second half of the day (usually with some calls in the morning).
  • Breaking up your work throughout the day.

You should choose the schedule that fits your biorhythm and situation best. However, if you have a tendency to work too hard, it’s very likely that you’re going to try to use all three schedules at once—i.e. work the whole day. Because no one is watching you, there can be a considerable temptation to finish your work by doing overtime… Don’t. Tasks often take more than one day, and it’s easy to underestimate how long any given task will take. You should communicate that you need more time to finish the task to your manager or team leader. Doing overtime is a straightforward recipe for a quick burn-out and draining of your natural enthusiasm for work.

Advanced scheduling

While it’s quite easy to schedule your working hours for either the first or second half of the day, I’ll explain how to approach scheduling a fragmented workday. Imagine you have some free time in the morning you can spend on working, but then you have to take your children to school, then you visit the nearest coffee shop because you need to have a meeting, you also work there for some time before getting back home and finishing up your workday. You can cross over your work with daily tasks and still get everything done; you might discover that this can be extremely beneficial. That said, I would recommend a fragmented work schedule for more experienced remote workers who have excellent time organization skills, as it’s easy to work too much or too little if you fail to plan it carefully.

Other techniques to help you draw a thicker dividing line between work and private life are:

  • Choosing a dedicated place in your home/room to work in. Somewhere you set the rules and won’t be interrupted.
  • Having a distinctive uniform just for work. It might be smart casual or some pajamas, but make sure it’s something you wear only while working. 
  • Turning off notifications. Some people are not bothered by notifications. Others require quality time without ‘work noise.’
Romove Tech Debt with Scalac

Self-organization

Let’s be honest,  the modern world has too many distractions. Workers must often really try hard to stay focused. Don’t blame people. It’s hard to keep a clear mind when you’re surrounded by media specifically engineered to grab your attention. It’s even harder at home because you don’t have coworkers who would give you dirty looks if they noticed you spending the whole day scrolling through news feeds.

How to deal with distractions? 

  • You might have noticed that I’ve mentioned this before: breaks! Adequate breaks are crucial for maintaining your mental capacity and staying focused. It might be a “tea break” every hour or quick breaks using the Pomodoro technique (which I use to refill my water tank and exercise). You should try out whatever you find works for you.
  • To-do lists. Knowing your plans makes them easier to follow. Remember to keep them simple and don’t waste too much time writing to-dos. I use a very minimalistic to-do app. You can do the same or use a more nuanced one, or don’t use an app at all – just describe your plan briefly in notepad.
  • Workflow apps. If you have a lot of responsibilities, it can be very beneficial to use apps for long term planning. You can use Gantt chart apps, agile apps, or even mind maps. Whatever suits you best.
  • Website blockers. There are a few apps that can block distracting websites and apps on a specified schedule. If you have a hard time restraining yourself from checking your favorite meme site every 5 minutes, maybe you should give one a try.
  • Time trackers. Plugins such as coding time trackers might give shocking results at first—in the programming world, not all of your time is spent coding (there are meetings, the creative aspects, the conceptual aspects, etc.). Time trackers will help you identify your productivity cycles and help to figure out how your work can fit in perfectly with your schedule. 
  • Well-implemented agile is a great tool for time and task organization for teams. An essential part of the agile process is to discuss tasks. This will help you organize time and help you build a representation of the task in your mind, generating ideas for solutions.
  • Focus on solutions, not tools. This can be a dead-end for a lot of young apprentices. Tools are meant to solve problems; if they’re becoming an obstacle they should be changed or improved or even thrown away. 
  • And, finally, to be well organized you should communicate with your teammates. Clear, polite and constructive communication is the key. 
We work remotely

Communication

This is an element of remote work – actually I would say any work – that needs a lot of your attention. Because interactions are not forced upon you by office conventions, they require a more proactive approach. You might find it surprising, but remote workers have to communicate! No, you can’t sit in your basement without talking to people for months. Sorry for spoiling that for you. With good leadership, good communication can result in better relationships, where interactions are more meaningful and involve an exchange of useful feedback. 


It’s easier when you work remotely

  • It is easier to schedule appointments working remotely.
  • When you’re not at the office you don’t waste time to find and book a conference room.
  • It is troublesome to interrupt someone speaking remotely.
  • It’s super convenient to use the messaging app and, because all messages are saved as text, sometimes this lets you skip overplanned meetings (and make no mistake, IT developers hate overplanned meetings).
  • It is also more convenient to pair program on other workstations, sharing your IDE session instead of a keyboard.

…but it’s not hassle-free

It all sounds incredible, doesn’t it? Of course! But there’s a dark side as well. Even though it’s mainly a stereotype, some IT workers, just like any other,  can be somewhat specific individuals, who don’t have a strong desire to communicate. Proactivity is crucial for keeping workers “alive” in a company network. No one will see your face or detect your mood. Remotely, your presence will be limited, so it’s super important to verbalize your needs and worries.

You might ask:

  • How will your team lead/manager know you’re struggling with a task?
  • How will anyone know that you’ve taken on too much work and need help?
  • How can you improve your project when you are frustrated with it but haven’t told anyone?
  • What should you do after finishing your current task?
  • What’s in your boss’s mind?

These are the kinds of questions that a remote worker must take into consideration and communicate. On a personal level, this requires practice, proactivity, and goodwill; on the company level, this involves strategy. At Scalac, we use different kinds of remote and in-person activities to engage employees. Mentoring programs to help newcomers with remote work, and special programs for exchanging feedback and to encourage coworkers to give constructive feedback.

Finally, I want you to remember that different people have different social sensitivities and needs. Some employees might be much more productive and communicative when doing all their communication remotely. Others require real-time interactions with varying frequencies to maintain their enthusiasm for the company’s mission. And both ways are okay. 

Summary

In my opinion, remote work is a great way to improve team spirit. It’s also a great life-choice when approached in the right way. Traditional office work hours fail to use employees’ productivity optimally and are often detrimental to their health and work-life balance. Remote work is an opportunity that can be beneficial for many people in different sectors. In my experience, it naturally boosts my excitement about the challenges posed by work. As Confucius said: “Choose a job you love, and you will never have to work a day in your life“. A work environment that you can shape to your needs is a powerful tool for maintaining this attitude throughout your entire life.

Are you Programming in Scala? Looking for new job opportunities? Wanting to work remotely?


You have probably encountered this problem while working with SBT and bigger projects. I’m talking about compilation times and test execution times, in other words, having to wait instead of working. Imagine working with a build tool that rebuilds only what is necessary, using a distributed cache, so if module A is built by one of your team members you won’t have to do it again. Or imagine being able to run builds of different parts of your project in parallel, or run tests only for the affected code that has been changed. Sounds promising right? That’s why, in this tutorial, I will be showing you what Bazel build is and how to set your project up in Scala.

Introduction to Bazel build


Bazel is a build tool from Google, which allows you to easily manage builds and tests in huge projects. This tool gives huge flexibility when it comes to the configuration and granularity of the basic build unit. It can be a set of packages, one package or even just one file. The basic build unit is called a target, the target is an instance of rules. A rule is a function that has a set of inputs and outputs; if the inputs do not change then the outputs stay the same. By having more targets (the disadvantage of this solution is having more build files to maintain) where not all of them depend on each other, more builds can run in parallel because Bazel build uses incremental builds, so it rebuilds only the part of the dependency graph that has been changed, as well as only running tests for the affected parts.

It can distribute, build and test actions across multiple machines, and then build and reuse previously done cached work, which makes your builds even more scalable.

Bazel can also print out a dependency graph, the results of which can be visualized on this page webgraphviz.com

So if your project takes a lot of time to build, and you don’t want to waste any more time, this tool is what you need. Speed up your compile times, speed up your tests, speed up your whole team’s work!

In this tutorial, we will be using Bazel version 1.0.0.

Project structure

We will be working on a project with this structure:
├── BUILD
├── WORKSPACE
├── bazeltest
│   ├── BUILD
│   └── src
│       ├── main
│       │ └── scala
│       │ └── bazeltest
│       │     └── Main.scala
│       └── test
│           └── scala
│               └── bazeltest
│                   └── MainSpec.scala
├── dependencies.yaml
└── othermodule
    ├── BUILD
    └── src
        ├── main
        │   └── scala
        │       └── othermodule
        │           └── Worker.scala
        └── test
            └── scala
                └── othermodule
                    └── WorkerSpec.scala

So we have two modules called: bazeltest and othermodule.
Bazeltest will depend on othermodule.

Workspace file setup

Each project has one WORKSPACE file, where we will define things like Scala version and dependencies. If in the project directory there is a  subdirectory with a WORKSPACE file, then while doing our builds this subdirectory will be omitted.
To make it work with Scala, then let’s take an already prepared boilerplate WORKSPACE file from:
https://github.com/bazelbuild/rules_scala#getting-started

Be aware of the change in rules_scala_version. Rules_scala_version is commit’s sha. So if you want to use the newest version of the rules, check GitHub repository and copy-paste commit’s sha.
We also have to add at the end of the file:
load(“//3rdparty:workspace.bzl”, “maven_dependencies”)
maven_dependencies()

This will be used by a third-party tool called bazel-deps, but we will come back to this at the next step.

So after the changes:
rules_scala_version=“0f89c210ade8f4320017daf718a61de3c1ac4773” # update this as needed

load(“@bazel_tools//tools/build_defs/repo:http.bzl”, “http_archive”)
http_archive(
    name = “io_bazel_rules_scala”,
    strip_prefix = “rules_scala-%s” % rules_scala_version,
   type = “zip”,
    url = “https://github.com/bazelbuild/rules_scala/archive/%s.zip” % rules_scala_version,
)

load(“@io_bazel_rules_scala//scala:toolchains.bzl”, “scala_register_toolchains”)
scala_register_toolchains()

load(“@io_bazel_rules_scala//scala:scala.bzl”, “scala_repositories”)
scala_repositories()

# bazel-skylib 0.8.0 released 2019.03.20 (https://github.com/bazelbuild/bazel-skylib/releases/tag/0.8.0)
skylib_version = “0.8.0”
http_archive(
    name = “bazel_skylib”,
   type = “tar.gz”,
    url = “https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib.{}.tar.gz”.format (skylib_version, skylib_version),
    sha256 = “2ef429f5d7ce7111263289644d233707dba35e39696377ebab8b0bc701f7818e”,
)

load(“//3rdparty:workspace.bzl”, “maven_dependencies”)
maven_dependencies()

scala_repositories((
    “2.12.8”,
    {
      “scala_compiler”: “f34e9119f45abd41e85b9e121ba19dd9288b3b4af7f7047e86dc70236708d170”,
      “scala_library”: “321fb55685635c931eba4bc0d7668349da3f2c09aee2de93a70566066ff25c28”,
      “scala_reflect”: “4d6405395c4599ce04cea08ba082339e3e42135de9aae2923c9f5367e957315a”
    }
))
 


If you wish to set a specific Scala version, add code from: https://github.com/bazelbuild/rules_scala#getting-started
scala_repositories((

    "2.12.8",

    {

       "scala_compiler": "f34e9119f45abd41e85b9e121ba19dd9288b3b4af7f7047e86dc70236708d170",

       "scala_library": "321fb55685635c931eba4bc0d7668349da3f2c09aee2de93a70566066ff25c28",

       "scala_reflect": "4d6405395c4599ce04cea08ba082339e3e42135de9aae2923c9f5367e957315a"

    }

))

In this file, we will setup the Scala rules and everything else that is needed to compile the Scala project.

BUILD files setup


To write BUILD files we will use the following methods:
  1. load – which loads the Bazel Scala rules, and extensions
  2. scala_binary – generates a Scala executable
  3. scala_library –  generates a .jar file from Scala source files.
  4. scala_test – generates a Scala executable that runs unit test suites written using the scalatest library.

Start from the BUILD file in a project folder.
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_binary")
scala_binary(
    name = "App",
    deps = [
        "//bazeltest"
    ],
    main_class = "bazeltest.Main"
)
  We have named it App, just one dependency to the bazeltest package. In deps, we list our dependencies, where our own modules or third party can be. Main_class is our entry point.

In the bazeltest package BUILD file:
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_library", "scala_test")
 
scala_library(
   name = "bazeltest",
   srcs = ["src/main/scala/bazeltest/Main.scala"],
   deps = [
       "//othermodule",
       "//3rdparty/jvm/joda_time:joda_time"
   ],
   visibility = ["//:__pkg__"]
)
 
scala_test(
    name = "test-main",
    srcs = ["src/test/scala/bazeltest/MainSpec.scala"],
    deps = [":bazeltest"]
)

Our Main.scala file will use some external third party dependency such as joda date time, and Worker from the subpack package. In srcs we set our Main.scala file, but it could be a list of files, listed one by one or a  matching path pattern for example:
glob(["src/main/scala/bazeltest/*.scala"]) 
( then we use glob ), could even be a package with all the subpackages, such as:
glob(["src/main/scala/bazeltest/**/*..scala"]) 
and in deps all the necessary dependencies, so for this example our own sub pack package plus third part joda date time. For now, it points to the 3rdparty folder which does not exist yet, this will be done at one of the next steps so don’t worry. Visibility is used to define which other targets can use this target as a dependency, in this example, we define a project folder containing the main BUILD file.
Now the BUILD file for othermodule:
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_library", "scala_test")
 
scala_library(
     name = "othermodule",
     srcs = glob(["src/main/scala/othermodule/*.scala"]),
     deps = [],
     visibility = ["//bazeltest:__pkg__"]
)
 
scala_test(
    name = "test-othermodule",
    srcs = ["src/test/scala/othermodule/WorkerSpec.scala"],
    deps = [":othermodule"]
)
Here we have set up a visibility param to the bazeltest package. So only this package can read from this one. If other packages try to reach this, we will see an error.  

Dependencies

We will use a third-party tool for this: https://github.com/johnynek/bazel-deps
Open the dependencies.yaml file and put this there:
options:
 buildHeader: [
   "load(\"@io_bazel_rules_scala//scala:scala_import.bzl\", \"scala_import\")",
   "load(\"@io_bazel_rules_scala//scala:scala.bzl\", \"scala_library\", \"scala_binary\", \"scala_test\")"
 ]
 languages: [ "java", "scala:2.12.8" ]
 resolverType: "coursier"
 resolvers:
   - id: "mavencentral"
     type: "default"
     url: https://repo.maven.apache.org/maven2/
   - id: "hmrc"
     type: "default"
     url: https://hmrc.bintray.com/releases
 strictVisibility: true
 transitivity: runtime_deps
 versionConflictPolicy: highest
 
dependencies:
 joda-time:
   joda-time:
     lang: java
     version: "2.10.4"
 
 com.typesafe.scala-logging:
   scala-logging:
     lang: scala
     version: "3.9.0"
 
 com.typesafe.akka:
   akka-http:
     lang: scala
     version: "10.1.7"
 
 org.scalatest:
   scalatest:
     lang: scala
     version: "3.0.8"
 
replacements:
 org.scala-lang:
   scala-library:
     lang: scala/unmangled
     target: "@io_bazel_rules_scala_scala_library//:io_bazel_rules_scala_scala_library"
   scala-reflect:
     lang: scala/unmangled
     target: "@io_bazel_rules_scala_scala_reflect//:io_bazel_rules_scala_scala_reflect"
   scala-compiler:
     lang: scala/unmangled
     target: "@io_bazel_rules_scala_scala_compiler//:io_bazel_rules_scala_scala_compiler"
 
 org.scala-lang.modules:
   scala-parser-combinators:
     lang: scala
     target:
       "@io_bazel_rules_scala_scala_parser_combinators//:io_bazel_rules_scala_scala_parser_combinators"
   scala-xml:
     lang: scala
     target:
       “@io_bazel_rules_scala_scala_xml//:io_bazel_rules_scala_scala_xml"
(Language is always required and may be one of java, Scala, Scala/unmangled. This is important, if you define an invalid language then errors will occur. Replacements are used for internal targets instead of Maven ones.)  

Save the system variable of this project path, for example (working on a Mac): export MY_PROJ_DIR=`pwd`
We will need this in a minute.

  Clone https://github.com/johnynek/bazel-deps and enter the bazel-deps folder. Ensure that this tool uses the same rules_scala commit sha.
Open the WORKSPACE file inside the bazel-deps and look for this:
git_repository(

    name = "io_bazel_rules_scala",

    remote = "https://github.com/bazelbuild/rules_scala",

    commit = "0f89c210ade8f4320017daf718a61de3c1ac4773" # HEAD as of 2019-10-17, update this as needed

)
  Commit is of course what we need to change ( if it is different than in our WORKSPACE file in rules_scala_version ).

  bazel run //:parse generate -- --repo-root "$MY_PROJ_DIR" --sha-file 3rdparty/workspace.bzl --deps dependencies.yaml

  This will download dependencies into a 3rdparty folder into your project directory.
INFO: Analyzed target //:parse (0 packages loaded, 0 targets configured).

INFO: Found 1 target...

Target //src/scala/com/github/johnynek/bazel_deps:parseproject up-to-date:

  bazel-bin/src/scala/com/github/johnynek/bazel_deps/parseproject

  bazel-bin/src/scala/com/github/johnynek/bazel_deps/parseproject.jar

INFO: Elapsed time: 0.168s, Critical Path: 0.01s

INFO: 0 processes.

INFO: Build completed successfully, 1 total action

INFO: Build completed successfully, 1 total action

wrote 26 targets in 8 BUILD files

The first run

Before doing the first run, let’s implement our Main and Worker classes.
package bazeltest
 
import othermodule.Worker
import org.joda.time.DateTime
 
object Main extends App {
  println("IN MAIN now: "+DateTime.now().plusYears(11))
  val worker = new Worker
  worker.doSomething()
 
 
  def status(): String = "OKi"
}
package othermodule
 
class Worker {
 
  def doSomething() : Int = {
    println("Doing something")
    12345
  }
 
  def pureFunc(): String = "ABC"
 
}
bazel run //:App
INFO: Analyzed target //:App (1 packages loaded, 2 targets configured).

INFO: Found 1 target...

INFO: From Linking external/com_google_protobuf/libprotobuf_lite.a [for host]:

/Library/Developer/CommandLineTools/usr/bin/libtool: file: bazel-out/host/bin/external/com_google_protobuf/_objs/protobuf_lite/io_win32.o has no symbols

INFO: From Linking external/com_google_protobuf/libprotobuf.a [for host]:

/Library/Developer/CommandLineTools/usr/bin/libtool: file: bazel-out/host/bin/external/com_google_protobuf/_objs/protobuf/error_listener.o has no symbols

INFO: From Building external/com_google_protobuf/libprotobuf_java.jar (122 source files, 1 source jar):

warning: -parameters is not supported for target value 1.7. Use 1.8 or later.

Target //:App up-to-date:

  bazel-bin/App

  bazel-bin/App.jar

INFO: Elapsed time: 52.246s, Critical Path: 23.22s

INFO: 194 processes: 189 darwin-sandbox, 5 worker.

INFO: Build completed successfully, 198 total actions

INFO: Build completed successfully, 198 total actions

IN MAIN now: 2030-10-11T11:26:07.533+01:00

Doing something
The first run takes some time because it has to download the dependencies, so don’t worry.

Unit tests

Now let’s write some simple unit tests:
package bazeltest
import org.scalatest._
 
class MainSpec extends FlatSpec with Matchers {
 
  "status" should "return OK" in {
    Main.status() shouldBe "OKi"
  }
 
}
package othermodule
import org.scalatest._
 
class WorkerSpec extends FlatSpec with Matchers {
 
    val worker = new Worker()
    
      "do something" should "return 12345" in {
        worker.doSomething() shouldBe 12345
      }
    
      "pureFunc" should "return ABC" in {
        worker.pureFunc() shouldBe "ABC"
 

And run them: bazel test //bazeltest:test-main
INFO: Analyzed target //bazeltest:test-main (0 packages loaded, 0 targets configured).

INFO: Found 1 test target...

Target //bazeltest:test-main up-to-date:

  bazel-bin/bazeltest/test-main

  bazel-bin/bazeltest/test-main.jar

INFO: Elapsed time: 1.047s, Critical Path: 0.89s

INFO: 3 processes: 2 darwin-sandbox, 1 worker.

INFO: Build completed successfully, 4 total actions

//bazeltest:test-main                                                    PASSED in 0.5s

 

Executed 1 out of 1 test: 1 test passes.

INFO: Build completed successfully, 4 total actions
bazel test //othermodule:test-othermodule

INFO: Analyzed target //othermodule:test-othermodule (0 packages loaded, 0 targets configured).

INFO: Found 1 test target...

Target //othermodule:test-othermodule up-to-date:

  bazel-bin/othermodule/test-othermodule

  bazel-bin/othermodule/test-othermodule.jar

INFO: Elapsed time: 1.438s, Critical Path: 1.29s

INFO: 2 processes: 1 darwin-sandbox, 1 worker.

INFO: Build completed successfully, 3 total actions

//othermodule:test-othermodule                                           PASSED in 0.6s

 

Executed 1 out of 1 test: 1 test passes.

INFO: Build completed successfully, 3 total actions
Try now to change the status method from Main, to return “OK” instead of “OKi”. Run the tests again: bazel test //bazeltest:test-main
INFO: Analyzed target //bazeltest:test-main (0 packages loaded, 0 targets configured).

INFO: Found 1 test target...

FAIL: //bazeltest:test-main (see /private/var/tmp/_bazel_maciejbak/16727409c9f0575889b09993f53ce424/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/bazeltest/test-main/test.log)

Target //bazeltest:test-main up-to-date:

  bazel-bin/bazeltest/test-main

  bazel-bin/bazeltest/test-main.jar

INFO: Elapsed time: 1.114s, Critical Path: 0.96s

INFO: 3 processes: 2 darwin-sandbox, 1 worker.

INFO: Build completed, 1 test FAILED, 4 total actions

//bazeltest:test-main                                                    FAILED in 0.6s

  /private/var/tmp/_bazel_maciejbak/16727409c9f0575889b09993f53ce424/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/bazeltest/test-main/test.log

 

INFO: Build completed, 1 test FAILED, 4 total actions
bazel test //othermodule:test-othermodule
INFO: Analyzed target //othermodule:test-othermodule (0 packages loaded, 0 targets configured).

INFO: Found 1 test target...

Target //othermodule:test-othermodule up-to-date:

  bazel-bin/othermodule/test-othermodule

  bazel-bin/othermodule/test-othermodule.jar

INFO: Elapsed time: 0.150s, Critical Path: 0.00s

INFO: 0 processes.

INFO: Build completed successfully, 1 total action

//othermodule:test-othermodule                                  (cached) PASSED in 0.6s

 

Executed 0 out of 1 test: 1 test passes.

INFO: Build completed successfully, 1 total action
Bazel build sees what has been changed, and runs tests only for the affected classes. So test results for othermodule are taken from the cache, and only the main tests run. The test failed because we didn’t change the results in the Spec file, so the change expected the result in the test to the Main.status() shouldBe “OK”. Run tests again: bazel test //bazeltest:test-main
INFO: Analyzed target //bazeltest:test-main (0 packages loaded, 0 targets configured).

INFO: Found 1 test target...

Target //bazeltest:test-main up-to-date:

  bazel-bin/bazeltest/test-main

  bazel-bin/bazeltest/test-main.jar

INFO: Elapsed time: 1.389s, Critical Path: 1.22s

INFO: 2 processes: 1 darwin-sandbox, 1 worker.

INFO: Build completed successfully, 3 total actions

//bazeltest:test-main                                                    PASSED in 0.6s

 

Executed 1 out of 1 test: 1 test passes.

INFO: Build completed successfully, 3 total actions

Dependency graph

We can easily visualize our dependency graph: In the command line run: bazel query --noimplicit_deps "deps(//:App)" --output graph
digraph mygraph {

  node [shape=box];

  "//:App"

  "//:App" -> "//bazeltest:bazeltest"

  "//bazeltest:bazeltest"

  "//bazeltest:bazeltest" -> "//bazeltest:src/main/scala/bazeltest/Main.scala"

  "//bazeltest:bazeltest" -> "//3rdparty/jvm/joda_time:joda_time"

  "//bazeltest:bazeltest" -> "//othermodule:othermodule"

  "//othermodule:othermodule"

  "//othermodule:othermodule" -> "//othermodule:src/main/scala/othermodule/Worker.scala"

  "//othermodule:src/main/scala/othermodule/Worker.scala"

  "//3rdparty/jvm/joda_time:joda_time"

  "//3rdparty/jvm/joda_time:joda_time" -> "//external:jar/joda_time/joda_time"

  "//external:jar/joda_time/joda_time"

  "//external:jar/joda_time/joda_time" -> "@joda_time_joda_time//jar:jar"

  "//bazeltest:src/main/scala/bazeltest/Main.scala"

  "@joda_time_joda_time//jar:jar"

  "@joda_time_joda_time//jar:jar" -> "@joda_time_joda_time//jar:joda_time_joda_time.jar\n@joda_time_joda_time//jar:joda_time_joda_time-sources.jar"

  "@joda_time_joda_time//jar:joda_time_joda_time.jar\n@joda_time_joda_time//jar:joda_time_joda_time-sources.jar"

}

Loading: 12 packages loaded

Paste results to webgraphviz.com Bazel build Scala graph

Generate jar

bazel build //:App
INFO: Analyzed target //:App (0 packages loaded, 0 targets configured).

INFO: Found 1 target...

Target //:App up-to-date:

  bazel-bin/App

  bazel-bin/App.jar

INFO: Elapsed time: 0.085s, Critical Path: 0.00s

INFO: 0 processes.

INFO: Build completed successfully, 1 total action

Bazel build: Summary

In this post, we showed what is bazel, when to use it, and how to make basic configuration. It can take some time to properly set up complex projects using bazel build, but I guarantee you, in the end, it will speed up the whole team’s work.


Useful links

  1. Official Bazel build documentation https://docs.bazel.build/versions/1.0.0/bazel-overview.html
  2. Building Scala with Bazel build- Natan Silnitsky https://www.youtube.com/watch?v=K2Ytk0S4PF0
  3. Building Java Applications with Bazel https://www.baeldung.com/bazel-build-tool