Dirty clean code. Creative Stuff. Stuff.

Golden master testing aka Characterization test: a powerful tool to win your fight against legacy code

In this post I will talk about golden master test aka characterization test: what it is and how to use it.

In the last few months the focus during my daily job was not only on mobile. I had the chance to work on some front-end and back-end application of group. In particular, I worked with my team to renew the customer area of all the main brands sites: volagratis .com, and During the last week I did pair programming with Emanuele Ianni. Emanuele is a senior full-stack software engineer and a true nerd :alien:/computer science lover :heart:. We needed to implement a new feature for a family of microservices (based on Java 1.8 and Spring Boot) that make up the back-end of the customer area, both for web and mobile apps of group. Unfortunately, we found some legacy code without tests, exactly where we planned to add the feature. At this moment Emanuele showed me the Golden master testing technique. Soooo what is golden master testing? As always (and maybe you can expect it because you are a huge fan of my blog and you read all my previous posts :laughing:) Wikipedia gives us all the answer we need:

In computer programming, a characterization test (also known as Golden Master Testing) is a means to describe (characterize) the actual behavior of an existing piece of software, and therefore protect existing behavior of legacy code against unintended changes via automated testing. This term was coined by Michael Feathers…… When creating a characterization test, one must observe what outputs occur for a given set of inputs. Given an observation that the legacy code gives a certain output based on given inputs, then a test can be written that asserts that the output of the legacy code matches the observed result for the given inputs.

So Golden master testing, mostly know as characterization test, is a technique by which we can be able to put large and complex legacy code under test: we generated some output given some input for a piece of code, and we write tests in which we assert that the output from the source code must be the same we received before. In this way we can start to refactor a piece of code and be sure that our modifications didn’t change the behaviour of the source code. Whooaaa!! No more risky approaches to do refactoring without tests!!! :relieved: :clap:
Now it’s time for an example. In this article I will show you a simple example where I apply this technique to put under test a piece of legacy code. You can find the entire source code in this github repository. Suppose for example that you found this class, TravelsAdapter, in the code you’re working on.

public class TravelsAdapter {
    public List<Travel> adapt(JsonNode jsonNode) throws InvalidTravelException {
        List<Travel> travels = new ArrayList<>();
        JsonNode payloadNode = jsonNode.with("data");
        if (payloadNode.findValue("orderId") == null || 
                StringUtils.isBlank(payloadNode.findValue("orderId").textValue())) {
            throw new InvalidTravelException("Invalid order id");
        long orderId = payloadNode.findValue("orderId").asLong();
        JsonNode flights = payloadNode.withArray("flights");
        if (flights.size() == 0) {
            throw new InvalidTravelException("Invalid json (no flights)");
        flights.iterator().forEachRemaining(flight -> {
            ObjectNode nodeFlight = (ObjectNode) flight;
            if (nodeFlight.get("flightId") == null || StringUtils.isBlank(nodeFlight.get("flightId").textValue())) {
                try {
                    throw new InvalidTravelException("Invalid flightNumber value");
                } catch (InvalidTravelException e) {
            String flightNumber = nodeFlight.get("flightId").textValue();
            String arrivalAirport = nodeFlight.get("to").textValue();
            String departureAirport = nodeFlight.get("from").textValue();
            String airline = nodeFlight.get("airline").textValue();
            travels.add(new Travel(
        return travels;

It’s really a mess. So we start to think “I want to see the tests of this class to understand what it does”, but we search for them in the project and……there aren’t any tests for this class!!! :fearful:. The logic contained in this class seems a little bit twisted, and also it would take a lot of time to write a complete suite of test case because we need to understand from the beginning every single path contained in this class. This is a case where golden master testing could help us.
The first thing we can do is to observe the method returns a list of Travel objects. To write our golden master tests we need to find a way to do a comparison between the Travel objects returned from the adapt method and the one we expect. To do this we can add for example a toString method the Travel class and test the returned value from it. So the Travel class will be the following one.

public class Travel {
    private final long orderId;
    private final String flights;
    private final String flightId;
    private final String airline;
    private final String departureAirport;
    private final String arrivalAirport;

    Travel(long orderId,
           String flights,
           String flightId,
           String airline,
           String departureAirport,
           String arrivalAirport) {
        this.orderId = orderId; = flights;
        this.flightId = flightId;
        this.airline = airline;
        this.departureAirport = departureAirport;
        this.arrivalAirport = arrivalAirport;

    public String toString() {
        return "Travel{" +
                    "orderId=" + orderId + ", " +
                    "flights='" + flights + '\'' + ", " +
                    "flightId='" + flightId + '\'' + ", " +
                    "airline='" + airline + '\'' + ", " +
                    "departureAirport='" + departureAirport + '\'' + ", " +
                    "arrivalAirport='" + arrivalAirport + '\'' +

Now we can write some tests and use the output as the expectation. In this way we will be sure that if we start to do some refactoring operation on this class our modification didn’t broken any behaviour of the class. So we can do our refactoring with an high level of confidence that everything is working as it was working before our modification :relieved:. To get the output for the test, you can write your test and made them fails, and in the meanwhile log the result so that we can copy it and use it in the next run iteration of our test. The following test is the one we generated for the class we saw before.

public class TravelsAdapterTest {

    public void goldenMaster() throws IOException, InvalidTravelException {
        TravelsAdapter travelsAdapter = new TravelsAdapter();

        List<Travel> travels = travelsAdapter.adapt(generateRequest());

        StringBuilder builder = new StringBuilder();
        travels.forEach(bp -> {
                is("Travel{" +
                            "orderId=0, " +
                            "flights='{" +
                                "\"from\":\"MXP\"," +
                                "\"to\":\"FCO\"," +
                                "\"flightId\":\"1111\"," +
                                "\"direction\":\"OUTBOUND\"," +
                                "\"airline\":\"U2\"," +
                                "\"departure\":\"2018-04-20T12:00:00\"," +
                                "\"boardingCard\":{" +
                                    "\"id\":\"485\"," +
                                    "\"firstName\":\"Fabrizio\"," +
                                    "\"lastName\":\" Duroni\"," +
                                    "\"seat\":\"V23\"," +
                                    "\"urls\":[" +
                                        "\"http://aboardingcard/resource1\"," +
                                        "\"http://aboardingcard/resource2\"," +
                                        "\"http://aboardingcard/resource3\"" +
                                "]}}', " +
                                "flightId='1111', " +
                                "airline='U2', " +
                                "departureAirport='MXP', " +
                                "arrivalAirport='FCO'" +
                          "}\n" +
                        "Travel{" +
                            "orderId=0, " +
                            "flights='{" +
                                "\"from\":\"FCO\"," +
                                "\"to\":\"MXP\"," +
                                "\"flightId\":\"1112\"," +
                                "\"direction\":\"RETURN\"," +
                                "\"airline\":\"AA\"," +
                                "\"departure\":\"2018-05-01T10:00:00\"," +
                                "\"boardingCard\":{" +
                                    "\"id\":\"486\"," +
                                    "\"firstName\":\"Chiara\"," +
                                    "\"lastName\":\"Polito\"," +
                                    "\"seat\":\"A15\"," +
                                    "\"urls\":[" +
                                        "\"http://aboardingcard/resource1\"," +
                                        "\"http://aboardingcard/resource2\"," +
                                        "\"http://aboardingcard/resource3\"" +
                                    "]}}', " +
                                    "flightId='1112', " +
                                    "airline='AA', " +
                                    "departureAirport='FCO', " +
                                    "arrivalAirport='MXP'" +

    private JsonNode generateRequest() throws IOException {
        return new ObjectMapper().readTree(
                "{\n" +
                "  \"data\": {\n" +
                "    \"orderId\": \"73hb6yh3be6ebe63bdy6\",\n" +
                "    \"flights\": [\n" +
                "      {\n" +
                "        \"from\": \"MXP\",\n" +
                "        \"to\": \"FCO\",\n" +
                "        \"flightId\": \"1111\",\n" +
                "        \"direction\": \"OUTBOUND\",\n" +
                "        \"airline\": \"U2\",\n" +
                "        \"departure\": \"2018-04-20T12:00:00\",\n" +
                "        \"boardingCard\": {\n" +
                "            \"id\": \"485\",\n" +
                "            \"firstName\": \"Fabrizio\",\n" +
                "            \"lastName\": \" Duroni\",\n" +
                "            \"seat\": \"V23\",\n" +
                "            \"urls\": [\n" +
                "              \"http://aboardingcard/resource1\",\n" +
                "              \"http://aboardingcard/resource2\",\n" +
                "              \"http://aboardingcard/resource3\"\n" +
                "            ]\n" +
                "        }\n" +
                "      },\n" +
                "      {\n" +
                "        \"from\": \"FCO\",\n" +
                "        \"to\": \"MXP\",\n" +
                "        \"flightId\": \"1112\",\n" +
                "        \"direction\": \"RETURN\",\n" +
                "        \"airline\": \"AA\",\n" +
                "        \"departure\": \"2018-05-01T10:00:00\",\n" +
                "        \"boardingCard\": {\n" +
                "            \"id\": \"486\",\n" +
                "            \"firstName\": \"Chiara\",\n" +
                "            \"lastName\": \"Polito\",\n" +
                "            \"seat\": \"A15\",\n" +
                "            \"urls\": [\n" +
                "              \"http://aboardingcard/resource1\",\n" +
                "              \"http://aboardingcard/resource2\",\n" +
                "              \"http://aboardingcard/resource3\"\n" +
                "            ]\n" +
                "        }\n" +
                "      }\n" +
                "    ]\n" +
                "  }\n" +

In this example we generated just one test case, but usually a lot more of them. Basically we can apply a technique named “property testing”: a lot of random input are generated so that there will be an high probability to execute all the possible branch in our source code (and in this way have a higher test coverage).
So we put our TravelsAdapter under test and we can now start to work on this class without any kind of risk :relieved:. Now it’s time to test this technique in your legacy code :grin:.

Code review: what it is and why it matters

In this post I will talk about code review: what it is and why it matters.

In some of my previous posts (for example in this one), I talked about my new experience at group and how much we care about code quality. In fact I already talked about the fact that we do pair programming during our daily job. But pair programming is not the only techniques we use to be sure that our software matches high code quality standard :sunglasses:.
One of the most important procedure I use during my daily job with my colleagues is code review. What is it? Let’s see a standard definition from wikipedia:

A code review is a process where two or more developers visually inspect a set of program code, typically, several times. The code can be a method, a class, or an entire program. The main code-review objectives are:

  • Best Practice: a more efficient, less error-prone, or more elegant way to accomplish a given task.
  • Error Detection: discovering logical or transitional errors.
  • Vulnerability Exposure: identifying and averting common vulnerabilities like Cross-Site Scripting, Injection, Buffer Overflow, Excessive Disclosure, etc.
  • Malware Discovery ~ This often-overlooked and very special code-review objective looks for segments of code that appear extraneous, questionable, or flat-out weird. The intent is to discover back doors, Trojans, and time bombs. In today’s world malevolent code is a very real threat and should not be overlooked, especially by Government agencies.

The definition is simple and clear. Basically you go through the code of another guy (or from a couple if they are doing pair programming) to find errors, bugs, code style/best practice not compliant to the team set of rules.
Three weeks ago I attended a coding dojo with my colleagues Angelo Sciarra. Angelo is a senior full-stack software engineer with many years of experience.
You may wonder now what is also a coding dojo. So again, here we are with another definition :bowtie::

A Coding Dojo is a meeting where a bunch of coders get together to work on a programming challenge. They have fun and they engage in order to improve their skills.

During the dojo that I attended with Angelo we tried to resolve the Minesweeper problem.
Basically we had to write an automatic Minesweeper resolver (do you remember the Windows game? :heart_eyes:). At the end of the dojo we didn’t complete the task, so I decided to try to solve it in another way. I developed a complete command line version of a Minesweeper resolver and let Angelo do the code review of my implementation. In this way I can show you the power of code review :neckbeard: (and last but not least how much meticulous is Angelo during his code review :cold_sweat::sweat_smile::cupid:).
Before starting, I suggest you to have a look at this repository that contains the entire Minesweeper implementation I develop and, on the Code review pull request opened on this repo you can find the observation/new implementation from Angelo. Usually the code reviewer doesn’t implement by himself/herself the stuff of his/her observation, but in this case we did it so that we can share the code before/after the code review in a pull request (and also to show you the Angelo’s skills :heart_eyes:).
To facilitate you in the navigation of the two different implementations I created two class diagram: one that describe my implementation before the code review, and the second one that shows the final result after Angelo’s code review. The following one describes my implementation of the minesweeper.

fabrizio duroni minesweeper

This one describes Angelo’s implementation.

angelo sciarra minesweeper

So let’s start to see which kind of observation I received from Angelo, that basically include most of the observation you could receive during a code review.
The first observation I received from Angelo is about the java JDK version I used for my project. I did the setup of the project using JDK 1.5 instead of JDK 1.8 (as you may know, this is a more recent version). In general it is common to receive suggestion about technology specific problems/setup/changes, especially if your code reviewer is more experienced than you on that type of technology.

technology version update

In fact Angelo gave me another technology advice during his review. He suggested to change some pieces of code with others that leverage the power of functional programming. This is really interesting because it is easy imagine how much knowledge you can absord from the experience of your code reviewer.

functional update functional update with new class

Another important aspect that is one of the main subject of the code review is software design. In fact Angelo discovered a series of improvement and refactoring opportunities in my code:

  • the Minesweeper class doesn’t need to receive the fields input at construction time but directly in the play() method. In this way the Minesweeper class becomes a stateless object, and the same istance could be used to resolve/unmask multiple fields input.

stateless object

  • The objects that are the building block of a chain of responsability
    named FieldRowParser could become lighter and some of their responsibility could be assigned to some new collaborators. Also the object that contains the parsing status could become more lighter.

lightweight chain parsing status

As you can see from these kind of comments the code review could really improve the general architectural design of your application :heart_eyes::relieved:. Code convention are another important thing to check during code review. For example Angelo told me to move all the constants at the beginning of some of the classes. Usually tools like Github or Gitlab let you discuss your code review by adding comments directly to the code.

constants position guidelines comments

Last but not least, if you are a real fan of clean code, you know that meaningful names are important. So you can suggest some more meaningful name for a class, variable or method.


That’s all for code review. I hope you understood how much important it is to do it and how much your codebase can improve if you use code review as a validation tool and as a tool to find new refactoring opportunities (anyway, I hope Angelo will never be your reviewer :laughing::sparkling_heart:).

Blender tutorial: selecting and transforming objects

Second post of the “Blender tutorial” series. This time we will learn how to select and move objects.

In the first post of the “Blender tutorial” series we learned how the user interface is composed and the most important commands to navigate inside a scene. This time we will be focus on selecting and moving objects inside the 3D view.
We can select an object by using the right button of your mouse. If you’re on the MacBook like me, the right mouse is emulated in some ways (my personal preferences is to use two fingers to emulate a right click). To select multiple objects we can hold the shift button and select with a right click the objects we want. The objects that we will select will be marked in the outliner editor, with a little circle, and in the 3D view with a little border. The color of the border will change based on the theme you selected. In the screenshot below we can see that I selected 2 of the 3 objects in the scene. If we have multiple objects selected, the last one will have a different border. In my case the cube is the last object selected.

blender selecting objects 1

To deselect an object we can just right click on it again. We can also select all the objects in a scene, including cameras and lights, by pressing the “a” key.
There’s also a select menu that gives us more control over the selections we can do. In particular, we have the Circle select, that lets us select objects based on a circle pattern of selection, and the Border select, that lets us select objects based on a squared pattern of selection. There are also other option to select random objects or invert the current selection.

blender selecting objects 2

To translate objects, we can use the transform tools. We can find them under Tools -> Transform. As a consequence of the fact that we are trying to translate an object in 3D space using the mouse pointer tha works in 2D space, it is difficult to understand in which direction we are doing our translation. We can constraint the move to just one axis by pressing:

  • “x” key for the x axis
  • “y” key for the y axis
  • “z” key for the z axis

blender moving objects 1

There’s also the possibility to move an object with discrete values by using its location properties panel under the properties editor or using the object properties panel in the 3D window. Finally we can move objects using also the 3D manipulator widget in the 3D window. We can activate it by pressing on its icon. After that when you select and object you will see three axes. Drag one of them to translate the object in that direction.

blender moving objects 2

We can rotate and scaling an object using the same tools we used for the translation:

  • the transformation tools
  • the 3D manipulator widget

One important thing to consider when we are working with transformation is the transform orientation. This option defines the orientation of the transform operation. This is very important because it influences the final result of the transform operation. You can change the transform orientation in the 3D manipulator widget.

blender moving objects 3

The 3D manipulator widget will place the start of the transform based on the origin of an objects. We can change it by selecting one of the option under Object -> Transform in object mode:

  • Geometry to origin
  • Origin to geometry
  • Origin to 3D cursor
  • Origin to Center of mass (surface)
  • Origin to center of mass (volume)

blender change objects origin 1

When we want to transform a group of objects at once we have a number of options to change the pivot point of the selection. We can choose it by selecting one of the option available from the list near the 3D transform manipulator widget.

blender change objects pivot 1

That’s all for selection and transform of objects. In the next post we will start to explore the art of modeling in Blender.

React Native: the power of RCTBundleURLProvider to build, run and debug on an iOS device from Xcode

In this post I will talk about how to setup up you React Native project on iOS to build, run and debug it on a real device from Xcode.

In the last few days I was working in pair programming with my colleague Mariano Patafio on some new features for a React Native app. Mariano is a senior iOS and Android developer and a true “:apple: Apple fag :apple::laughing: (like me :stuck_out_tongue_closed_eyes:). At some point during our pair session we wanted to test the app on a real iOS device. The app we were working on was an existing iOS app in which we added some React Native views. If you follow the instructions contained in the React Native doc about integrating it in an existing app, you will discover that with that setup you will not be able to run your app on a real device from Xcode. It will work just in the simulator.
In this post I will show you what we discovered: it is possible with the right setup to build, run and debug your React Native app from Xcode. To do this I will use the React Native example app I used in this previous post I wrote about how to create multiple RCTRootView inside you existing app integrated with React Native. The app is very simple: it contains a main screen with 2 buttons that let the user open two different React Native views. You can find this example with the implementation described below in this github repo.
Let’s assume we start with the old implementation of the app described above, where we implemented a
ReactNativeBridgeDelegate that returns the url of the index.bundle that contains our React Native code JS compiled. This url was pointing to a localhost environment.

class ReactNativeBridge {
    let bridge: RCTBridge
    init() {
        bridge = RCTBridge(delegate: ReactNativeBridgeDelegate(), launchOptions: nil)

class ReactNativeBridgeDelegate: NSObject, RCTBridgeDelegate {
    func sourceURL(for bridge: RCTBridge!) -> URL! {
        return URL(string: "http://localhost:8081/index.bundle?platform=ios")

React Native bridge delegate localhost

If we try to build this app on an iPhone, and we open one of the React Native screen we will receive the following error (obviously based on the fact that we are trying to access localhost from the iPhone, and our React Native node server is running on the MacBook Pro where we are building the app).

React Native error on device

How can we build on a real device? First of all we need to add a new build phase to our project that let us run the React Native Xcode Bundler before the real build. The React Native Xcode Bundler is a shell script with name that you can find inside your react native npm package under <you app root folder.>/node_modules/react-native/scripts/. This script must take as input our React Native index.js.

React Native setup bundler

Now we can change our ReactNativeBridgeDelegate implementation. Instead of returning an hard coded url, we use the RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackResource: nil) method. We need to pass "index" as bundle root parameter (the name of the main js file).

React Native bundle url provider setup

Now we can try to build an run again the app on a real device. As you can see now everything works as expected.

React Native app working on device

What’s happening under the hood? Which kind of “magic” are we using here :smirk:? If we start to debug from the call to RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackResource: nil) and we go inside the React Native source code at some point we will see a call to a method named guessPackagerHost. In this method there’s a piece of code that tries to open and read the content of a file named ip.txt (this file is supposed to be in the main bundle of the app). The string returned by this method is used as hostname in the url used by React Native to call the packager we are running on our mac.
Who did create this ip.txt file? Previously we added the execution of the React Native Bundler script as build phase. If we look at the source code of this script you will find the following piece of code:

React Native ip txt generation

Whaaaaaaattttt?!?!?!?!?!? :satisfied: This piece of code basically creates a file named ip.txt that contains the IP address of your computer, extracted using an ifconfig command, concatenated with the domain So the file will contain a string like the following one: <your computer IP address> This is the string returned by the guessPackagerHost method. In the screenshot below you can find the source code of this method and the string that it returns.

React Native my local ip

What is the string added after the IP address? is a public free DNS server created at basecamp. Below you can find a quote from the homepage of the service:

What is is a magic domain name that provides wildcard DNS for any IP address. Say your LAN IP address is Using,   resolves to   resolves to   resolves to   resolves to

…and so on. You can use these domains to access virtual hosts on your development web server from devices on your local network, like iPads, iPhones, and other computers. No configuration required!

How does it work? runs a custom DNS server on the public Internet. When your computer looks up a domain, the DNS server extracts the IP address from the domain and sends it back in the response.

React Native

This basically means that is a domain name we can use to access our local packager environment on our mac from our iPhone and iPad, based on the fact that the devices are all on the same network.
That’s all, and as you can see everything works “like magic” :relaxed:.

Blender tutorial: user interface

In this new series of post I will talk about learning to use Blender, the famous 3D computer graphics software. A series of tutorial for beginners/newbies (like me).

If you like computer graphics, at some point during your studies you will want to learn to use a 3D content creation software. That’s why I started to study Blender, the most beautiful and famous open source 3D software available for free in the market. In this series of posts I will guide you through its features with some tutorials and references list. At the time of this writing the available version of Bender used for this tutorials is the 2.79. All the tutorials are written using Blender on a MacBook Pro.
Let’s start from the user interface.

The default layout is composed of individual panels, and inside each one of them we can find an editor. The main editors are:

  • info editor, in the top left part of the screen. It contains the main menu of Blender. It contains also a layout switcher, to quickly change the layout of Blender based on our needs (animation, modeling…) and a renderer switcher, to select the renderer engine.
  • outliner editor, it contains a list of all the objects in the scene.
  • properties editor, it contains the properties of an object. It is context specific, so its content will change accordingly to the selected object. It contains also a lot of context specific tabs with specific properties for different context.
  • timeline and animation editor, used to create and modify animation
  • viewport, that contains the 3D window in which our scene is shown and where we can add, remove or modify objects.

blender ui editors

We can switch a panel from one editor to another by clicking on the icon that shows the current editor selected: a list with all the available editors will be shown and we can choose one of them.

blender ui switch editor

On the left side of the viewport we can find a series of tabs that contain some operations, tools and actions we can apply to the 3D window content. This tabs will change based on the fact that we selected or not an object and also based on which type of object we selected. We can also show the object properties sub-panel by clicking the plus (+) button on the right. That sub-panel gives us some information about the object we selected in the 3D window.
At the bottom of the 3D window we can find the 3D manipulator widget, that allows us to scale, rotate and translate object with the mouse drag.
Then we have the layer switcher, that will let us create layered scene (we will talk about layers in a future post).
We have also the viewport shading button, that let use choose the desired type of visualization we want for our scene:

  • bounding box
  • wireframe
  • solid, that shows also colors of the objects
  • texture mode, that shows also textures of the objects
  • materials, that let us adds the materials to our objects
  • rendered

Finally we have the editing interaction mode selector, that allow us to switch between editing mode:

  • object mode, that allow us to deal with individual objects
  • edit mode, that allow us to change the objects

The menus on the left of the editing mode selector will change accordingly to the mode selected.

blender ui 3D window

To navigate in the 3D space, usually Blender require a 3 button mouse (we will see below how to emulate a 3 buttons mouse). Anyway, as we’re on a MacBook pro we can do the following basic operation with the “alternative” default mapping:

  • orbit around in the scene by dragging with two fingers
  • zoom in/out in the scene with pinch and zoom
  • pan in the scene with shift + drag with two fingers

There are also some other basic useful 3D navigation commands:

  • align view to cursor and show all objects with shift + “c” (or alternatively in object mode View -> Align View -> Center Cursor)
  • align view to one side with the options Left, Right, Top, Bottom, Front, Back contained in the View menu
  • change between orthographic and perspective view with the menu option View -> View Persp/Ortho

You can change the user preferences by going to File -> User Preferences. Here you can modify settings for:

  • Interface, so what Blender should show in the interface
  • Editing, so how we edit objects
  • Input, how mouse and keyboard are configured
  • Add-ons, where you can manage plugins
  • Themes, to change the color of the interface
  • File, to configure standard paths
  • System, for system specific settings

To be noted is the option “Emulate 3 Button mouse” in the input settings. This option let Blender emulates a 3 button mouse using the Alt button. Int this way you can use this setting to use Blender with standard keys for mouse.
That’s enough first post. See you in the second tutorial about selecting and translating objects.