[ This is a content summary only. Visit our website http://ift.tt/1b4YgHQ for full links, other content, and more! ]
by Web Desk via Digital Information World
"Mr Branding" is a blog based on RSS for everything related to website branding and website design, it collects its posts from many sites in order to facilitate the updating to the latest technology.
To suggest any source, please contact me: Taha.baba@consultant.com
The following is a short extract from our book, Researching UX: Analytics, written by Luke Hay. It's the ultimate guide to using analytics for improved user experience. SitePoint Premium members get access with their membership, or you can buy a copy in stores worldwide.
When you first start analyzing data, it’s easy to make mistakes, particularly if you’re new to analytics. Don’t let that put you off, though! This section lists some of the main pitfalls, and how they’re best avoided—to ensure your analysis paints a true picture of user behavior.
Different analytics tools will use different terminology to describe the same thing. For rookie analysts, this can cause confusion, and can mean that the wrong data is reported. Even within the same tool, terminology can be confusing. One of the most common mistakes people make is to confuse visits and views.
A visit (now known as a session in Google Analytics) generally describes a group of interactions one user takes within a given time frame on your website. A view (or “pageview” in some tools) describes a view of a page on your site that is tracked by the analytics tracking code.
These are two entirely different things, but visits and views are sometimes used interchangeably when people talk about their analytics. As you can imagine, this can cause problems for analysts, as reports will become inaccurate. Make sure you understand the terminology, so that you know what you’re reporting on. (See the Google Analytics glossary at the end of this book if you’re unsure.)
When it comes to analyzing your data, you need to make sure you’re analyzing the most important areas. A very common mistake people make is to focus purely on visits and views. Because you’re a UXer, I know I don’t need to convince you that there’s more to a website than just a lot of people visiting it! You may still find yourself under pressure, though, to increase page views or even visits. Leave this side of things to marketers, and focus your efforts on the numbers that relate to user experience.
Quantitative data is all about numbers. If your account is set up correctly, the numbers don’t lie! Despite this, you need to make sure you don’t forget what the numbers actually represent: real users.
As stated previously, the numbers will tell you what happened, not why, and this is why it’s important not to forget to ask why. You’ll need to look beyond the numbers and consider their context. Make sure you don’t fall into the trap of just reporting what has happened: be sure to consider the bigger picture and think about what the numbers mean for the user experience of your website.
This is where you’ll need to bring in the qualitative methods we touched on previously. You can often use analytics to find a problem, and user research methods to solve it.
One side effect of getting drawn into the numbers is that you automatically consider low numbers, or a drop in numbers, to be bad. While a drop in purchases is likely to be a bad thing, a reduction in the time users spend on particular pages, for example, could be good or bad.
If you’ve redesigned the home page on a website and the time people are spending on it drops, this could be due to the improved efficiency of your design. It may be that people are able to navigate more quickly to areas of interest to them. Once again, context is key here. Work out what any drops actually mean for the website as a whole, rather than assuming they’re always going to be negative.
Just because something happens to your analytics at the same time as you make a change to the website doesn’t mean the two are connected. If you notice changes to your analytics after making a change, you need to be sure it’s not a coincidence and that the two are connected.
You’re likely to have to delve a little deeper into your reports to prove that the rise in conversion rate was due to your great new design. This is covered in more detail in Chapter 6, but it’s something you should be aware of before you take credit (or blame!) for any sizable shifts in your reporting data.
The graph below, taken from tylervigen.com, shows a correlation of close to 95% for cheese consumption and number of people who died by becoming tangled in their bed sheets:
There’s also a strong correlation between ice cream sales and drownings at sea, as both go up in the summer. Only an analyst severely lacking common sense would say that ice cream causes drowning, though!
The correlation versus causation issue is probably the most prolific mistake I see people make when analyzing data. When it comes to website analytics, one example of this might be where data shows that people who use site search covert 50% more than those who don’t. This could convince UXers to encourage more people to use the site search. However, the more likely correlation is that people who use the site search are a more engaged audience than the average users, and also have a better idea of what they’re looking for—meaning that they naturally have higher conversion rates.
Combining quant and qual (and sometimes your own common sense) will help ensure you don’t fall into the trap of confusing correlation and causation. Split testing is also a great way to determine true causation, and will help to protect against drawing incorrect conclusions from your data. We’ll cover split testing more in Chapter 6.
As UXers, we know that different people use websites in different ways. We also know that the same person is likely to use a website differently when using different devices, or even using the same website at different times of the day. We need to include these considerations of user behavior in our quantitative analysis.
Continue reading %11 Common Analytics Pitfalls to Watch Out For%
In my previous articles we have discussed various Elixir terms and written a hefty amount of code. What we have not discussed, however, is how to structure and organize your code so that it is easy to maintain and release.
Applications are very common for Erlang and Elixir and are used to build reusable components that behave as stand-alone units. One application may have its own supervision tree and configuration, and it can rely on other applications that are available either locally or on some remote server. All in all, working with applications is not that complex, and people who have come, say, from the world of Ruby will find many familiar concepts.
In this article you will learn what applications are, how they can be created, how to specify and install dependencies, and how to provide environment values. At the end of the article we will do some practice and create a web-based calculator.
I will be using Elixir 1.5 in this article (it was released a couple of months ago), but all the explained concepts should apply to version 1.4 as well.
Some might argue that the term "application" is not very appropriate because in Erlang and Elixir it actually means a component, or some code that has a bunch of dependencies. The application itself can be used as a dependency as well—in Ruby world we would call it a "gem".
All in all, applications are very common in Elixir and allow you to craft reusable components while also providing easy dependency management. They consist of one or multiple modules with zero or more dependencies and are described by the application resource file. This file contains information about the application's name, version, its modules, dependencies, and some other stuff. You may create the resource file manually, but it is much easier to do so with the mix tool that will also prepare a correct folder structure for you.
So let's see how we can create a new Elixir application!
To create a new application, all you need to do is run the following command:
mix new app_name
We can also provide the --sup flag to create an empty supervisor for us. Let's create a new application called Sample this way:
mix new sample --sup
This command will create a sample directory for you with a handful of files and folders inside. Let me quickly guide you through them:
start/2 function that creates an empty supervisor.project function, you provide the app's name (as an atom), version, and environment. The application function contains information about the application module callback and runtime dependencies. In our case, Sample.Application is set as the application module callback (that can be treated as the main entry point), and it has to define a start/2 function. As already mentioned above, this function was already created for us by the mix tool. Lastly, the deps function lists build-time dependencies.It is quite important to distinguish between runtime and build-time dependencies. Build-time dependencies are loaded by the mix tool during the compilation and are basically compiled into your application.
They can be fetched from a service like GitHub, for example, or from the hex.pm website, an external package manager that stores thousands of components for Elixir and Erlang. Runtime dependencies are started before the application starts. They are already compiled and available for us.
There are a couple of ways to specify build-time dependencies in a mix.exs file. If you'd like to use an application from the hex.pm website, simply say:
{:dependency_name, "~> 0.0.1"}
The first argument is always an atom representing the application's name. The second one is the requirement, a version that you desire to use—it is parsed by the Version module. In this example, ~> means that we wish to download at least version 0.0.1 or higher but less than 0.1.0. If we say ~> 1.0, it means we'd like to use version greater than or equal to 1.0 but less than 2.0. There are also operators like ==, >, <, >=, and <= available.
It is also possible to directly specify a :git or a :path option:
{:gettext, git: "http://ift.tt/2y1Di4v", tag: "0.1"}
{:local_dependency, path: "path/to/local_dependency"}
There is also a :github shortcut that allows us to provide only the owner's and a repo's name:
{:gettext, github: "elixir-lang/gettext"}
To download and compile all dependencies, run:
mix deps.get
This will install a Hex client if you don't have one and then check if any of the dependencies needs to be updated. For instance, you can specify Poison—a solution to parse JSON—as a dependency like this:
defp deps do
[
{:poison, "~> 3.1"}
]
end
Then run:
mix deps.get
You will see a similar output:
Running dependency resolution... Dependency resolution completed: poison 3.1.0 * Getting poison (Hex package) Checking package (http://ift.tt/2y2ev01) Fetched package
Poison is now compiled and available on your PC. What's more, a mix.lock file will be created automatically. This file provides the exact versions of the dependencies to use when the application is booted.
To learn more about dependencies, run the following command:
mix help deps
Applications are behaviours, just like GenServer and supervisors, which we talked about in the previous articles. As I already mentioned above, we provide a callback module inside the mix.exs file in the following way:
def application do
[
mod: {Sample.Application, []}
]
end
Sample.Application is the module's name, whereas [] may contain a list of arguments to pass to the start/2 function. The start/2 function must be implemented in order for the application to boot properly.
The application.ex contains the callback module that looks like this:
defmodule Sample.Application do
use Application
def start(_type, _args) do
children = [
]
opts = [strategy: :one_for_one, name: Sample.Supervisor]
Supervisor.start_link(children, opts)
end
end
The start/2 function must either return {:ok, pid} (with an optional state as the third item) or {:error, reason}.
Another thing worth mentioning is that applications do not really require the callback module at all. It means that the application function inside the mix.exs file may become really minimalistic:
def application do
[]
end
Such applications are called library applications. They do not have any supervision tree but can still be used as dependencies by other applications. One example of a library application would be Poison, which we specified as a dependency in the previous section.
The easiest way to start your application is to run the following command:
iex -S mix
You will see an output similar to this one:
Compiling 2 files (.ex) Generated sample app
A _build directory will be created inside the sample folder. It will contain .beam files as well as some other files and folders.
If you don't want to start an Elixir shell, another option is to run:
mix run
The problem, though, is that the application will stop as soon as the start function finishes its job. Therefore, you may provide the --no-halt key to keep the application running for as long as needed:
mix run --no-halt
The same can be achieved using the elixir command:
elixir -S mix run --no-halt
Note, however, that the application will stop as soon as you close the terminal where this command was executed. This can be avoided by starting your application in a detached mode:
elixir -S mix run --no-halt --detached
Sometimes you may want the user of an application to set some parameter before the app is actually booted. This is useful when, for example, the user should be able to control which port a web server should listen to. Such parameters can be specified in the application environment that is a simple in-memory key-value storage.
In order to read some parameter, use the fetch_env/2 function that accepts an app and a key:
Application.fetch_env(:sample, :some_key)
If the key cannot be found, an :error atom is returned. There are also a fetch_env!/2 function that raises an error instead and get_env/3 that may provide a default value.
To store a parameter, use put_env/4:
Application.put_env(:sample, :key, :value)
The fourth value contains options and is not required to be set.
Lastly, to delete a key, employ the delete_env/3 function:
Application.delete_env(:sample, :key)
How do we provide a value for the environment when starting an app? Well, such parameters are set using the --erl key in the following way:
iex --erl "-sample key value" -S mix
You can then easily fetch the value:
Application.get_env :sample, :key # => :value
What if a user forgets to specify a parameter when starting the application? Well, most likely we need to provide a default value for such cases. There are two possible places where you can do this: inside the config.exs or inside the mix.exs file.
The first option is the preferred one because config.exs is the file that is actually meant to store various configuration options. If your application has lots of environment parameters, you should definitely stick with config.exs:
use Mix.Config config :sample, key: :value
For a smaller application, however, it is quite okay to provide environment values right inside mix.exs by tweaking the application function:
def application do
[
extra_applications: [:logger],
mod: {Sample.Application, []},
env: [ # <====
key: :value
]
]
end
Okay, in order to see applications in action, let's modify the example that was already discussed in my GenServer and Supervisors articles. This is a simple calculator that allows users to perform various mathematical operations and fetch the result quite easily.
What I want to do is make this calculator web-based, so that we can send POST requests to perform calculations and a GET request to grab the result.
Create a new lib/calc_server.ex file with the following contents:
defmodule Sample.CalcServer do
use GenServer
def start_link(initial_value) do
GenServer.start_link(__MODULE__, initial_value, name: __MODULE__)
end
def init(initial_value) when is_number(initial_value) do
{:ok, initial_value}
end
def init(_) do
{:stop, "The value must be an integer!"}
end
def add(number) do
GenServer.cast(__MODULE__, {:add, number})
end
def result do
GenServer.call(__MODULE__, :result)
end
def handle_call(:result, _, state) do
{:reply, state, state}
end
def handle_cast(operation, state) do
case operation do
{:add, number} -> {:noreply, state + number}
_ -> {:stop, "Not implemented", state}
end
end
def terminate(_reason, _state) do
IO.puts "The server terminated"
end
end
We will only add support for the add operation. All other mathematical operations can be introduced in the same way, so I won't list them here to make the code more compact.
The CalcServer utilizes GenServer, so we get child_spec automatically and can start it from the callback function like this:
def start(_type, _args) do
children = [
{Sample.CalcServer, 0}
]
opts = [strategy: :one_for_one, name: Sample.Supervisor]
Supervisor.start_link(children, opts)
end
0 here is the initial result. It must be a number, otherwise CalcServer will immediately terminate.
Now the question is how do we add web support? To do that, we'll need two third-party dependencies: Plug, which will act as an abstraction library, and Cowboy, which will act as an actual web server. Of course, we need to specify these dependencies inside the mix.exs file:
defp deps do
[
{:cowboy, "~> 1.1"},
{:plug, "~> 1.4"}
]
end
Now we can start the Plug application under our own supervision tree. Tweak the start function like this:
def start(_type, _args) do
children = [
Plug.Adapters.Cowboy.child_spec(
:http, Sample.Router, [], [port: Application.fetch_env!(:sample, :port)]
),
{Sample.CalcServer, 0}
]
# ...
end
Here we are providing child_spec and setting Sample.Router to respond to requests. This module will be created in a moment. What I don't like about this setup, however, is that the port number is hard-coded, which is not really convenient. I might want to tweak it when starting the application, so let's instead store it in the environment:
Plug.Adapters.Cowboy.child_spec( :http, Sample.Router, [], [port: Application.fetch_env!(:sample, :port)] )
Now provide the default port value inside the config.exs file:
config :sample, port: 8088
Great!
What about the router? Create a new lib/router.ex file with the following contents:
defmodule Sample.Router do use Plug.Router plug :match plug :dispatch end
Now we need to define a couple of routes to perform addition and fetch the result:
get "/result" do
conn |> ok(to_string(Sample.CalcServer.result))
end
post "/add" do
fetch_number(conn) |> Sample.CalcServer.add
conn |> ok
end
We are using get and post macros to define the /result and /add routes. Those macros will set the conn object for us.
ok and fetch_number are private functions defined in the following way:
defp fetch_number(conn) do
Plug.Conn.fetch_query_params(conn).params["number"] |>
String.to_integer
end
defp ok(conn, data \\ "OK") do
send_resp conn, 200, data
end
fetch_query_params/2 returns an object with all the query parameters. We are only interested in the number that the user sends to us. All parameters initially are strings, so we need to convert it to integer.
send_resp/3 sends a response to the client with the provided status code and a body. We won't perform any error-checking here, so the code will always be 200, meaning everything is okay.
And, this is it! Now you may start the application in any of the ways listed above (for example, by typing iex -S mix) and use the curl tool to perform the requests:
curl http://localhost:8088/result # => 0 curl http://localhost:8088/add?number=1 -X POST # => OK curl http://localhost:8088/result # => 1
In this article we have discussed Elixir applications and their purpose. You have learned how to create applications, provide various types of information, and list dependencies inside the mix.exs file. You've also seen how to store the configuration inside the app's environment and learned a couple of ways to start your application. Lastly, we have seen applications in action and created a simple web-based calculator.
Don't forget that the hex.pm website lists many hundreds of third-party applications ready for use in your projects, so be sure to browse the catalog and pick the solution that suits you!
Hopefully, you found this article useful and interesting. I thank you for staying with me and until the next time.