<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Subvisual - Medium]]></title>
        <description><![CDATA[We design and develop thoughtful web &amp; mobile products - Medium]]></description>
        <link>https://medium.com/subvisual?source=rss----bc6257b530c5---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Subvisual - Medium</title>
            <link>https://medium.com/subvisual?source=rss----bc6257b530c5---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 07:05:41 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/subvisual" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How we set and track goals]]></title>
            <link>https://medium.com/subvisual/how-we-set-and-track-goals-714176d189b2?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/714176d189b2</guid>
            <category><![CDATA[goal-setting]]></category>
            <category><![CDATA[goals]]></category>
            <category><![CDATA[okr]]></category>
            <dc:creator><![CDATA[Laura Esteves]]></dc:creator>
            <pubDate>Fri, 21 Aug 2020 14:38:12 GMT</pubDate>
            <atom:updated>2020-08-21T14:38:12.239Z</atom:updated>
            <content:encoded><![CDATA[<p>This is the first of a series of blog posts about how we set and track goals at Subvisual.</p><p>We’ve been experimenting a lot during the last years and we’ve also tried to have one year without defining any goals, just going with the flow and taking all the opportunities that arise.</p><p>We ended the year with one big learning: setting goals is important. Not because last year wasn’t a good one (in retrospect, we’ve had great achievements and a lot of happy moments), but because without goals we couldn’t have a clear way to measure our progress. We couldn’t know if what we’re doing was aligned with our vision, we’re just being reactive and got some luck on the way.</p><p>We also learned during that year that goals must be flexible. We enjoyed this time without goals because we’re more aware of the opportunities around us and that’s something we don’t want to lose. That’s why we not only define yearly goals and track them, but we also schedule some time to review and adapt them according to new opportunities.</p><p>Goal setting can follow many different processes and, during the past 5 years, we’ve been using and adapting a framework called OKRs (Objectives and Key Results) created by Andy Grove. If you’re interested in learning more about this framework I recommend you to start with <a href="https://www.goodreads.com/book/show/39286958-measure-what-matters">‘Measure What Matters’ by John Doerr</a>, I’ll share just a part of the book that described the framework in a really simple way.</p><blockquote><em>Objectives are the “Whats.” They:<br>- </em>express goals and intents;<br>- are aggressive yet realistic;<br>- must be tangible, objective, and unambiguous;<br>- should be obvious to a rational observer whether an objective has been achieved;<br>- The successful achievement of an objective must provide clear value (…).</blockquote><blockquote><em>Key Results are the “Hows.” They:<br>- </em>express measurable milestones which, if achieved, will advance objective(s) in a useful manner to their constituents;<br>- must describe outcomes, not activities(…);<br>- must include evidence of completion. This evidence must be available, credible, and easily discoverable. Examples of evidence include change lists, links to docs, notes, and published metrics reports.</blockquote><blockquote><em>John E. Doerr, in </em>Measure What Matters</blockquote><p>This blog post will give you an inside glance at our full process and some extra insights about how we define our goals at the beginning of each year.</p><h3>Goal-Setting Process</h3><p>Our 7-steps process to define and track goals.</p><h3>Step 1: Define Yearly Goals</h3><p>We start every year defining our yearly goals. So the first step is to schedule a team moment to discuss and define goals. You’ll find more info about this step below.</p><h3>Step 2: Share Goals</h3><p>It’s crucial to have goals shared with the team, they must be visible to everyone in the company and on a tool the team uses daily. At Subvisual, we use <a href="https://basecamp.com/">Basecamp</a> for internal communication, so we have a <a href="https://3.basecamp-help.com/article/48-to-dos">to-do list</a> with our OKRs where each Key Result is a task. That allows us to assign the team member responsible and to have a place to discuss the next steps and to share progress about each KRs.</p><h3>Step 3: Define DRI &amp; Contributors for each KR</h3><p>Yep, we love acronyms, and here’s another one we use: <a href="https://www.youtube.com/watch?v=xCqKmhCBtJk">DRI</a> (Directly Responsible Individual), coined by Apple. This concept about fostering a culture of clear responsibilities and accountability within our team, and so it is part of the process.</p><p>The third step is to have a DRI for each Key Result; someone who’s going to be the KR’s ambassador, guide, and motivate the team to achieve what we’ve set for. At the same time, being DRI doesn’t mean the team member has to do all the tasks by himself/herself.</p><p>And since we’re a small team and each one of us needs to choose wisely the way we want to contribute, we also create a small task force for each KR.</p><h3>Step 4: Definition of Next steps</h3><p>For each Key Result we define the next steps, new habits, and whatever we’ll have to do to achieve them. This can happen async (on Basecamp) or with some work sessions. It depends on the DRI, the task force, and the Key Results’ needs.</p><h3>Step 5: Track OKRs</h3><p>Another learning from our experience: we need a system that ensure we remember our goals and they are guiding our priorities.</p><p>So every month, we have a team moment to share &amp; discuss the progress of our goals so we’re able to make some adjustments if needed.</p><h3>Step 6: Review &amp; Adjust OKRs</h3><p>This step is about keeping our yearly goals flexible. At the end of the first, second, and third quarter of the year we have a Subvisual Day (usually the last Friday of the quarter) where we do a retrospective, review our progress, and redefine our goals.</p><h3>Step 7: return to step 2</h3><p>Unless it’s the end of the year, and then we have to return to step 1.</p><h3>How we define yearly goals</h3><p>The first step of the process happens at the beginning of the year, where we have what we call Subvisual Days with the following agenda:</p><h3>Day 1 — Prepare &amp; Understand</h3><p>We start by analyzing our last year and understand what went well, what didn’t go so well, what we’ve learned and what still puzzles us. After reviewing the previous year, we’ll be better prepared to define our future.</p><p>We need approximately 2.5 hours and we follow this session structure:</p><ul><li>[5 min] Expectations — we start with an explanation of how our work session will be and we also share some expectations for this and the next day sessions.</li><li>[30 min] Self-reflection about last year — we usually share some retrospective exercises like Start/Stop/Continue analysis.</li><li>[30 min] Add info on post-its, read and vote — usually 3–5 votes/person on the most important post-its we want to discuss.</li><li>[15 min] Break — because we need a break after one hour of focus.</li><li>[60 min] Team discussion — we take the most voted topics and start a discussion. We don’t expect to find solutions and define the next steps, we just want everyone sharing what’s on their minds.</li><li>[5 min] Wrap up and a short description about what we’ll be doing during the next day.</li></ul><h3>Day 2 — Goals &amp; Strategy</h3><p>The second day is all about defining goals and strategies together and we need a full day for this. Our goals (objectives) tell us what is important to achieve and they should be ambitious, qualitative, and actionable. We start by defining 3 to 5 Objectives we want to achieve during the year.</p><p>The strategies (Key Results) tell us how we are going to achieve our goals. And under each Objective, we set 3 to 7 Key Results. They show us the most important things we need to do to achieve a goal and it’s important to keep in mind that they are not tasks.</p><p>This session starts at 10:00 and goes until 17:00. Here’s a regular agenda we follow:</p><p><strong>Morning</strong></p><ul><li>[30 min] Self-reflection about ‘What this year will be like?’</li><li>[30 min] Add Goals on post-its, read, and vote on the 3 most important goals.</li><li>[15 min] Break</li><li>[90 min] Discussion &amp; converge about objectives.</li></ul><p><strong>Afternoon</strong></p><ul><li>[30 min] Self-reflection about key results for each goal.</li><li>[30 min] Create smaller teams to share, discuss and define key results</li><li>[15 min] Break</li><li>[90 min] Share key results &amp; team discussion</li></ul><p>One small thing that had a huge impact on our work sessions is the time we set for self-reflection. It allows everyone to have time to think alone and take personal notes before starting a discussion. So don’t underestimate this time.</p><p>After these two days, <a href="https://twitter.com/rmdgb">Roberto</a> and I gather together our notes, review every post-it, and define the first draft of our OKRs. This draft contains OKRs of the year and also our OKRs for the first quarter — the last ones are a prioritization of our yearly OKRs and more specifically about our next steps. That allows us to break our yearly goals throughout the quarters and ensure we can easily update our plans according to our context and opportunities.</p><p>And as soon as the draft is done, we send it to the team for some rounds of asynchronous feedback. After some iteration and back and forth feedback we have our goals defined. \o/</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*VJIkC2aPcDOAGhl3.gif" /></figure><p>That’s all for today! 🙃 On my next blog post, I’ll share how we define next steps and track OKRs. Let me know on <a href="https://twitter.com/lauraeesteves">Twitter</a> if you have any thoughts to share with me.</p><p><em>Originally published at </em><a href="https://subvisual.com/blog/posts/how-we-set-and-track-goals/"><em>https://subvisual.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=714176d189b2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/how-we-set-and-track-goals-714176d189b2">How we set and track goals</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[8 Habits To Help You Through The Pandemic Times]]></title>
            <link>https://medium.com/subvisual/8-habits-to-help-you-through-the-pandemic-times-312089450815?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/312089450815</guid>
            <dc:creator><![CDATA[Laura Esteves]]></dc:creator>
            <pubDate>Wed, 17 Jun 2020 11:36:16 GMT</pubDate>
            <atom:updated>2020-06-17T11:40:07.951Z</atom:updated>
            <content:encoded><![CDATA[<p>Your brain is constantly building new neural pathways and, if you’re staying at home, this can be the perfect opportunity to start breaking bad habits and replacing them with some good ones.</p><blockquote>You and your plastic brain are constantly being shaped by the world around you. Understand that everything you do, everything you encounter, and everything you experience is changing your brain.</blockquote><blockquote><em>Lara Boyd</em></blockquote><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FLNHBMFCzznE%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DLNHBMFCzznE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FLNHBMFCzznE%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/f277e83deeeb607bfc34cc506e2c8ae0/href">https://medium.com/media/f277e83deeeb607bfc34cc506e2c8ae0/href</a></iframe><p>To help you define what good habits you could be creating during this time at home, here’s a list of the ones I consider essential.</p><h3>Habit 1 — Make your bed every morning</h3><p>Making our bed in the morning might seem like something small and not really important. But “it will give you a small sense of pride and it will encourage you to do another task and another and another.”</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FpxBQLFLei70%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DpxBQLFLei70&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FpxBQLFLei70%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/c92fcef1533c3343893472cd0cc60feb/href">https://medium.com/media/c92fcef1533c3343893472cd0cc60feb/href</a></iframe><h3>Habit 2 — Drink plenty of water</h3><p>You already know this but it’s important so here’s a friendly reminder. Keeping hydrated is crucial for your health and well-being.</p><p>And an extra tip: if you’re tired of buying water every time you go to the supermarket, buy a water filter and get it straight from the tap. 😊</p><h3>Habit 3 — Get more sunlight</h3><p>Our body creates vitamin D from direct sunlight on our skin. So, make sure you enjoy the sunny days and, during pauses, open a window to get fresh air and sunlight. This will improve your energy and sleep quality.</p><h3>Habit 4 — Get quality sleep</h3><p>Start by avoiding screens before bedtime, defining a routine, and being consistent with your bedtime. And if you want more tips about this, we recommend reading this book: <a href="https://www.goodreads.com/book/show/26114128-sleep-smarter">Sleep Smarter by Shawn Stevenson</a>.</p><h3>Habit 5 — Don’t skip meals</h3><p>Skipping meals may mean you’re missing out on essential nutrients and that will lead you to feel tired. So plan your meals, try new recipes, and keep a balanced diet (between healthy and goodness that makes your belly happy). 🤪</p><blockquote>People who love to eat are always the best people.</blockquote><blockquote><em>Julia Child</em></blockquote><h3>Habit 6 — Stay connected</h3><p>Keeping the distance from someone you love can be difficult. But we have technology nowadays that allows us to virtually stay in touch with friends and family. So don’t wait anymore and call someone!</p><h3>Habit 7 — Keep mentally &amp; physically healthy</h3><p>Ensure you have a routine to take care of our mind and body. You can do it through mindfulness practices like meditation and yoga. The most important: keep consistency.</p><h3>Habit 8 — Learn something new</h3><p>Last but not least, strive to learn every day and if you’re not sure about why this habit is so important, check Ken Jennings’ TED talk.</p><blockquote>Every day we should be striving to learn something new. We should have this unquenchable curiosity for the world around us.</blockquote><blockquote><em>Ken Jennings</em></blockquote><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fb2M-SeKey4o%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Db2M-SeKey4o&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fb2M-SeKey4o%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/c06aa22a7857e12ba741e91d6eda0137/href">https://medium.com/media/c06aa22a7857e12ba741e91d6eda0137/href</a></iframe><p>If I caught your interest, check this <a href="https://jamesclear.com/habit-guide">blog post</a> where James Clear shows that it’s not that hard to create new habits. The secret is to start with one small habit, increase it in small ways, and keep consistency.</p><p>I love the concept of neuroplasticity and the idea that we can, with some work, build new neural pathways in our brains and improve the way it works is really exciting to me.</p><p>If you’re interested in learning more about how you can create good habits and eliminate bad ones, I recommend you start with James Clear’s book: <a href="https://www.goodreads.com/book/show/40121378-atomic-habits">Atomic Habits</a>. It’s, without a doubt, one of the best books I read this year and it truly made me think about my routine.</p><p><em>Originally published at </em><a href="https://subvisual.com/blog/posts/8-habits-to-help-you-through-the-pandemic-times/"><em>https://subvisual.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=312089450815" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/8-habits-to-help-you-through-the-pandemic-times-312089450815">8 Habits To Help You Through The Pandemic Times</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Apprenticeship and Summer Camp programs]]></title>
            <link>https://medium.com/subvisual/apprenticeship-and-summer-camp-programs-e30673e392aa?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/e30673e392aa</guid>
            <category><![CDATA[summer-camp]]></category>
            <category><![CDATA[apprenticeship]]></category>
            <category><![CDATA[web]]></category>
            <dc:creator><![CDATA[Laura Esteves]]></dc:creator>
            <pubDate>Sun, 23 Feb 2020 17:44:10 GMT</pubDate>
            <atom:updated>2020-02-23T17:44:10.511Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SNq9vGo2pMRNURjgwqoAjQ@2x.png" /></figure><p>At Subvisual, we never assume we know everything. We know there’s something new to learn every day. We also know that one of the best ways to learn is to put your hands on and share. That’s why we focus on training and continuous learning opportunities.</p><p>In 2020 we want to keep crafting our training opportunities.</p><p>If you want to pursue a career in technology and product, we have two programs in store for you! Our Apprentice and Summer Camp program.</p><p>In these programs, you’ll work in a creative environment with a mentor.</p><h4><strong>What’s a mentor?</strong></h4><p>A mentor is a member of our team. They will help you define goals, give your guidance, and answer all your questions.</p><p>And we have big news! This year our friends at <a href="http://auroradigital.co/">Aurora</a>, <a href="https://www.finiam.com/">Finiam</a>, and <a href="http://ondastudio.co/">Onda</a> will join our team of mentors. \o/</p><h3>More about the programs</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AOnqSQjoxq9NU3ochUaDTg.jpeg" /></figure><blockquote><em>“They never offered me ready-made solutions, they showed me how to get there on my own, thinking about the problem from the ground up.” </em><a href="https://www.linkedin.com/in/franciscobaila/"><em>Francisco Baila</em></a><em>, Designer</em></blockquote><p>Both programs are a 10-week period of full-time work.</p><h4><strong>Apprenticeship program</strong></h4><p>As an apprentice, you’ll work on real projects with real impact, access to online courses, and create challenges according to your goals. Your mentor will be with you throughout the program.</p><p>Every 2 or 3 weeks, you’ll move to a different mentor. This rotation will be a unique development experience for you. It will allow you to work on different projects, meet our people, and apply what you will learn in different contexts.</p><h4><strong>Summer Camp program</strong></h4><p>The first 5 weeks are like our apprenticeship program. You’ll also have a mentor to guide you through your experience.</p><p>During the last 5 weeks, with the help of your mentors, all Summer Campers will form a team and build a product together to solve a problem of your choice. The purpose is not to create a product ready to be launched but to give you a taste of what it is like to work on a team and build a product from scratch.</p><p><strong>👉One small note</strong>: as the name implies, our Summer Camp program will happen during the summer. If you’re studying, this may be the perfect opportunity for a season full of adventures, new learnings and fun.</p><h3>Who is it for?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*epHqNYVh7eZzQlgRwBXrBw.jpeg" /></figure><p>Students, recent graduates and experienced professionals are welcome to apply to our programs.</p><p>We have openings in:</p><ul><li>Programming</li><li>Design</li><li>Product Management</li><li>Operations</li><li>Marketing</li></ul><p>And, regardless of your field of interest, we’re looking for independent and self-driven people. If you’re a curious mind, eager to experience new things and learn a little bit more every day, Subvisual is the place for you.</p><p>Teamwork and a user-centered approach are at our core. That’s why we value people who are, empathetic, humble, and good communicators.</p><h3>How to apply</h3><p>We’ve kept the application process simple so you can tell us about yourself the way you want.</p><p>Just send us an email at <a href="/service/mailto:aloha@subvisual.academy">aloha@subvisual.academy</a> with the answers to these 3 questions:</p><ul><li>What accomplishments/projects are you most proud of? Provide links if you can.</li><li>How do you want to grow?</li><li>Why do you think the apprenticeship/summer camp is right for you?</li></ul><p>Don’t forget to tell us for which program you’re applying to. You can add a resume/portfolio if you want.</p><p>We’re flexible on the starting and ending dates.</p><p>Applications for an Apprenticeship are open throughout the year. For our Summer Camp, you should apply until the end of May.</p><h3>Benefits</h3><ul><li>Weekly allowance depending on where you live</li><li>Free access to our office in Braga</li><li>Free weekly physiotherapy session</li><li>Free team lunch every Friday</li></ul><p>At the end of the apprenticeship, we may offer you a position at Subvisual or at one of our partners.</p><p>💪 <strong>Join us! We’ll love to have you!</strong></p><p>Hope to hear from you!</p><iframe src="https://www.instagram.com/p/BTrBCexFzsc/embed/?cr=1&amp;amp;rd=https%3A%2F%2Fwww.instagram.com" width="658" height="882" frameborder="0" scrolling="no"><a href="https://medium.com/media/52704dc71209a537b0b8e910dab432c4/href">https://medium.com/media/52704dc71209a537b0b8e910dab432c4/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e30673e392aa" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/apprenticeship-and-summer-camp-programs-e30673e392aa">Apprenticeship and Summer Camp programs</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Subvisual is hiring a Front End Developer]]></title>
            <link>https://medium.com/subvisual/subvisual-is-hiring-a-front-end-developer-e8a8e3f2e314?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/e8a8e3f2e314</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[remote-working]]></category>
            <category><![CDATA[jobs]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[hiring]]></category>
            <dc:creator><![CDATA[Roberto Machado]]></dc:creator>
            <pubDate>Mon, 10 Feb 2020 19:01:33 GMT</pubDate>
            <atom:updated>2020-05-07T14:22:20.083Z</atom:updated>
            <content:encoded><![CDATA[<p>It has been more than three years since we hired our last developer, and I’m not sure that we even know how long since we last put out a job opening!</p><p>As a company, we have evolved a lot in the last (almost) seven years. We started as a Ruby on Rails Development shop, working with companies from all over the world. Later we shifted to a Design and Development Consultancy firm and, even more recently, to a Venture Studio that helps founders create global companies. We are certainly proud of our past list of clients, from AT&amp;T, DoctorLink and Uphold, to helping in the development of exciting startups like UTRUST or Coverflex.</p><p>Along the way, we organized events such as RubyConf Portugal, Creators School, MirrorConf, several meetups, and other initiatives that forced us to grow beyond our natural craft.</p><p>Turning Subvisual into a relevant company was accomplished by a fantastic group of 12 people. Helped by a vast group of friends that we have gathered from across the globe, to whom we will be forever grateful.</p><p>Internally, we fought hard to create a workplace in which everyone can feel welcome and part of the team. We make sure that we live by our values, and walk the talk. This can be something as simple as a weekly 30 minute catch up call, where we share what is going on in our personal lives, or something lengthier such as our retreat, where we spend 3 to 4 days together, rethinking the company, what we do and where we want to go.</p><p>In terms of hard skills, we’ve always been a full-stack oriented company. In our rapidly evolving environment, it was important for everyone to feel comfortable working on any level of the system, whether that was a design tweak on the UI or a performance issue in the back-end. We believe this horizontal knowledge to be essential, as it helps us understand the overall project much better, and allows us to communicate transparently with our clients.</p><p>Over time, however, we have grown not only as a company but as individuals. The nature of the projects changed a lot, and each of us started to tune their craft in a particular field.</p><p>Some of us focused on gaining expertise in building high-quality UIs for our products. Others have worked tirelessly on the infrastructure side to make those products more scalable and reliable. But our background as full-stack developers has allowed us to excel in different areas, without ever losing sight of the bigger picture.</p><p>We’re now looking for someone who can help us grow even more. Adding another human being to this equation as a full-time member of our company is something that really excites us.</p><h3>About you</h3><p>There isn’t a checklist of requirements that you need to tick to work at Subvisual. You don’t need proficiency with some technology, or a college degree. We expect that you love what you do, respect the job, and work sustainably.</p><p>For this role, the two things you need are knowledge in the field of UI development, and the will to learn more, the latter being way more important than the former. Having a Continuous Improvement mindset is crucial for us.</p><p>We set high expectations for ourselves, and we’ll set the same for you. As a front-end developer, you are expected to collaborate with everyone. You are expected to learn about animations, accessibility, and performance. And more importantly, you are expected to contribute and take the lead in these subjects. We want you to be passionate about the web and explore its boundaries.</p><p>You are expected to be autonomous. We rely on you to manage yourself and help manage others. You should be comfortable interacting with our global clients directly, so your English should be fluent. You will have to ask as opposed to wait to be asked. You should be open to and give clear feedback. We want you to take a stand and disagree, but also commit to the team’s decision when agreements need to be reached. We value strong opinions weakly held.</p><p>We want you to give back. It’s one of our core values. We want you to participate in meetups, organize events, write blog posts. Are you not used to that? No worries, a lot of us weren’t when we joined Subvisual. We are here to help you get comfortable with sharing. All you need to bring to the table is the will to do that.</p><p>You will have to be a mentor. Not only inside the team, but also the people that might join us looking to get into this industry.</p><h3>Salary and Benefits</h3><p>We don’t benchmark our pay. We pay honest salaries that we want to grow continuously. We aren’t yet in a position to pay everyone San Francisco salaries; we would love to. What we can offer is above the market salary, with quarterly reviews.</p><p>We offer a set of Benefits at Subvisual focused on your well being, mostly outside of work. We want you to live a sustainable life, where we respect your individual values, but nudge you to be healthier. That includes a Gym membership, health insurance, budget for books, opportunity to attend conferences, and other events, physiotherapy, and a lot of good moments to relax with the team as well as outside of the company.</p><p>We are remote-friendly, working towards becoming a Remote Team. We do still have two offices, one in Portugal and another one in Boston, both of which we will keep, but you are free to work from anywhere (within a reasonable timezone difference). We subsidize coworking spaces or home offices, to provide you the best possible environment to work, regardless of where you are. We will also invest in your continuing education, on the professional or hobbyist level.</p><p>We offer unlimited paid vacations, and you are free to take a longer journey once in a while, whitin reason. We do need to make sure that we continue a sustainable and profitable company after all.</p><h3>How to apply</h3><p>If you think this is you, send an application e-mail to <a href="/service/mailto:hiring@subvisual.com">hiring@subvisual.com</a> with your name, your portfolio with visual examples of what you have done in the past, Github link and a cover letter explaining why you want to join us, as well as describing a recent technology you like and why you like it. Provided your application meets these criteria, we will be in touch.</p><p>Join us! We’ll love to have you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e8a8e3f2e314" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/subvisual-is-hiring-a-front-end-developer-e8a8e3f2e314">Subvisual is hiring a Front End Developer</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Upsert statements with Ecto]]></title>
            <link>https://medium.com/subvisual/upsert-statements-with-ecto-b9eab8b63ddf?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/b9eab8b63ddf</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[elixir]]></category>
            <category><![CDATA[ecto]]></category>
            <dc:creator><![CDATA[Luís Ferreira]]></dc:creator>
            <pubDate>Wed, 15 Jan 2020 15:22:47 GMT</pubDate>
            <atom:updated>2020-01-15T15:28:24.428Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*B6YxPvAMw_kx5D-_RQpotw.jpeg" /></figure><p>From the Postgres documentation we define an upsert as:</p><blockquote>a (…) feature that allows (…) to atomically either insert a row, or on the basis of the row already existing, UPDATE that existing row instead, while safely giving little to no further thought to concurrency.</blockquote><p>Obviously this logic can be implemented at the application level, although you then need to worry about the concurrency part. However, this sort of operation is exactly what we should enlist our database to help us with, as they are exceptionally good at it.</p><p>Upsert is a commonly used term to refer to adding an ON CONFLICT clause to an INSERT statement. As we’ll see there are different ways to define the target of the conflict but it always boils down to some constraint violation.</p><h3>Ecto</h3><p>Now that we know what Upserts are, let’s see them in action with Ecto. As an example, let’s say that we have bank accounts associated with a customer email, which should be unique, a balance and a boolean to lock accounts for security reasons.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/74e6e617c19d6e8ef1d1f9c054c6c0fd/href">https://medium.com/media/74e6e617c19d6e8ef1d1f9c054c6c0fd/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c59a4e448500d5a6a6a6c7f378f87900/href">https://medium.com/media/c59a4e448500d5a6a6a6c7f378f87900/href</a></iframe><p>With our database set up and schema in place we can go ahead and insert our first account!</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d61553cc6e9d20790a803602c5977c0e/href">https://medium.com/media/d61553cc6e9d20790a803602c5977c0e/href</a></iframe><p>Nothing fancy so far, however if we try to run the above statement again we’ll get an error from the uniqueness constraint on the email. If we know that the account is already there, we can use Repo.update/2. There is also Repo.insert_or_update/2 but it relies on us having an existing struct that might have been loaded from the db or not, thus it’s not an atomic operation.</p><h3>Upserting</h3><p>Let’s imagine a feature on a system used by a bank teller to create an account, they don’t know for sure if the customer is already in the system or not, but they just got handed $50 to deposit on that account.</p><p>We could do it in multiple steps in a non atomic way:</p><ol><li>Check if the account exists</li><li>Create one with the balance if not</li><li>Update the existing one adding to the previous balance if yes</li></ol><p>That’s too many steps though. Let’s do it all in a single step!</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a4631dc179b83c7996202de7e6ff45cf/href">https://medium.com/media/a4631dc179b83c7996202de7e6ff45cf/href</a></iframe><p>There’s a few things of note here, most importantly, the on_conflict option which takes different formats of input. In this case we are passing it an update like set of operation, namely the inc operation, which will do exactly what we wanted, by incrementing the previous value, instead of replacing.</p><p>Secondly, we use the conflict_target option, which goes in tandem with on_conflict. We simply state the conflict we care about will happen on the email field if at all, however, we can also specify a constraint by name if we want to be more specific.</p><p>Last but not least, we have the returning option. In this specific scenario it is not needed, as we are not using the return value of the call. In the case we did use it, we will usually want returning to be true as it will ensure we got the value that was persisted and not the struct we were trying to persist but couldn’t. More details on this can be found in <a href="https://hexdocs.pm/ecto/Ecto.Repo.html#c:insert/2-upserts">the </a><a href="https://hexdocs.pm/ecto/Ecto.Repo.html#c:insert/2-upserts">Ecto.Repo documentation</a>.</p><h3>Upserts with conditions</h3><p>So far we’ve looked at how we can perform an upsert on every conflict, regardless of the row that conflicted, however, it’s a totally valid for us to want to do things conditionally.</p><p>Let’s take the previous example, of incrementing the balance, and add another constraint. We only actually perform the operation if the account is not locked, otherwise we return an error.</p><p>Remember how I said that on_conflict takes different types of inputs? Well, one of them (and the one that gives us more control) is a generic Ecto.Query struct, which we already know how to add conditions to, by using the where clause. All put together it might look something like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2e1321942c96949ab76aa3c92fd5684e/href">https://medium.com/media/2e1321942c96949ab76aa3c92fd5684e/href</a></iframe><p>As you can see the on_conflict is now a standard Ecto.Query. We reuse the operation keyword list and pass it to update and we add the condition we wanted. There a few important things to have in mind as to how this query will be run, though.</p><ol><li>The records from which it will select are the subset that triggered the conflict, not the entire dataset</li><li>The updates will be ran via an update_all, which do not update autogenerated fields, for example</li></ol><p>Other than that, it should work pretty much as expected. In the example above, it will successfully increment the balance of the account if it is not locked, returning the updated value.</p><p>If the account is locked, however, it will return an error via an error tuple, the error will be stale_entry and will be applied to the changeset, on the field specified by stale_error_field. The reason this happens is because the insert didn’t actually insert anything, since the on_conflict query will return an empty set. Ecto treats these scenarios as a StaleEntryError and would generally raise, but in the upsert scenario we know that it might happen and stale_error_field is how we tell Ecto that we are expecting it, so there is no need to raise.</p><h3>Conclusion</h3><p>Upserts are a powerful tool to have in our database querying tool belt and can be useful in many situations. We do need to keep in mind that it is not without it’s drawbacks, though. For instance its use is not recommend while also working with associations, the insert call becomes more verbose or if we want to handle conflicts in more complex ways that involve system parts other than the database (by losing the atomicity), it might not be the thing for us.</p><p>We did not cover the on_conflict option extensively and I do recommend reading the documentation where you’ll also see :nothing and {:replace, ...}.</p><p>All in all it’s relatively simple to use and it’s a good way to handle scenarios such as the ones described above.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b9eab8b63ddf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/upsert-statements-with-ecto-b9eab8b63ddf">Upsert statements with Ecto</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hacking your own company]]></title>
            <link>https://medium.com/subvisual/hacking-your-own-company-d7da17e08dab?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/d7da17e08dab</guid>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[programing]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[hacks]]></category>
            <dc:creator><![CDATA[João Justo]]></dc:creator>
            <pubDate>Tue, 26 Nov 2019 18:01:31 GMT</pubDate>
            <atom:updated>2019-11-26T18:01:31.724Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kNkS2YV8j0EVGbTt-TodBQ.jpeg" /></figure><p>I have a confession to make. A while ago I hacked my own company.</p><h4>Motivation</h4><p>You might be wondering why someone would hack his own company. A company like <a href="https://subvisual.com/">Subvisual</a> has a transparent communication and processes. So, if I want to know something, all I got to do is ask.</p><p>The answer to this question is <a href="http://www.imdb.com/title/tt4158110">Mr. Robot</a>!<br>Yes, the TV show.</p><p>I’m a big fan of Mr. Robot.<br>For those of you who don’t know it, it’s a hacker TV series that’s very realistic. Instead of showing some random letters on a terminal they showed the viewers real techniques and exploits.</p><p>If you watched the series you certainly have noticed that our favourite hacker Elliot accomplishes some hacks by masquerading as a trustworthy entity and then simply ask for information directly to the victim.</p><p>This technique is called a phishing scam and despite being one of the most used exploits on the internet, it’s still one of the most effective.</p><p>I was skeptic that people would fall so easily on such a simple exploit so I became very curious on this. After some time I came up with a simple case study:</p><p>I wanted to create a phishing scam targeting my co-workers. The goal was to send a fake email to my whole team, containing a link to a malicious site, in order to see how many people would login on it, giving me their credentials.</p><p>If you put some thought on the matter your own team members are the perfect test subjects. You spend at least 8 hours per day with them, you know some of their habits, some of their tools and most importantly some of the sites they use and therefore some of the emails they receive. You also have the opportunity to watch first-hand how they will react when they see it.</p><p>Now you might be wondering if this is reasonable. After all getting someone’s private information might have a devastating effect on both the victim and the hacker, also worth mentioning that such action is… illegal. Considering that the victim will be sitting next to you this might not seem like a good idea after all. Also worth mentioning that my targets are experienced web developers so their defences are probably a step higher.</p><p>How can this be accomplished in such conditions? If you stick with me a little longer I’ll care to explain.</p><h4>Preparation</h4><p>My first plan was to attack the whole company at once keeping the whole thing secret and then, on a Friday Talk reveal what happened and how many people had fallen. After some days thinking on this and given the reasons above I changed the plan a bit.</p><p>The first thing I did was to ask permission and guidance to Roberto, our CEO. He received the idea surprisingly well and like me he was curious to know if our team would be able to recognise a simple phishing scam and if so, how could we improve the company security and awareness. We also shared the same concerns regarding personal information so it was decided that passwords or other relevant information would not be stored. The only thing that I would try to capture was the password length as proof that the given person had been victim of the attack.</p><p>With this set I began to prepare the hack.</p><p>After some time observing the team I noticed that most of our internal communication is done on <a href="https://slack.com/">Slack</a>, <a href="https://trello.com/">Trello</a> and <a href="https://github.com/">GitHub</a>. The emails that we received are mostly notifications from these apps so I started to analyse how easily I could create a clone of those and trick my coworkers to login to it.</p><p>My weapon of choice was Slack. The main reason for this was the fact that almost all of our important communication is generated on it. Theoretically if someone received an important email saying that he/she missed an important message this person should follow the link to catch up.</p><p>Here’s an example of a normal notification email from Slack:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1012/1*--qb164TtnMc3FR1NkL6lQ.png" /><figcaption>A legitimate slack email notification</figcaption></figure><p>The email itself shows the missing mention so you might think that this not an ideal situation. For an efficient phishing scam we usually need some content that requires an action, a hook that leads the victims to follow a malicious link.</p><p>For this to work I needed to change the content by inserting a partial message and a call to action button, but maintain the familiar layout and appearance.</p><h4>Building the attack</h4><p>This is the geeky part but there is not much to it on this field. All we need is a simple static web page and some place to save the emails and password lengths.</p><p>I chose to host the page on <a href="https://pages.github.com/">GitHub Pages</a> and to use<a href="https://parse.com/"> Parse</a> as my attack storage for the sake of simplicity.</p><p>Then I started searching for a domain that resembled slack.com and indeed I found one available — slaack.co.</p><p>To clone the whole slack.com site I used an app called SiteSucker. This duplicates the site directory structure and files on your machine meaning that my cloned slack would look exactly like the original even on mobile.</p><p>With this set getting the emails and passwords lengths was very easy. I just removed the code from the login form and added some lines:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b752f935d36f0f83faa75c91c2beb3ff/href">https://medium.com/media/b752f935d36f0f83faa75c91c2beb3ff/href</a></iframe><p>Finally, the fake email looked like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ma0hEfsZgJNf_0EN5NknTg.png" /></figure><h4>Attacking</h4><p>This whole thing was online for more than 3 days, ready and waiting for the perfect opportunity. I chose to strike on a Thursday by the end of the day as people left the office. I sent the fake email. That way, as people arrived home, they would see an email notification from the team. Even better, they would see a notification from their CEO on a channel called “#secretProject” so the curiosity factor was involved.</p><h4>Results</h4><p>In the end 20% of our team fell on the attack (all of them are developers). While this number might seem acceptable, it is not. On such a sensible platform like Slack, where most of our company’s communication happens, a malicious attacker only needed one person to gain access to privileged information. Also worth noticing that if someone gained access to Slack this person could easily try to impersonate the victim in order to collect other information from the victim’s coworkers.</p><p>I presented this results on a Friday Talk and after some discussion I understood the rest of the people didn’t open the link only because they didn’t care about Slack email notifications. I also presented some context and countermeasures about phishing attacks that helped raising the awareness for this kind of vulnerability.</p><p>The most important lessons taking from this are:</p><ul><li>Nobody is safe from being victim of a phishing attack, even experienced developers can easily be victims.</li><li>It’s hard to identify fake communication from the platforms we use every day. We don’t pay that much attention to it so it’s only natural that our defences are lower than normal.</li><li>People now better understand the importance of security measures like two factor authentication.</li><li>It was fun and a completely different approach to this security theme; by feeling the problem people understand better that they need to create defences against such attacks.</li></ul><p>On the end what I have to tell you is to go ahead and do the same on your company. It’s easier to construct defences with a real understanding of the problem than just trying to fight something that was not experienced by anyone.</p><p>I will try to identify and correct more weaknesses in Subvisual and I hope you will do the same at your own work place.</p><p>Happy hacking.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d7da17e08dab" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/hacking-your-own-company-d7da17e08dab">Hacking your own company</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Jobs and Timers in neovim: How to watch your builds fail]]></title>
            <link>https://medium.com/subvisual/jobs-and-timers-in-neovim-how-to-watch-your-builds-fail-f18931f2ffb6?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/f18931f2ffb6</guid>
            <category><![CDATA[vim]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[git]]></category>
            <category><![CDATA[github]]></category>
            <dc:creator><![CDATA[Fernando Mendes]]></dc:creator>
            <pubDate>Fri, 07 Jun 2019 16:17:32 GMT</pubDate>
            <atom:updated>2019-06-07T16:17:32.745Z</atom:updated>
            <content:encoded><![CDATA[<p>If you’re like me (and for your own sake, I truly hope you are not), you probably tend to have a lot of builds fail. Even worse, if you <strong>really</strong> are like me, you spend most of your time in vim.</p><p>If that is not the case, you’re in the clear, there’s nothing wrong with you, feel free to go, end this blog post now, be free, happy, enjoy the sunlight and the birds and the trees. Life is good.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>.</p><p>… Are we, the sadists, all alone now? Cool. Ok, so you use vim a lot and you make builds fail. Chances are you would like to know when that happens without ever leaving vim. It’s alright. I got you, mate.</p><p>Here’s an asciicast of my nvim. Notice how the status bar includes, on the bottom right, the status of the CI. Notice how it updates. Damn, that’s neat. You want that.</p><figure><a href="https://asciinema.org/a/5ynHiyckpQmQP7oWYI6HsVKKI"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7yuBwjz3t0zsgvgMQLEBFA.png" /></a></figure><p>First things first, either make an API wrapper, preferably in Rust or Go, something compiled and fancy, that allows you to check the <a href="https://developer.github.com/v3/checks/">GitHub checks API</a>. Got it? Good. Now stop being a muppet and use <a href="https://hub.github.com/">hub</a> instead.</p><p>Now that you have `hub`, you can make use of the `hub ci-status` command.</p><pre>$ hub ci-status<br>success</pre><p>Coolio.</p><p>Now let’s change our custom status bar.</p><p>First, we want to check if we’re in a git project:</p><pre>let s:in_git = system(“git rev-parse — git-dir 2&gt; /dev/null”)</pre><pre>if s:in_git == 0<br> “ call hub<br>endif</pre><p>So now we need to call `hub`. However just doing a `system` call to `hub` would be a blocking operation and we don’t want our vim to block every few moments for like 5 seconds. So let’s use `jobstart`.</p><p>Start by calling `:h jobstart` from your (n)vim. You can see that it runs an asynchronous job and it supports shell commands.</p><p>So let’s create a `CiStatus` function that looks like this:</p><pre>function! CiStatus()<br> let l:callbacks = {<br> \ ‘on_stdout’: function(‘OnCiStatus’),<br> \ }</pre><pre>call jobstart(‘hub ci-status’, l:callbacks)<br>endfunction</pre><p>We define a map of callbacks for `stdout` and delegate that to a new function called `OnCiStatus`. This is a very simple function that gets the output from `hub` and converts it to whatever we want, storing it in a `g:ci_status` variable. We will later use this variable in our statusline.</p><pre>function! OnCiStatus(job_id, data, event) dict<br> if a:event == “stdout” &amp;&amp; a:data[0] != ‘’<br> let g:ci_status = ParseCiStatus(a:data[0])<br> endif<br>endfunction</pre><pre>function! ParseCiStatus(out)<br> let l:states = {<br> \ ‘success’: “ci passed”,<br> \ ‘failure’: “ci failed”,<br> \ ‘neutral’: “ci yet to run”,<br> \ ‘error’: “ci errored”,<br> \ ‘cancelled’: “ci cancelled”,<br> \ ‘action_required’: “ci requires action”,<br> \ ‘pending’: “ci running”,<br> \ ‘timed_out’: “ci timed out”,<br> \ ‘no status’: “no ci”,<br> \ }</pre><pre>return l:states[a:out] . “, “<br>endfunction</pre><p>There are a couple of things missing though. This runs the `hub ci-status` job only once. We want to have it perform constant checks. If we do `:h timers`, we can see the new `time` API in neovim. Theres a `timer_start` that takes a period and a callback to run after that period.</p><p>We can then change our `OnCiStatus` function to call `timer_start` with that first `CiStatus` function again:</p><pre>function! OnCiStatus(job_id, data, event) dict<br> if a:event == “stdout” &amp;&amp; a:data[0] != ‘’<br> let g:ci_status = ParseCiStatus(a:data[0])<br> call timer_start(30000, ‘CiStatus’) “ relevant new part<br> endif<br>endfunction</pre><p>Now `CiStatus` gets called by `timer_start` every 3 seconds. `timer_start`, however, passes the `timer_id` as an argument to the callback. So we will need to modify `CiStatus` to accept an argument (that we can safely ignore):</p><pre>function! CiStatus(timer_id)<br> let l:callbacks = {<br> \ ‘on_stdout’: function(‘OnCiStatus’),<br> \ }</pre><pre>call jobstart(‘hub ci-status’, l:callbacks)<br>endfunction</pre><pre>“ We also need to change the first CiStatus call to receive an int<br>“ Since we don’t care about it, let’s just use 0</pre><pre>let s:in_git = system(“git rev-parse — git-dir 2&gt; /dev/null”)</pre><pre>if s:in_git == 0<br> call CiStatus(0)<br>endif</pre><p>All that’s missing now is to take the value of `g:ci_status` and put into the statusline. That’s pretty simple, using some code borrowed from <a href="https://kadekillary.work/post/statusline-vim/">Kade Killary</a>.</p><pre>set statusline=<br>set statusline+=\ \ \ “ Empty space<br>set statusline+=%&lt; “ Where to truncate line<br>set statusline+=%f “ Path to the file in the buffer, as typed or relative to current directory<br>set statusline+=%{&amp;modified?’\ +’:’’}<br>set statusline+=%{&amp;readonly?’\ ’:’’}<br>set statusline+=%= “ Separation point between left and right aligned items<br>set statusline+=\ %{g:ci_status} “ Our custom CI status check<br>set statusline+=col:\ %c<br>set statusline+=\ \ \ “ Empty space</pre><p>And that’s that. Find a lot more goodies in <a href="https://github.com/justmendes/dotfiles">my dotfiles</a>. Cheerios. Hugs n kisses and all that.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f18931f2ffb6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/jobs-and-timers-in-neovim-how-to-watch-your-builds-fail-f18931f2ffb6">Jobs and Timers in neovim: How to watch your builds fail</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[It’s not Continuous Delivery (yet)]]></title>
            <link>https://medium.com/subvisual/its-not-continuous-delivery-yet-27a9e838f5df?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/27a9e838f5df</guid>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[continuous-delivery]]></category>
            <dc:creator><![CDATA[Pedro Costa]]></dc:creator>
            <pubDate>Tue, 05 Feb 2019 12:00:21 GMT</pubDate>
            <atom:updated>2019-02-05T12:00:21.512Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r7VUwRlhkX4X6q5mMM-BtQ.jpeg" /><figcaption>Source: <a href="https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/">https://www.pexels.com/photo/abstract-art-circle-clockwork-414579/</a></figcaption></figure><p><em>First published on </em><a href="https://subvisual.co/blog/posts/143-its-not-continuous-delivery-yet/"><em>Subvisual’s blog</em></a><em>.</em></p><p>Any project started at Subvisual has always been demanded the best development processes we know, to assure the highest quality. Among other things, this means we advocate that all our projects follow a Continuous Delivery process.</p><p>Recently we decided to start sharing this approach with the community outside our own ventures. And like any good teacher, we sought to learn more about the subject and ended up studying the <em>Continuous Delivery</em> book, by <a href="https://www.continuousdelivery.com/">Jez Humble</a> and <a href="http://www.davefarley.net/">David Farley</a>. It so happened that, in that effort, we learned that we ourselves are not actually doing it, we only practice some of its ideas.</p><h3>The Continuous Spectrum</h3><p>Anyone who looks for it is bound to find several software development buzzwords with the “continuous” word on them, the most common being Continuous Integration, Continuous Delivery, and Continuous Deployment. These three are all different things but they are all linked.</p><h3>Continuous Integration</h3><p>Consider a regular software project using <a href="https://git-scm.com/">Git</a>, where developers work on their changes in the isolation of their own branches, all originating from a main one (usually master).</p><p>Continuous Integration (CI) is a practice where developers are encouraged to integrate their changes in the main branch as often and as early as possible. Integration here does not simply refer to the act of merging the code, but performing whatever checks the team needs to feel confident the new changes did not break anything and are working as they’re expected.</p><p>Practicing Continuous Integration requires both a Version Control System (VCS) like Git or <a href="https://www.mercurial-scm.org/">Mercurial</a>, and a way to trigger an automated build pipeline when a new change is committed. This is usually done through a service like <a href="https://github.com/">GitHub</a>, <a href="https://bitbucket.org/">Bitbucket</a>, or <a href="https://gitlab.com/">GitLab</a>, which provide a central repository for changes to be merged into, automatically triggering a CI service to build the project.</p><p>The build run by the CI service will depend on what the team considers required to feel confident nothing was broken by a change. This usually includes unit and integration tests, may also include code quality checking, and possibly a test deployment (to a staging environment).</p><p>For a team practicing CI, there is no task more important than keeping the build pipeline working. If the build fails, it is everyone’s top priority to fix it. And if the problem is not solved quickly (under 20 minutes, for instance), then the breaking change must be reverted and fixed in isolation.</p><h3>Continuous Delivery</h3><p>Continuous Delivery (CD) builds upon Continuous Integration. It boils down to being able to deliver any change whatsoever to production quickly and safely.</p><p>This means the project’s code must be ready to ship at all times. For instance, in a regular web project using Git, this implies that the master branch is always deployable, and keeping it that way is everyone’s main priority. It also means that the deployment process must be as easy and automated as possible, and that deployments should happen as early and often as possible.</p><p>Practicing CD implies the build pipeline includes a suite of acceptance tests (automated and/or manual) to assert the product does what it is expected, and possibly non-functional tests required to assert it is ready to be delivered (load testing, security checks, etc.). Once the build is finished and considered successful the team is confident it can be delivered to production.</p><p>One crucial distinction between Continuous Integration and Continuous Delivery is the approach to new functionality. CI requires only new changes not to break existing functionality, so unfinished features are accepted as long as the rest of the product works. But since CD requires the project to be deliverable, any unfinished features have to be hidden or disabled until they’re considered ready to be released.</p><h3>Continuous Deployment</h3><p>Continuous Deployment is just an extension on Continuous Delivery where the product is actually delivered on every change. It is a specially good fit for web products since the delivery process is completely under the team’s control, whereas a mobile application, for instance, would require users to download the updated version.</p><p>Typically a Continuous Deployment process will be fully automated, which increases the importance of having reliable acceptance tests. However, it is not required to be fully automated, and the build pipeline can also include a manual exploratory testing step. The difference being that once those tests are deemed successful, the tested version is deployed automatically.</p><p>At Subvisual we do not aim for Continuous Deployment because delivery is a business decision, not a technical decision. While Continuous Delivery fits all projects, the specific requirements for Continuous Deployment are not met by most projects, especially until a certain maturity is reached.</p><h3>How to not practice Continuous Delivery</h3><p>As I wrote above, we have been stating that we practice Continuous Delivery for a while, but the truth is that we actually don’t even fully practice Continuous Integration to start with.</p><p>Services like <a href="https://travis-ci.org/">Travis CI</a>, <a href="https://semaphoreci.com/">Semaphore CI</a>, and <a href="https://circleci.com/">Circle CI</a> all use the CI acronym because the existence of a system able to test the main branch and make sure the latest changes do not break anything is essential for a project practicing Continuous Integration. However, just using a service like this to run an automated build pipeline is not enough.</p><p>For a team to practice Continuous Integration, there must be a culture of integrating changes to the main branch often (at least a couple of times a day according to some authors). This prevents pull-requests with hundreds of changed lines, or changing multiple different things, both of which make code reviews a lot harder and error prone. And while we do discourage long pull-requests, we never actually refuse them and force people to go back and break it into smaller changes.</p><p>The way we see it, there might be good reasons on why a developer is not integrating with the main branch frequently, like experimenting with a new approach or a refactor. But aside from very rare exceptions, large changes can always be broken into small and easy to comprehend chunks.</p><p>Even if we disregard that we are not actually practicing Continuous Integration, we still can’t consider we’re doing Continuous Delivery. One of the reasons is that, historically, the build pipelines in our projects do not run acceptance tests against live production-like environments. This is a side effect of the tools we normally use, which assume a clean and controlled testing environment for functional tests.</p><p>Normally, we also do not include any non-functional tests in our projects. These are tests designed to verify the application meets its non-functional requirements, like being able to handle a minimum number of users at the same time, or implementing some specific security rules, or responding to any request within a given time frame. Since ventures go on their own before that, there is rarely the need for tests like these when we’re working on the projects.</p><p>Take the case of <a href="https://www.crediflux.pt/">Crediflux</a>, for instance, which had a comprehensible suite of feature tests since its earliest stages. These were never run against a live environment. Therefore its releases required stakeholders to go through the most common flows by hand in a staging environment, and this would often uncover issues associated with the data already in the system. And as it also lacked any non-functional tests, it was only when the first big clients started using the system and the amount of data started building up that we noticed performance issues in some tasks.</p><p>In some cases there is another reason we can’t say we’re doing CD. Normally we use <a href="https://www.heroku.com/">Heroku</a> and automate the deployment process from the CI, but there have been cases where the project required another environment and the effort of automating deployments was considered to exceed the return-on-investment (ROI). Of course this flexibility of doing what is best for the project is required for any successful software team, but the truth is we should review this decision periodically and we don’t normally do so. And in every single case the project reached a point where the cost of doing it manually exceeded the tolerable, and the deed had to be done anyway.</p><p>–</p><p>In summary, if a project is often in a broken state (<em>the build is failing</em>), not ready to ship (<em>feature X is not complete yet</em>), or requiring human intervention to deploy successfully (<em>we’re just waiting for Miguel to get here and deploy to production</em>), then the team is not practicing Continuous Delivery. Without it, we’re losing valuable feedback both from tools we should be using, and from real users (because we’re not deploying as often as we could). And in order to fix this, we need to own it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=27a9e838f5df" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/its-not-continuous-delivery-yet-27a9e838f5df">It’s not Continuous Delivery (yet)</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to program Vim using Ruby]]></title>
            <link>https://medium.com/subvisual/how-to-program-vim-using-ruby-e6bebf1f1d83?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/e6bebf1f1d83</guid>
            <category><![CDATA[vim]]></category>
            <category><![CDATA[ruby]]></category>
            <dc:creator><![CDATA[Gabriel Poça]]></dc:creator>
            <pubDate>Mon, 02 Oct 2017 15:20:22 GMT</pubDate>
            <atom:updated>2017-10-02T15:20:51.859Z</atom:updated>
            <content:encoded><![CDATA[<p>I recently started working in an Angular project where I’m not able to use <a href="https://github.com/tpope/vim-projectionist">vim-projectionist</a> to navigate the code. vim-projectionist is awesome, and I’ve grown used to it. Searching for files by name, in a code base with hundreds of files, started to become painful and I needed an alternative. Because I couldn’t find a plug-in that satisfied my needs, I decided to do it myself. In this article, I hope to demonstrate how you can program Vim using Ruby.</p><p>Let’s say that you have an HTML file that looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/88a19ee0d6fda569a66897b93bc2a528/href">https://medium.com/media/88a19ee0d6fda569a66897b93bc2a528/href</a></iframe><p>When the cursor is on line two or four (the timepicker tag), you want to trigger a shortcut that opens the JavaScript file for the directive timepicker.</p><h3>Ruby to the rescue</h3><p>In this project, every directive is in the folder javascript/directives/, where the directive&#39;s name is also the file&#39;s name. If the name has more than one word, such as <em>chart-timepicker</em>, the file name would be snake case: <em>chart_timepicker</em>.</p><p>I’m assuming you don’t know enough VimScript to make this work (I don’t), but fear not, if you compiled Vim with Ruby support, this will be enough:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6fc714465f271ac64d022f07851856ab/href">https://medium.com/media/6fc714465f271ac64d022f07851856ab/href</a></iframe><p>It’s a Vim function that you can trigger with C-] or call with :call AngularTemplateToDirective() (or map to a shortcut). Notice that it uses a module called VIM on line three. That module comes from Vim and it allows us to control it from the Ruby. If you want to learn more use :help ruby inside Vim.</p><p>This function fetches the current buffer and the current line. If the line matches an HTML tag (something like &lt;timepicker&gt; , &lt;/timepicker&gt; or &lt;timepicker something&gt;), it takes the tag&#39;s name, turns it to snakecase, and opens the corresponding directive&#39;s file.</p><p>Cool right? Five years using Vim and there’s still so much to learn!</p><h3>A little more advanced</h3><p>With the function above, you can open directives from the HTML. How nice would it be to open CSS files from the HTML as well?</p><p>Taking the previous HTML example, when I’m in a line with class=&quot;timepicker&quot; I want to open the <a href="http://getbem.com/">BEM</a> component named timepicker that, by convention, sits in stylesheets/components/timepicker.scss.</p><p>Building on the previous implementation, you first check if the current line contains class=&quot;, if not then look for the tag using the code from before. If it does match, you extract the component&#39;s name from the class, turn it into snake case and open the file:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/476c0dacc9289bc09795a84860378776/href">https://medium.com/media/476c0dacc9289bc09795a84860378776/href</a></iframe><p>I know that this code could be better, but I’m not concerned with that because it’s part of my Vim configuration, I’m always changing it, and it actually works!</p><p>I hope that you’ve found something new in this blog post. If you’re looking for more ideas for your Vim setup, check out <a href="https://subvisual.co/blog/posts/133-super-powered-vim-part-i-projections/">this blog post from Miguel</a> and subscribe to our blog. There are many Vim users at Subvisual and we always publish new content.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e6bebf1f1d83" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/how-to-program-vim-using-ruby-e6bebf1f1d83">How to program Vim using Ruby</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Typography as Base: From the Content Out]]></title>
            <link>https://medium.com/subvisual/typography-as-base-from-the-content-out-c59fe7bfb633?source=rss----bc6257b530c5---4</link>
            <guid isPermaLink="false">https://medium.com/p/c59fe7bfb633</guid>
            <category><![CDATA[ui-design]]></category>
            <category><![CDATA[ui]]></category>
            <category><![CDATA[content]]></category>
            <category><![CDATA[typography]]></category>
            <category><![CDATA[web-design]]></category>
            <dc:creator><![CDATA[Francisco Baila]]></dc:creator>
            <pubDate>Tue, 06 Jun 2017 11:03:59 GMT</pubDate>
            <atom:updated>2017-06-06T14:56:26.793Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1Km4fqgsA1Qod5grVqAECQ.png" /><figcaption>Photo by <a href="https://unsplash.com/@raphaelphotoch">Raphael Schaller</a></figcaption></figure><p><em>First published on </em><a href="https://subvisual.co/blog/posts/138-typography-as-base-from-the-content-out"><em>Subvisual’s blog</em></a><em>. </em>This blog post was born out of my necessity to find a structure in which I could rely on when designing any kind of web project.</p><h3>0. Random</h3><p>Before I started this research, my structure was very naive. When I came across a new project, my first move was to start drawing boxes and text blocks with randomly selected typefaces and margins. Not completely random of course, but with no serious thought behind it. If I needed a margin, I would start with 20px, and whenever I needed a bigger one I would double that value, so I ended up almost every time with margins like 20px, 40px, 80px and so on. The same with the typefaces chosen and their sizes. Selecting sizes always started at 16px or 18px adding 4px to get new ones. Once again the sizes would always end up being 16px, 20px, 24px and so on.</p><p>I started my journey on design through graphic design. In college, I spent a lot of time creating posters, books, and magazines. To do these kinds of pieces, I always went through very thorough processes of selecting fonts, sizes, margins, grids, etc. and I had excellent teachers that showed me how to do it. I liked doing graphic design, and I still do, but the web called me, and here I am, giving my first big steps after some big web projects. I also find myself asking why it is that I am not using processes like the ones I used before, on books and magazines, to do websites and products.</p><p>I am happy with the projects I’ve done so far, but I always get that feeling that something is missing. Some craftsmanship I would say. At Subvisual we care about our processes, and we are always searching for ways to improve them. The thing is that most of those processes are focused on User Experience, a subject that we care about. However, there is no good UX with a bad User Interface. I’m not saying that our UIs are bad. In fact, I think they are pretty cool but they lack craftsmanship. And you know, we strive for it. Curious and stubborn as I am, I went looking for solutions to this problem.</p><p>I started by googling and reading everything that could be interesting. I found some excellent articles, especially <a href="https://medium.com/tradecraft-traction/harmonious-typography-and-grids-10da490a17d">this one from Zac Halbert</a> that ended up being an inspiration for this post and a formula that I used in my work ever since. I asked some friends that are working on graphic design how they are doing their stuff nowadays and found some books that helped me a lot in my quest.</p><h3>Our Project — <a href="https://www.turngram.com/">TurnGram</a></h3><p>I’m going to take you through the process of bootstrapping a project using typography as base. We will start by the art direction and finish on the typography scale. Our project is TurnGram, a service that delivers your photos to your loved ones on a regular basis, hassle free. The design sprint has ended, our prototype is done and tested, and the first version will be born.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_9cuEOL2vOdCBeNQ4JwYag@2x.png" /></figure><h3>1. Art Direction</h3><p>Let’s start with the Art Direction or goals, of the project. This is where we think about the mood of the project, the feel that we want users to have when looking to our website. Take the time to read the project’s copy carefully and to look at its images, if possible. We want to understand our project’s personality through its content. As you do it, write it down: <strong>cozy, familiar and nostalgic</strong>.</p><h3>2. Hierarchy</h3><p>Every structure needs hierarchy. You should take advantage of the time you are spending reading the content to set the rules of your project’s hierarchy. Set what is a text block, what is a heading, what is a secondary heading, and so on. Mark them, find examples for every type of content.</p><ol><li><strong>H1</strong> — Some of our favorite TurnGrams;</li><li><strong>H2</strong> — Recipient Name &amp; TurnGram Instructions;</li><li><strong>H3</strong> — Do you ship overseas and to P.O. boxes?;</li><li><strong>Text block</strong> — I would like to send my mother (Maria Eastman) photos of my family on a monthly basis. She loves to display photos around her home and show her guests recent pictures of the grandkids. So please make sure to include the kids in your photo selections as much as possible.;</li><li><strong>Buttons</strong> — Start Now;</li></ol><h3>3. Typefaces selection</h3><p>Once there are no more examples to cover, it’s time to make the most important style decision. Let’s select the typefaces we are going to use.</p><p>From now on, every decision that we make has to take into account <strong>readability</strong> and <strong>legibility</strong>. As described on Wikipedia, readability is the ease with which a reader can understand a written text. Legibility is the ease with which a reader can recognize individual characters in the text. I will be addressing them through the post.</p><p>Picking a typeface early on a project’s life will change the way you will make decisions later. There is one book that helped me a lot on how to choose and combine typefaces. <a href="https://www.goodreads.com/book/show/44735.The_Elements_of_Typographic_Style">“The Elements of Typographic Style” by Robert Bringhurst</a> is considered by many a typography bible.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zxuu_UecxZmRbf3t-dGoMw@2x.png" /></figure><p>The first two advices that Robert Bringhurst gives us are <strong>“Consider the medium for which the typeface was originally designed”</strong> and <strong>“When using digital adaptations of letterpress faces, choose fonts that are faithful to the spirit as well as the letter of the old designs.”</strong> Be sure that the typeface you want was designed to be displayed on a screen or, if it is an adaptation, check if the font weights and proportions are well adapted.</p><p><strong>“Choose fonts that will survive, and if possible prosper, under the final printing conditions.”</strong> From this, we must bear in mind what sizes our typefaces will be rendered in, a question of legibility. Before choosing the typeface, go for its specimen and check what sizes it is best rendered in. Our example has some long text blocks so we should aim for a base font size of 20px. If you are designing a blog post, for instance, you will want to be using a base font size between 20px and 24px with a good x-height(the height of the lowercase). This is a rule that I regularly apply in my work, but like all rules, it can be broken when we feel it can work differently.</p><p><strong>“Choose faces that suit the task as well as the subject.”</strong> This project’s personality is cozy, familiar and nostalgic, so we should pick a typeface that reflects this.</p><p><strong>“Choose faces that can furnish whatever special effects you require.”</strong> If your content has a lot of numbers in the text, for example, you want to choose a typeface that contemplates <a href="https://en.wikipedia.org/wiki/Text_figures">text figures</a>. The same goes to texts that need some emphasis where you could use italic, bold or even <a href="https://en.wikipedia.org/wiki/Small_caps">small caps</a>.</p><p><strong>“Start with a single typographic family.”</strong> A lot of the projects that we see using two families could be set in only one. We should take advantage of the resources that our typeface gives us before we appeal to a new typeface.</p><p>Summing up, these are the guidelines to keep in mind when choosing typefaces:</p><ol><li>Be sure that it was designed to be displayed on a screen;</li><li>Look for a font that looks good on 20px;</li><li>A typeface that looks good on long texts, cosy, familiar and nostalgic;</li><li>Be aware if your content needs “special effects”;</li><li>Take advantage of the typeface resources.</li></ol><p>Make sure you do a lot of tests with multiple examples from your content before you make a decision. The best way to know if your typeface is the right one is to read the content with it. I will choose <a href="https://www.fontfont.com/fonts/tisa">Tisa Pro</a>, a serif font with multiple weights. It looks good on 20px; it looks good on long texts; it’s cosy and familiar due to its humanistic stroke. I don’t think that Tisa Pro can be considered to be nostalgic but not every requirement as to be achieved with type. You can rely on images, illustration, color, etc. I’ve checked that Tisa looks good in every kind of content that we have so we are ready to go.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kmKqR2X5EWPXm1_uZbdtfg.png" /></figure><p>Almost ready. One thing that we can try here is the branding typeface. If you are doing a website for a project that already as branding work done, you should try to use its typeface or, at least, use one that looks good with it. However, in some cases, you will not like the branding typeface and that is ok. That is what happened to us here so we went in a different direction. Although it is good to stick with one typeface, we felt the need to use a different one because we were needing an extra layer of contrast.</p><p>We are going to use <a href="https://www.daltonmaag.com/library/effra">Effra</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*5OUVDBgQb9yxp-gLB4Q0kA.png" /></figure><h3>3.1. Pairing Typefaces</h3><p>When pairing two typefaces we want to have contrast between them with linking details at the same time. First, Tisa is a serif and Effra is a sans-serif which is a great contrast point. They have similar x-heights which prevent us from creating two different scales — we will address this later. Effra mixes a geometric basis with some humanistic details, great to both create contrast and linking details with Tisa.</p><h3>4 . Sizes</h3><p>In the previous stages, we have already talked about some points that will come in handy here. As I said earlier, to choose a typeface you have to know the job it will perform. We already saw that our website has some long text blocks and that 20px is a good size, this is our base font size.</p><p>With a base font size comes a base line-height. Line-height is your font size plus the leading you want to give it. Leading is the space between one text line and the next. If you want your user to read faster or if you need to save space you can reduce the leading, like in books or newspapers. You can do the opposite if you want your user to have a more relaxed and comfortable reading.</p><p>Now that we need more numbers we need a scale to be the logic behind them.</p><blockquote><em>“By using culturally relevant, historically pleasing ratios to create modular scales and basing the measurements in our compositions on values from those scales, we can achieve a visual harmony not found in layouts that use arbitrary, conventional, or easily divisible numbers.”</em></blockquote><blockquote><strong><em>Tim Brown</em></strong></blockquote><p>So we start with our base font size of 20px, and we want a comfortable reading. There is one tool that I find really useful and that will save our life at this point: <a href="http://www.modularscale.com/">modularscale.com</a> by Tim Brown. This website lets you enter your base and a ratio and then it does all the math for you. In our example we want a relaxed pace reading so the ratio we will choose will be augmented fourth(1,414) 20 * 1,414 = 28.28. After rounding, our base line-height is 28px. Some other examples of modular scales:</p><ol><li><strong>Minor third(1,2) </strong><strong>20 * 1,2 = 24</strong> - fast reading speed and great space saving;</li><li><strong>Perfect fourth(1,333) </strong><strong>20 * 1,333 = 26,66</strong> - good reading speed and good space saving;</li><li><strong>Perfect fifth(1,5) </strong><strong>20 * 1,5 = 30</strong> - super relaxed reading speed.</li><li><strong>Golden section(1,618) </strong><strong>20 * 1,618 = 32,36</strong> - super duper relaxed reading speed.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/911/1*jsEcmLicghI-G6mHfzp8IA@2x.png" /></figure><h3>4.1. Modular Scales</h3><p>These scales are everywhere. They can be seen in molecules, flowers, the human body and that is why they make things so much more harmonious than randomly selected numbers. If we see something made of the same numbers as we are it will look much more harmonious.</p><blockquote><em>“Simple, right? And, at its core, the idea is pretty basic. But, oddly enough, it’s quite easy to both under-estimate its implications and over-estimate its complexity (at least once you start to dig into it a bit).”</em></blockquote><blockquote><strong><em>Billy Whited</em></strong></blockquote><p>They started to first appear in musical intervals and have been used through history by architects, painters, musicians, furniture makers, and others. So, why shouldn’t we use them?</p><h3>4.2. Typographic Scale</h3><p>Modular scales will give us a visual harmony, a rhythm. Like in music, our websites and products need a flow that makes sense.</p><p>We have already chosen our scale so now you are going to apply it, creating our typographic scale. Remember when we set the hierarchy at phase 2? Let’s translate it now into numbers.</p><ol><li><strong>H1</strong> — 28,28 * 1,414 = 39,988 ~ 40px</li><li><strong>H2</strong> — 20 * 1,414 = 28,28 ~ 28px</li><li><strong>H3</strong>–20px (bold)</li><li><strong>Text block</strong> — 20px (the base)</li><li><strong>Captions</strong> — 20 / 1,414 = 14,144 ~ 14px (uppercase, bold)</li></ol><p>I started at the base and followed what the modular scale gave me with my hierarchy in mind. For the buttons and labels, we are going to use 14px because we can use them in uppercase, so the legibility will not be damaged. When you are making these decisions make sure that you are testing them, don’t follow the scale blindly. It may happen that you find the scale not suitable for this task. In that case, go back and try another one. I will leave the line-height setting for later; you will see why.</p><h3>5. Horizontal Grid</h3><p>We can now start giving our first steps into our grid. The grid can be viewed from two perspectives, the horizontal and the vertical ones. Let’s start with the horizontal, the one that you may have seen more often. Grids are a fascinating subject; I recommend that you read <a href="https://www.goodreads.com/book/show/350962.Grid_Systems_in_Graphic_Design_Raster_Systeme_Fur_Die_Visuele_Gestaltung">“Grid Systems” a beautiful book by Josef Müller-Brockmann</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jEoCIfJRUuf-sFxYsujLFA@2x.png" /></figure><p>Grids allow us to solve visual organization problems. With these helpers it is easier to organize texts, images and other elements of our content. As Josef tells us in his book, the grid can only be conceived when we have an idea of the texts and images we are going to use. It is the content that is going to tell us our grid sizes.</p><p>We have already one size, the gutter (space between columns). The gutter should have the same size as our base line-height, 28px because this will be the most used margin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/452/1*WV2zckqjC_SzSYi1URrQbA@2x.png" /></figure><p>Text lines should have an average of 10 words, so this will be our column width. We are going to pick some pieces of text from our content, set them at 20px/28px and adapt its width to the numbers of our scale.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8VUz_kl9zv6tOh79N4AiYA.png" /></figure><p>452px is a good number for this. You don’t want to have text lines that are either too short or too long. Reading becomes more tiring, and it damages the readability.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/453/1*00f1sulKiGpeahauhNpiAA@2x.png" /></figure><p>We will start with 1440px of width because that is the maximum width to where we want to go with this project. In 1440px there could be three columns with 452px of width and between them two gutters with 28px of width. Our grid has a total width of 1412px.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*phsnJa9NzCW7RRRN6Yd10Q@2x.png" /></figure><p>Now, following Josef’s advice, the more columns we have, the more dynamic and creative we can be. So how about dividing our columns by 2? 452(one column) - 28(one gutter) = 424; 424 / 2 = 212 px(new column size). Our total grid size is still the same, but our number of columns is now 6 and our text block will occupy two columns and one gutter.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4puYPozvbj97-Ol32w-dUQ@2x.png" /></figure><p>The number of columns should depend on the dynamism you want to give to your content as well.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aIj-zCoeroxWU1ZSVLfXHA@2x.png" /></figure><h3>5.1. Vertical Grid</h3><p>The horizontal perspective is set. One more to go.</p><p>Baselines are where all our content will rest. With these lines it is much easier to align elements. So, our baselines are going to be half of the line-height, 14px and our scale will do the rest.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jH_2M8_kEajFwM1Rnq-zew@2x.png" /></figure><p>On good examples of print projects, all the texts are aligned with the baselines and that gives us an exquisite look that is hard to reach on the web. Go to <a href="http://www.modularscale.com/">modularscale.com</a> again and pick as much margin sizes as your project needs and list them neatly; have them match your baselines. Your margins will need a role. This role will be to separate different sections, titles from text blocks, elements inside a section, and others.</p><ol><li><strong>14,144 ~ 14</strong> — Spacing inside an element;</li><li><strong>28,28 ~ 28</strong> — Sub-section and text blocks or other elements;</li><li><strong>39,988 ~ 42</strong> — Sub-sections;</li><li><strong>113,052 ~ 112</strong> — Different sections.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HA7h_TMrcYddV4Ij_jENdA@2x.png" /></figure><p>Now that we have baselines we can go back to our typographic scale. We have lines every 14px, so we want our scale to match them.</p><h3>6. Typographic Scale (with baselines)</h3><p>We already knew our base line-height, 28px, the number right after our base font size, 20px. Text block — 20px — line-height — 28px — 2 baselines;</p><ol><li><strong>H1</strong>–40px; To know the line-height for font-size 40px you have to do a cross multiplication. So, if 20px -&gt; 28px, 40px -&gt; x, x = (40 * 28) / 20, x = 56. Placing this number in our baseline will give us 56 but but you may need to round it. <strong>H1</strong> - 40px/56px - 4 baselines;</li><li><strong>H2</strong>–28px/42px — 3 baselines;</li><li><strong>H3</strong>–20px/28px — 2 baselines;</li><li><strong>Captions</strong> — 14px; This case is not so simple. Font sizes that have the same size of baselines, or similar, need more space to breathe. So let’s add an extra baseline to this one. This will cause some imbalance when captions and text blocks are side by side. It’s something I’m still trying to sort out. <strong>Captions</strong> — 14px/28px — 2 baselines.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kTIkLyNjd5T2UbgzSw-Wzg@2x.png" /></figure><h3>What has changed?</h3><p>It’s easy to think that there is no real impact for users with this process but I’ll tell you what it has changed for me. Before this journey, I had no strong opinion on this subject. It was that feeling that something was missing that kept pushing me to start learning about it. Now, after some websites and products, I can say that my projects have harmony on them and that the content dictated the appearance of the project. It may be psychological, but I firmly believe it isn’t. People read my projects better because they have a well-thought scale. People will not get bored so easily because my websites are more dynamic now. We designers have to think about the people that use our products every day and they are worth every effort that we can put into them. I strongly believe that this is something that will have an enormous impact on a product’s lifetime.</p><h3>What about the 8pt grid, responsiveness, communication with developers, and all that stuff?</h3><p>As everything we do here at Subvisual, this process is not written in stone. We are always trying to improve ourselves and our way of doing things. This has proven to be a very worthy system to follow but with some flaws that easily solved with other methods like the 8pt grid, which we also use. Plus, the number of variables in this process is very hard to incorporate into our designer-developer communication. These and other reasons led us into creating our own structure combining what is best on all systems we have tried before. We are working and testing it and soon we will be able to share it with the world, it will be worth the wait, I promise.</p><h3>References</h3><p>Books</p><ol><li>The Elements of Typographic Style — Robert Bringhurst</li><li>Grid Systems — Josef Müller-Brockmann</li></ol><p>Posts</p><ol><li><a href="https://medium.com/tradecraft-traction/harmonious-typography-and-grids-10da490a17d">Harmonious Typography and Grids</a> — Zac Halbert</li><li><a href="https://alistapart.com/article/more-meaningful-typography">More Meaningful Typography</a> — Tim Brown</li><li><a href="https://www.youtube.com/watch?v=6s3XwSpY2vc">More Perfect Typography</a> — Tim Brown</li><li><a href="https://8thlight.com/blog/billy-whited/2011/10/28/r-a-ela-tional-design.html">R(a|ela)tional Design</a> — Billy Whited</li></ol><h3>Thank you!</h3><p>Thank you for reading this, I hope you found it useful. If you have questions or something to share please drop me a line here or at twitter <a href="https://twitter.com/fcBaila">@fcBaila</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c59fe7bfb633" width="1" height="1" alt=""><hr><p><a href="https://medium.com/subvisual/typography-as-base-from-the-content-out-c59fe7bfb633">Typography as Base: From the Content Out</a> was originally published in <a href="https://medium.com/subvisual">Subvisual</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>