<?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[Stories by Peloton Engineering on Medium]]></title>
        <description><![CDATA[Stories by Peloton Engineering on Medium]]></description>
        <link>https://medium.com/@PelotonEngineering?source=rss-4b65c8436f31------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*RuC-d_gcJeqwo-O8NHcTdw.jpeg</url>
            <title>Stories by Peloton Engineering on Medium</title>
            <link>https://medium.com/@PelotonEngineering?source=rss-4b65c8436f31------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 11 May 2026 16:53:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@PelotonEngineering/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Using Real-time Messaging at Peloton]]></title>
            <link>https://medium.com/peloton-engineering/using-real-time-messaging-at-peloton-933e18867867?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/933e18867867</guid>
            <category><![CDATA[pubnub]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[api]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Thu, 13 Dec 2018 15:03:01 GMT</pubDate>
            <atom:updated>2018-12-13T15:03:01.050Z</atom:updated>
            <content:encoded><![CDATA[<p>By <a href="https://medium.com/u/2237ad1304a0">Douglas Crossley</a> and <a href="https://medium.com/u/1b7ccb03379d">Chris Mohr</a></p><p>As our user base at Peloton continues to grow we’ve found some interesting opportunities to connect members to each other. We think that creating more opportunities for shared, real-time workout experiences is an important initiative and something we wanted to invest in. The first large feature based around this goal was something we called Working Out Now, which involved letting members know in real-time that another member they had followed on our platform was currently working out. To support this, we wanted a mechanism that could easily notify members anywhere in the product. We wanted it to be minimally invasive while still providing detailed information when needed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UWMSeo2gOT34td53iTPzIA.png" /><figcaption>Working Out Now Dialog</figcaption></figure><h3>Real-Time Messaging Integration</h3><p>We were already using <a href="https://www.pubnub.com/">PubNub</a> to send real-time updates for our user activity feed, which shows members their friends’ activity. We decided to continue using PubNub for our real-time messaging and simply expand on what we had in place.</p><p>For each member we create a PubNub channel that their device subscribes to upon login. Whenever we need to send a real-time update to that member, we publish a message on that member’s channel. Each message has a type which we use to identify the schema of the payload. This allows us to easily create and consume new messages types.</p><p>On the client side, we encapsulate the ability to connect to PubNub and receive messages in our Messaging Service, which can easily be injected throughout the app for use. This Service exposes a Rx Observable that supports filtering the message stream by type. This gives clients a simple way to only get messages they care about and know how to consume.</p><h3>Know When Your Friends Are Working Out</h3><p>In order to know which of a member’s friends are currently working out, we need to know every time one of those members joins or leaves a workout. We defined two types of messages: “Someone you follow joined a workout” and “Someone you follow left a workout”. Whenever a member joins or leaves a workout, the Peloton API publishes a message to the PubNub channel of each of the member’s followers.</p><p>After defining these message, we hooked up the client to receive them in our bottom navigation component. We decided to build a cache that would update every time we received one of these messages from the server and then request additional information as needed. This worked well while a member was on their Bike or Tread, but we still needed a way to know who was in a workout when the member first started their session.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Z1zX07kNdYX1tRzdPrs5IA.png" /><figcaption>Messaging Data Flow</figcaption></figure><p>We created a new API endpoint that allowed us retrieve all the data for a member’s followers that we could leverage when our cache was stale or needed to be initialized. There was also a risk that the client’s local list of friends who were working out got out of date for a number of reasons. Instead of the client incrementally updating their local list, they request the full list of friends in classes each time they receive a message. Once the client has this information we use it render our Working Out Now dialog that members see when clicking on a notification.</p><h3>Conclusion</h3><p>As we added more types of messages that were used by different parts of the app, it became more important to document the schema of these messages. We use an OpenAPI specification to document the schema of our REST API and applied this same pattern to real-time messages by treating them like endpoints. This allowed for all client teams to easily consume any new messages that were added and understand how they could be used.</p><p>After allowing members to see which classes their friends were in, we built on top of this by allowing them to see their friends while they were in any class, including On Demand classes. We were then able to work with our Leaderboard team to provide an experience that better connected members to friends in class as well. This real-time messaging infrastructure gives us a base to expand upon for new features in the future.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=933e18867867" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/using-real-time-messaging-at-peloton-933e18867867">Using Real-time Messaging at Peloton</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Growing While Remaining Productive]]></title>
            <link>https://medium.com/peloton-engineering/growing-while-remaining-productive-3e260eb9ff99?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/3e260eb9ff99</guid>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Thu, 11 Oct 2018 15:07:31 GMT</pubDate>
            <atom:updated>2018-10-11T15:07:31.570Z</atom:updated>
            <content:encoded><![CDATA[<p>By <a href="https://medium.com/u/acc439286cc0">Rich Luick</a> and <a href="https://medium.com/u/2ea8472dfd9b">Gennadiy Shafranovich</a></p><p><em>We gave this talk at </em><a href="https://docs.google.com/presentation/d/e/2PACX-1vRUwqQovilB12-FCKzNOgJNJCLX-wAOQKuuK9HZ76m67vQFz8fosieTqHJ15iYHATLd387UDTebtOkB/pub?start=false&amp;loop=false&amp;delayms=3000"><em>Droidcon 2018</em></a>.</p><p>The Android team at Peloton has grown a lot recently. Our team has grown to <em>5 times</em><strong><em> </em></strong>the number of engineers it was 18 months ago, and what we have learned during this rapid growth is that teams need to work differently at different sizes. This is evident in both the ideal workflow and communication patterns<em> </em>of teams.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*DOZl-gVtubdb6cOC" /></figure><h3>Small Teams</h3><p>Smaller teams are often concerned with the rapid delivery of new features. They are trying to get new things shipped and are often only focused on one or two features at a time. Communication is easy and direct within the team as well as with other stakeholders such as product or QA.</p><h3>Larger Teams</h3><p>Larger teams may find themselves broken into sub-teams and working in parallel on a diverse set of features, often on different timelines. Communication is no longer direct across the greater team and yet is even more important since sub-teams can develop their own patterns that could end up clashing.</p><h3>So, how do you grow while remaining productive?</h3><p>First, we have to define what we mean by a team being “productive.” For us, this includes engineers being efficient when developing, having features be of a high enough quality to be releasable, and delivering said features to our end users. All of this needs to be done while not overloading any personnel or tooling involved in the process. Being able to make technical and process decisions as a group is part of being able to stay productive as a team.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*00IWQuCXMpwqE7_a" /></figure><h3>Make a space where open discussions are held.</h3><p>At the core of the process for making decisions together is a space where members of a team can have honest and open discussions. It needs to be an <em>inclusive</em> venue where any member of the team can contribute as little or as much as they are comfortable with. Individual seniority doesn’t matter in this venue, except for when it is used to backup a particular line of reasoning with examples and experience. No question or issue is too small to bring up either, including team processes..</p><p>At Peloton, this is a weekly one hour meeting where all Android team members are invited. A document is created after each of these for the next week’s agenda, and anyone can contribute to it throughout the week. The first thing we do in this gathering is review the previous week’s action items in order to keep everyone accountable for tasks that they signed up for. The rest of the meeting is spent in discussing issues on the agenda and making decisions as a group.</p><h3>Your decisions must be actionable.</h3><p>The decisions you arrive at as a team need to apply to all the members of your team. If individuals or groups are excluded, you risk creating tiers within your group. Some decisions can be made in the room with just a short discussion while others will require investigative work or a proof-of-concept project to back up the decision. Assigning this work to volunteers in the group as action items helps move the work forward. Remember, you will review these action items in following meetings and receive progress reports from the assigned volunteers. Once they are done and present their work, you can make a decision to proceed or not as a group.</p><h3>Communicate your decisions…</h3><p>The decisions you make won’t matter much if people are not aware of them. What convinces the rest of your group that the right thing is being done is knowing the “what” and the “why” of each decision. Documenting these improves communication and has the extra benefit of making onboarding of new team members much easier.</p><h3>…and enforce them</h3><p>The trust behind this process is that the decisions you make are enforced by the entire group. It shows your team that if they follow the process and bring up an issue or suggestion, it will be discussed and any outcome will be communicated and enforced.</p><p>Where possible, you should use tooling to do this. It is easier with things like code style since a simple lint rule can cause pull requests to be flagged. Enforcement becomes a bit harder with things like patterns (e.g. MVVM) or usages of specific libraries.</p><p>For decisions that are more difficult to automatically enforce, use code reviews. Your entire team is aware of the rules and should comment on code when these are violated. This is also a great way for new members of the team to learn the “right way” to do things. They are simply pointed to the right pieces of documentation as they go through their code review comments.</p><h3>When things change, iterate.</h3><p>While trust behind the process is enforcement, the real power of it is in iteration. The reality is that your environment will change over time. This can include the makeup of your team, your requirements, the ecosystem you are developing in, or all of the above.</p><p>Use your discussion venue to revisit previous decisions and check if they are still applicable to your current situation. Questioning your past decisions can also lead you to find better ways to solve the problem. A good sign that it is time to revisit a decision is when the original reasoning behind it no longer applies. Basically, if the answer to the question of “why did we do this” is something that may no longer apply, it is time to revisit that decision.</p><p>Iteration also allows you to make a good decision, and not wait to make a perfect one. Any move in your team that improves your current situation is a positive move. It also allows you to question the process itself. If the way you setup your discussion venue is no longer working out, discuss it, and see if the group can come up with a better solution.</p><h3>Example: The `googleJavaFormat` plugin</h3><p>Just like most growing teams, our Android team at Peloton had issues deciding exactly what code style we should follow. As most readers will know, this means religious arguments on the number of spaces to indent a line, where do curly braces go, and most of all what should be your the maximum line length. Just like most teams we used our discussion forum to work through these one by one.</p><p>However, during one of our weekly team meetings a team member suggested we use a <a href="https://github.com/google/google-java-format">highly opinionated</a> formatter instead of trying to decide and enforce every formatting rule. We investigated what this would look like in practice and realized that while no one will be 100% happy with the outcome, the formatter completely removed the ambiguity. There is one way to format your code and that’s it. This completely removed the cognitive overhead that was connected to Java code styling and formatting.</p><h3>Example: Github CODEOWNERS</h3><p>At Peloton our Android team ran into the problem that all growing teams face. One engineer made a minor change and a fellow team member reviewed the change and approved it. This is not an issue of course, this is the regular course of work, but for the reviewer, the change did not include enough context to flag issues that may arise. The story then follows a very predictable course, ending with a bug in production. All of a sudden, a tiny change in the code base causes unexpected behavior somewhere else. The underlying cause has to do with the structure of the code base and the component changed. No component should be able to cause this big of an unexpected change.</p><p>The two engineers involved brought this up in one of our weekly team gatherings and the group proceeded to discuss long term solutions. Something that came out of the conversation was the usual “how can we prevent this for now?” question. Someone on the team had experience with GitHub’s <a href="https://help.github.com/articles/about-codeowners/">CODEOWNERS</a> feature and we decided to immediately add code owner definitions to sensitive parts of the code base. This means that team members with context on specific areas get added to pull requests and get a chance to glance at them to ensure strange side effects don’t happen. We also instituted a rule that if the author and the reviewer do not have full context on a component, and the code owners set up isn’t suggesting a reviewer, it is up to the author to find who to add in order to get a thorough review.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/517/1*mRwJhvcF84R4xBB-a06R2Q.png" /><figcaption><a href="https://creativecommons.org/licenses/by/2.0/">Photo</a> by Eoin Gardiner <a href="https://creativecommons.org/licenses/by/2.0/">CC BY</a> / Desaturated from Original</figcaption></figure><h3>Considerations</h3><p>We’ve had plenty of success using this process, but as we all know nothing is perfect. There will always be some things that require thought and consideration with any process, including this one.</p><p><strong>Continued Growth</strong></p><p>We’ve successfully scaled this process from 5 to roughly 20 engineers and found that it worked well within that range. There is the feeling that as we keep growing, it might be difficult to get everything done in one meeting. The plan here is to start to split up to more concentrated town squares and go from there.</p><p><strong>Minority Opinions</strong></p><p>It is nearly impossible to get a group of engineers to all agree on something. Even if we have a majority opinion we may end up with dissenters who are passionate about their point of view. One of the most important parts of this process is that everyone needs to be heard. All ideas need to be considered and we need to be ready to explain why something is not right for our team. Be sure to document the “why” here as this alleviates the stress of explaining these decisions to new team members.</p><p><strong>Action Items With No Progress</strong></p><p>Not having forward progress on action items can lead to losing trust in the process. Team members need to be held accountable for tasks assigned to them to ensure we maintain momentum. Remember to review these items at the start of each town hall and ask for assignees to provide an explanation for why certain tasks have not been completed.</p><p><strong>Time</strong></p><p>The town halls and all the work that comes out of them take time. It is imperative that the rest of the organization buys into the process and understands that time spent now is better than having to spend even more time later on. Every action item we complete should help diminish how long things take down the road.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*XTvXYCMomKRP87Zn" /></figure><h3>But it’s worth it!</h3><p>This process has allowed us to adapt to a growing team, with changing requirements, in an evolving ecosystem while delivering consistent, high quality work, with a low defect rate. Everyone has a voice and engineers are empowered to push for positive change. Finally, we have a clear process to improve and learn.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3e260eb9ff99" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/growing-while-remaining-productive-3e260eb9ff99">Growing While Remaining Productive</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Talking Strava / How our teams came together for a successful launch]]></title>
            <link>https://medium.com/peloton-engineering/talking-strava-how-our-teams-came-together-for-a-successful-launch-9b3c635dab52?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/9b3c635dab52</guid>
            <category><![CDATA[ux]]></category>
            <category><![CDATA[cycling]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Thu, 25 Feb 2016 19:56:56 GMT</pubDate>
            <atom:updated>2016-02-25T22:48:55.712Z</atom:updated>
            <content:encoded><![CDATA[<p>Talking Strava / How our teams came together for a successful launch</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/565/0*Wj-Cz-bP5iD3iB3s.jpg" /></figure><p>Strava is a new integration we recently launched that brings the best of social networking and the quantified self movement to the Peloton community. Launching the Strava integration was a group effort that required the coordination of three teams: developers, product and design. We took some time to talk to our team to understand the collaborative effort that brought this project to life.</p><p><strong>Why is the new Strava integration such an exciting launch?</strong></p><p><strong>Dave, Product Manager:</strong> The launch of our Strava integration is a step toward holistic fitness tracking for our users. Since Peloton riders are active beyond the bike (they are runners, outdoor cyclists, etc), we are excited to give them a way to track all of their fitness activities in one place.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/565/0*Xa4jUGPyOysfEUY3.jpg" /></figure><p><strong>How are the riders able to use this? What are the specific features?</strong></p><p><strong>Dave:</strong> Peloton riders can now use Strava to track and measure their progress and ride results. This creates a fun new way to see and share the history of your workouts, further enhancing the Peloton riding experience.</p><p>A really cool feature that was actually Ben’s idea was the ability to auto-post any future rides to Strava. So, rather than having to worry about sharing to Strava at the end of your ride, there’s a setting that you can activate that will automatically share your ride to Strava.</p><p><strong>How will this impact Peloton riders?</strong></p><p><strong>Dave:</strong> I think for existing Strava users they’re going to be really excited to have this data be in sync with their fitness activities. For users who don’t know what Strava is, this is going to really turn them onto a really exciting fitness platform. This is just another reason to get out there and be active!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/565/0*Pl6PEdx3cskr96_m.jpg" /></figure><p><strong>What was the interaction like between each team for this feature to come alive?</strong></p><p><strong>Swarna, Software Engineer:</strong> The communication between the product, dev and design is crucial in all projects. The communication is very effective when product and design understand the technical challenges involved and then dev understands the actual rationale behind the requirement.</p><p>​The coordination between design, product and Android was clear and that helped us to create smooth animations during the Strava upload. ​For example, a 45 minute Peloton ride takes approximately nine seconds to upload. It would be a bad experience for t​he ​user if ​Android’s default ​infinite loading bar ran during the upload.</p><p>​Eric, our multimedia creative director, came up with a loading progress bar that provides the status for the upload. This was challenging due to Android’s limitations. Android only knows if the upload is completed successfully or not. By setting up a max time limit and by animating the progress status, we were able to overcome this obstacle and create a pleasing user experience.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/565/0*Kz3Z09efg8w-yF8y.jpg" /></figure><p><strong>What was the most exciting part about this project from your personal perspective?</strong></p><p><strong>Dave:</strong> For me, it was taking my first ride that I could share to Strava. Doing pre-launch testing and being able to see what it looked like and having people like it on Strava. That was cool and exciting.This is Strava’s first experience in the indoor cycling market so having them be just as pumped up about this project was a huge bonus.</p><p><strong>Ben, Software Engineer Manager:</strong> The most exciting part about this is that I’ve never used Strava before. Dave got me into Strava and it’s something that I’ll be able to use myself, so that’s pretty awesome!</p><p><strong>Want to learn more on our Strava launch? </strong><a href="http://cadence.pelotoncycle.com/syncing-peloton-rides-to-your-strava-feed/808/"><strong>Click here.</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9b3c635dab52" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/talking-strava-how-our-teams-came-together-for-a-successful-launch-9b3c635dab52">Talking Strava / How our teams came together for a successful launch</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tech Stories / Cezar Cocu]]></title>
            <link>https://medium.com/peloton-engineering/tech-stories-cezar-cocu-f5663b2803b1?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/f5663b2803b1</guid>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[design]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Tue, 19 Jan 2016 21:35:05 GMT</pubDate>
            <atom:updated>2016-01-19T21:35:05.447Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ae6khZnIuTwrherCHFmcpw.jpeg" /></figure><p>We see so much of Peloton’s action on the bike and in the studio but what is at the core of our operations is our amazing tech team making it all happen. We got to talk more with one of our software engineers, Cezar Cocu, to learn more about his role and experience in the Peloton tech space.</p><ol><li><strong>What is your role at Peloton? What does your job entail?</strong></li></ol><p>I mostly maintain the iOS app on both the retail side and on the consumer side. That’s how we refer to it internally. We have a consumer app used for viewing live streaming and on-demand rides, and then we have an internal app for POS (point-of-service) transactions like buying the bike and apparel items, which our retail stores use.</p><p><strong>2. How did you get into this field?</strong></p><p>I’ve always enjoyed computer science in school. I enjoyed making stuff with computers. When it comes to iOS, I think I just fell into it. I wanted to do something cool, and probably the easiest way to get started is either to create something on the web or create something on a mobile native interface, like Android or iOS. I happen to have an iPhone, so I was like, “I’m going to start doing the iPhone.” That was really it. I had an iPhone, and I wanted to do something on mobile natively.</p><p><strong>3. What attracted you to working at Peloton?</strong></p><p>After college I joined an agency. I did that for a little bit, working on different projects, like three months here, three months there. I thought I would enjoy that, and I really didn’t. I wanted to work at least on one project for a longer duration of time. Some people really enjoy jumping from project to project to project. I didn’t particularly enjoy it. When it comes to software, if you jump from project to project to project, sometimes you don’t have to deal with the consequences of your decisions. When you work on something more long term, you deal with that constantly. You’re always making trade offs. “Let me fix this. Let me do this. Let me put in the time to get that.”</p><p><strong>4. How is Peloton different than any other tech company?</strong></p><p>We own the entire stack. From creating the content all the way to the bike itself. It’s incredibly motivating as an engineer to be seen as value creator instead of a cost center. Because we’re still small, the way everything works is just based on trust. Our Project Managers trust that you’re going to get it done however you’re going to get it done, so you don’t have to deal with politics, which I appreciate because it’s more natural. It’s a natural way to do things. It’s not about what I appear to be doing, it’s what I pump out on the other end. My work is about the results. Teamwork is huge as well. There has to be that trust there where you have to make sure that it can be possible or it can’t be possible. It’s a little bit more high-stakes. There’s less of a fail-safe system, which is cool. I like that. Working at a startup is more about learning and growing as a developer than it is for pumping out stuff. You have to go at a faster pace and you get to learn more because you’re handling so many things.</p><p><strong>5. What was your first project?</strong></p><p>The iPad app. We made it cooler. We added more rides and improved the customer experience, resulting in a near 5-star app.</p><p>6.<strong> Why are you excited about the iPhone app launch?</strong></p><p>The amount of devices and people who own and use an iPhone is much greater than the iPad. The iPhone is a more personal device. We’re able to reach a broader audience. The users are engaged and we get tons of feedback. It’s a better experience!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*U1lkKg7xLQEIF-pz.jpg" /></figure><p><strong>7. How important is the TECH aspect of Peloton to the company as a whole?</strong></p><p>Very important. That’s one of the reasons why I picked this company. A lot of other fitness companies the tech aspect doesn’t really enable them produce the bulk of their product. Obviously, for us we manage the tech side, hardware, and produce the content all in-house.</p><p><strong>8. What are you most looking forward to building/making next year at Peloton?</strong></p><p>We can’t talk about a lot of the things we have planned. However, we are looking forward to adding more exciting features to iOS and bringing Peloton content to an even greater audience.</p><p><strong>9. What sort of personal software or hardware project do you work on outside of Peloton?</strong></p><p>I made a Metro-North train schedule app plus some other open source components.</p><p><strong>10. Finally, what 3 words would you use to describe the work you do at Peloton?</strong></p><p>Fun, challenging and collaborative.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f5663b2803b1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/tech-stories-cezar-cocu-f5663b2803b1">Tech Stories / Cezar Cocu</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using HTML5 Canvas to Post Directly to Facebook]]></title>
            <link>https://medium.com/peloton-engineering/using-html5-canvas-to-post-directly-to-facebook-4f3c729cc04b?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/4f3c729cc04b</guid>
            <category><![CDATA[angularjs]]></category>
            <category><![CDATA[peloton-cycling-hq]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Wed, 07 Oct 2015 18:36:40 GMT</pubDate>
            <atom:updated>2015-10-07T18:36:40.035Z</atom:updated>
            <content:encoded><![CDATA[<p>Using HTML5 Canvas to Post Directly to Facebook</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/831/1*hfbyRYgFNWmNPE-cO1vY9A.png" /><figcaption>Facebook Share Modal on Peloton.com</figcaption></figure><p><strong>From Static to Rich : The Obstacles</strong></p><p>Within Peloton’s webapp, we provide our users the ability to see their performance for each class they take. Included within this report is a chart that maps their cadence, power, distance, calories burned, and heart beat. Users can opt to “Share” this report to Facebook, but doing so simply provides a link back to our webapp, with no visual representation of the workout, just a static brand image that we feared was becoming redundant.</p><p>While brainstorming ways to extend our features abilities, we proposed a system that allowed the user to share a “snapshot” of this graph — the only problem was, the graph wasn’t an image, but a living-breathing SVG based data representation that had no home on a server. Thus, no URL to access with an image MIME type.</p><p>As far as Facebook’s JavaScript SDK documentation goes, the only mention of sharing images to a user’s feed assumes the passing of a URL where said image resides. Facebook will then transload the image, run their own compression processes, and publish it accordingly. As such, the initial proposal for our post-graph-to-Facebook process included creating our own PNG snapshot and uploading it to S3, then returning that newly-created image URL to Facebook. That sounded perfectly fine, but we knew there had to be a better, faster way.</p><p><strong>Leveraging Technologies : Canvas to the Rescue</strong></p><p>“[The HTML5 canvas element] is part of HTML5 and allows for dynamic, scriptable rendering of 2D shapes and bitmap images. It is a low level, procedural model that updates a bitmap and does not have a built-in scene graph.” This element has many uses including: web game development, graph and chart rendering, and interactive applications, to name a few.</p><p>Though our performance graphs are SVG-based (vector) and not drawn in canvas, we knew we could load SVG’s onto canvas or use a similar process to extract our Base64 encoded image data. The first step was getting that Base64 encoded data from our canvas element:</p><pre>var canvas = document.getElementById(‘canvas’);<br>var dataURI = canvas.toDataUrl();</pre><p>Then, we needed to find what we cared about:</p><pre>var imgdata = dataUrl.match(/data:(image\/.+);base64,(.+)/);</pre><p>From there, we converted the data to a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>: “A Blob object represents a file-like object of immutable, raw data. Blobs represent data that isn’t necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user’s system.”</p><pre><em>function dataURItoBlob(dataURI, mime) {<br>  var byteString = window.atob(dataURI);<br>  var ia = new Uint8Array(byteString.length);</em></pre><pre><em>  for (var i = 0; i &lt; byteString.length; i++) {<br>  ia[i] = byteString.charCodeAt(i);<br>  }</em></pre><pre><em> var blob = new Blob([ia], { type: mime });<br> return blob;<br>}</em></pre><pre>var blob = dataURItoBlob(imgdata[2], imgdata[1]);</pre><p>Once our data was represented as a Blob, the last step was to use the the <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects">FormData object</a> which we could send to Facebook in our POST:</p><pre>var fd = new FormData();<br>fd.append(‘access_token’, $scope.facebook.authToken);<br>fd.append(‘source’, blob);<br>fd.append(‘message’, $scope.canvas.background.getCaption());</pre><p>Above, you might notice Angular $scope variables as we used <a href="https://angularjs.org/">AngularJS</a> for this application. Below, is the final piece that uses Angular’s $http to POST and pull the thread through:</p><pre>$http.post(‘https://graph.facebook.com/me/photos?access_token=&#39; + $scope.facebook.authToken, fd, {<br> transformRequest: angular.identity,<br>headers: {<br>‘Content-Type’: undefined<br>   }<br>})<br>.success(function (res) { // Success logic })<br>.error(function (res) { // Error logic });</pre><p><strong>The Prototype : Precursor to Implementation</strong></p><p>As with any new feature, we thought it best to test the waters and see how this approach would work in the wild, without a complete rewrite our our existing implementation. It just so happened with Valentine’s Day around the corner, our social and marketing teams were dreaming up ways to engage our users on social media. The idea was to create an interactive Valentine’s Day app that allowed the user to customize a Peloton-themed candy heart, as well as tag their friends, and share their own message.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4f3c729cc04b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/using-html5-canvas-to-post-directly-to-facebook-4f3c729cc04b">Using HTML5 Canvas to Post Directly to Facebook</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SQL NYC Meeting @ Peloton HQ]]></title>
            <link>https://medium.com/@PelotonEngineering/sql-nyc-meeting-peloton-hq-8c0a896a38d5?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/8c0a896a38d5</guid>
            <category><![CDATA[sql-nyc]]></category>
            <category><![CDATA[meetup]]></category>
            <category><![CDATA[peloton-cycling-hq]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Thu, 24 Sep 2015 19:21:49 GMT</pubDate>
            <atom:updated>2015-09-24T19:23:13.312Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*aHlaQoFxTvfydxu9Z7p9vg.jpeg" /><figcaption>Free beer and pizza @ Peloton HQ!</figcaption></figure><p>Today, <a href="http://www.meetup.com/mysqlnyc/events/225122166/">SQL NYC </a>will be hosting a meet-up event in our office from <strong>6:30–8:30pm</strong>.</p><p>This evening’s topic is about “Database Architecture &amp; Scaling Strategies, in the Cloud &amp; on the Rack”. Pizza and beer will be provided (as always), so please feel free to grab a slice and listen in!</p><p>For more information, please RSVP <a href="http://www.meetup.com/mysqlnyc/events/225122166/">here</a>. Hope to see you there!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8c0a896a38d5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Happy Leap Second Day!]]></title>
            <link>https://medium.com/peloton-engineering/happy-leap-second-day-19775b663126?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/19775b663126</guid>
            <category><![CDATA[akamai]]></category>
            <category><![CDATA[leap-second]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Tue, 30 Jun 2015 20:45:10 GMT</pubDate>
            <atom:updated>2015-06-30T20:45:10.546Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K9xI0OSLmFA0jRz0vneQ3A.jpeg" /></figure><p>Time synchronization is a hard problem to solve. Layer on various ways to handle leap second, issues might be even more obscure. <a href="https://twitter.com/awscloud?nc1=f_so_tw">AWS</a> and <a href="https://twitter.com/Akamai">Akamai</a> both use a technique called <a href="http://googleblog.blogspot.com/2011/09/time-technology-and-leaping-seconds.html">time smear</a>. Make sure all your services agree on how to handle that extra second!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=19775b663126" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/happy-leap-second-day-19775b663126">Happy Leap Second Day!</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Communication within Angular]]></title>
            <link>https://medium.com/peloton-engineering/communication-within-angular-d8eaaa7fd5b?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/d8eaaa7fd5b</guid>
            <category><![CDATA[code]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Wed, 17 Jun 2015 19:19:23 GMT</pubDate>
            <atom:updated>2015-06-17T19:19:23.479Z</atom:updated>
            <content:encoded><![CDATA[<p>When scaling an angular application, it can get very confusing as to how you send messages around between controllers, services, directives, etc. We’ve compiled a few guidelines that we use in order to keep our code clean as it scales.</p><h4>$scope Broadcasts</h4><p>To be perfectly honest, these are messy. We avoid broadcasting through $scope like the plague. We believe that the point of these events are for very high level angular operations to broadcast their events as an API. Take the ‘$destroy’ event for example, it is provided as a piece of an API so that the developer has a convenient hook to destroy their directive in the appropriate fashion. So then how do we broadcast information across our angular application? Our solution involves rolling our own isolated PubSub mixing throughout our angular services.</p><h4>Service Broadcasts</h4><p>Services/Factories/Providers do not come built with any method of broadcasting information. Our first attempt to solve this was to namespace $rootScope broadcasts and send information around that way. While this was the easier solution, we quickly abandoned this approach because we preferred a more explicit way of communicating from services. The solution then became to roll our own PubSub into our service layer via a mixin. The basic PubSub mixin looks like this:</p><pre>angular.module(‘app’)<br>  .factory(‘PubSub’, [‘$rootScope’, function($rootScope) {</pre><pre>    function PubSub() {</pre><pre>      this.observers = {};</pre><pre>    }</pre><pre>    PubSub.prototype.on = function(name, fn) {</pre><pre>      this.observers[name] = this.observers[name] || {};</pre><pre>      var key = Object.keys(this.observers[name]).length + &#39;&#39;;</pre><pre>      this.observers[name][key] = fn;</pre><pre>      return key;</pre><pre>    };</pre><pre>    PubSub.prototype.off = function(name, id) {</pre><pre>      if (this.observers[name] &amp;&amp; this.observers[name][id]) {</pre><pre>        delete this.observers[name][id];</pre><pre>      }</pre><pre>    };</pre><pre>    PubSub.prototype.broadcast = function(name, event) {</pre><pre>      if (!this.observers[name]) {<br>      <br>        return;<br>      <br>      }</pre><pre>      var observers = this.observers[name];</pre><pre>      Object.keys(this.observers[name]).forEach(function(key) {</pre><pre>        if (!observers[key]) {<br>          return;<br>        }</pre><pre>        observers[key](event);</pre><pre>      });</pre><pre>      if (!$rootScope.$$phase) {</pre><pre>        $rootScope.$apply();<br>      <br>      }</pre><pre>    };</pre><pre>    return PubSub;</pre><pre>}]);</pre><p>To extend this, we include it when we create our service like so:</p><pre>angular.module(‘app’)<br>  .factory(‘SomeService’, [‘PubSub’, function(PubSub) {</pre><pre>    // constructor, implemented like you would an angular service<br>    var SomeService = function() {</pre><pre>      PubSub.call(this);</pre><pre>    }<br>    <br>    angular.extend(SomeService.prototype, PubSub.prototype);</pre><pre>    return new SomeService();</pre><pre>}]);</pre><p>This then allows us to listen to the broadcast in other locations that would import this.</p><pre>angular.module(‘app’)<br>  .controller(‘SomeController’, [‘$scope’, ‘SomeService’,   <br>    function($scope, SomeService) {</pre><pre>    var listener = SomeService.on(‘update’, function(data) {</pre><pre>      $scope.data = data;</pre><pre>    });</pre><pre>    $scope.$on(‘$destroy’, function() {</pre><pre>      SomeService.off(listener);</pre><pre>    });</pre><pre>}]);</pre><p>The above approach works very well if you like a more explicit way of listening to services. The approach however does not work very well when listening to controllers.</p><h4>Directive Controllers</h4><p>The approach we take to listening to controllers came about when we figured out why we would listen to controllers. We wanted to listen to controllers specifically when communicating between directives. It was then that we realized that angular already had this functionality built in. They have done a good job of documenting this implementation <a href="https://docs.angularjs.org/guide/directive#creating-directives-that-communicate">here.</a></p><p>The <a href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/#mediatorpatternjavascript">concept</a> is that instead of using $broadcast/$emit, you would rely on your controller to update your dependent directives in the fashion of the mediator pattern.</p><p>Using these three types of communication in conjunction with angular’s built-in two-directional bindings should decouple and clean up most cases where you would otherwise have messy events and watches flying around in all directions. For a higher level view of keeping your applications scalable, I suggest reading through <a href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/">this link</a> in order to inform yourself of the many ways to design pieces of your application.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d8eaaa7fd5b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/communication-within-angular-d8eaaa7fd5b">Communication within Angular</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[EVENT RECAP: The Future of Cloud Computing and Databases]]></title>
            <link>https://medium.com/peloton-engineering/event-recap-the-future-of-cloud-computing-and-databases-6e7f57bd3753?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/6e7f57bd3753</guid>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Thu, 11 Jun 2015 21:56:32 GMT</pubDate>
            <atom:updated>2015-06-15T20:01:25.679Z</atom:updated>
            <content:encoded><![CDATA[<p>This past Monday we hosted <a href="http://www.DatabaseMonth.com/database/cloud-databases">A Database Month event</a> with a talk from <a href="https://www.clusterpoint.com/about">Zigmars Rasscevskis</a>, Chief Executive Officer, <a href="https://www.clusterpoint.com/">Clusterpoint</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*ebIbxVxdEf6K_90Fzt_yCQ.jpeg" /><figcaption>Image Source: Meetup.com</figcaption></figure><p>The talk touched upon a lot of things, such as: learning how distributed databases can serve as a solid foundation for massively-parallel and instantly-scaleable distributed computing, leveraging NoSQL technologies, and its community, as it contributes to the architecture of a ‘future computer,’ and practical matters of large-scale distributed system design.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*puY1j1sWbcurGT9NY-5Q-A.jpeg" /><figcaption>Image Source: Meetup.com</figcaption></figure><p>There were nearly 250 people in attendance, and we were happy to make some new friends! Check out more photos from the event <a href="http://www.meetup.com/mysqlnyc/photos/26198258/438708990/#438708877">here</a>. We will update this post once the live-stream recording is available.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6e7f57bd3753" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/event-recap-the-future-of-cloud-computing-and-databases-6e7f57bd3753">EVENT RECAP: The Future of Cloud Computing and Databases</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Future of Cloud Computing and Databases NoSQL Meetup]]></title>
            <link>https://medium.com/peloton-engineering/the-future-of-cloud-computing-and-databases-nosql-meetup-66b259246d3a?source=rss-4b65c8436f31------2</link>
            <guid isPermaLink="false">https://medium.com/p/66b259246d3a</guid>
            <dc:creator><![CDATA[Peloton Engineering]]></dc:creator>
            <pubDate>Fri, 05 Jun 2015 02:00:10 GMT</pubDate>
            <atom:updated>2015-06-05T02:00:10.669Z</atom:updated>
            <content:encoded><![CDATA[<p>On Monday, June 8, 2015, we will be hosting <a href="http://www.DatabaseMonth.com/database/cloud-databases">A Database Month event</a> with a talk from <a href="https://www.clusterpoint.com/about">Zigmars Rasscevskis</a>, Chief Executive Officer, <a href="https://www.clusterpoint.com/">Clusterpoint</a>. There will be pizza, refreshments, t-shirts &amp; swag, and a chance to win an Oculus Dev Kit.</p><p>You can read all about the event in detail on <a href="http://www.meetup.com/mysqlnyc/events/222130858/">Meetup.com</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66b259246d3a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/peloton-engineering/the-future-of-cloud-computing-and-databases-nosql-meetup-66b259246d3a">The Future of Cloud Computing and Databases NoSQL Meetup</a> was originally published in <a href="https://medium.com/peloton-engineering">Peloton-Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>