s Fluid Dog Illustrations by Marina Okhromenko By icanbecreative.com Published On :: Sun, 15 Mar 2020 21:27:25 PDT Fluid design of swirling dogs are captured by Moscow-based illustrator Marina Okhromenko in her colorful digital illustrations, she depicts expressions of joy that makes us adore more our canine... Full Article Design Inspiration
s Profession Of The Future: Why Is Programmer Education Still Relevant? By icanbecreative.com Published On :: Mon, 16 Mar 2020 08:07:37 PDT In 2020, there is no doubt that people and technology will be very close friends in the future. The modern inhabitant of our planet spends about 45% of his time connecting with technology. We are... Full Article Learning
s The Best Way To Improve Your Business Skills By icanbecreative.com Published On :: Mon, 16 Mar 2020 08:40:10 PDT Are you thinking about running a business after getting a degree? This article will help you find the best ways to make your business skills more efficient and useful. The Best Way To Improve Your... Full Article Business
s How A Web Design Business Can Benefit From Using Accounting Applications By icanbecreative.com Published On :: Wed, 18 Mar 2020 14:58:32 PDT Accounting applications help web design businesses in many ways. As a web design service provider, you should use them to boost your business. Start by browsing some resources online that provide... Full Article Business
s Which Graphics Editor To Choose For The Novice By icanbecreative.com Published On :: Thu, 19 Mar 2020 09:59:19 PDT Photos and other images are used in different fields, so those who know how to work with high-resolution mockups are in demand as professionals. It is useful to be able to take photos, draw, edit... Full Article Learning
s 5 Ways To Make Working From Home Easier By icanbecreative.com Published On :: Tue, 24 Mar 2020 13:44:03 PDT Working from home might sound like a fun and relaxing way to do your job, but many people who switch to working from home find it surprisingly difficult. In addition to finding the right tools, you... Full Article Learning
s Why Use A Digital Marketing Agency? By icanbecreative.com Published On :: Wed, 25 Mar 2020 18:38:23 PDT Outsourcing your marketing when you're running a small or medium sized business is often seen as an expensive option, one that can be done yourself. It might even be seen as something that's... Full Article Marketing
s What Are The Essential Tools For Painting? By icanbecreative.com Published On :: Thu, 26 Mar 2020 12:41:10 PDT Painting a room can be a scary venture. Once you have got chosen on the unused color for the room, you’re prepared to begin. Maler has prepared a list of necessary equipment you may need during... Full Article Learning
s Top 5 Best Internet Live Support Extension To Increase Customers Interactions By icanbecreative.com Published On :: Fri, 27 Mar 2020 03:19:08 PDT Creative interactions call for creative measures - numerous extensions reduce, minimize or dilute the frustration of the customers and resolve issues quickly without the customer support team need.... Full Article Learning
s Which Programming Language Should Mobile Developers Choose? By icanbecreative.com Published On :: Fri, 27 Mar 2020 08:11:50 PDT When building new apps, the most important thing developers must decide is which language to program in. There are several languages out there, and some are preferred for certain operating... Full Article Learning
s How To Restore Hard Drive From A Time Machine + Other Ways By icanbecreative.com Published On :: Sun, 29 Mar 2020 06:25:37 PDT Have you chosen Mac for its reliable system? They really have a lot of advantages and are of the best quality. Mac users don’t face serious problems with hard drives often. But the reality is such... Full Article Learning
s 5 Tips That You Absolutely Must Know To Design A Unique Metal Business Card By icanbecreative.com Published On :: Sat, 04 Apr 2020 04:15:51 PDT Every day thousands of business cards exchange hands, and these business cards often get lost in mounds of other cards. Often, clients are unable to reach you just because they couldn't find your... Full Article Design Roud-up
s How Can SEO Help Market Your Designing Agency? By icanbecreative.com Published On :: Sun, 12 Apr 2020 17:28:24 PDT It's unusual, as indeed Google says that in case you've got to enlist an SEO strategy, you ought to do so early instead of late, like when you're appropriate arranging to launch a new site. Because... Full Article SEO
s 6 Ways To Step Up Your Instagram Stories Game By icanbecreative.com Published On :: Wed, 15 Apr 2020 16:45:29 PDT Instagram Stories are an integral part of the platform. Though Instagram copied Snapchat’s concept a few years ago, over 500 million accounts use the Stories feature on a daily basis. Some users... Full Article Learning
s Why Choosing The Best Web Hosting Is Crucial For Your Business By icanbecreative.com Published On :: Wed, 15 Apr 2020 17:49:11 PDT Not many business owners think about hosting when building a new website for their business. But failing to choose the right web hosting can have a great impact on your website and, of course, your... Full Article Learning
s 5 Tips For Doing A Fantastic Graphic Project By icanbecreative.com Published On :: Fri, 17 Apr 2020 17:00:24 PDT You’ve probably had the experience of browsing other people’s graphic projects and wishing you could achieve such effects too. In order to accomplish that, you should expand your knowledge by... Full Article Learning
s Online Logo Design Makers Will See Huge Growth In 2020 By icanbecreative.com Published On :: Fri, 17 Apr 2020 17:27:47 PDT At no other time in the history of the internet has it been easier to design your own logo than it is right now. You could say that the world of online logo design makers is in a perfect position to... Full Article Learning
s How To Create A Trustworthy Brand By icanbecreative.com Published On :: Sat, 25 Apr 2020 23:04:44 PDT The variables that determine business success are continually evolving. More than ever, customers want to be able to trust businesses with which they are transacting business. This involves building... Full Article Business
s Advanced Photography Tips And Hints By icanbecreative.com Published On :: Sat, 25 Apr 2020 23:54:17 PDT It is in every case critical to pay special mind to any computerized photography insights and tips. A few people can truly take awesome photos without truly trying, yet most of us need whatever... Full Article Learning
s Creative Marketing Strategies For Law Firms To Engage With Potential Clients By icanbecreative.com Published On :: Sun, 26 Apr 2020 15:20:57 PDT The success of any organization strongly depends on the marketing strategies they use to reach their potential customers. Law firms are no exception since they also operate in a competitive field... Full Article Marketing
s Disney Princesses Comic Book Style By icanbecreative.com Published On :: Sun, 26 Apr 2020 15:56:22 PDT What happens when you mash-up Disney princesses with Marvel Super Heros, artist cartooncookie did an excellent job creating this mix: Marvel x Disney Princesses: a celebration of the X-Men joining... Full Article Design Roud-up
s Where To Find Some Papers For Sale By icanbecreative.com Published On :: Wed, 06 May 2020 07:01:33 PDT If you look for a place to find academic papers for sale, you should know that there are lots of writing services on the Internet. But your task is to find a reliable online resource that would offer... Full Article Review
s Surrender By feedproxy.google.com Published On :: Monday, February 19, 2018 - 2:51pm To be a caregiver at home for someone who is severely injured is to surrender. You surrender your time, put your ambitions on hold, and surrender many of the simple pleasures. You also surrender your peace of mind, your good night’s sleep, and routine. But there are ways to make life a little easier and more enjoyable... Full Article
s What Stephen Hawking Taught Us About Living with Disability By feedproxy.google.com Published On :: Monday, March 19, 2018 - 9:16am Stephen Hawking, a world-renowned scientist who recently passed away, had a brilliant mind that was trapped inside a paralyzed body, and I could not stop thinking about how the opposite is often the case with traumatic brain injury. Full Article
s Is Caregiving a Burden? By feedproxy.google.com Published On :: Monday, March 26, 2018 - 10:10am The truth is, all family members are both a source of joy and a burden at one time or another. That’s what family life is: the art of weaving webs of joy between strands of pain is what creates the intricate fabric of family love. It’s not the people in our care who burden us; it’s our anger over circumstances... Full Article
s Pity and Friendship after TBI By feedproxy.google.com Published On :: Monday, April 23, 2018 - 3:47pm We’ve all see that face. The well-meaning face of pity: the downturned brows and lips, the misty eyes. After Hugh’s TBI, I seldom met a friend or acquaintance who did not flash this expression at me every time we met. My daughters felt it, too. The funny thing is, we did not want pity. We’d had our fill of it in the ICU. Full Article
s Loosening the Caregiver's Grip By feedproxy.google.com Published On :: Monday, June 11, 2018 - 12:47pm It happens slowly, like that metaphorical frog you’ve heard about. Possessiveness and controlling behavior in TBI caregivers is something that creeps up on you, and I suspect it is common — not because people are trying to be annoying, but because they care so much and want to see that their loved one is treated well in every respect. Full Article
s Never Stop Asking 'What If?' By feedproxy.google.com Published On :: Monday, July 16, 2018 - 6:26am We imagine the what-ifs as a worst case scenario, our worst nightmare happening to us, our life falling apart. But here’s another way of looking at it. Full Article
s To Love What Is: A Marriage Transformed By feedproxy.google.com Published On :: Monday, August 20, 2018 - 2:46pm I wish I had found Alix Kates Shulman’s memoir "To Love What Is: A Marriage Transformed" in the first month of my husband’s severe TBI, and yet I may not have absorbed it the way I did reading it fifteen years post-injury. Full Article
s The Unspoken Shame of Anger in Caregiving By feedproxy.google.com Published On :: Monday, December 17, 2018 - 9:10am I didn’t even know who or what I was angry at. Fate? Bad luck? The person who hit my husband with her car? Full Article
s Book Review: Love You Hard by Abby Maslin By feedproxy.google.com Published On :: Monday, January 21, 2019 - 8:33am This book packs a lot of wisdom. You’ll learn about aphasia; you’ll understand ambiguous loss; you’ll follow Abby down dark hallways and into sunlit rooms and learn what it means to own a life built on raw truth. Full Article
s Dear friends... By feedproxy.google.com Published On :: Monday, April 22, 2019 - 9:56am Hope—love—tenacity—go for it—get mad, let yourself be sad—but don’t let the madness or sadness swallow you. These were repeated themes, said in a thousand ways for a thousand reasons. These are the messages we need to hear again and again. Full Article
s Neural network generates convincing songs by famous singers By flowingdata.com Published On :: Thu, 30 Apr 2020 19:25:39 +0000 Jukebox from OpenAI is a generative model that makes music in the same…Tags: Jukebox, music, neural network, OpenAI Full Article Statistics Jukebox music neural network OpenAI
s Looking for generational gaps in music By flowingdata.com Published On :: Fri, 01 May 2020 11:36:23 +0000 Inspired by the genre of YouTube videos where younger people listen to older…Tags: generations, music, Pudding Full Article Statistics generations music Pudding
s Playable simulations to decide what happens next By flowingdata.com Published On :: Mon, 04 May 2020 07:21:03 +0000 The timelines keep shifting and people are getting antsy for many valid (and…Tags: coronavirus, Marcel Salathé, Nicky Case, simulation Full Article Infographics coronavirus Marcel Salathé Nicky Case simulation
s Comparing Covid-19 models By flowingdata.com Published On :: Tue, 05 May 2020 07:44:30 +0000 FiveThirtyEight compared six Covid-19 models for a sense of where we might be…Tags: coronavirus, FiveThirtyEight, modeling Full Article Statistics coronavirus FiveThirtyEight modeling
s Coronavirus testing accuracy By flowingdata.com Published On :: Tue, 05 May 2020 12:45:44 +0000 Medical tests do not always provide certain results. Quartz illustrated this with the…Tags: coronavirus, Quartz, testing, uncertainity Full Article Infographics coronavirus Quartz testing uncertainity
s Possible vaccine timelines By flowingdata.com Published On :: Wed, 06 May 2020 08:40:38 +0000 It’d be great if we could conjure a vaccine or a “cure” seemingly…Tags: coronavirus, New York Times, Stuart A. Thompson, vaccine Full Article Infographics coronavirus New York Times Stuart A. Thompson vaccine
s Remix and make music with audio from the Library of Congress By flowingdata.com Published On :: Wed, 06 May 2020 19:13:15 +0000 Brian Foo is the current Innovator-in-Residence at the Library of Congress. His latest…Tags: Brian Foo, Library of Congress, music Full Article Apps Brian Foo Library of Congress music
s Who should receive care first, an ethical dilemma By flowingdata.com Published On :: Thu, 07 May 2020 07:04:43 +0000 At greater disparities between low resources and high volumes of sick people, doctors…Tags: coronavirus, Feilding Cage, healthcare, policy, Reuters Full Article Infographics coronavirus Feilding Cage healthcare policy Reuters
s ✚ Tornado Lines – Useful or Not? (The Process 088) By flowingdata.com Published On :: Thu, 07 May 2020 17:30:48 +0000 It looks like a tornado. It's messy. It's circular. It almost looks intentionally confusing. But how bad is it really?Tags: novelty, tornado Full Article The Process novelty tornado
s Famous Hope Quotes as Charts By flowingdata.com Published On :: Fri, 08 May 2020 07:18:08 +0000 I thought we (i.e. me) could use a break, so I made these abstract charts to represent the most popular quotes about hope.Tags: hope, quote Full Article Chart Everything hope quote
s How to Foster Real-Time Client Engagement During Moderated Research By feedproxy.google.com Published On :: Mon, 17 Feb 2020 08:00:00 -0500 When we conduct moderated research, like user interviews or usability tests, for our clients, we encourage them to observe as many sessions as possible. We find when clients see us interview their users, and get real-time responses, they’re able to learn about the needs of their users in real-time and be more active participants in the process. One way we help clients feel engaged with the process during remote sessions is to establish a real-time communication backchannel that empowers clients to flag responses they’d like to dig into further and to share their ideas for follow-up questions. There are several benefits to establishing a communication backchannel for moderated sessions:Everyone on the team, including both internal and client team members, can be actively involved throughout the data collection process rather than waiting to passively consume findings.Team members can identify follow-up questions in real-time which allows the moderator to incorporate those questions during the current session, rather than just considering them for future sessions.Subject matter experts can identify more detailed and specific follow-up questions that the moderator may not think to ask.Even though the whole team is engaged, a single moderator still maintains control over the conversation which creates a consistent experience for the participant.If you’re interested in creating your own backchannel, here are some tips to make the process work smoothly:Use the chat tool that is already being used on the project. In most cases, we use a joint Slack workspace for the session backchannel but we’ve also used Microsoft Teams.Create a dedicated channel like #moderated-sessions. Conversation in this channel should be limited to backchannel discussions during sessions. This keeps the communication consolidated and makes it easier for the moderator to stay focused during the session.Keep communication limited. Channel participants should ask basic questions that are easy to consume quickly. Supplemental commentary and analysis should not take place in the dedicated channel.Use emoji responses. The moderator can add a quick thumbs up to indicate that they’ve seen a question.Introducing backchannels for communication during remote moderated sessions has been a beneficial change to our research process. It not only provides an easy way for clients to stay engaged during the data collection process but also increases the moderator’s ability to focus on the most important topics and to ask the most useful follow-up questions. Full Article Process Research
s TTT in SPAAACE By feedproxy.google.com Published On :: Mon, 24 Feb 2020 09:33:00 -0500 By now, you’ve probably heard of TTT, our quarterly team events. If you haven’t, you should read all about their history. TTT, or Third Third Thursday, is a time for us to look back and look ahead. Twice a year, all four offices come together for an all-hands, conference-style experience. The other two TTTs are celebrated locally and casually. Each office meets for a round-table discussion followed by a fun activity out of the office. In these meetings, we discuss team and industry changes and review business health metrics. Additionally, at each TTT, both our President, Andy Rankin, and CEO Brian Williams, directly field questions from any member of our team. At our TTTs we’ve talked about team diversity and tech ethics, celebrated our victories, and worked through our failures. The conversations have sparked new understanding, new initiatives, new processes, and have truly shaped the company over time. We come together in the spirit of “progress, not perfection.” While each office is unique, and the conversation is tailored to and shaped by each audience, the People Team finds ways to make everyone’s TTT similar, particularly our afternoon activity, so we can bond over shared experiences, even miles apart. This summer, we all tried our hands at ax throwing, and just a few weeks ago each of our offices got to venture into Space.Well, sort of. After a morning meeting, Boulder visited the Fiske Planetarium at CU Boulder. Durham visited UNC’s Morehead Planetarium. And since the Smithsonian is refurbishing the Einstein Planetarium, our Falls Church office made our way to the Udvar Hazy center to catch an Imax show and fly a few jets, via simulator. Each office also got a taste of space food trying Astronaut ice cream, to mixed reviews. TTTs are more than fun snacks and field trips. They are about finding common ground with colleagues, challenging each other to grow, and re-connecting with folks you don’t work with day-to-day. They are about setting aside time for frank discussion across disciplines and experience levels, and getting outside the office for new perspectives. They are just a little part of what makes Viget so unique. Are you ready to join us for our next big TTT adventure? It’s Viget20, and it’s going to be a good one. We're hiring. Full Article News & Culture
s Concurrency & Multithreading in iOS By feedproxy.google.com Published On :: Tue, 25 Feb 2020 08:00:00 -0500 Concurrency is the notion of multiple things happening at the same time. This is generally achieved either via time-slicing, or truly in parallel if multiple CPU cores are available to the host operating system. We've all experienced a lack of concurrency, most likely in the form of an app freezing up when running a heavy task. UI freezes don't necessarily occur due to the absence of concurrency — they could just be symptoms of buggy software — but software that doesn't take advantage of all the computational power at its disposal is going to create these freezes whenever it needs to do something resource-intensive. If you've profiled an app hanging in this way, you'll probably see a report that looks like this: Anything related to file I/O, data processing, or networking usually warrants a background task (unless you have a very compelling excuse to halt the entire program). There aren't many reasons that these tasks should block your user from interacting with the rest of your application. Consider how much better the user experience of your app could be if instead, the profiler reported something like this: Analyzing an image, processing a document or a piece of audio, or writing a sizeable chunk of data to disk are examples of tasks that could benefit greatly from being delegated to background threads. Let's dig into how we can enforce such behavior into our iOS applications. A Brief History In the olden days, the maximum amount of work per CPU cycle that a computer could perform was determined by the clock speed. As processor designs became more compact, heat and physical constraints started becoming limiting factors for higher clock speeds. Consequentially, chip manufacturers started adding additional processor cores on each chip in order to increase total performance. By increasing the number of cores, a single chip could execute more CPU instructions per cycle without increasing its speed, size, or thermal output. There's just one problem... How can we take advantage of these extra cores? Multithreading. Multithreading is an implementation handled by the host operating system to allow the creation and usage of n amount of threads. Its main purpose is to provide simultaneous execution of two or more parts of a program to utilize all available CPU time. Multithreading is a powerful technique to have in a programmer's toolbelt, but it comes with its own set of responsibilities. A common misconception is that multithreading requires a multi-core processor, but this isn't the case — single-core CPUs are perfectly capable of working on many threads, but we'll take a look in a bit as to why threading is a problem in the first place. Before we dive in, let's look at the nuances of what concurrency and parallelism mean using a simple diagram: In the first situation presented above, we observe that tasks can run concurrently, but not in parallel. This is similar to having multiple conversations in a chatroom, and interleaving (context-switching) between them, but never truly conversing with two people at the same time. This is what we call concurrency. It is the illusion of multiple things happening at the same time when in reality, they're switching very quickly. Concurrency is about dealing with lots of things at the same time. Contrast this with the parallelism model, in which both tasks run simultaneously. Both execution models exhibit multithreading, which is the involvement of multiple threads working towards one common goal. Multithreading is a generalized technique for introducing a combination of concurrency and parallelism into your program. The Burden of Threads A modern multitasking operating system like iOS has hundreds of programs (or processes) running at any given moment. However, most of these programs are either system daemons or background processes that have very low memory footprint, so what is really needed is a way for individual applications to make use of the extra cores available. An application (process) can have many threads (sub-processes) operating on shared memory. Our goal is to be able to control these threads and use them to our advantage. Historically, introducing concurrency to an app has required the creation of one or more threads. Threads are low-level constructs that need to be managed manually. A quick skim through Apple's Threaded Programming Guide is all it takes to see how much complexity threaded code adds to a codebase. In addition to building an app, the developer has to: Responsibly create new threads, adjusting that number dynamically as system conditions change Manage them carefully, deallocating them from memory once they have finished executing Leverage synchronization mechanisms like mutexes, locks, and semaphores to orchestrate resource access between threads, adding even more overhead to application code Mitigate risks associated with coding an application that assumes most of the costs associated with creating and maintaining any threads it uses, and not the host OS This is unfortunate, as it adds enormous levels of complexity and risk without any guarantees of improved performance. Grand Central Dispatch iOS takes an asynchronous approach to solving the concurrency problem of managing threads. Asynchronous functions are common in most programming environments, and are often used to initiate tasks that might take a long time, like reading a file from the disk, or downloading a file from the web. When invoked, an asynchronous function executes some work behind the scenes to start a background task, but returns immediately, regardless of how long the original task might takes to actually complete. A core technology that iOS provides for starting tasks asynchronously is Grand Central Dispatch (or GCD for short). GCD abstracts away thread management code and moves it down to the system level, exposing a light API to define tasks and execute them on an appropriate dispatch queue. GCD takes care of all thread management and scheduling, providing a holistic approach to task management and execution, while also providing better efficiency than traditional threads. Let's take a look at the main components of GCD: What've we got here? Let's start from the left: DispatchQueue.main: The main thread, or the UI thread, is backed by a single serial queue. All tasks are executed in succession, so it is guaranteed that the order of execution is preserved. It is crucial that you ensure all UI updates are designated to this queue, and that you never run any blocking tasks on it. We want to ensure that the app's run loop (called CFRunLoop) is never blocked in order to maintain the highest framerate. Subsequently, the main queue has the highest priority, and any tasks pushed onto this queue will get executed immediately. DispatchQueue.global: A set of global concurrent queues, each of which manage their own pool of threads. Depending on the priority of your task, you can specify which specific queue to execute your task on, although you should resort to using default most of the time. Because tasks on these queues are executed concurrently, it doesn't guarantee preservation of the order in which tasks were queued. Notice how we're not dealing with individual threads anymore? We're dealing with queues which manage a pool of threads internally, and you will shortly see why queues are a much more sustainable approach to multhreading. Serial Queues: The Main Thread As an exercise, let's look at a snippet of code below, which gets fired when the user presses a button in the app. The expensive compute function can be anything. Let's pretend it is post-processing an image stored on the device. import UIKit class ViewController: UIViewController { @IBAction func handleTap(_ sender: Any) { compute() } private func compute() -> Void { // Pretending to post-process a large image. var counter = 0 for _ in 0..<9999999 { counter += 1 } } } At first glance, this may look harmless, but if you run this inside of a real app, the UI will freeze completely until the loop is terminated, which will take... a while. We can prove it by profiling this task in Instruments. You can fire up the Time Profiler module of Instruments by going to Xcode > Open Developer Tool > Instruments in Xcode's menu options. Let's look at the Threads module of the profiler and see where the CPU usage is highest. We can see that the Main Thread is clearly at 100% capacity for almost 5 seconds. That's a non-trivial amount of time to block the UI. Looking at the call tree below the chart, we can see that the Main Thread is at 99.9% capacity for 4.43 seconds! Given that a serial queue works in a FIFO manner, tasks will always complete in the order in which they were inserted. Clearly the compute() method is the culprit here. Can you imagine clicking a button just to have the UI freeze up on you for that long? Background Threads How can we make this better? DispatchQueue.global() to the rescue! This is where background threads come in. Referring to the GCD architecture diagram above, we can see that anything that is not the Main Thread is a background thread in iOS. They can run alongside the Main Thread, leaving it fully unoccupied and ready to handle other UI events like scrolling, responding to user events, animating etc. Let's make a small change to our button click handler above: class ViewController: UIViewController { @IBAction func handleTap(_ sender: Any) { DispatchQueue.global(qos: .userInitiated).async { [unowned self] in self.compute() } } private func compute() -> Void { // Pretending to post-process a large image. var counter = 0 for _ in 0..<9999999 { counter += 1 } } } Unless specified, a snippet of code will usually default to execute on the Main Queue, so in order to force it to execute on a different thread, we'll wrap our compute call inside of an asynchronous closure that gets submitted to the DispatchQueue.global queue. Keep in mind that we aren't really managing threads here. We're submitting tasks (in the form of closures or blocks) to the desired queue with the assumption that it is guaranteed to execute at some point in time. The queue decides which thread to allocate the task to, and it does all the hard work of assessing system requirements and managing the actual threads. This is the magic of Grand Central Dispatch. As the old adage goes, you can't improve what you can't measure. So we measured our truly terrible button click handler, and now that we've improved it, we'll measure it once again to get some concrete data with regards to performance. Looking at the profiler again, it's quite clear to us that this is a huge improvement. The task takes an identical amount of time, but this time, it's happening in the background without locking up the UI. Even though our app is doing the same amount of work, the perceived performance is much better because the user will be free to do other things while the app is processing. You may have noticed that we accessed a global queue of .userInitiated priority. This is an attribute we can use to give our tasks a sense of urgency. If we run the same task on a global queue of and pass it a qos attribute of background , iOS will think it's a utility task, and thus allocate fewer resources to execute it. So, while we don't have control over when our tasks get executed, we do have control over their priority. A Note on Main Thread vs. Main Queue You might be wondering why the Profiler shows "Main Thread" and why we're referring to it as the "Main Queue". If you refer back to the GCD architecture we described above, the Main Queue is solely responsible for managing the Main Thread. The Dispatch Queues section in the Concurrency Programming Guide says that "the main dispatch queue is a globally available serial queue that executes tasks on the application’s main thread. Because it runs on your application’s main thread, the main queue is often used as a key synchronization point for an application." The terms "execute on the Main Thread" and "execute on the Main Queue" can be used interchangeably. Concurrent Queues So far, our tasks have been executed exclusively in a serial manner. DispatchQueue.main is by default a serial queue, and DispatchQueue.global gives you four concurrent dispatch queues depending on the priority parameter you pass in. Let's say we want to take five images, and have our app process them all in parallel on background threads. How would we go about doing that? We can spin up a custom concurrent queue with an identifier of our choosing, and allocate those tasks there. All that's required is the .concurrent attribute during the construction of the queue. class ViewController: UIViewController { let queue = DispatchQueue(label: "com.app.concurrentQueue", attributes: .concurrent) let images: [UIImage] = [UIImage].init(repeating: UIImage(), count: 5) @IBAction func handleTap(_ sender: Any) { for img in images { queue.async { [unowned self] in self.compute(img) } } } private func compute(_ img: UIImage) -> Void { // Pretending to post-process a large image. var counter = 0 for _ in 0..<9999999 { counter += 1 } } } Running that through the profiler, we can see that the app is now spinning up 5 discrete threads to parallelize a for-loop. Parallelization of N Tasks So far, we've looked at pushing computationally expensive task(s) onto background threads without clogging up the UI thread. But what about executing parallel tasks with some restrictions? How can Spotify download multiple songs in parallel, while limiting the maximum number up to 3? We can go about this in a few ways, but this is a good time to explore another important construct in multithreaded programming: semaphores. Semaphores are signaling mechanisms. They are commonly used to control access to a shared resource. Imagine a scenario where a thread can lock access to a certain section of the code while it executes it, and unlocks after it's done to let other threads execute the said section of the code. You would see this type of behavior in database writes and reads, for example. What if you want only one thread writing to a database and preventing any reads during that time? This is a common concern in thread-safety called Readers-writer lock. Semaphores can be used to control concurrency in our app by allowing us to lock n number of threads. let kMaxConcurrent = 3 // Or 1 if you want strictly ordered downloads! let semaphore = DispatchSemaphore(value: kMaxConcurrent) let downloadQueue = DispatchQueue(label: "com.app.downloadQueue", attributes: .concurrent) class ViewController: UIViewController { @IBAction func handleTap(_ sender: Any) { for i in 0..<15 { downloadQueue.async { [unowned self] in // Lock shared resource access semaphore.wait() // Expensive task self.download(i + 1) // Update the UI on the main thread, always! DispatchQueue.main.async { tableView.reloadData() // Release the lock semaphore.signal() } } } } func download(_ songId: Int) -> Void { var counter = 0 // Simulate semi-random download times. for _ in 0..<Int.random(in: 999999...10000000) { counter += songId } } } Notice how we've effectively restricted our download system to limit itself to k number of downloads. The moment one download finishes (or thread is done executing), it decrements the semaphore, allowing the managing queue to spawn another thread and start downloading another song. You can apply a similar pattern to database transactions when dealing with concurrent reads and writes. Semaphores usually aren't necessary for code like the one in our example, but they become more powerful when you need to enforce synchronous behavior whille consuming an asynchronous API. The above could would work just as well with a custom NSOperationQueue with a maxConcurrentOperationCount, but it's a worthwhile tangent regardless. Finer Control with OperationQueue GCD is great when you want to dispatch one-off tasks or closures into a queue in a 'set-it-and-forget-it' fashion, and it provides a very lightweight way of doing so. But what if we want to create a repeatable, structured, long-running task that produces associated state or data? And what if we want to model this chain of operations such that they can be cancelled, suspended and tracked, while still working with a closure-friendly API? Imagine an operation like this: This would be quite cumbersome to achieve with GCD. We want a more modular way of defining a group of tasks while maintaining readability and also exposing a greater amount of control. In this case, we can use Operation objects and queue them onto an OperationQueue, which is a high-level wrapper around DispatchQueue. Let's look at some of the benefits of using these abstractions and what they offer in comparison to the lower-level GCI API: You may want to create dependencies between tasks, and while you could do this via GCD, you're better off defining them concretely as Operation objects, or units of work, and pushing them onto your own queue. This would allow for maximum reusability since you may use the same pattern elsewhere in an application. The Operation and OperationQueue classes have a number of properties that can be observed, using KVO (Key Value Observing). This is another important benefit if you want to monitor the state of an operation or operation queue. Operations can be paused, resumed, and cancelled. Once you dispatch a task using Grand Central Dispatch, you no longer have control or insight into the execution of that task. The Operation API is more flexible in that respect, giving the developer control over the operation's life cycle. OperationQueue allows you to specify the maximum number of queued operations that can run simultaneously, giving you a finer degree of control over the concurrency aspects. The usage of Operation and OperationQueue could fill an entire blog post, but let's look at a quick example of what modeling dependencies looks like. (GCD can also create dependencies, but you're better off dividing up large tasks into a series of composable sub-tasks.) In order to create a chain of operations that depend on one another, we could do something like this: class ViewController: UIViewController { var queue = OperationQueue() var rawImage = UIImage? = nil let imageUrl = URL(string: "https://example.com/portrait.jpg")! @IBOutlet weak var imageView: UIImageView! let downloadOperation = BlockOperation { let image = Downloader.downloadImageWithURL(url: imageUrl) OperationQueue.main.async { self.rawImage = image } } let filterOperation = BlockOperation { let filteredImage = ImgProcessor.addGaussianBlur(self.rawImage) OperationQueue.main.async { self.imageView = filteredImage } } filterOperation.addDependency(downloadOperation) [downloadOperation, filterOperation].forEach { queue.addOperation($0) } } So why not opt for a higher level abstraction and avoid using GCD entirely? While GCD is ideal for inline asynchronous processing, Operation provides a more comprehensive, object-oriented model of computation for encapsulating all of the data around structured, repeatable tasks in an application. Developers should use the highest level of abstraction possible for any given problem, and for scheduling consistent, repeated work, that abstraction is Operation. Other times, it makes more sense to sprinkle in some GCD for one-off tasks or closures that we want to fire. We can mix both OperationQueue and GCD to get the best of both worlds. The Cost of Concurrency DispatchQueue and friends are meant to make it easier for the application developer to execute code concurrently. However, these technologies do not guarantee improvements to the efficiency or responsiveness in an application. It is up to you to use queues in a manner that is both effective and does not impose an undue burden on other resources. For example, it's totally viable to create 10,000 tasks and submit them to a queue, but doing so would allocate a nontrivial amount of memory and introduce a lot of overhead for the allocation and deallocation of operation blocks. This is the opposite of what you want! It's best to profile your app thoroughly to ensure that concurrency is enhancing your app's performance and not degrading it. We've talked about how concurrency comes at a cost in terms of complexity and allocation of system resources, but introducing concurrency also brings a host of other risks like: Deadlock: A situation where a thread locks a critical portion of the code and can halt the application's run loop entirely. In the context of GCD, you should be very careful when using the dispatchQueue.sync { } calls as you could easily get yourself in situations where two synchronous operations can get stuck waiting for each other. Priority Inversion: A condition where a lower priority task blocks a high priority task from executing, which effectively inverts their priorities. GCD allows for different levels of priority on its background queues, so this is quite easily a possibility. Producer-Consumer Problem: A race condition where one thread is creating a data resource while another thread is accessing it. This is a synchronization problem, and can be solved using locks, semaphores, serial queues, or a barrier dispatch if you're using concurrent queues in GCD. ...and many other sorts of locking and data-race conditions that are hard to debug! Thread safety is of the utmost concern when dealing with concurrency. Parting Thoughts + Further Reading If you've made it this far, I applaud you. Hopefully this article gives you a lay of the land when it comes to multithreading techniques on iOS, and how you can use some of them in your app. We didn't get to cover many of the lower-level constructs like locks, mutexes and how they help us achieve synchronization, nor did we get to dive into concrete examples of how concurrency can hurt your app. We'll save those for another day, but you can dig into some additional reading and videos if you're eager to dive deeper. Building Concurrent User Interfaces on iOS (WWDC 2012) Concurrency and Parallelism: Understanding I/O Apple's Official Concurrency Programming Guide Mutexes and Closure Capture in Swift Locks, Thread Safety, and Swift Advanced NSOperations (WWDC 2015) NSHipster: NSOperation Full Article Code
s Markdown Comes Alive! Part 1, Basic Editor By feedproxy.google.com Published On :: Wed, 26 Feb 2020 08:00:00 -0500 In my last post, I covered what LiveView is at a high level. In this series, we’re going to dive deeper and implement a LiveView powered Markdown editor called Frampton. This series assumes you have some familiarity with Phoenix and Elixir, including having them set up locally. Check out Elizabeth’s three-part series on getting started with Phoenix for a refresher. This series has a companion repository published on GitHub. Get started by cloning it down and switching to the starter branch. You can see the completed application on master. Our goal today is to make a Markdown editor, which allows a user to enter Markdown text on a page and see it rendered as HTML next to it in real-time. We’ll make use of LiveView for the interaction and the Earmark package for rendering Markdown. The starter branch provides some styles and installs LiveView. Rendering Markdown Let’s set aside the LiveView portion and start with our data structures and the functions that operate on them. To begin, a Post will have a body, which holds the rendered HTML string, and title. A string of markdown can be turned into HTML by calling Post.render(post, markdown). I think that just about covers it! First, let’s define our struct in lib/frampton/post.ex: defmodule Frampton.Post do defstruct body: "", title: "" def render(%__MODULE{} = post, markdown) do # Fill me in! end end Now the failing test (in test/frampton/post_test.exs): describe "render/2" do test "returns our post with the body set" do markdown = "# Hello world!" assert Post.render(%Post{}, markdown) == {:ok, %Post{body: "<h1>Hello World</h1> "}} end end Our render method will just be a wrapper around Earmark.as_html!/2 that puts the result into the body of the post. Add {:earmark, "~> 1.4.3"} to your deps in mix.exs, run mix deps.get and fill out render function: def render(%__MODULE{} = post, markdown) do html = Earmark.as_html!(markdown) {:ok, Map.put(post, :body, html)} end Our test should now pass, and we can render posts! [Note: we’re using the as_html! method, which prints error messages instead of passing them back to the user. A smarter version of this would handle any errors and show them to the user. I leave that as an exercise for the reader…] Time to play around with this in an IEx prompt (run iex -S mix in your terminal): iex(1)> alias Frampton.Post Frampton.Post iex(2)> post = %Post{} %Frampton.Post{body: "", title: ""} iex(3)> {:ok, updated_post} = Post.render(post, "# Hello world!") {:ok, %Frampton.Post{body: "<h1>Hello world!</h1> ", title: ""}} iex(4)> updated_post %Frampton.Post{body: "<h1>Hello world!</h1> ", title: ""} Great! That’s exactly what we’d expect. You can find the final code for this in the render_post branch. LiveView Editor Now for the fun part: Editing this live! First, we’ll need a route for the editor to live at: /editor sounds good to me. LiveViews can be rendered from a controller, or directly in the router. We don’t have any initial state, so let's go straight from a router. First, let's put up a minimal test. In test/frampton_web/live/editor_live_test.exs: defmodule FramptonWeb.EditorLiveTest do use FramptonWeb.ConnCase import Phoenix.LiveViewTest test "the editor renders" do conn = get(build_conn(), "/editor") assert html_response(conn, 200) =~ "data-test="editor"" end end This test doesn’t do much yet, but notice that it isn’t live view specific. Our first render is just the same as any other controller test we’d write. The page’s content is there right from the beginning, without the need to parse JavaScript or make API calls back to the server. Nice. To make that test pass, add a route to lib/frampton_web/router.ex. First, we import the LiveView code, then we render our Editor: import Phoenix.LiveView.Router # … Code skipped ... # Inside of `scope "/"`: live "/editor", EditorLive Now place a minimal EditorLive module, in lib/frampton_web/live/editor_live.ex: defmodule FramptonWeb.EditorLive do use Phoenix.LiveView def render(assigns) do ~L""" <div data-test=”editor”> <h1>Hello world!</h1> </div> """ end def mount(_params, _session, socket) do {:ok, socket} end end And we have a passing test suite! The ~L sigil designates that LiveView should track changes to the content inside. We could keep all of our markup in this render/1 method, but let’s break it out into its own template for demonstration purposes. Move the contents of render into lib/frampton_web/templates/editor/show.html.leex, and replace EditorLive.render/1 with this one liner: def render(assigns), do: FramptonWeb.EditorView.render("show.html", assigns). And finally, make an EditorView module in lib/frampton_web/views/editor_view.ex: defmodule FramptonWeb.EditorView do use FramptonWeb, :view import Phoenix.LiveView end Our test should now be passing, and we’ve got a nicely separated out template, view and “live” server. We can keep markup in the template, helper functions in the view, and reactive code on the server. Now let’s move forward to actually render some posts! Handling User Input We’ve got four tasks to accomplish before we are done: Take markdown input from the textarea Send that input to the LiveServer Turn that raw markdown into HTML Return the rendered HTML to the page. Event binding To start with, we need to annotate our textarea with an event binding. This tells the liveview.js framework to forward DOM events to the server, using our liveview channel. Open up lib/frampton_web/templates/editor/show.html.leex and annotate our textarea: <textarea phx-keyup="render_post"></textarea> This names the event (render_post) and sends it on each keyup. Let’s crack open our web inspector and look at the web socket traffic. Using Chrome, open the developer tools, navigate to the network tab and click WS. In development you’ll see two socket connections: one is Phoenix LiveReload, which polls your filesystem and reloads pages appropriately. The second one is our LiveView connection. If you let it sit for a while, you’ll see that it's emitting a “heartbeat” call. If your server is running, you’ll see that it responds with an “ok” message. This lets LiveView clients know when they've lost connection to the server and respond appropriately. Now, type some text and watch as it sends down each keystroke. However, you’ll also notice that the server responds with a “phx_error” message and wipes out our entered text. That's because our server doesn’t know how to handle the event yet and is throwing an error. Let's fix that next. Event handling We’ll catch the event in our EditorLive module. The LiveView behavior defines a handle_event/3 callback that we need to implement. Open up lib/frampton_web/live/editor_live.ex and key in a basic implementation that lets us catch events: def handle_event("render_post", params, socket) do IO.inspect(params) {:noreply, socket} end The first argument is the name we gave to our event in the template, the second is the data from that event, and finally the socket we’re currently talking through. Give it a try, typing in a few characters. Look at your running server and you should see a stream of events that look something like this: There’s our keystrokes! Next, let’s pull out that value and use it to render HTML. Rendering Markdown Lets adjust our handle_event to pattern match out the value of the textarea: def handle_event("render_post", %{"value" => raw}, socket) do Now that we’ve got the raw markdown string, turning it into HTML is easy thanks to the work we did earlier in our Post module. Fill out the body of the function like this: {:ok, post} = Post.render(%Post{}, raw) IO.inspect(post) If you type into the textarea you should see output that looks something like this: Perfect! Lastly, it’s time to send that rendered html back to the page. Returning HTML to the page In a LiveView template, we can identify bits of dynamic data that will change over time. When they change, LiveView will compare what has changed and send over a diff. In our case, the dynamic content is the post body. Open up show.html.leex again and modify it like so: <div class="rendered-output"> <%= @post.body %> </div> Refresh the page and see: Whoops! The @post variable will only be available after we put it into the socket’s assigns. Let’s initialize it with a blank post. Open editor_live.ex and modify our mount/3 function: def mount(_params, _session, socket) do post = %Post{} {:ok, assign(socket, post: post)} end In the future, we could retrieve this from some kind of storage, but for now, let's just create a new one each time the page refreshes. Finally, we need to update the Post struct with user input. Update our event handler like this: def handle_event("render_post", %{"value" => raw}, %{assigns: %{post: post}} = socket) do {:ok, post} = Post.render(post, raw) {:noreply, assign(socket, post: post) end Let's load up http://localhost:4000/editor and see it in action. Nope, that's not quite right! Phoenix won’t render this as HTML because it’s unsafe user input. We can get around this (very good and useful) security feature by wrapping our content in a raw/1 call. We don’t have a database and user processes are isolated from each other by Elixir. The worst thing a malicious user could do would be crash their own session, which doesn’t bother me one bit. Check the edit_posts branch for the final version. Conclusion That’s a good place to stop for today. We’ve accomplished a lot! We’ve got a dynamically rendering editor that takes user input, processes it and updates the page. And we haven’t written any JavaScript, which means we don’t have to maintain or update any JavaScript. Our server code is built on the rock-solid foundation of the BEAM virtual machine, giving us a great deal of confidence in its reliability and resilience. In the next post, we’ll tackle making a shared editor, allowing multiple users to edit the same post. This project will highlight Elixir’s concurrency capabilities and demonstrate how LiveView builds on them to enable some incredible user experiences. Full Article Code Back-end Engineering
s Why's it so hard to get the cool stuff approved? By feedproxy.google.com Published On :: Thu, 27 Feb 2020 00:00:00 -0500 The classic adage is “good design speaks for itself.” Which would mean that if something’s as good of an idea as you think it is, a client will instantly see that it’s good too, right? Here at Viget, we’re always working with new and different clients. Each with their own challenges and sensibilities. But after ten years of client work, I can’t help but notice a pattern emerge when we’re trying to get approval on especially cool, unconventional parts of a design. So let’s break down some of those patterns to hopefully better understand why clients hesitate, and what strategies we’ve been using lately to help get the work we’re excited about approved.Imagine this: the parallax homepage with elements that move around in surprising ways or a unique navigation menu that conceptually reinforces a site’s message. The way the content cards on a page will, like, be literal cards that will shuffle and move around. Basically, any design that feels like an exciting, novel challenge, will need the client to “get it.” And that often turns out to be the biggest challenge of all. There are plenty of practical reasons cool designs get shot down. A client is usually more than one stakeholder, and more than the team of people you’re working with directly. On any project, there’s an amount of telephone you end up playing. Or, there’s always the classic foes: budgets and deadlines. Any idea should fit in those predetermined constraints. But as a project goes along, budgets and deadlines find a way to get tighter than you planned. But innovative designs and interactions can seem especially scary for clients to approve. There’s three fears that often pop up on projects:The fear of change. Maybe the client expected something simple, a light refresh. Something that doesn’t challenge their design expectations or require more time and effort to understand. And on our side, maybe we didn’t sufficiently ease them into our way of thinking and open them up to why we think something bigger and bolder is the right solution for them. Baby steps, y’all. The fear of the unknown. Or, less dramatically, a lack of understanding of the medium. In the past, we have struggled with how to present an interactive, animated design to a client before it’s actually built. Looking at a site that does something conceptually similar as an example can be tough. It’s asking a lot of a client’s imagination to show them a site about boots that has a cool spinning animation and get meaningful feedback about how a spinning animation would work on their site about after-school tutoring. Or maybe we’ve created static designs, then talked around what we envision happening. Again, what seems so clear in our minds as professionals entrenched in this stuff every day can be tough for someone outside the tech world to clearly understand. The fear of losing control. We’re all about learning from past mistakes. So lets say, after dealing with that fear of the unknown on a project, next time you go in the opposite direction. You invest time up front creating something polished. Maybe you even get the developer to build a prototype that moves and looks like the real thing. You’ve taken all the vague mystery out of the process, so a client will be thrilled, right? Surprise, probably not! Most clients are working with you because they want to conquer the noble quest that is their redesign together. When we jump straight to showing something that looks polished, even if it’s not really, it can feel like we jumped ahead without keeping them involved. Like we took away their input. They can also feel demotivated to give good, meaningful feedback on a polished prototype because it looks “done.”So what to do? Lately we have found low-fidelity prototypes to be a great tool for combating these fears and better communicating our ideas. What are low-fidelity prototypes?Low fidelity prototypes are a tool that designers can create quickly to illustrate an idea, without sinking time into making it pixel-perfect. Some recent examples of prototypes we've created include a clickable Figma or Invision prototype put together with Whimsical wireframes: A rough animation created in Principle illustrating less programatic animation: And even creating an animated storyboard in Photoshop: They’re rough enough that there’s no way they could be confused for a final product. But customized so that a client can immediately understand what they’re looking at and what they need to respond to. Low-fidelity prototypes hit a sweet spot that addresses those client fears head on. That fear of change? A lo-fi prototype starts rough and small, so it can ease a client into a dramatic change without overwhelming them. It’s just a first step. It gives them time to react and warm up to something that’ll ultimately be a big change.It also cuts out the fear of the unknown. Seeing something moving around, even if it’s rough, can be so much more clear than talking ourselves in circles about how we think it will move, and hoping the client can imagine it. The feature is no longer an enigma cloaked in mystery and big talk, but something tangible they can point at and ask concrete questions about.And finally, a lo-fi prototype doesn’t threaten a client’s sense of control. Low-fidelity means it’s clearly still a work in progress! It’s just an early step in the creative process, and therefore communicates that we’re still in the middle of that process together. There’s still plenty of room for their ideas and feedback. Lo-fi prototypes: client-tested, internal team-approvedThere are a lot of reasons to love lo-fi prototypes internally, too! They’re quick and easy. We can whip up multiple ideas within a few hours, without sinking the time into getting our hearts set on any one thing. In an agency setting especially, time is limited, so the faster we can get an idea out of our own heads, the better.They’re great to share with developers. Ideally, the whole team is working together simultaneously, collaborating every step of the way. Realistically, a developer often doesn’t have time during a project’s early design phase. Lo-fi prototypes are concrete enough that a developer can quickly tell if building an idea will be within scope. It helps us catch impractical ideas early and helps us all collaborate to create something that’s both cool and feasible. Stay tuned for posts in the near future diving into some of our favorite processes for creating lo-fi prototypes! Full Article Design & Content
s Committed to the wrong branch? -, @{upstream}, and @{-1} to the rescue By feedproxy.google.com Published On :: Thu, 27 Feb 2020 00:00:00 -0500 I get into this situation sometimes. Maybe you do too. I merge feature work into a branch used to collect features, and then continue development but on that branch instead of back on the feature branch git checkout feature # ... bunch of feature commits ... git push git checkout qa-environment git merge --no-ff --no-edit feature git push # deploy qa-environment to the QA remote environment # ... more feature commits ... # oh. I'm not committing in the feature branch like I should be and have to move those commits to the feature branch they belong in and take them out of the throwaway accumulator branch git checkout feature git cherry-pick origin/qa-environment..qa-environment git push git checkout qa-environment git reset --hard origin/qa-environment git merge --no-ff --no-edit feature git checkout feature # ready for more feature commits Maybe you prefer git branch -D qa-environment git checkout qa-environment over git checkout qa-environment git reset --hard origin/qa-environment Either way, that works. But it'd be nicer if we didn't have to type or even remember the branches' names and the remote's name. They are what is keeping this from being a context-independent string of commands you run any time this mistake happens. That's what we're going to solve here.Shorthands for longevityI like to use all possible natively supported shorthands. There are two broad motivations for that.Fingers have a limited number of movements in them. Save as many as possible left late in life.Current research suggests that multitasking has detrimental effects on memory. Development tends to be very heavy on multitasking. Maybe relieving some of the pressure on quick-access short term memory (like knowing all relevant branch names) add up to leave a healthier memory down the line.First up for our scenario: the - shorthand, which refers to the previously checked out branch. There are a few places we can't use it, but it helps a lot: Bash # USING - git checkout feature # hack hack hack git push git checkout qa-environment git merge --no-ff --no-edit - # ???? git push # hack hack hack # whoops git checkout - # now on feature ???? git cherry-pick origin/qa-environment..qa-environment git push git checkout - # now on qa-environment ???? git reset --hard origin/qa-environment git merge --no-ff --no-edit - # ???? git checkout - # ???? # on feature and ready for more feature commits Bash # ORIGINAL git checkout feature # hack hack hack git push git checkout qa-environment git merge --no-ff --no-edit feature git push # hack hack hack # whoops git checkout feature git cherry-pick origin/qa-environment..qa-environment git push git checkout qa-environment git reset --hard origin/qa-environment git merge --no-ff --no-edit feature git checkout feature # ready for more feature commits Switch We cannot use - when cherry-picking a range > git cherry-pick origin/-..- fatal: bad revision 'origin/-..-' > git cherry-pick origin/qa-environment..- fatal: bad revision 'origin/qa-environment..-' and even if we could we'd still have provide the remote's name (here, origin).That shorthand doesn't apply in the later reset --hard command, and we cannot use it in the branch -D && checkout approach either. branch -D does not support the - shorthand and once the branch is deleted checkout can't reach it with -: # assuming that branch-a has an upstream origin/branch-a > git checkout branch-a > git checkout branch-b > git checkout - > git branch -D - error: branch '-' not found. > git branch -D branch-a > git checkout - error: pathspec '-' did not match any file(s) known to git So we have to remember the remote's name (we know it's origin because we are devoting memory space to knowing that this isn't one of those times it's something else), the remote tracking branch's name, the local branch's name, and we're typing those all out. No good! Let's figure out some shorthands.@{-<n>} is hard to say but easy to fall in love withWe can do a little better by using @{-<n>} (you'll also sometimes see it referred to be the older @{-N}). It is a special construct for referring to the nth previously checked out ref. > git checkout branch-a > git checkout branch-b > git rev-parse --abbrev-rev @{-1} # the name of the previously checked out branch branch-a > git checkout branch-c > git rev-parse --abbrev-rev @{-2} # the name of branch checked out before the previously checked out one branch-a Back in our scenario, we're on qa-environment, we switch to feature, and then want to refer to qa-environment. That's @{-1}! So instead of git cherry-pick origin/qa-environment..qa-environment We can do git cherry-pick origin/qa-environment..@{-1} Here's where we are (🎉 marks wins from -, 💥 marks the win from @{-1}) Bash # USING - AND @{-1} git checkout feature # hack hack hack git push git checkout qa-environment git merge --no-ff --no-edit - # ???? git push # hack hack hack # whoops git checkout - # ???? git cherry-pick origin/qa-environment..@{-1} # ???? git push git checkout - # ???? git reset --hard origin/qa-environment git merge --no-ff --no-edit - # ???? git checkout - # ???? # ready for more feature commits Bash # ORIGINAL git checkout feature # hack hack hack git push git checkout qa-environment git merge --no-ff --no-edit feature git push # hack hack hack # whoops git checkout feature git cherry-pick origin/qa-environment..qa-environment git push git checkout qa-environment git reset --hard origin/qa-environment git merge --no-ff --no-edit feature git checkout feature # ready for more feature commits Switch One down, two to go: we're still relying on memory for the remote's name and the remote branch's name and we're still typing both out in full. Can we replace those with generic shorthands?@{-1} is the ref itself, not the ref's name, we can't do > git cherry-pick origin/@{-1}..@{-1} origin/@{-1} fatal: ambiguous argument 'origin/@{-1}': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git <command> [<revision>...] -- [<file>...]' because there is no branch origin/@{-1}. For the same reason, @{-1} does not give us a generalized shorthand for the scenario's later git reset --hard origin/qa-environment command.But good news!Do @{u} @{push} @{upstream} or its shorthand @{u} is the remote branch a that would be pulled from if git pull were run. @{push} is the remote branch that would be pushed to if git push was run. > git checkout branch-a Switched to branch 'branch-a' Your branch is ahead of 'origin/branch-a' by 3 commits. (use "git push" to publish your local commits) > git reset --hard origin/branch-a HEAD is now at <the SHA origin/branch-a is at> we can > git checkout branch-a Switched to branch 'branch-a' Your branch is ahead of 'origin/branch-a' by 3 commits. (use "git push" to publish your local commits) > git reset --hard @{u} # <-- So Cool! HEAD is now at <the SHA origin/branch-a is at> Tacking either onto a branch name will give that branch's @{upstream} or @{push}. For example git checkout branch-a@{u} is the branch branch-a pulls from.In the common workflow where a branch pulls from and pushes to the same branch, @{upstream} and @{push} will be the same, leaving @{u} as preferable for its terseness. @{push} shines in triangular workflows where you pull from one remote and push to another (see the external links below).Going back to our scenario, it means short, portable commands with a minimum human memory footprint. (🎉 marks wins from -, 💥 marks the win from @{-1}, 😎 marks the wins from @{u}.) Bash # USING - AND @{-1} AND @{u} git checkout feature # hack hack hack git push git checkout qa-environment git merge --no-ff --no-edit - # ???? git push # hack hack hack # whoops git checkout - # ???? git cherry-pick @{-1}@{u}..@{-1} # ???????? git push git checkout - # ???? git reset --hard @{u} # ???? git merge --no-ff --no-edit - # ???? git checkout - # ???? # ready for more feature commits Bash # ORIGINAL git checkout feature # hack hack hack git push git checkout qa-environment git merge --no-ff --no-edit feature git push # hack hack hack # whoops git checkout feature git cherry-pick origin/qa-environment..qa-environment git push git checkout qa-environment git reset --hard origin/qa-environment git merge --no-ff --no-edit feature git checkout feature # ready for more feature commits Switch Make the things you repeat the easiest to doBecause these commands are generalized, we can run some series of them once, maybe git checkout - && git reset --hard @{u} && git checkout - or git checkout - && git cherry-pick @{-1}@{u}.. @{-1} && git checkout - && git reset --hard @{u} && git checkout - and then those will be in the shell history just waiting to be retrieved and run again the next time, whether with CtrlR incremental search or history substring searching bound to the up arrow or however your interactive shell is configured. Or make it an alias, or even better an abbreviation if your interactive shell supports them. Save the body wear and tear, give memory a break, and level up in Git.And keep goingThe GitHub blog has a good primer on triangular workflows and how they can polish your process of contributing to external projects.The FreeBSD Wiki has a more in-depth article on triangular workflow process (though it doesn't know about @{push} and @{upstream}).The construct @{-<n>} and the suffixes @{push} and @{upstream} are all part of the gitrevisions spec. Direct links to each:@{-<n>}@{push}@{upstream} Full Article Code Front-end Engineering Back-end Engineering
s Setting New Project Managers Up for Success By feedproxy.google.com Published On :: Wed, 11 Mar 2020 08:00:00 -0400 At Viget, we’ve brought on more than a few new Project Managers over the past couple of years, as we continue to grow. The awesome new people we’ve hired have ranged in their levels of experience, but some of them are earlier in their careers and need support from more experienced PMs to develop their skills and flourish. We have different levels of training and support for new PMs. These broadly fall into four categories: Onboarding: Learning about Viget tools and processesShadowing: Learning by watching othersPairing: Learning by doing collaborativelyLeading: Learning by doing solo Onboarding In addition to conducting intro sessions to each discipline at Viget, new Viget PMs go through a lengthy set of training sessions that are specific to the PM lab. These include intros to: PM tools and resourcesProject processesProject typesProject checklistsProject taskingProject planningBudgets, schedules, and resourcingRetrospectivesWorking with remote teamsProject kickoffsThinking about developmentGithub and development workflowTickets, definition, and documentationQA testingAccount management Shadowing After PMs complete the onboarding process, they start shadowing other PMs’ projects to get exposure to the different types of projects we run (since the variety is large). We cater length and depth of shadowing based on how much experience a PM has coming in. We also try to expose PMs to multiple project managers, so they can see how PM style differs person-to-person. We’ve found that it can be most effective to have PMs shadow activities that are more difficult to teach in theory, such as shadowing a PM having a difficult conversation with a client, or shadowing a front-end build-out demo to see how the PM positions the meeting and our process to the client. More straightforward tasks like setting up a Harvest project could be done via pairing, since it’s easy to get the hang of with a little guidance. Pairing While shadowing is certainly helpful, we try to get PMs into pairing mode pretty quickly, since we’ve found that most folks learn better by doing than by watching. Sometimes this might mean having a new PM setting up an invoice or budget sheet for a client while a more experienced PM sits next to them, talking them through the process. We’ve found that having a newer PM lead straightforward activities with guidance tends to be more effective than the newer PM merely watching the more experienced PM do that activity. Another tactic we take is to have both PMs complete a task independently, and then meet and talk through their work, with the more experienced PM giving the less experienced PM feedback. That helps the newer PM think through a task on their own, and gain experience, but still have the chance to see how someone else would have approached the task and get meaningful feedback. Leading Once new PMs are ready to be in the driver’s seat, they are staffed as the lead on projects. The timing of when someone shifts into a lead role depends on how much prior experience that person has, as well as what types of projects are actively ready to be worked on. Most early-career project managers have a behind-the-scenes project mentor (another PM) on at least their first couple projects, so they have a dedicated person to ask questions and get advice from who also has more detailed context than that person’s manager would. For example, mentors often shadow key client and internal meetings and have more frequent check-ins with mentees. This might be less necessary at a company where all the projects are fairly similar, but at Viget, our projects vary widely in scale and services provided, as well as client needs. Because of this, there’s no “one size fits all” process and we have a significant amount of customization per project, which can be daunting to new PMs who are still getting the hang of things. For these mentorship pairings, we use a mentorship plan document (template here) to help the mentor and mentee work together to define goals, mentorship focuses, and touchpoints. Sometimes the mentee’s manager will take a first stab at filling out the plan, other times, the mentor will start that process. Management Touchpoints Along the way, we make sure new PMs have touchpoints with their managers to get the level of support they need to grow and succeed. Managers have regular 1:1s with PMs that are referred to as “project 1:1s”, and are used for the managee to talk through and get advice on challenges or questions related to the projects they’re working on—though really, they can be used for whatever topics are on the managee’s mind. PMs typically have 1:1s with managers daily the first week, two to three times per week after that for the first month or so, then scale down to once per week, and then scale down to bi-weekly after the first six months. In addition to project 1:1s, we also have monthly 1:1s that are more bigger-picture and focused on goal-setting and progress, project feedback from that person’s peers, reflection on how satisfied and fulfilled they’re feeling in their role, and talking through project/industry interests which informs what projects we should advocate for them to be staffed on. We have a progress log template that we customize per PM to keep track of goals and progress. We try to foster a supportive environment that encourages growth, feedback, and experiential learning, but also that lets folks have the autonomy to get in the driver’s seat as soon as they’re comfortable. Interested in learning more about what it’s like to work at Viget? Check out our open positions here. Full Article Process Project Management
s TrailBuddy: Using AI to Create a Predictive Trail Conditions App By feedproxy.google.com Published On :: Thu, 19 Mar 2020 08:00:00 -0400 Viget is full of outdoor enthusiasts and, of course, technologists. For this year's Pointless Weekend, we brought these passions together to build TrailBuddy. This app aims to solve that eternal question: Is my favorite trail dry so I can go hike/run/ride? While getting muddy might rekindle fond childhood memories for some, exposing your gear to the elements isn’t great – it’s bad for your equipment and can cause long-term, and potentially expensive, damage to the trail. There are some trail apps out there but we wanted one that would focus on current conditions. Currently, our favorites trail apps, like mtbproject.com, trailrunproject.com, and hikingproject.com -- all owned by REI, rely on user-reported conditions. While this can be effective, the reports are frequently unreliable, as condition reports can become outdated in just a few days. Our goal was to solve this problem by building an app that brought together location, soil type, and weather history data to create on-demand condition predictions for any trail in the US. We built an initial version of TrailBuddy by tapping into several readily-available APIs, then running the combined data through a machine learning algorithm. (Oh, and also by bringing together a bunch of smart and motivated people and combining them with pizza and some of the magic that is our Pointless Weekends. We'll share the other Pointless Project, Scurry, with you soon.) Learn More We're hiring Front-End Developers in our Boulder, Chattanooga, Durham, Falls Church and Remote (U.S. Only) offices. Learn more and introduce yourself. The quest for data. We knew from the start this app would require data from a number of sources. As previously mentioned, we used REI’s APIs (i.e. https://www.hikingproject.com/data) as the source for basic trail information. We used the trails’ latitude and longitude coordinates as well as its elevation to query weather and soil type. We also found data points such as a trail’s total distance to be relevant to our app users and decided to include that on the front-end, too. Since we wanted to go beyond relying solely on user-reported metrics, which is how REI’s current MTB project works, we came up with a list of factors that could affect the trail for that day. First on that list was weather. We not only considered the impacts of the current forecast, but we also looked at the previous day’s forecast. For example, it’s safe to assume that if it’s currently raining or had been raining over the last several days, it would likely lead to muddy and unfavorable conditions for that trail. We utilized the DarkSky API (https://darksky.net/dev) to get the weather forecasts for that day, as well as the records for previous days. This included expected information, like temperature and precipitation chance. It also included some interesting data points that we realized may be factors, like precipitation intensity, cloud cover, and UV index. But weather alone can’t predict how muddy or dry a trail will be. To determine that for sure, we also wanted to use soil data to help predict how well a trail’s unique soil composition recovers after precipitation. Similar amounts of rain on trails of very different soil types could lead to vastly different trail conditions. A more clay-based soil would hold water much longer, and therefore be much more unfavorable, than loamy soil. Finding a reliable source for soil type and soil drainage proved incredibly difficult. After many hours, we finally found a source through the USDA that we could use. As a side note—the USDA keeps track of lots of data points on soil information that’s actually pretty interesting! We can’t say we’re soil experts but, we felt like we got pretty close. We used Whimsical to build our initial wireframes. Putting our design hats on. From the very first pitch for this app, TrailBuddy’s main differentiator to peer trail resources is its ability to surface real-time information, reliably, and simply. For as complicated as the technology needed to collect and interpret information, the front-end app design needed to be clean and unencumbered. We thought about how users would naturally look for information when setting out to find a trail and what factors they’d think about when doing so. We posed questions like: How easy or difficult of a trail are they looking for?How long is this trail?What does the trail look like?How far away is the trail in relation to my location?For what activity am I needing a trail for? Is this a trail I’d want to come back to in the future? By putting ourselves in our users’ shoes we quickly identified key features TrailBuddy needed to have to be relevant and useful. First, we needed filtering, so users could filter between difficulty and distance to narrow down their results to fit the activity level. Next, we needed a way to look up trails by activity type—mountain biking, hiking, and running are all types of activities REI’s MTB API tracks already so those made sense as a starting point. And lastly, we needed a way for the app to find trails based on your location; or at the very least the ability to find a trail within a certain distance of your current location. We used Figma to design, prototype, and gather feedback on TrailBuddy. Using machine learning to predict trail conditions. As stated earlier, none of us are actual soil or data scientists. So, in order to achieve the real-time conditions reporting TrailBuddy promised, we’d decided to leverage machine learning to make predictions for us. Digging into the utility of machine learning was a first for all of us on this team. Luckily, there was an excellent tutorial that laid out the basics of building an ML model in Python. Provided a CSV file with inputs in the left columns, and the desired output on the right, the script we generated was able to test out multiple different model strategies, and output the effectiveness of each in predicting results, shown below. We assembled all of the historical weather and soil data we could find for a given latitude/longitude coordinate, compiled a 1000 * 100 sized CSV, ran it through the Python evaluator, and found that the CART and SVM models consistently outranked the others in terms of predicting trail status. In other words, we found a working model for which to run our data through and get (hopefully) reliable predictions from. The next step was to figure out which data fields were actually critical in predicting the trail status. The more we could refine our data set, the faster and smarter our predictive model could become. We pulled in some Ruby code to take the original (and quite massive) CSV, and output smaller versions to test with. Now again, we’re no data scientists here but, we were able to cull out a good majority of the data and still get a model that performed at 95% accuracy. With our trained model in hand, we could serialize that to into a model.pkl file (pkl stands for “pickle”, as in we’ve “pickled” the model), move that file into our Rails app along with it a python script to deserialize it, pass in a dynamic set of data, and generate real-time predictions. At the end of the day, our model has a propensity to predict fantastic trail conditions (about 99% of the time in fact…). Just one of those optimistic machine learning models we guess. Where we go from here. It was clear that after two days, our team still wanted to do more. As a first refinement, we’d love to work more with our data set and ML model. Something that was quite surprising during the weekend was that we found we could remove all but two days worth of weather data, and all of the soil data we worked so hard to dig up, and still hit 95% accuracy. Which … doesn’t make a ton of sense. Perhaps the data we chose to predict trail conditions just isn’t a great empirical predictor of trail status. While these are questions too big to solve in just a single weekend, we'd love to spend more time digging into this in a future iteration. Full Article News & Culture