Dunja Radulov wrote this on December 16, 2015

Rails Girls Novi Sad #3 at Rendered Text

On 5 and 6 December we had the pleasure of welcoming the third Rails Girls workshop at our office.

Rails Girls is a global volunteer community with the goal to give women the opportunity to learn how to code in Ruby on Rails, and use that knowledge to build their own applications.

Rails Girls Novi Sad at Rendered Text

The third Rails Girls workshop in Novi Sad was organised by Kristina Stojaković, Aleksandra Vukošić and Milana Ljubisavljević, who have done a wonderful job of getting together a great team of mentors, coordinating the workshop, and creating a perfect opportunity for women interested in programming to take their first steps in the world of Ruby on Rails.

Three of our colleagues participated as mentors in the workshop - Nemanja is an experienced mentor who has already taught at two workshops in Belgrade and Novi Sad, and Milana and Jelena were participants in previous workshops, and now they are Rails Girls mentors and our new colleagues at Rendered Text.

Rails Girls Novi Sad Workshop

We are proud to support Rails Girls Novi Sad in their mission to encourage more women to enter the world of technology, and are looking forward to supporting future Rails Girls workshops and seeing more women develop their first Ruby on Rails applications.

Rails Girls Novi Sad Workshop

If you’d like to see more photos from the workshop, you can take a peek at our Rails Girls Facebook album.

To keep up with news about future Rails Girls events, you can follow @RailsGirlsNS and @RenderedText on Twitter, or subscribe to our events RSS feed.

Igor Šarčević wrote this on December 11, 2015

Inheritance in the Database

In martial arts, fundamentals are everything. The basic kicks, rolls and jumps are far more important that any fancy technique you will learn during the years of practice. When you improve your basic rolls even a little bit, all the body throws that depend on your ability to roll on the floor will improve tenfold.

Software engineering is almost like training martial arts. We should practice every day, and focus on improving our fundamentals instead of running for the next big shinny thing that we read on Hacker News. Of course, this is easier said that done. It is always easier to learn the basics of a new programming language, than to get better at designing classes and polymorphism.

The rest of this article describes one of the fields that I tried to improve recently — Inheritance design in relational databases.

Administrators

Let’s start with a simple problem. Imagine, that we have a web application and we store information about our users in a database table called users. We keep only the basic information about our users: their first name, last name, and a username that they use to log in to our app.

We, the developers, are also users in our application and we have the corresponding table rows in the users table. But we want to have greater permissions on our system than the rest of our users. We want to be admins — users that can manage the rest of the users, and even tweak the web application’s features.

This can be achieved easily. We can simply create a new database table called admins that will contain information about our admin users. But when we start to write out our SQL CREATE TABLE statements, something feels very odd. All the columns from the users table need to be created in the admins table too. This, of course, feels very wrong. We should take a different route.

Instead of creating an admins table, we can also add an existing column to our users table and use it to distinguish between regular users and administrators. We will call this column type, and will allow two values in its fields: regular for our regular users, and admin for our administrators.

Corresponding to these values we can construct three SQL queries.

To fetch all the users we can write:

SELECT * FROM users;

To fetch regular users, we can write:

SELECT * FROM users WHERE users.type = 'regular';

Finally, to fetch all the admins, we would write:

SELECT * FROM users WHERE users.type = 'admin';

Adding moderators

As our web application grows bigger, we find it increasingly difficult to manage the user interactions on our website. Our company decided that we should allow some of the outstanding users registered on our application to gain additional privileges. We shall call these users moderators.

Let’s add support for moderators in our database. It is easy. We just follow the design for our administrators and allow the moderator value in the type column.

The moderator lookup is simple and follows the example from our previous queries:

SELECT * FROM users WHERE users.type = 'moderator';

Banning users

One of the privileges that our moderators need is the ability to ban misbehaving users from our application. However, we also want to prevent overly eager moderators, that would ban too much of our users.

There is a simple solution. Every time a moderator bans another user, a counter will be increased. Let’s call this counter banned_users, and add it as a column to our users table. But wait, this is very strange. For a regular user, a banned_users column doesn’t make sense. They can’t ban other users.

Well, there is no nice solution to this issue if we want to store moderators in the same table as our regular users. We will simply need to accept this fact and save a default null or 0 as banned_users value for regular users.

Vehicles

I have talked so much about our little imaginary web application, but I haven’t introduced the main concern it solves. Our imaginary application sells vehicles. Cars, trucks, bicycles, ships, boats… basically everything that can move you or your cargo. Our database also needs to reflect this fact.

Let’s use the previous idea to implement a table for all our vehicles. First, we should list all the information about our vehicles. Price, color, weight and brand name are just some of the things we want to store. Also it would be nice to store some more specific data, for example, number of wheels on a truck.

After tinkering with the column names a little bit, we can see that there are a lot of fields that can not be shared between boats and bicycles. We could fill those fields with null values, but that decision feels a little weird. That could mean that a good portion of the table will be filled with nothing but null values. What can we do?

Using OOP-like inheritance in our databases

How would we design such a structure in an OOP inspired programming language? We would probably create an abstract class called Vehicle and create several subclasses for each type of vehicle. Let’s try to reflect this design into our database.

First, let’s create a vehicles table, that will contain the shared fields for all our vehicles. Price, color, weight and speed come to the mind. Following this step, we would create a table for every kind of vehicle. A table for cars, for example, would only contain the fields relevant to cars that are not present in the vehicles table and a foreign key that points to the rest of the data in the vehicles table.

After a bit of SQL hackery, our database contains all the necessary tables, and our application is ready to consume it. Let’s try some simple queries.

To count the number of vehicles in our database, we can execute the following query:

SELECT COUNT(*) FROM vehicles;

To select every car that has only two seats, we can use the following query:

SELECT COUNT(*) FROM cars WHERE number_of_seats = 2;

Now, let’s try something trickier. List all the cars that are cheaper than $10,000. Don’t forget, the price is saved in the parent vehicle table. We need to use JOIN:

SELECT * FROM cars
INNER JOIN vehicles ON cars.vehicles_id = vehicles.id
WHERE vehicles.price < 10000;

This last query was harder than what we are used to. If the cars table contained the price column, we could write it easier:

SELECT * FROM cars WHERE cars.price < 10000;

Can we design our database schema, to help us to achieve easier lookups?

Design patterns for database inheritance

Before we continue with an improved design, let’s review what we used until now.

In the first example, where we used a single table to store our administrators, moderators and regular users is called single table inheritance. This design pattern is usable when the inherited entities (in our example admins and moderators) have little or no additional fields in comparison to the super entity (in our case user).

In the second example, we designed our vehicles table using class table inheritance design pattern. It is useful for representing a structure in our database that resembles our application level design. However, databases are not well suited for this kind of inheritance, and this design can lead to more complicated database queries and even degraded performance.

The third design pattern for designing inheritance in the database is called concrete table inheritance. It is the design pattern we will use to redesign our database schema and simplify our vehicle related queries.

Simplifying vehicle related queries

To simplify our queries, we will remove the table that represents the abstract entity vehicle and store all the shared fields in every concrete table. This means that our cars table will contain all the data about a car, even its price and color. The trucks table will also have a price column.

Let’s try our lookup for cheaper than $10.000 cars with this new schema:

SELECT * FROM cars WHERE cars.price < 10000;

Much simpler!

Downsides of concrete table inheritance

In the above example, it looks like the last design pattern is the winner. However, life is just not so simple :)

Consider the request to rename the price column, or to add a new age column to vehicles. It is achievable, but we need to remember to rename/add the column in every vehicle like table. With the previous design this was much simpler.

One other common pitfall when using concrete table inheritance is that we can’t mix various types of vehicles in our code if we want to have unique IDs on our objects. Remember, every entity has its own table, that means that the primary keys are only unique on one type of entity.

Final words

I hope you have enjoyed this little trip through various database inheritance schemes. Keep in mind that this was not an exhaustive list, but only a friendly introduction to the topic. Here are some excelent resources that can help you further:

Happy database hacking!

Igor Šarčević wrote this on November 18, 2015

Closures are not magic

Several years ago, while I was still a high school student, a friend of mine introduced me the concept of closures. I didn’t understand even a bit of what he wanted to show me, but he looked really hyped when he talked about them. To me, it all looked like some kind of deep magic. Even Google didn’t help. All I could find were scientific papers, that were incomprehensible for a high school student.

I giggle a bit when I think back at my high school programming struggles. This article is an attempt to explain closures in simple terms, that would help my old high school self to easily grasp their power.

Counting events

We’ll start with a simple problem, that can be easily solved by introducing closures in our program.

Let’s say that we want to create a mechanisms for counting events. Such a mechanism would help us to keep track of our code’s execution, or even while trying to debug some issues. For example, we could use it like in the following example:

increment();  // Number of events: 1
increment();  // Number of events: 2
increment();  // Number of events: 3

As you can see in the above example, our desired code would display a message “Number of events: x” every time we execute the increment() function. Here is a simple attempt to write such a function:

var counter = 0;

function increment() {
  counter = counter + 1;

  console.log("Number of events: " + counter);
}

Multiple counters

The above code is pretty straightforward. However, we quickly run into an issue if we want to introduce a second counter. Of course, we can implement two separate counter mechanisms, like in the following example, but it is obvious that something can be improved:

var counter1 = 0;

function incrementCounter1() {
  counter1 = counter1 + 1;

  console.log("Number of events: " + counter1);
}

var counter2 = 0;

function incrementCounter2() {
  counter2 = counter2 + 1;

  console.log("Number of events: " + counter2);
}

incrementCounter1();  // Number of events: 1
incrementCounter2();  // Number of events: 1
incrementCounter1();  // Number of events: 2

The above code screams of unnecessary duplication. Obviously, this solution won’t scale to more than two or three counters. We need to figure out something better.

Introducing our first closure

What we would really like in the above example, is to somehow introduce new counters, bundled with a function that can increase them without duplicating lots of code. Here is such an attempt using closures:

function createCounter() {
  var counter = 0;

  function increment() {
    counter = counter + 1;

    console.log("Number of events: " + counter);
  }

  return increment;
}

Let’s see how this works. We will create two counters, and use them to track two independent events:

var counter1 = createCounter();
var counter2 = createCounter();

counter1(); // Number of events: 1
counter1(); // Number of events: 2

counter2(); // Number of events: 1

counter1(); // Number of events: 3

Ugh, that looks complicated… However, it is actually really simple. We just need to separate the implementation logic into small, easily digestible chunks. Let’s see what our implementation does:

  • First, it creates a local variable named counter.

  • Secondly, it creates a local function named increment that can increment the counter variable. This can be pretty strange, if you have never worked with functional languages that treat functions as data. However, it is perfectly normal, and it only takes a little practice to get used to this idea.

Please notice that at this point, the implementation of createCounter() looks almost exactly like our original implementation of a counter. The only difference is the fact that it is wrapped, or enclosed, in a function’s body. Hence, these constructs are called closures.

Now comes the tricky part:

  • The last step in createCounter() returns the local increment function. Please notice, that it does not return the result of calling the function, but the function itself.

That means, when we create new counters with the snippet bellow, we are actually generating new functions.

// fancyNewCounter is a function in this scope

var fancyNewCounter = createCounter();

This is were the power of closures lie. Every function generated with createCounter() keeps track of their own generated counter value. In a sense, the returned function remembers the environment that it was created in.

An important thing should be observed. The internal counter variables are independent of each other! For example, if we create two counters, each of them will allocate a new counter variable in the body of the closure. We can observe two things:

Each counter will start counting from number 1:

var counter1 = createCounter();
counter1(); // Number of events: 1
counter1(); // Number of events: 2

var counter2 = createCounter();
counter2(); // Number of events: 1

The second counter does not interfere with the value of the first counter:

counter1(); // Number of events: 3

Naming our counters

The message “Number of events: x” is OK, but it would be more helpful if the message could describe the type of the event we are counting. For example, it would be nice if we could add a name to our counters, like in the following example:

var catCounter = createCounter("cats");
var dogCounter = createCounter("dogs");

catCounter(); // Number of cats: 1
catCounter(); // Number of cats: 2
dogCounter(); // Number of dogs: 1

We can achieve this simply by passing an argument to our closures.

function createCounter(counterName) {
  var counter = 0;

  function increment() {
    counter = counter + 1;

    console.log("Number of " + counterName + ": " + counter);
  }

  return increment;
}

Nice! Please notice an interesting behavior in the above createCounter() implementation. Not only does it remembers the value of the local counter variable, but also the value of the passed arguments.

Improving the public interface

When I say public interface, I mean how we use the counters. It is not intuitive that the created counter is a function that will increment its value when we execute it. The following would be much simpler:

var dogCounter = createCounter("dogs");

dogCounter.increment(); // Number of dogs: 1

Let’s create such an implementation:

function createCounter(counterName) {
  var counter = 0;

  function increment() {
    counter = counter + 1;

    console.log("Number of " + counterName + ": " + counter);
  };


  return { increment : increment };
}

In the above code snippet, we simply return an object that contains all the functions in our closure. In a sense, we are defining a set of messages that our closure can respond to.

Adding a decrement

Now, we can very simply introduce a decrement function to our counter.

function createCounter(counterName) {
  var counter = 0;

  function increment() {
    counter = counter + 1;

    console.log("Number of " + counterName + ": " + counter);
  };

  function decrement() {
    counter = counter - 1;

    console.log("Number of " + counterName + ": " + counter);
  };

  return {
    increment : increment,
    decrement : decrement
  };
}

var dogsCounter = createCounter("dogs");

dogsCounter.increment(); // Number of dogs: 1
dogsCounter.increment(); // Number of dogs: 2
dogsCounter.decrement(); // Number of dogs: 1

Hidden counter actions

The above code has two redundant lines. Yes, the ones with the console.log. It would be nice to create a function explicitly for displaying the value of the counter. Let’s call such a function display.

function createCounter(counterName) {
  var counter = 0;

  function display() {
    console.log("Number of " + counterName + ": " + counter);
  }

  function increment() {
    counter = counter + 1;

    display();
  };

  function decrement() {
    counter = counter - 1;

    display();
  };

  return {
    increment : increment,
    decrement : decrement
  };
}

var dogsCounter = createCounter("dogs");

dogsCounter.increment(); // Number of dogs: 1
dogsCounter.increment(); // Number of dogs: 2
dogsCounter.decrement(); // Number of dogs: 1

It looks very similar to the increment() and decrement() functions, yet it is very different. We didn’t return it in the resulting object! That means that the following will fail:

var dogsCounter = createCounter("dogs");

dogsCounter.display(); // ERROR !!!

We made the display() function hidden from the outside world. It is only available from inside of createCounter().

Abstract data types

As you can see, we can very easily introduce abstract data types with closures. For example, let’s create an implementation for a stack using closures.

function createStack() {
  var elements = [];

  return {
    push: function(el) { elements.unshift(el); },
    pop: function() { return elements.shift(); }
  };
}

var stack = createStack();

stack.push(3);
stack.push(4);
stack.pop(); // 4

Note: Closures are probably not the best implementation for a stack data type in JavaScript. Prototypes are probably more memory friendly.

Closures and OOP

If you have done any object oriented programming in your life, you will probably notice that the above constructs look very similar to classes, objects, instance variables and private/public methods.

A closure, similarly like a class, associates some data with a couple of functions that operate on them. Consequently, you can use a closure anywhere that you might normally use an object.

Final words

Closures are an awesome property of a programming language. They can come very handy in situations when we want to create “true” hidden fields in JavaScript, or need to create very simple constructs, that would be considered an overkill for a class.

Marko Anastasov wrote this on November 13, 2015

Framing Risk

Risk has a bad reputation. In both everyday and business context, when we say that something is “risky”, we usually mean “dangerous”, “maybe you shouldn’t be doing that”, “you don’t know what you’re doing”, and so on. I’d like to reset that thinking in myself.

In fact, “a risky business move” is more of an oxymoron. A company puts its resources, means of production and employees' time and effort into use today for an expected return in the future. The future is unknown and unpredictable by definition. Therefore, risk is the basis of all economic activity. It’s just that we tend to forget that. But why?

Entrepreneurs out there hiring their first employee right now are, through that action, taking a risk. They don’t know what the outcome is going to be. Hiring that person might turn out to be a bad choice for all sorts of reasons, which is ultimately relatively easy to detect and fix. But the potential upside is much larger than the downside: together, the team may do things that are much larger than the sum of their individual efforts, and the hiring decision may be the moment a successful company is born. Entrepreneurs know this, as much as they know that taking that “risk” is the only way to move towards the goal they are trying to reach. No “risk”, no fulfillment.

We hear so often that big companies are “risk-averse”. This is exactly why a lot of them die. There is a quote that’s been passed around recently stating that “in 10 years, 40% of Fortune 500 companies will no longer exist.” Probably as much it is clear to an entrepreneur that making change (also known as “disruption” and “taking risk”) is necessary for success, to the people in a big company it is not. An entrepreneur’s antennae are tuned directly to signals of environment, while the people in an enterprise may not realize that the bigger the organization, the thicker are the layers of isolation from the outside world and its constant changes.

So I’d say the next time you find yourself pondering doing something risky, go ahead. Just make sure you’re picking the good kind of risk and prefer the action with a much bigger upside than downside.

Dunja Radulov wrote this on October 22, 2015

Meet the New Rendered Text

Behind every great product is a great group of people that make it all happen. Rendered Text has welcomed several new team members over the past few months (including myself!). Check out our refreshed About page to meet the people who make up our growing team dedicated to optimizing Semaphore for the happiness of our users.

The folks pictured above are fun, friendly, and they (usually) don’t bite. If you’re clever, creative and you’d like to work in a great atmosphere developing an awesome product head to our Jobs page and drop us a line.

Igor Šarčević wrote this on October 13, 2015

Banning Iteration

In the last couple of months I have had the honor of being a mentor to several students that were taking part in our summer internship program. I had a ton of fun, learning not only about programming, but also about the art of teaching other programmers and helping them overcome their fear of complexity.

Even though they were all exceptional computer science students, a common pattern was their overdependency on the good old for loop. This was, of course, understandable. Java and C/C++ are the most popular teaching languages on our local universities. None of which, in my opinion, are good enough to prepare the students for the modern web and the level of abstraction required for working on bigger projects.

Basic iteration

One of the first things any computer science undergraduate learns is the for keyword. The magic word that can repeat common tasks and can even make our programs run forever. Here is a simple Java example that counts from one to ten:

for(int i=0; i < 10; i++) {
  System.out.println(i);
}

Another common thing is iterating over a list of values. For example, to collect the age of every user in an array, we could write:

int[] ages(User[] users) {
  int[] result = new int[users.lenght];

  for(int i=0; i < users.length; i++) {
    result[i] = users[i].getAge();
  }

  return result;
}

The issue with iterating with a for loop

Take a look at the above example that transforms the array of users into an array of numbers. It is a lot of work for such a simple task. The following list contains the mental steps needed for writing the above implementation:

  1. Create an array that will hold the results
  2. Set the capacity of the array to match the number of users
  3. Create an iterator named i that will hold the current index of the array
  4. Set up an iteration construct that will loop over every user in the array
  5. Limit the iteration when the iterator i is the same as the number of users
  6. Increase the iterator i after each step in the iteration
  7. In every iteration lookup the user on the i-th location in the array
  8. Get the age of that user
  9. Save the age value in the result array on the i-th place
  10. When the iteration is over, return the result to the caller

Well… this was a lot of typing. Plenty of room for making an error while writing the implementation.

Luckily, there are much better ways to achieve our goals.

Eliminating the redundant i iterator

Many students learn the for(int i=0; i < N; i++) construct by heart and replicate it everywhere, replacing the value of N with an appropriate value. But why would we do this? Automating things is one of the core principles of our craft. We should never let the computers make a fool of us!

Let’s switch from arrays to lists and use the newer for loop syntax:

List<Integer> ages(List<User> users) {
  List<Integer> result = new ArryaList<User>();

  for(User user : users) {
    result.add(user.getAge());
  }

  return result;
}

The above code looks nicer. Let’s write down the mental steps for this implementation.

  1. Create an array that will hold the results
  2. Set up an iteration construct that will loop over every user in the list
  3. Get the age of the user in each iteration
  4. Save the age value in the result list
  5. When the iteration is over return the result to the caller

Much nicer and easier to understand. Here are some steps that we don’t have to worry about anymore:

  1. Set the capacity of the array to match the number of users
  2. Create an iterator named i that will hold the current index of the array
  3. Limit the iteration when the iterator i is the same as the number of users
  4. Increase the iterator i after each step in the iteration
  5. In every iteration, look up the user on the i-th location in the array
  6. Save the age value in the result array on the i-th place

Language switch

Unfortunately, vanilla Java can take us only this far. It is still possible to conceptually improve the above, but it takes a lot of effort and it is against the flow of the language.

Introducing Ruby! The language that can easily take us to the next level.

First, let’s rewrite the above snippet in Ruby:

def ages(users)
  result = []

  for user in users do
    result.push(user.get_age())
  end

  return result
end

A note for experienced Ruby programmers: I know you want to tear your eyes out, but please bare with me. The above monstrosity is only for demonstration purposes.

Let’s continue!

Eliminating the result set

First, let’s remove the non-typical for loop. Ruby programmers always prefer the each method over the for operator.

def ages(users)
  result = []

  users.each do |user|
    result.push(user.get_age())
  end

  return result
end

While the above snippet looks quite nice, it is still far from perfect! Notice the redundant result list that we explicitly create for every list transformation.

Introducing the map method. It is very similar to the each method with a simple but very important feature. It creates the result set instead of us, and places the result of every iteration in the appropriate spot.

def ages(users)
  return users.map do |user|
    user.get_age()
  end
end

Let’s review the mental steps in the above code snippet:

  1. Set up an iteration construct that will loop over every user in the list
  2. Get the age of the user in each iteration
  3. When the iteration is over return the result to the caller

The following steps are no longer needed:

  1. Create an array that will hold the results
  2. Save the age value in the result list

Eliminating the return statements

The last step that returns the value of the calculation is usually not needed in Ruby. The language is smart enough to return the last calculated value from any method.

def ages(users)
  users.map do |user|
    user.get_age()
  end
end

This snippet reduces the number of mental steps to only two steps.

  1. Set up an iteration construct that will loop over every user in the list
  2. Get the age of the user in each iteration

Making the code nicer and more idiomatic

A true Ruby programmer would never write a get_age() method. Explicit actions are a relic of the past. Welcome to the age of declarative programming.

To access the age attribute of the method, we can simply write .age. Also, parentheses are optional. We will optionally remove them :)

def ages(users)
  users.map do |user|
    user.age
  end
end

The above method could be even shorter. A one-liner. In Ruby, the do ... end block is equivalent to curly braces.

def ages(users)
  users.map { |user| user.age }
end

Going even further by eliminating an explicit get

You probably thought that we could not go any further and declared it finished. However, there are still a couple of things that can be done. Notice that in the above example we explicitly read out the age value from every user.

Ruby has a shorthand operator for this.

def ages(users)
  users.map(&:age)
end

The above code snippet is equivalent to the previous one, but with one less mental step. Here is the current list of needed mental steps:

  1. Collect the age of every user

The following step is no longer needed:

  1. Set up an iteration construct that will loop over every user in the list

With the above code snippet, you could become good friends with any Ruby programmer. I am always happy to drink a couple of beers with programmers who can write code like this. Just saying…

The second Language switch

We are still not finished! Ruby is a great language but it has its limitations. But what could possibly be left to improve, you ask. Come and see. Introducing Haskell!

First, let’s start by rewriting the above snippet into executable Haskell code.

ages users =
  map age users

Eliminating the arguments

Haskell is quite smart when it comes to handling function arguments. It can pass the arguments to the end of a function’s body. The following is equivalent to the above:

ages = map age

It looks weird. I know! But you get used to it :)

Finally, let’s review the necessary mental steps for this implementation:

  • None. The above code is practically effortless.

Conclusion

We came a long way from our original implementation in Java. Just for comparison, here are two identical implementations:

int[] ages(User[] users) {
  int[] result = new int[users.length];

  for(int i=0; i < users.length; i++) {
    result[i] = users[i].getAge();
  }

  return result;
}
ages = map age

I hope you, beloved reader, understand why I think that Java is far from ideal when it comes to teaching the next generation of engineers and overcoming the challenges that our craft presents.

Marko Anastasov wrote this on September 10, 2015

Enjoying The Conversations

One of the less obvious things that I enjoy about running a product company are the diverse conversations that I get to have with our customers. It starts with a formal correspondence, initiated by a support request, customer interview or feedback discussion. And it often ends there. But sometimes after you’ve exchanged enough words or spent enough time talking, something clicks. People relax and tell you more about what it is that they do, what’s happening, what have they learned recently, or what’s bothering them. It’s just a common human trait to enjoy sharing and hearing stories, I suppose. Count me in.

I’ve noticed that it is an often repeated startup lesson to go out and talk to your current or potential users. People get a little obsessed with the ideas that they have and start ignoring the rest of the world. And I can relate to that. New ideas can be really exciting. But if you’re building a product and not talking to your users on a regular basis, it’s not only the product-market fit that you’re likely going to miss. It’s the timeless pleasure of establishing human contact too.

Marko Anastasov wrote this on June 4, 2015

Our First Hackathon

On May 30 and 31st we organized the first Rendered Text web hackathon. Five teams of students from Novi Sad, Belgrade and Niš competed in developing a static code analysis web application for Elixir, using Elixir of course. They didn’t know the language or the objective prior to coming to the hackathon, as we held it as a surprise.

The hackathon was a big success: for 24 hours the teams worked hard to show what they can do, met fellow hackers and had some fun. We just enjoyed helping them do all that. The iPads went to good hands: the winning app can tell you a few basic things about the coding style and function complexity in a snippet of Elixir source code.

Rendered Text Hackathon

The 30 hours later picture

Keeping an Open Mind

Telling people to program in a functional, dynamic language which they’ve never used before is simply our idea of fun. It’s what we’d like to do on a hackathon ourselves.

Most of the software companies in Serbia are quite conservative when it comes to using and exploring new platforms. The term “new” in this context is relative: many regard Python and Ruby as new, even though they’re over 20 years old. This feeds back into the local education system, creating an environment in which students are often trapped in a closed mindset.

We believe the opposite — that during your studies is a great time to try very different things. This helps you discover what’s possible, try various programming languages, stack levels and paradigms. You also get to know and compare communities and start getting a sense of what is happening in the industry. For this reason we decided to make this hackathon an opportunity to work with something previously unknown. Darko wrote earlier about what makes Elixir particularly interesting. It has grown to version 1.0 since then and Phoenix has become a fully functional web framework.

“The topic was interesting and the atmosphere great. We never programmed in a functional language, so learning Elixir was both interesting and a big challenge. With a little more experience, you could use Elixir and Phoenix to build quite powerful things in a simple way,” said Marko Papić from the winning team.

Congratulations to all teams for the work and effort they put in!

You can view more photos from the hackathon here.

Marko Anastasov wrote this on February 18, 2015

Semaphore in DZone's 2015 Guide to Continuous Delivery

Many thanks to DZone for including Semaphore again in its annual report on continuous delivery, recognizing Rendered Text as a featured vendor.

DZone’s Guide to Continuous Delivery is a a premium resource focused on continuous integration and DevOps management trends, strategies, and tools. It gives an overview of continuous delivery practices and how continuous delivery affects many aspects of an organization.

You can download a free copy of the guide here.

Browse Archive

If you like what you are reading, subscribe to our RSS. You can also follow us on @renderedtext for updates.

Contact

Rendered Text is a software company. For questions regarding Semaphore, please visit semaphoreci.com. Otherwise, feel free to get in touch any time by sending us an email.

Rendered Text
Svetozara Miletica 10
21000 Novi Sad
Serbia