Getting your application to send an email from a development or staging environment can be an onerous task depending on how much user workflow and data setup is required for a given email. This is where the mail_view gem can really help you out.
The mail_view gem lets us easily preview emails right from within your Rails application running in the development environment
mail_view is built into Rails 4.1+, so there is no additional setup or configuration to start using it.
You can read more about support for mail_view in Rails 4.1 in the following links:
By default, Rails 4.1 expects the mail preview classes to be located in the test/mailers/previews directory. If you use the mail generator, a preview file will be created for you automatically. You create a class that inherits from ActionMailer::Preview for each email to be previewed.
1 2 3 4 5 6 |
|
Browsing to http://localhost:3000/rails/mailers/welcome_mailer/welcome_investor will show you a preview of the email. But before you do that you will probably need to set up some data for the preview
For Rails versions prior to 4.1, there is just a little work to do to get set up.
First you will need to add the gem to your Gemfile.
1
|
|
Then you mount the mail_view engine into your application via the routes.rb file.
1 2 3 |
|
I wanted to make the mail_view available on my staging server, so I used an environment variable to enable it.
1 2 3 |
|
With the engine mounted at mail_view, browsing to http://localhost:3000/mail_view will present us with a list of emails to preview. But before we do that, we need to set up the emails to preview.
You set up the emails to preview by creating a class that inherits from MailView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Now that we have some emails to preview, we can browse to http://localhost:3000/mail_view will present us with a list of email preview links as defined in the MailPreview class.
Typically our emails are working with data from our database. The mail_view documentation describes some of the ways you can provide data to the mailer, using either actual data from the database, using a factory pattern, or providing a stub.
In the examples above, I am using data from the database. Each approach has its advantages and disadvantages, and it really depends on how you data is structured as to which approach you use. You can also mix and match the different approaches as you see fit.
mail_view displays a preview of the email with the header information shown in the page header and the body in an iframe, as shown below.
If you have provided a text and html template for the email, a dropdown is displayed in the page header to allow you to preview the different formats. Here we are displaying the text version of the email
Since the body of the email is displayed in an iframe, clicking on a link in the email will open the link inside the iframe.
The mail_view gem is a great tool to allow you to visually inspect the emails sent by your Rails application.
]]>When running under Rails, the gem uses Capybara to capture its screenshots. Any Capybara driver that supports screenshot capture should work, though we’ve only tested this with Poltergeist so far.
In your spec_helper.rb
, add:
1 2 3 |
|
Now the Capybara page object will have a looks_like?(predicate)
method that can call to make screenshot assertions:
1 2 3 4 5 6 |
|
Check out all the details over at the project’s Github page and let us know what you think.
]]>Typical scenario #2: We’ve just spent several hours modifying an application feature. Now in the last part of the day we are tasked with re-styling the feature. We’re a little tired, it’s after lunch, and we have little patience for mucking around in CSS. We open the stylesheets only to find that little attention was paid to the structure and organization of them. As a result we have to spend twice as long as we should combing through lines of CSS in order to figure out how our feature was styled in the first place. Our frustration with the current state of the CSS causes us to write even sloppier CSS to address today’s issue. We exacerbate the problem.
We write clean, maintainable application code. We do this because we know that the code will eventually need to change. Writing with change in mind informs our process. Yet with CSS we often let this discipline slip. We don’t spend the time to construct CSS the right way, choosing instead the path of least resistance. Perhaps because CSS is simpler than application code, we feel that it is below us and we can hustle through it without wasting too many brain cycles. Perhaps it’s just boring to write CSS and we want to get it out of the way. Whatever the excuse, it often leads to poorly-planned and un-maintainable styles. This leads to angst about writing CSS. Bad CSS taints our impression of all CSS. If we make a commitment to write more maintainable CSS, we will make our own lives significantly happier when we inevitably get back into those styles.
Here are some high-level concepts we should keep in mind to help write maintainable CSS. None of these are complicated, and may even seem common-sense. But are we always really following them? The broken window effect can quickly spiral out of control with CSS, so keeping the fundamentals in mind at all times will help keep us sharp.
This should be the first question we ask when styling any element. Instead of diving right into the CSS, we should take a few seconds to ask “does this element occur anywhere else?” 90% of the time the answer will be yes. At that point it’s up to us to determine if the style is better suited for a more global stylesheet, a mixin, or an extendable class. If it’s more efficient to create the style in one place first and only abstract it once it re-occurs, that’s fine. As long as we’ve made the decision to eventually globalize the style, we’re on the right path.
1 2 3 4 5 6 7 8 9 10 |
|
This style looks fine initially. But before or after composing this CSS, we should take a quick look over the design to determine if any of these styles are more global. Let’s say we discover that there will be several side menus with the same border and padding styles. We can then make the aside style more global:
1 2 3 4 5 |
|
1 2 3 4 5 |
|
We don’t allow unnecessary duplicate methods to occur in our code; why then should we allow a set of CSS styles to occur more than once in our stylesheets? The most agonizing task when working in CSS is making adjustments to elements that are being styled from multiple places. Ideally we should only have to modify CSS in one place when making an update. Even if it feels like we’re writing a little more CSS initially in order to keep things dry, in most cases it’s way to go.
We don’t always know ahead of time where a duplication will occur; we may need to style a few elements and then factor out the common styles afterwards.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
The refactor creates more CSS than the original, but is is more manageable. If we need to change the width, border, or color of these form elements, we now only need to change them in one place.
global.css can become quite a large file if left unmanaged. Oftentimes there are groups of global styles which can be split off into separate files. Form styles are a good example. Typically the majority of form element styles will be consistent across our app, and they usually require a significant amount of CSS. Moving these form styles out of our global stylesheet and into a global feature stylesheet helps keep our styles organized and our files as small as possible.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
This sounds a bit dramatic, and it may not be possible given project and client needs. But the point it demonstrates should not be overlooked. If establishing global styles early is a priority (as it should be), beginning our CSS work on the home page can present a challenge. If there is one page in our app that contains unique design characteristics or diverges from the global styles, it’s the home page. A lot of effort is dedicated to styling the home page. If we start there, when we move on to an inner page we will find ourselves saying “this style is like the home page style but it differs a little.” In fact the opposite is typically true: the home page often differs from the global styles, with some similarities. Using the home page for establishing canonical styles can therefore confuse the process.
Ideally we should start our CSS work on an internal page full of global style elements. Conveniently, our app’s core functionality is usually contained in these inner pages, and that core functionality is typically the starting point for the development process. Though it may feel awkward - for our client as much as ourselves - to initially avoid the homepage, it can make for a more streamlined process in the long run.
The most elegant solution is not always immediately obvious. As long as we keep our eyes open for a better solution, we will continue to keep our CSS robust and flexible. We should approach our CSS with the intent of refactoring it as soon as it is appropriate. We constantly refactor our application code, yet too often we leave crummy, outdated CSS to rot. Taking the time to refactor CSS makes our lives exponentially better when we inevitable dip back into the styles.
As a whole we are too lenient with CSS. As we all know, many hours can be sunk into a style update due to poorly-maintained CSS. Part of the difficulty in keeping CSS up to a high standard is the lack of outside attention paid to it. In the application world our code is under much more scrutiny than is our CSS. The discipline to keep the ship righted must then be self-imposed. It is in our (and our clients’) best interest to keep a sharp eye on our styles. We should hold our CSS to as high a standard as we hold our code.
]]>Here’s what the generic .travis.yml
file we start out with looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Learning how to test RubyMotion apps can be daunting if you’re coming from a server-side programming background, especially one like Rails with a mature ecosystem of testing tools and community wisdom. Full-stack integration testing—firing up the entire system and putting it through through its paces as a user would—can be particularly challenging.
We recently wrapped up an engagement with one of our favorite clients, MeYouHealth, during which we needed to build a way to sanely test a RubyMotion app backed by a JSON-serving Rails backend. I’ll cover both the strategies we tried and discarded as well as our most successful approach.
A brief RubyMotion testing aside: there are two libraries we use to write tests for our RubyMotion apps.
For both of these types of tests, we needed a way to mock out the JSON responses from our backend.
Our first approach to making sure our tests didn’t depend on the backend was to simply stub out the HTTP responses in our Bacon specs using webstub. This worked, but it quickly became a pain to keep the stubbed responses in sync with the backend under active development. When they’d fall out of sync, debugging what was wrong in the tests wasn’t straightforward.
Worse, while technically possible to use webstub for Frank tests, to do so would have involved some signification contortions. Because Frank itself runs outside the app, the only way of stubbing is to add methods to the AppDelegate class and call them using Frank’s remote execution, doing so for each request we wanted to stub. Yikes.
The next tack we tried was recording responses from the server once and playing them back, inspired by VCR. VCR itself doesn’t work in RubyMotion (as with most regular Ruby gems), so we used a custom recording proxy server written in Go with a thin Ruby wrapper for driving cassette use inside tests. This would record HTTP interactions with a local test server once, then replay them each subsequent time.
This worked, and let us run our Frank specs without a live backend. However, it suffered from the same skew between backend development and recorded cassettes. Changing modeling on the backend necessitated either some tricky editing of the cassette files or setting up the scenario again and re-recording the whole scenario. Time-sensitive data became tricky as well, with the timestamps being fixed in the cassettes once recorded. Not great.
First, we stopped trying to emulate actual HTTP tests in our Bacon controller and model specs, instead favoring use of dependency injection to test components in isolation. Any testing of HTTP concerns was deferred to the integration tests.
Next, to get our Frank features in shape, we built out a system to let us talk to a local instance of the backend and selectively load small scenarios for each individual feature to run against.
We’ve put together a pair of example applications to showcase this approach, along with instructions on how to get up and running. Note that while our example iOS app is written in RubyMotion, since Frank works independently of the app, there’s no reason this can’t be adapted for Obj-C or Swift iOS apps.
@api_fixture_NAME
will push a command over the named pipe for the Rails instance to load and run a scenario file with the specified NAME
.This isn’t all roses.
For one, it’s slow. This is a problem with any form of iOS testing, as the app needs to be compiled and launched in the simulator before the tests can run, and it’s exacerbated here by the time it takes for the server’s state to be set up and torn down in between features.
It also adds complexity to the testing process by requiring you to have the Rails environment up and running for the Frank tests run at all. This also means some extra work to set up on a CI environment like Travis.
We’re overall pretty happy with this approach: it lets us do full-stack integration testing without tearing our hair out trying to manage a bunch of mocked state. It also does a great job of letting us know when the client’s expectations of the API have gotten out of sync with reality on the server side. Despite the downsides it’s still a huge win in our minds.
]]>This doesn’t aim to be a comprehensive guide to Objective-C, but rather to get you just enough information to visually parse example code.
A method signature with no arguments in Objective-C looks like:
1
|
|
The -
mark at the beginning indicates this is an instance method; class methods are indicated with a +
. The (BOOL)
is the type of the method’s value (here, a boolean).
In Objective-C, methods are called using infix notation. The Ruby
1
|
|
is equivalent to
1
|
|
Objective-C methods can have named arguments. This UITableViewDelegate methods:
1 2 3 |
|
Become the following Ruby methods:
1 2 3 4 5 |
|
Note that these named parameters are actually a part of the method’s name; that is, different named parameters constitute a different method. The method names have the parameters separated by colons, like: tableView:didSelectRowAtIndexPath
and tableView:heightForRowAtIndexPath
.
This looks a bit funny when translated into Ruby, as a first glance would seem to indicate you’ve defined the same method twice. These methods are called just like you’d call methods with named parameters (in Ruby 2.0 and up) or optional hash arguments. For example, a UIViewController implements:
1
|
|
We’d call this method in Ruby by:
1
|
|
From here, you can dig deeper into Objective-C with Apple’s language docs, but you should now know enough to grok most of the examples you’ll run across in the wild.
]]>It’s clear that the only way for a company to survive over the long term is to successfully evolve the company’s product offering. Companies that have rested on their prized revenue streams found themselves on a slow death march to oblivion. As an example, take a look at former Boston area titans: Wang Computer, Digital Equipment Corporation, and Polaroid.
The current success stories, that everyone likes to talk about, are Google and Apple. Google has been successful in evolving their product offering by investing in opportunities that have been tangential to their main business of search. Apple revived itself by transforming their hardware and software into indispensable technology for the masses.
At Terrible Labs we’re constantly trying to evolve our own product offering by being current on new technologies and design practices that will better help our clients solve their business problems. One example of this has been our effort to bolster our mobile design and development service offerings. Since making that investment, we’ve seen our mobile business grow from nothing into nearly 50% of our revenue each year.
As a leading product design and development shop, we have the privilege of working with many established companies to help them exploit new business opportunities through technology applications. One of those companies is MeYou Health, a subsidiary of the benefits provider, Healthways.
MeYou Health is a company that is constantly surveying their industry to find opportunities where technology can solve a problem for their network of subscribers. I recently caught up with Jake Butler, Product Manager at MeYou Health, to learn more about how their company identifies and ultimately pursues various market opportunities.
For Jake, new business and product opportunities reveal themselves when the team can apply their product approach to a market trend in the health or well-being space. “The market dictates the general space we’re going to move into: overall well-being, physical activity, weight management, smoking cessation, etc. Once we’ve established a market opportunity, we begin a process to see how our core design principles like small actions and an open social environment can be incorporated into this.”
After identifying various opportunities, the Heads of Product and Design, Trapper Markelz and Sean Landry, make the call on which opportunities to pursue. “While everything is undoubtedly a team effort, you’ve really got to have a single product owner to have a clear vision and direction. Trapper and Sean ensure that that we’re going in the right general direction, but ultimately, it falls on the product manager to gather requirements, ideas, and concerns from team members and other stakeholders, synthesize all that information, and drive the product towards success.”
Once a solid direction has been established, the team begins to test the viability of the product idea through design. “We start with low fidelity prototyping to validate our initial concepts internally and this is really a whole team effort. This includes everybody from game designers, UX designers, developers, content creators, implementation specialists - everybody is pitching in at this stage.”
If they see positive results in the design and user testing phase, the team will develop the product and ultimately get it to market. “Once we’ve got something with legs, we build out an MVP which we refine and continue to validate with real users. When we’re confident that we’re going down the right path, we build it to scale and deploy it to customer pilots and take it to market.”
MeYou Health has built a great business by successfully applying their product domain expertise to new market opportunities. Since their inception in 2009, the team has built over 15 web and mobile products. Some of those products have been sunsetted, some are currently in the market while others are at different stages of initial development.
If you’re looking for a great model on how to drive the creation of new products at an established company, get to know MeYou Health. Jake and team are some of the best in the business.
We’re always interested in hearing from other established companies who have been successful at developing new products. If you’re one of those companies or if you’re looking for help creating new products, shoot us an email to hi@terriblelabs.com.
]]>In early April, Terrible Labs and Silicon Valley Bank hosted the first Quantified Summit. The summit was a discussion about the future of the quantified movement as it relates to lifestyle, health and fitness.
As a design and development shop that works with so many clients in the health and fitness space, this was a great great opportunity for us to learn more from the experts in the industry.
The summit featured panelists from companies such as: LG, Comcast, Samsung, ESPN, Turner, Partners Healthcare, UnderArmour, New Balance, RunKeeper, Withings, Orreco, Sociometrics, MC10, Bolt, Crisply, Lose It and more. Having all of the leading companies and people from the quantified movement in one location made for stellar discussion about the plethora of opportunities that exist.
We are excited to see the progress in the space between this year and next. If you’re working on something in the quantified space and would like to get involved in next year’s summit, feel free to reach out!
]]>Today, I want to introduce motion-juxtapose, a library for adding screenshot-driven assertions to your RubyMotion tests.
Literally, it_should_look_like "the login screen"
in your specs.
Write a test that puts your app in the state you want to capture and make a screenshot assertion.
A simple controller test might look like:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
The first time this assertion is made, your test will fail with the error “No accepted screen shot”.
Run the juxtapose server with `bundle exec juxtapose` and browse to http://localhost:4567 — you should see the just-captured screenshot, like below.
If the screenshot looks like what you expect, click Accept to save the image. Future runs of this test will be compared against the accepted one.
Run the tests again, and they should be green.
Later, when you introduce a change (intentionally or not), the tests will fail with the message “Screenshot did not match”. Open up the juxtapose server again, and you’ll see a comparison of your accepted screenshot with what the test captured.
If the change was intentional, you can accept the new screenshot - otherwise, you’ve got some fixin’ to do!
We use screenshot assertions to supplement our isolated model and controller tests, not to replace them. Since they don’t inform the design of the code they’re testing, screenshot assertions don’t help you write better code, nor can they be used for TDD. Instead, they’re designed to help write tests that guard against visual and functional regressions.
We use motion-juxtapose in two main ways:
It’s also been useful when we’ve inherited an app with no tests. Screenshot assertions are a quick way to wrap an existing project in a set of black-box tests that capture a bunch of information about an application’s behavior. This lets us begin refactoring without as much fear of regressions.
Head over to GitHub for the rest of the story and try out motion-juxtapose on your next project!
]]>As a design and development shop, the lifeblood of our business is designing and building products for clients. If our business is going to grow, we need to add designers and developers to our team, and the only way to do that is to bring in more client work.
In order order for us to bring in more clients we need to make sure that our services offering appeals to our prospective clients. Because the technology landscape changes so rapidly, the only way for us to ensure we’re providing the best services is to invest in our team’s learning and growth.
I’ve previously written about our struggle to find the right balance between client work and investing in our team. As we continue to figure it out, here are some things we’re trying out to help our team learn.
One of the benefits of working on greenfield projects is that we get use the latest and greatest technology. Many times, the libraries that we use or the design tools that we employ haven’t been leveraged by everyone on the team. We treat these situations as learning opportunities where the person using the new technology or tool, will give a presentation to the company.
We usually have these talks over lunch on Fridays. Terrible Labs buys food for everyone (typically via Foodler) and the team gets a crash course in something new that they might be able to leverage on their current or a future project.
We expect everyone on the Terrible team to push themselves to get better. Part of that includes learning through attending or speaking at conferences. We don’t have an explicit conference budget so we encourage our team to let us know which conference they’d like to attend and how we can help make it happen. For those on the team who are attending a conference we ask that they share what they learned with the team upon their return. They can do this through either a blog post or a brownbag lunch.
I spoke about Project Weeks before but for those who missed that post, a Project Week is is one developer/designer week of time where the sole focus is to complete or improve upon a current open source or passion project. So far we’ve had several successful projects including Motion Juxtapose and TicketZen.
An important part of every project we work on is the retrospective. Retrospectives are an opportunity for our team to learn about a project they didn’t work on and more specifically: what went well with the project, what didn’t go well, and what we need to do in order to make the next project better.
We host retrospectives at the end of a project. We take an hour at the end of the day to drink a few beers and discuss what we need to do as a team to select better projects and how to improve the execution of our projects. What we really like about retrospectives is that they don’t just help us run projects better but they also help us learn how to better sell our services.
We’re not the only ones focused on improving our product and team. The team at RunKeeper is heavily invested in keeping their product and team ahead of the curve. I was recently chatting with Tom Boates, VP of UX at RunKeeper, and he explained how they use internal, team hackathons, to make improvements to an already great product experience and office culture.
Here is what Tom had to say:
“RunKeeper has a really great product process when it comes to iterative improvements, but so far, for our big picture feature innovations, we’ve turned to our hackathons for inspiration. We do hackathons once every 6 months and have plans to increase the frequency.
At the start of the hackathon, the team spends some time pitching project ideas and recruiting members to help. Some of our hackathons have themes, but it’s usually totally open field for the teams.
Projects that have come out of hackathons have certainly ended up in our product: our existing website design as well as our April Fool’s Day pranks, RunKeeper for iPad, and RunKeepah were all thanks to our hackathons.”
Not all of their hackathon projects are focused on improving their products. Some are focused on improving the office. “We’ve also had a couple teams create office hacks as well. Check out RumKeeper, our office bar, as well as Rupee light, which lights up when we get a new RunKeeper Elite subscriber.”
Investing in your team and the future of your product isn’t something revolutionary. Most of us know that we need to do it. The difficulty of making the investment is figuring out which efforts your company should invest in.
Taking staff away from your core business – and having them work on something that isn’t necessarily going to produce revenue in the near term – can be a scary thought. However, the thought of losing your business because you didn’t make the investment is a much scarier thought to me.
Hopefully some of you will find these examples helpful. If you have any examples of what you and your business are investing in, we’d love to hear about them. Feel free to drop us a comment below.
]]>Since starting Terrible Labs nearly three years ago, we’ve struggled to come up with the right strategy to balance the learning required to remain a top design and development shop and billable client work to keep the lights on.
Thanks to the Terrible Thomas Mayfield, we’ve instituted Project Weeks to help our team invest in making themselves better. A project week is a scheduled developer/designer week of time where the sole focus is to complete an open source, passion, or personal project.
Since instituting Terrible Project Weeks we’ve had our team develop some great projects. Two of those projects include:
Terrible Labs has been an early adopter of RubyMotion, a toolchain that lets developers quickly create and test native iOS applications, using Ruby. Part of developing high quality Ruby applications is writing well-tested code. Thomas leveraged a project week to develop an approach for using screenshots as assertions in RubyMotion test suits and released it as an open-source library: motion-juxtapose.
When RubyMotion was launched a few years ago, we were super excited to use it for a project. Unfortunately we didn’t have a mobile client project, since we had built up the Terrible Labs brand as a web design and development shop. In an effort to show our mobile prowess we searched for a simple idea that we could develop into a mobile application. That idea came in the form of a tweet from Paul English: “I want an iPhone app to take a photo of any parking ticket and pay for it from a credit card on file.”
Since seeing that tweet, we’ve launched TicketZen, the easiest way to pay a parking ticket. We spent a week building the initial RubyMotion prototype. Since then, most of our team has been able to work on the application to learn the RubyMotion toolchain. As a result of releasing TicketZen, we’ve experienced a dramatic increase in the number of Terrible clients looking to build mobile products.
As a consulting shop, it’s not easy finding the right balance of learning and client work. We still have a long way to go, but since investing in Project Weeks, we feel like we’re on the right track.
Stay tuned to the Terrible Blog as there are several more open-source and passion projects being worked on by folks at Terrible Labs. We’re excited to see where these projects go but we’re even more excited to continue watching our team level up their skills and keep Terrible Labs at the forefront of design and development.
]]>Oftentimes we work with a client who has already established an account for DNS, and it’s simpler for the client to stick with that provider when purchasing an SSL certificate. Oftentimes this provider is GoDaddy. Say what you will about GoDaddy, they are a very relevant player in this space and it’s important to know how to work within their system, even as we may steer clients to preferred providers such as DNSimple or NameCheap.
And as is common with our Rails apps, we’re hosting on Heroku.
We found ourselves jumping back and forth between Heroku’s SSL endpoint docs and GoDaddy’s SSL certificate docs. The following is a roadmap between the two sets of docs, with some extra screenshots and clarification on a step that isn’t explicitly covered in either.
The common name must match the common name used with the current certificate, and the presence or lack of “www” matters. Refer to your current certificate on GoDaddy.
The steps are listed under ”To Re-Key an SSL Certificate.” Unless you know of any reason to change the signature algorithm or certificate issuing organization, make sure they match the current setup.
Heroku instructs to select Nginx as the server, Apache 2.x if Nginx is not an available option. (Note: we encountered this option later, during the certificate download step rather than the certificate request submission step.)
In our case, the new certificate was immediately available in our GoDaddy certificates dashboard, right below the current certificate. The old and new certificates look identical from the dashboard.
In order to distinguish which certificate is the old and which is the new, click into each certificate. The old certificate will have a warning message at the top of the page announcing that the certificate will soon be expired. Download the other certificate.
This step is not clearly outlined in either sets of documentation, but it is a necessary step. When you download the certificate, you will receive two files: the certificate file specific to your account and an intermediate certificate bundle.
The intermediate certificate bundle is a combination of public certificates explaining to GoDaddy how to use the private certificate file. The intermediate bundles can also be found here. GoDaddy provides some more info on intermediate certificates.
Concat the certificate file and the bundle file (both will likely have the .crt extension). We named the new file using the certificate file name plus “_bundle” to keep things straight. We also updated the permissions on the new file to match that of the other .crt files.
(The “@” symbol listed at the end of the .crt files’ permissions info indicates that there are “extended attributes” (metadata) associated with the file. More on extended attributes.)
Replace “server.crt” in Heroku’s example with your newly-created .crt file name.
That should do it.
(What’s a .pem file? With Heroku you update the .crt file and the .key file using the certs:update command. The other option in some scenarios is to combine the .crt and .key into one file. That file is typically given a .pem extension.)
]]>But why stop there? Each week we’ll share a tidy little compilation of our best discoveries with the community, starting today.
Mike: Listening to the HBR podcast, I learned about Deliberately Developmental Organizations (DDO). At most companies, people spend a lot of mental energy hiding their weaknesses, but the culture in DDOs values openness about goals and growth towards getting better. I want to look into it more.
Taylor: Setting an absolute- or relative-positioned element’s left and right attributes will automatically calculate the element’s width.
Jeremy: ActiveRecord #assign_attributes
is similar to #update_attributes
, but doesn’t save.
Tim: Photoshop CC has a feature for generating assets from layers upon save, similar to Slicy. It works by naming layers and layer groups with special syntax. You can append an image extension + quality level, and prepend sizing info in percentage or dimensions. SVG export is still in beta, but can be enabled with this hack.
Also, as of Jan 14th, you can use SmartObjects that are separate files instead of embedded. This could be really helpful when collaborating on pieces of a design, and for keeping the primary PSD file smaller.
]]>The very first subject is scanning the screen and thinking out loud, understanding, dissecting, validating or rejecting. I sneak a peek at my client, and catch a tiny smile, eyes wide and eyebrows raised.
The experience we’re witnessing is invaluable, and he knows it.
This is the moment where he realizes that iterating on a product in the design phase is not merely uncovering a few blemishes, but qualitatively improving his product. Had he attempted this during development, the cost in both time and dollars would have been orders of magnitude greater.
How do we do it? After an intense week of discovery and rapid collaborative design, we create a fairly high-fidelity prototype and we use it to test our riskiest assumptions. Armed with the results, we’ll improve and re-test, refine and re-test, and in a matter of weeks we’ll be ready for technical development with a high level of confidence in our design.
There’s no terrifying unveiling of a mockup I’ve been designing in a cave for weeks, headphones on, making my best guess at what will work and praying it will be accepted by the client. No dog and pony show. No crowd-goes-ahh (or crowd chases me out with pitchforks). In fact, the whole process is relatively (and refreshingly) surprise-free.
Designing and refining a prototype collaboratively is an incredibly powerful process. We have buy-in throughout the process from key decision makers, the development team, and even potential customers. We often significantly improve upon the original concept. And most importantly, our clients avoid the potential for a costly investment in a product that no one will use.
And that’s exactly what that tiny smile is all about.
]]>We’re looking for someone who has experience hosting stakeholder and end-user interviews, moderating requirements workshops, developing user personas, and creating flow diagrams, wireframes, prototypes, and high-fidelity, production-ready deliverables.
For all of you who care about design, have a proven track record of turning ideas into products that ship, and want to help shape the future of design at Terrible Labs, shoot us a note to: jobs@terriblelabs.com.
We are not interested in engaging with a recruiter, so don’t waste your time or ours!
Terrible Labs is a small team of senior level developers and designers who are passionate about creating great products. We’ve been working with established companies and startups over the past few years to help them design and build applications that solve problems.
You must have a strong appreciation of design thinking, and understand how it integrates into the process of creating digital products.
This is a position for an experienced designer, who is comfortable working independently, and has a strong sense of ownership of his or her work, but values a collaborative environment.
We look forward to hearing from you!
]]>At Terrible Labs, we’re invested in the happiness of our coworkers. Jeremy and I recently spent an afternoon building a simple Rails app to help us gauge the mood of the company.
This iPad lives in the kitchen. The background cycles through popular nature photos from Flickr and prominently asks “Are you happy?” You simply tap “Yes” or “No” and your answer is recorded anonymously. You’re rewarded and inspired with a random Star Trek or Simpsons quote after answering. If you’d like to be even more anonymous, just load up the web app in your local browser and answer without a crowd.
According to the first few weeks of usage, we’re happy 81.7% of the time. That’s promising, but we’re going to look at the data over time to get a sense of mood. Are we improving? Are things getting worse? Are people happier on different days of the week, times of day, or times of year?
This data doesn’t answer the question of what we should do differently – that’s where the hard work starts. It also isn’t a substitute for regularly meeting with employees and asking them how things are going. The metrics here are only another data point to be considered with the whole.
30% of Americans may claim to be happy with their job, but some portion of that percent is probably just happy to have a job in this recovering economy. In the world of software, your employees are spammed by recruiters several times a day and could trip over three more jobs on the way home from work. We have to try harder. Good developers already have the bottom sections of Maslow’s Hierarchy of Needs under control and are looking for esteem, achievement, and self-actualization. If you can’t keep them engaged and help them achieve those things, they’ll look elsewhere (see also: Bored people quit).
Are your employees happy? Do you have any idea? Find out.
The code to our (very simple) app is here on GitHub. The README has all you need to get it running on Heroku and collecting data.
]]>If you missed the presentation, check out the video below (Thanks to Jeff Swank for the Oscar-worthy cinematography).
A big thank you to all that came out and voted for us!
]]>We couldn’t have had such a successful event without the help of our sponsors:
We had a beautiful fall day with over 60 folks from the Boston startup community out playing golf for a good cause. You can check out some of the photos from the event below.
A big thank you to all of the companies who participated this year!
]]>That picture is from a little over a year ago. I had just received a new hat and was vaguely buzzed from a job interview at Terrible Labs. Honestly I wasn’t expecting such a warm reception – I only got the interview after attending a meetup hosted in a bar in downtown Boston. I was unaware of the chain of events and truly interesting people that I would meet because of it. It all started with this picture, sitting at State Street Station, head full of Ruby code and a little IPA, unaware that I didn’t get the Job I just interviewed for.
Not yet, at least.
A little context: I moved from Connecticut to Boston in February 2011, just after another record snowstorm. I decided that I wanted to program after attempting to be an ad executive, a Wordpress maintainer, and – lord help me – a ‘social media expert’. I had some history with the CS field, but nothing stuck. I picked up a painfully small amount of Java, some Python, some Javascript. It was on a hot August day that a friend of mine passed me a link and I got my first taste of the Ruby community writ large. I fell in love with the language on August 19th, 2011, otherwise known as _Why Day.
I distinctly recall wanting to be a part of any community that could produce someone like _Why. Ruby was a great programming language, the one that made the most sense to me at the outset – but it was the style of _Why that made me want to join the party. I started attending as many meetups as I could find, trying to absorb as much as I could. My github is littered with a number of aborted projects, sites born to familiarize me with a new concept and then left in the dust. I felt like most intermediate beginners do: like a living god (Note: That goes away, but not as much as you might think.)
I attended meetings and project nights, listened to lightning talks, subscribed to Railscasts. I began getting familiar with the different faces and companies in the area, meeting so many people who were just as eager to learn and teach. I felt very welcomed, and it helped me learn. Still, I was hungry for more, and I felt like I was just about ready to be hired by a company, if only I could find one that would have me.
Though I was nervous about going to the Drinkup, I wasn’t nervous about emailing the man with the beard who was in charge of that interesting company with the T-Rex logo. I forwarded him my Github account, and I was absolutely shocked when I heard back from him. I was on top of the world, well on my way to becoming the newest hotshot developer. I walked into the Terrible Labs office, meeting Jeremy (previously mentioned bearded fella) and the rest of the Terrible team. They offered me a beer, and I began to pair with some Terrible folks on a gem I had made – a dice simulator for RPG tabletop games.
Looking back, the gem was not pretty. So much documentation, so little code. My description was much less of a joke then: my gem really was just a wrapper for the ‘Rand’ function, one that you could call with a series of shake-and-bake constants. Despite all of this, Jeffrey Chupp sat down with me and paired on this silly gem for the better part of two hours. Jeffrey took two hours out of his day to help me roll fake dice.
Most tellingly, he’d continue to do it for the next seven months.
Within a week or so, I heard back that I was too new to get the job. Jeremy sent me an email that didn’t read as stock, describing the various reasons why they couldn’t hire me at present. Admittedly I was too green, way too fresh to be job hunting. But Terrible surprised me again: Jeffrey was interested in working with me further, helping me work through my problems and giving me a desk whenever I needed it. I had a mentor, and – as I would learn – a damn helpful one at that. I learned to appreciate how one-on-one help with code, combined with a helpful community, can really lift a new programmer. For seven months, I came in as often as I could. I’d code like crazy whenever there was downtime from my various jobs, and then come in and present my conundrums to Jeffrey. The entire Terrible Labs team would pitch in and teach me new tools, neat tricks, and things that I would not have learned without such a context.
Jeffrey is a fantastic mentor, more willing to course-correct than simply provide an easy answer. For my learning style, this is paramount – I’d much rather know what to Google than know what to type. As it turns out, knowing the former tends to reinforce knowledge of the latter.
One day I was working on a side project of mine and came to Terrible Labs for some more debugging. I sat at the empty desk, as I always had, when Jeffrey – who is as bad at lying as he is good a mentoring – began to ask me questions about my “current employment situation.” Within a week, I was his co-worker, and I met the rest of the Terrible team who have each taught me loads more than I would have alone. I am deeply grateful for their help, even if I occasionally repay them with mistyped commit messages and awkward Cosby-related humor. Y’see.
Last week, I attended a local project night and went toe-to-toe with local up-and-coming Ruby dev Alex Wheeler on the merits of Bootstrap (formerly of Twitter) and Zurb Foundation. It was a blast. Alex has come into the office sometimes with various programs he is working on, and it’s been a great experience sitting down and dedicating a few hours of time to helping him out.
Developers: you should know how important the donation of time can feel to someone just starting out. Programming is daunting, and it helps to have someone more skilled give you the time of day. Simple answers, nudges in the right direction, an invitation to email – being able to rely on these things can really help unstuck a problem and keep the learning momentum up. If you don’t already, please volunteer yourself, even if only for a few hours a week. That one simple gesture can mean the difference between a hopeful newbie and a salaried employee.
New folks: embrace the community. People can’t wait to help get you here. Take advantage of local meet-ups (I always enjoy the Boston Ruby Project Nights, myself). There are organizations like RailsBridge, BostonRb, and LaunchAcademy that are geared at ramping up new developers. Join mailing lists. Work on projects that teach you something new.
If nothing else, feel free to email me at alxjrvs (at) gmail (dot) com. I’ll do what I can to help. If I can’t offer some advice, I can definitely forward you to a local group or friend that will.
Until then, Keep Building.
]]>As a development shop that builds payment technologies as well as applications integrating technology produced by the payments industry, we are always looking to learn more about the state of the payments industry.
From Monday’s discussion, it’s clear that the payments space, especially B2B payments, is ripe for disruption but startups face some very big obstacles. The biggest obstacle being the behavioral evolution of the accounts payable and accounts receivable departments at corporations. There has yet to be a technology that’s 10x better than the current billing/invoice and remittance processes. Until a common standard is adopted by all industries (or even within specific verticals) the ability for mass innovation in the B2B payments space will be slow.
If you’re interested in coming out to a future Terrible Labs event, reach out to us at info@terriblelabs.com.
]]>