s Resumable File Uploads to Auphonic By feedproxy.google.com Published On :: Tue, 04 Sep 2018 09:39:53 +0000 Large file uploads in a web browser are problematic, even in 2018. If working with a poor network connection, uploads can fail and have to be retried from the start. At Auphonic, our users have to upload large audio and video files, or multiple media files when creating a multitrack production. To minimize any potential issues, we integrated various external services which are specialized for large file transfers, like FTP, SFTP, Dropbox, Google Drive, S3, etc. To further minimize issues, as of today we have also released resumable and chunked direct file uploads in the web browser to auphonic.com. If you are not interested in the technical details, please just go to the section Resumable Uploads in Auphonic below. The Problem with Large File Uploads in the Browser If using either mobile networks (which remain fragile) or unstable WiFi connections, file uploads are often interrupted and will fail. There are also many areas in the world where connections are quite poor, which makes uploading big files frustrating. After an interrupted file upload, the web browser must restart the whole upload from the start, which is a problem when it happens in the middle of a 4GB video file upload on a slow connection. Furthermore, the longer an upload takes, the more likely it is to have a network glitch interrupting the upload, which then has to be retried from the start. The Solution: Chunked, Resumable Uploads To avoid user frustration, we need to be able to detect network errors and potentially resume an upload without having to restart it from the beginning. To achieve this, we have to split a file upload in smaller chunks directly within the web browser, so that these chunks can then be sent to the server afterwards. If an upload fails or the user wants to pause, it is possible to resume it later and only send those chunks that have not already been uploaded. If there is a network interruption or change, the upload will be retried automatically. Companies like Dropbox, Google, Amazon AWS etc. all have their own protocols and API's for chunked uploads, but there are also some open source implementations available, which offer resumable uploads: resumable.js [link]: "A JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API" This solutions is a JavaScript library only and requires that the protocol is implemented on the server as well. tus.io [link]: "Open Protocol for Resumable File Uploads" Tus.io offers a simple, cheap and reusable stack for clients and servers (in many languages). They have a blog with further information about resumable uploads, see tus blog. plupload [link]: A JavaScript library, similar to resumable.js, which requires a separate server implementation. We chose to use resumable.js and developed our own server implementation. Resumable Uploads in Auphonic If you upload files to a singletrack or multitrack production, you will see the upload progress bar and a pause button, which is one way to pause and resume an upload: It is also possible to close the browser completely or shut down your computer during the upload, then edit the production and upload the file again later. This will just resume the file upload from the position where it was stopped before. (Previously uploaded chunks are saved for 24h on our servers, after that you have to start the whole upload again.) In case of a network problem or if you switch to a different connection, we will resume the upload automatically. This should solve many problems which were reported by some users in the past! You can of course also use any of our external services for stable incoming and outgoing file transfers! Do you still have Uploading Issues? We hope that uploads to Auphonic are much more reliable now, even on poor connections. If you still experience any problems, please let us know. We are very happy about any bug reports and will do our best to fix them! Full Article Development News
s Auphonic Adaptive Leveler Customization (Beta Update) By feedproxy.google.com Published On :: Mon, 05 Nov 2018 11:42:22 +0000 In late August, we launched the private beta program of our advanced audio algorithm parameters. After feedback by our users and many new experiments, we are proud to release a complete rework of the Adaptive Leveler parameters: In the previous version, we based our Adaptive Leveler parameters on the Loudness Range descriptor (LRA), which is included in the EBU R128 specification. Although it worked, it turned out that it is very difficult to set a loudness range target for diverse audio content, which does include speech, background sounds, music parts, etc. The results were not predictable and it was hard to find good target values. Therefore we developed our own algorithm to measure the dynamic range of audio signals, which works similarly for speech, music and other audio content. The following advanced parameters for our Adaptive Leveler allow you to customize which parts of the audio should be leveled (foreground, all, speech, music, etc.), how much they should be leveled (dynamic range), and how much micro-dynamics compression should be applied. To try out the new algorithms, please join our private beta program and let us know your feedback! Leveler Preset The Leveler Preset defines which parts of the audio should be adjusted by our Adaptive Leveler: Default Leveler: Our classic, default leveling algorithm as demonstrated in the Leveler Audio Examples. Use it if you are unsure. Foreground Only Leveler: This preset reacts slower and levels foreground parts only. Use it if you have background speech or background music, which should not be amplified. Fast Leveler: A preset which reacts much faster. It is built for recordings with fast and extreme loudness differences, for example, to amplify very quiet questions from the audience in a lecture recording, to balance fast-changing soft and loud voices within one audio track, etc. Amplify Everything: Amplify as much as possible. Similar to the Fast Leveler, but also amplifies non-speech background sounds like noise. Leveler Dynamic Range Our default Leveler tries to normalize all speakers to a similar loudness so that a consumer in a car or subway doesn't feel the need to reach for the volume control. However, in other environments (living room, cinema, etc.) or in dynamic recordings, you might want more level differences (Dynamic Range, Loudness Range / LRA) between speakers and within music segments. The parameter Dynamic Range controls how much leveling is applied: Higher values result in more dynamic output audio files (less leveling). If you want to increase the dynamic range by 3dB (or LU), just increase the Dynamic Range parameter by 3dB. We also like to call this Loudness Comfort Zone: above a maximum and below a minimum possible level (the comfort zone), no leveling is applied. So if your input file already has a small dynamic range (is within the comfort zone), our leveler will be just bypassed. Example Use Cases: Higher dynamic range values should be used if you want to keep more loudness differences in dynamic narration or dynamic music recordings (live concert/classical). It is also possible to utilize this parameter to generate automatic mixdowns with different loudness range (LRA) values for different target environments (very compressed ones like mobile devices or Alexa, very dynamic ones like home cinema, etc.). Compressor Controls Micro-Dynamics Compression: The compressor reduces the volume of short and loud spikes like "p", "t" or laughter ( short-term dynamics) and also shapes the sound of your voice (it will sound more or less "processed"). The Leveler, on the other hand, adjusts mid-term level differences, as done by a sound engineer, using the faders of an audio mixer, so that a listener doesn't have to adjust the playback volume all the time. For more details please see Loudness Normalization and Compression of Podcasts and Speech Audio. Possible values are: Auto: The compressor setting depends on the selected Leveler Preset. Medium compression is used in Foreground Only and Default Leveler presets, Hard compression in our Fast Leveler and Amplify Everything presets. Soft: Uses less compression. Medium: Our default setting. Hard: More compression, especially tries to compress short and extreme level overshoots. Use this preset if you want your voice to sound very processed, our if you have extreme and fast-changing level differences. Off: No short-term dynamics compression is used at all, only mid-term leveling. Switch off the compressor if you just want to adjust the loudness range without any additional micro-dynamics compression. Separate Music/Speech Parameters Use the switch Separate MusicSpeech Parameters (top right), to see separate Adaptive Leveler parameters for music and speech segments, to control all leveling details separately for speech and music parts: For dialog intelligibility improvements in films and TV, it is important that the speech/dialog level and loudness range is not too soft compared to the overall programme level and loudness range. This parameter allows you to use more leveling in speech parts while keeping music and FX elements less processed. Note: Speech, music and overall loudness and loudness range of your production are also displayed in our Audio Processing Statistics! Example Use Case: Music live recordings or dynamic music mixes, where you want to amplify all speakers (speech dynamic range should be small) but keep the dynamic range within and between music segments (music dynamic range should be high). Dialog intelligibility improvements for films and TV, without effecting music and FX elements. Other Advanced Audio Algorithm Parameters We also offer advanced audio parameters for our Noise, Hum Reduction and Global Loudness Normalization algorithms: For more details, please see the Advanced Audio Algorithms Documentation. Want to know more? If you want to know more details about our advanced algorithm parameters (especially the leveler parameters), please listen to the following podcast interview with Chris Curran (Podcast Engineering School): Auphonic’s New Advanced Features, with Georg Holzmann – PES 108 Advanced Parameters Private Beta and Feedback At the moment the advanced algorithm parameters are for beta users only. This is to allow us to get user feedback, so we can change the parameters to suit user needs. Please let us know your case studies, if you need any other algorithm parameters or if you have any questions! Here are some private beta invitation codes: jbwCVpLYrl 6zmLqq8o3z RXYIUbC6al QDmIZLuPKa JIrnGRZBgl SWQOWeZOBD ISeBCA9gTy w5FdsyhZVI qWAvANQ5mC twOjdHrit3 KwnL2Le6jB 63SE2V54KK G32AULFyaM 3H0CLYAwLU mp1GFNVZHr swzvEBRCVa rLcNJHUNZT CGGbL0O4q1 5o5dUjruJ9 hAggWBpGvj ykJ57cFQSe 0OHAD2u1Dx RG4wSYTLbf UcsSYI78Md Xedr3NPCgK mI8gd7eDvO 0Au4gpUDJB mYLkvKYz1C ukrKoW5hoy S34sraR0BU J2tlV0yNwX QwNdnStYD3 Zho9oZR2e9 jHdjgUq420 51zLbV09p4 c0cth0abCf 3iVBKHVKXU BK4kTbDQzt uTBEkMnSPv tg6cJtsMrZ BdB8gFyhRg wBsLHg90GG EYwxVUZJGp HLQ72b65uH NNd415ktFS JIm2eTkxMX EV2C5RAUXI a3iwbxWjKj X1AT7DCD7V y0AFIrWo5l We are happy to send further invitation codes to all interested users - please do not hesitate to contact us! If you have an invitation code, you can enter it here to activate the advanced audio algorithm parameters: Auphonic Algorithm Parameters Private Beta Activation Full Article Audio Development
s More Languages for Amazon Transcribe Speech Recognition By feedproxy.google.com Published On :: Thu, 31 Jan 2019 10:30:26 +0000 Until recently, Amazon Transcribe supported speech recognition in English and Spanish only. Now they included French, Italian and Portuguese as well - and a few other languages (including German) are in private beta. Update March 2019: Now Amazon Transcribe supports German and Korean as well. The Auphonic Audio Inspector on the status page of a finished Multitrack Production including speech recognition. Please click on the screenshot to see it in full resolution! Amazon Transcribe is integrated as speech recognition engine within Auphonic and offers accurate transcriptions (compared to other services) at low costs, including keywords / custom vocabulary support, word confidence, timestamps, and punctuation. See the following AWS blog post and video for more information about recent Amazon Transcribe developments: Transcribe speech in three new languages: French, Italian, and Brazilian Portuguese. Amazon Transcribe is also a perfect fit if you want to use our Transcript Editor because you will be able to see word timestamps and confidence values to instantly check which section/words should be corrected manually to increase the transcription accuracy: Screenshot of our Transcript Editor with word confidence highlighting and the edit bar. These features are also available if you use Speechmatics, but unfortunately not in our other integrated speech recognition services. About Speech Recognition within Auphonic Auphonic has built a layer on top of a few external speech recognition services to make audio searchable: Our classifiers generate metadata during the analysis of an audio signal (music segments, silence, multiple speakers, etc.) to divide the audio file into small and meaningful segments, which are processed by the speech recognition engine. The results from all segments are then combined, and meaningful timestamps, simple punctuation and structuring are added to the resulting text. To learn more about speech recognition within Auphonic, take a look at our Speech Recognition and Transcript Editor help pages or listen to our Speech Recognition Audio Examples. A comparison table of our integrated services (price, quality, languages, speed, features, etc.) can be found here: Speech Recognition Services Comparison. Conclusion We hope that Amazon and others will continue to add new languages, to get accurate and inexpensive automatic speech recognition in many languages. Don't hesitate to contact us if you have any questions or feedback about speech recognition or our transcript editor! Full Article Development News
s Advanced Multitrack Audio Algorithms Release (Beta) By feedproxy.google.com Published On :: Fri, 29 Mar 2019 10:16:41 +0000 Last weekend, at the Subscribe10 conference, we released Advanced Audio Algorithm Parameters for Multitrack Productions: We launched our advanced audio algorithm parameters for Singletrack Productions last year. Now these settings (and more) are available for Multitrack Algorithms as well, which gives you detailed control for each track of your production. The following new parameters are available: Fore/Background Settings: keep your music/clip tracks unchanged and set a custom background gain Multitrack Leveler Parameters: control the stereo panorama, leveling algorithm, dynamic range and compression Better Hum and Noise Reduction Controls for each track Maximum True Peak Level setting for the final mixdown Full API Support Please join our private beta program and let us know how you use these new features or if you need even more control! Fore/Background Settings The parameter Fore/Background controls whether a track should be in foreground, in background, ducked, or unchanged, which is especially important for music or clip tracks. For more details, please see Automatic Ducking, Foreground and Background Tracks . We now added the new option Unchanged and a new parameter to set the level of background segments/tracks: Unchanged (Foreground): We sometimes received complaints from users, which produced very complex music or clip tracks, that Auphonic changes the levels too hard. If you set the parameter Fore/Background to the new option Unchanged (Foreground), Level relations within this track won’t be changed at all. It will be added to the final mixdown so that foreground/solo parts of this track will be as loud as (foreground) speech from other tracks. Background Level: It is now possible to set the level of background segments/tracks (compared to foreground segments) in background and ducking tracks. By default, background and ducking segments are 18dB softer than foreground segments. Leveler Parameters Similar to our Singletrack Advanced Leveler Parameters (see this previous blog post), we also released leveling parameters for Multitrack Productions now. The following advanced parameters for our Multitrack Adaptive Leveler can be set for each track and allow you to customize which parts of the audio should be leveled, how much they should be leveled, how much dynamic range compression should be applied and to set the stereo panorama (balance): Leveler Preset: Select the Speech or Music Leveler for this track. If set to Automatic (default), a classifier will decide if this is a music or speech track. Dynamic Range: The parameter Dynamic Range controls how much leveling is applied: Higher values result in more dynamic output audio files (less leveling). If you want to increase the dynamic range by 3dB (or LU), just increase the Dynamic Range parameter by 3dB. For more details, please see Multitrack Leveler Parameters. Compressor: Select a preset for Micro-Dynamics Compression: Auto, Soft, Medium, Hard or Off. The Compressor adjusts short-term dynamics, whereas the Leveler adjusts mid-term level differences. For more details, please see Multitrack Leveler Parameters. Stereo Panorama (Balance): Change the stereo panorama (balance for stereo input files) of the current track. Possible values: L100, L75, L50, L25, Center, R25, R50, R75 and R100. If you understand German and want to know more about our Advanced Leveler Parameters and audio dynamics in general, watch our talk at the Subscribe10 conference: Video: Audio Lautheit und Dynamik. Better Hum and Noise Reduction Controls We now offer three parameters to control the combination of our Multitrack Noise and Hum Reduction Algorithms for each input track: Noise Reduction Amount: Maximum noise and hum reduction amount in dB, higher values remove more noise. In Auto mode, a classifier decides if and how much noise reduction is necessary (to avoid artifacts). Set to a custom (non-Auto) value if you prefer more noise reduction or want to bypass our classifier. Hum Base Frequency: Set the hum base frequency to 50Hz or 60Hz (if you know it), or use Auto to automatically detect the hum base frequency in each speech region. Hum Reduction Amount: Maximum hum reduction amount in dB, higher values remove more noise. In Auto mode, a classifier decides how much hum reduction is necessary in each speech region. Set it to a custom value (> 0), if you prefer more hum reduction or want to bypass our classifier. Use Disable Dehum to disable hum reduction and use our noise reduction algorithms only. Behavior of noise and hum reduction parameter combinations: Noise Reduction Amount Hum Base Frequency Hum Reduction Amount Auto Auto Auto Automatic hum and noise reduction Auto or > 0 * Disabled No hum reduction, only denoise Disabled 50Hz Auto or > 0 Force 50Hz hum reduction, no denoise Disabled Auto Auto or > 0 Automatic dehum, no denoise 12dB 60Hz Auto or > 0 Always do dehum (60Hz) and denoise (12dB) Maximum True Peak Level In the Master Algorithm Settings of your multitrack production, you can set the maximum allowed true peak level of the processed output file, which is controlled by the True Peak Limiter after our Loudness Normalization algorithms. If set to Auto (which is the current default), a reasonable value according to the selected loudness target is used: -1dBTP for 23 LUFS (EBU R128) and higher, -2dBTP for -24 LUFS (ATSC A/85) and lower loudness targets. Full API Support All advanced algorithm parameters, for Singletrack and Multitrack Productions, are available in our API as well, which allows you to integrate them into your scripts, external workflows and third-party applications. Singletrack API: Documentation on how to use the advanced algorithm parameters in our singletrack production API: Advanced Algorithm Parameters Multitrack API: Documentation of advanced settings for each track of a multitrack production: Multitrack Advanced Audio Algorithm Settings Join the Beta and Send Feedback Please join our beta and let us know your case studies, if you need any other algorithm parameters or if you have any questions! Here are some private beta invitation codes: 8tZPc3T9pH VAvO8VsDg9 0TwKXBW4Ni kjXJMivtZ1 J9APmAAYjT Zwm6HabuFw HNK5gF8FR5 Do1MPHUyPW CTk45VbV4t xYOzDkEnWP 9XE4dZ0FxD 0Sl3PxDRho uSoRQxmKPx TCI62OjEYu 6EQaPYs7v4 reIJVOwIr8 7hPJqZmWfw kti3m5KbNE GoM2nF0AcN xHCbDC37O5 6PabLBRm9P j2SoI8peiY olQ2vsmnfV fqfxX4mWLO OozsiA8DWo weJw0PXDky VTnOfOiL6l B6HRr6gil0 so0AvM1Ryy NpPYsInFqm oFeQPLwG0k HmCOkyaX9R G7DR5Sc9Kv MeQLSUCkge xCSvPTrTgl jyQKG3BWWA HCzWRxSrgW xP15hYKEDl 241gK62TrO Q56DHjT3r4 9TqWVZHZLE aWFMSWcuX8 x6FR5OTL43 Xf6tRpyP4S tDGbOUngU0 5BkOF2I264 cccHS0KveO dT29cF75gG 2ySWlYp1kp iJWPhpAimF We are happy to send further invitation codes to all interested users - please do not hesitate to contact us! If you have an invitation code, you can enter it here to activate the Multitrack Advanced Audio Algorithm Parameters: Auphonic Algorithm Parameters Private Beta Activation Full Article Audio Development News
s The New Loudness Target War By feedproxy.google.com Published On :: Wed, 12 Jun 2019 09:32:51 +0000 In the classic loudness war, music and radio producers have been trying to create their recordings as loud as possible and loudness normalization was introduced to stop that. Now one can see the start of a new loudness target war, where podcasters set their loudness targets higher and higher, mainly triggered by high target recommendations of platforms like Spotify or Amazon Alexa. In this article, we will show how to resist the loudness target war and still be compliant with major platforms. Resist the loudness target war! (Photo by Nayani Teixeira) What's the problem? “Two or three years ago it seemed that many stations were finally realizing that better radio could improve ratings. And the major myth brought over from AM radio – that a louder signal, regardless of quality, attracts more listeners – appeared to be losing its strength,” writes Robert Orban. The times of excessively compressed audio, putting loudness over sound quality, were coming to an end. We were hoping the same when we wrote about the CALM Act and EBU R128 in 2012. Those measures were meant to make programs sound more evened out and set a standard for a reasonable loudness level. Except, Orban's article was published in 1979 (PDF, p. 60 ff.), and he concludes: "The loudness war has escalated, and quality is once again being sacrificed." 40 years later, a new loudness target war is emerging. While, yes, radio and TV stations have widely adopted the new standards, prominent competitors in the audio market are pushing for higher loudness targets once again. Loudness war: the trend of increasing audio levels in recorded music over time. (Screenshot delamar.de) Why LOUDER is not better Historically, the loudness war has escalated with the advent of digital technology. Peak level normalization and quasi peak program meters (QPPM) encouraged producers to push audio signals to the limit. Just shy of clipping, signals could now be compressed to the highest possible levels, using multiband compressors and limiters. While this lifted quieter signals up, transforming a waveform into a brick, marketers thought that the louder songs on CDs and almost yelling voices on FM radio would attract listeners. On the other hand, reduced dynamics makes audio less interesting and can lead to listener fatigue, as Rip Rowan pointedly illustrated in his 2002 article "Over the Limit": WHY IS THE LOUDER IS BETTER APPROACH THE WRONG APPROACH? BECAUSE WHEN ALL OF THE SIGNAL IS AT THE MAXIMUM LEVEL, THEN THERE IS NO WAY FOR THE SIGNAL TO HAVE ANY PUNCH. THE WHOLE THING COMES SCREAMING AT YOU LIKE A MESSAGE IN ALL CAPITAL LETTERS. AS WE ALL KNOW, WHEN YOU TYPE IN ALL CAPITAL LETTERS THERE ARE NO CUES TO HELP THE BRAIN MAKE SENSE OF THE SIGNAL, AND THE MIND TIRES QUICKLY OF TRYING TO PROCESS WHAT IS, BASICALLY, WHITE NOISE. LIKEWISE, A SIGNAL THAT JUST PEGS THE METERS CAUSES THE BRAIN TO REACT AS THOUGH IT IS BEING FED WHITE NOISE. WE SIMPLY FILTER IT OUT AND QUIT TRYING TO PROCESS IT. Hence, many spoken word producers and broadcasters luckily wisened up and committed to new standards, based on loudness normalization instead of peak normalization. LUFS, Loudness Units relative to Full Scale, is a unit that measures an audio track's average loudness. All segments of a program can then be normalized to a certain LUFS value. As we have discussed before, -23 LUFS is standard now for broadcasters of the EBU, which for example has led to advertising segments no longer being much louder than the rest of any particular program. For a short while, it seemed like a peace agreement, or at least a truce had been achieved in the loudness war. Human loudness perception is based on average levels instead of peak levels. (Screenshot theproaudiofiles.com) Loudness Targets and Dynamic Range However, while LUFS adoption is increasing across the industry, this doesn't mean that people have stopped trying to be louder than everybody else. And indeed -23 LUFS is not the one-size-fits-all value. We have recommended -16 LUFS for podcasts ourselves. The loudness of a production played in a cinema should be different from one made for earphones and noisy listening environments. Some headphones expect a louder signal and don't have enough gain to work with -23 LUFS under all circumstances. The closer a production gets to 0 LUFS though, the less dynamic range can be reproduced. However, the dynamic range also depends on the dBTP, the maximum True Peak level, which indicates the level of the highest possible peak value. For instance, the aforementioned EBU R128 standard of -23 LUFS also defines a -1 dBTP. The difference between the LUFS and dBTP levels is called Peak to Loudness Range, PLR. For EBU R128 the PLR would be 22 LU (Loudness Units), a podcast with -16 LUFS and -1 dBTP has a PLR of 15 LU. Thus, the PLR is a measure of the maximum possible dynamic range of an audio production. Platforms: Apple, Google, Amazon, and Spotify Our already pretty high recommendation of -16 LUFS, -1 dBTP for mobile listening was also adopted by Apple's best practices for podcasts and recommendations for Google Assistant. Some are pushing it too far, though. A daily updated analysis by podnews shows that many podcasts are much louder than -16 LUFS. Distribution of loudness across a selection of podcasts. (Screenshot podnews.net) This might in part be due to specs published by other competitors in the audio space: Amazon, for instance, recommends -14 LUFS at -2 dBTP for Alexa skills, meaning a PLR of only 12 LU. While this might work for Alexa's synthesized voice, which doesn't have much variability, it produces a dynamic range too low for spoken word content. However, Amazon also says that a skill may be rejected if the program loudness is lower -19 LUFS or higher -9 LUFS, therefore a target of -16 LUFS is perfectly fine, which means that Alexa's robot voice leads by 2 LU compared to the audio content. Spotify normalizes audio to the equivalent of about -14 LUFS, -1 dbTP, but they still use ReplayGain, which is not exactly the same as LUFS but gives similar results. Spotify mainly decreases the volume of overly loud productions, but can also increase the volume on some playback devices if the audio is much too soft. For pop music, -14 LUFS is acceptable, but for podcasts or classical music, it is too high. However, (pop) music can always be played a bit louder compared to speech, therefore a loudness target of -16 LUFS for podcasts is fine on Spotify as well. Make LUFS, not war If producers just use the highest recommended target and therefore the loudness (target) war goes into another battle, we will hear more compressed, distorted voices once again, lacking emotion and many subtleties that are reflected in the dynamic range of how we speak. Setting a loudness target higher than -16 LUFS does not improve the listening experience in any way. However, many productions would benefit from sensitively adjusting differences in dynamics throughout the production, lifting up quieter segments, lowering loud segments, and treating speech and music differently. As pointed out in a presentation recently (video, in German), you can do that directly in your DAW or use a leveler to automate dynamics processing. Instead of just raising the loudness target, adjusting differences in levels can help to make the listening experience much more enjoyable. Recent album releases suggest that the music industry is still in the middle of the loudness war, often limiting the peak to loudness range to single digit LU values. (By the way, your vinyl-buying friend is right, vinyl records do sound better because they don't work with the highest compression rates.) Hopefully, podcasters, radio producers and other spoken word artists, as well as the platforms that host and publish their productions, can resist the temptation of louder and louder audio. Make (no more than -16) LUFS, not war! Conclusion With some podcasts, smart speakers and streaming platforms trying to be louder than the competition, the listening experience deteriorates. However, podcasts can sound great and loud enough even in noisy environments, when well produced: Never set a loudness target higher than -16 LUFS for spoken word audio. If your audio is too quiet, try lifting up quieter sections and reducing the volume of louder sections, directly in your DAW or by using a leveler. These settings will work fine on all current platforms, including Amazon Alexa and Spotify. Resist the loudness target war! Full Article Audio
s Dynamic Range Processing in Audio Post Production By feedproxy.google.com Published On :: Mon, 19 Aug 2019 06:35:36 +0000 If listeners find themselves using the volume up and down buttons a lot, level differences within your podcast or audio file are too big. In this article, we are discussing why audio dynamic range processing (or leveling) is more important than loudness normalization, why it depends on factors like the listening environment and the individual character of the content, and why the loudness range descriptor (LRA) is only reliable for speech programs. Photo by Alexey Ruban. Why loudness normalization is not enough Everybody who has lived in an apartment building knows the problem: you want to enjoy a movie late at night, but you're constantly on the edge - not only because of the thrilling story, but because your index finger is hovering over the volume down button of your remote. The next loud sound effect is going to come sooner rather than later, and you want to avoid waking up your neighbors with some gunshot sounds blasting from your TV. In our previous post, we talked about the overall loudness of a production. While that's certainly important to keep in mind, the loudness target is only an average value, ignoring how much the loudness varies within a production. The loudness target of your movie might be in the ideal range, yet the level differences between a gunshot and someone whispering can still be enormous - having you turn the volume down for the former and up for the latter. While the average loudness might be perfect, level differences can lead to an unpleasant listening experience. Of course, this doesn't apply to movies alone. The image above shows a podcast or radio production. The loud section is music, the very quiet section just breathing, and the remaining sections are different voices. To be clear, we're not saying that the above example is problematic per se. There are many situations, where a big difference in levels - a high dynamic range - is justified: for instance, in a movie theater, optimized for listening and without any outside noise, or in classical music. Also, if the dynamic range is too small, listening can be tiring. But if you watch the same movie in an outdoor screening in the summer on a beach next to the crashing waves or in the middle of a noisy city, it can be tricky to hear the softer parts. Spoken word usually has a smaller dynamic range, and if you produce your podcast for a target audience of train or car commuters, the dynamic range should be even smaller, adjusting for the listening situation. Therefore, hitting the loudness target has less impact on the listening experience than level differences (dynamic range) within one file! What makes a suitable dynamic range does not only depend on the listening environment, but also on the nature of the content itself. If the dynamic range is too small, the audio can be tiring to listen to, whereas more variability in levels can make a program more interesting, but might not work in all environments, such as a noisy car. Dynamic range experiment in a car Wolfgang Rein, audio technician at SWR, a public broadcaster in Germany, did an experiment to test how drivers react to programs with different dynamic ranges. They monitored to what level drivers set the car stereo depending on speed (thus noise level) and audio dynamic range. While the results are preliminary, it seems like drivers set the volume as low as possible so that they can still understand the content, but don't get distracted by loud sounds. As drivers adjust the volume to the loudest voice in a program, they won't understand quieter speakers in content with a high dynamic range anymore. To some degree and for short periods of time, they can compensate by focusing more on the radio program, but over time that's tiring. Therefore, if the loudness varies too much, drivers tend to switch to another program rather than adjusting the volume. Similar results have been found in a study conducted by NPR Labs and Towson University. On the other hand, the perception was different in pure music programs. When drivers set the volume according to louder parts, they weren't able to hear softer segments or the beginning of a song very well. But that did not matter to them as much and didn't make them want to turn up the volume or switch the program. Listener's reaction in response to frequent loudness changes. (from John Kean, Eli Johnson, Dr. Ellyn Sheffield: Study of Audio Loudness Range for Consumers in Various Listening Modes and Ambient Noise Levels) Loudness comfort zone The reaction of drivers to variable loudness hints at something that BBC sound engineer Mike Thornton calls the loudness comfort zone. Tests (...) have shown that if the short-term loudness stays within the "comfort zone" then the consumer doesn’t feel the need to reach for the remote control to adjust the volume. In a blog post, he highlights how the series Blue Planet 2 and Planet Earth 2 might not always have been the easiest to listen to. The graph below shows an excerpt with very loud music, followed by commentary just at the bottom of the green comfort zone. Thornton writes: "with the volume set at a level that was comfortable when the music was playing we couldn’t always hear the excellent commentary from Sir David Attenborough and had to resort to turning on the subtitles to be sure we knew what Sir David was saying!" Planet Earth 2 Loudness Plot Excerpt. Colored green: comfort zone of +3 to -5LU around the loudness target. (from Mike Thornton: BBC Blue Planet 2 Latest Show In Firing Line For Sound Issues - Are They Right?) As already mentioned above, a good mix considers the maximum and minimum possible loudness in the target listening environment. In a movie theater the loudness comfort zone is big (loudness can vary a lot), and loud music is part of the fun, while quiet scenes work just as well. The opposite was true in the aforementioned experiment with drivers, where the loudness comfort zone is much smaller and quiet voices are difficult to understand. Hence, the loudness comfort zone determines how much dynamic range an audio signal can use in a specific listening environment. How to measure dynamic range: LRA When producing audio for various environments, it would be great to have a target value for dynamic range, (the difference between the smallest and largest signal values of an audio signal) as well. Then you could just set a dynamic range target, similarly to a loudness target. Theoretically, the maximum possible dynamic range of a production is defined by the bit-depth of the audio format. A 16-bit recording can have a dynamic range of 96 dB; for 24-bit, it's 144 dB - which is well above the approx. 120 dB the human ear can handle. However, most of those bits are typically being used to get to a reasonable base volume. Picture a glass of water: you want it to be almost full, with some headroom so that it doesn't spill when there's a sudden movement, i.e. a bigger amplitude wave at the top. Determining the dynamic range of a production is easier said than done, though. It depends on which signals are included in the measurement: for example, if something like background music or breathing should be considered at all. The currently preferred method for broadcasting is called Loudness Range, LRA. It is measured in Loudness Units (LU), and takes into account everything between the 10th and the 95th percentile of a loudness distribution, after an additional gating method. In other words, the loudest 5% and quietest 10% of the audio signal are being ignored. This way, quiet breathing or an occasional loud sound effect won't affect the measurement. Loudness distribution and LRA for the film 'The Matrix'. Figure from EBU Tech Doc 3343 (p.13). However, the main difficulty is which signals should be included in the loudness range measurement and which ones should be gated. This is unfortunately often very subjective and difficult to define with a purely statistical method like LRA. Where LRA falls short Therefore, only pure speech programs give reliable LRA values that are comparable! For instance, a typical LRA for news programs is 3 LU; for talks and discussions 5 LU is common. LRA values for features, radio dramas, movies or music very much depend on the individual character and might be in the range between 5 and 25 LU. To further illustrate this, here are some typical LRA values, according to a paper by Thomas Lund (table 2): ProgramLoudness Range Matrix, full movie25.0 NBC Interstitials, Jan. 2008, all together (3:30)9.4 Friends Episode 166.6 Speak Ref., Male, German, SQUAM Trk 546.2 Speak Ref., Female, French, SQUAM Trk 514.8 Speak Ref., Male, English, Sound Check3.3 Wish You Were Here, Pink Floyd22.1 Gilgamesh, Battle of Titans, Osaka Symph.19.7 Don’t Cry For Me Arg., Sinead O’Conner13.7 Beethoven Son in F, Op17, Kliegel & Tichman12.0 Rock’n Roll Train, AC/DC6.0 I.G.Y., Donald Fagen3.6 LRA values of music are very unpredictable as well. For instance, Tom Frampton measured the LRA of songs in multiple genres, and the differences within each genre are quite big. The ten pop songs that he analyzed varied in LRA between 3.7 and 12 LU, country songs between 3.6 and 14.9 LU. In the Electronic genre the individual LRAs were between 3.7 and 15.2 LU. Please see the tables at the bottom of his blog post for more details. We at Auphonic also tried to base our Adaptive Leveler parameters on the LRA descriptor. Although it worked, it turned out that it is very difficult to set a loudness range target for diverse audio content, which does include speech, background sounds, music parts, etc. The results were not predictable and it was hard to find good target values. Therefore we developed our own algorithm to measure the dynamic range of audio signals. In conclusion, LRA comparisons are only useful for productions with spoken word only and the LRA value is therefore not applicable as a general dynamic range target value. The more complex a production gets, the more difficult it is to make any judgment based on the LRA. This is, because the definition of LRA is purely statistical. There's no smart measurement using classifiers that distinguish between music, speech, quiet breathing, background noises and other types of audio. One would need a more intelligent algorithm (as we use in our Adaptive Leveler), that knows which audio segments should be included and excluded from the measurement. From theory to application: tools Loudness and dynamic range clearly is a complicated topic. Luckily, there are tools that can help. To keep short-term loudness in range, a compressor can help control sudden changes in loudness - such as p-pops or consonants like t or k. To achieve a good mid-term loudness, i.e. a signal that doesn't go outside the comfort zone too much, a leveler is a good option. Or, just use a fader or manually adjust volume curves. And to make sure that separate productions sound consistent, loudness normalization is the way to go. We have covered all of this in-depth before. Looking at the audio from above again, with an adaptive leveler applied it looks like this: Leveler example. Output at the top, input with leveler envelope at the bottom. Now, the voices are evened out and the music is at a comfortable level, while the breathing has not been touched at all. We recently extended Auphonic's adaptive leveler, so that it is now possible to customize the dynamic range - please see adaptive leveler customization and advanced multitrack audio algorithms. If you wanted to increase the loudness comfort zone (or dynamic range) of the standard preset by 10 dB (or LU), for example, the envelope would look like this: Leveler with higher dynamic range, only touching sections with extremely low or extremely high loudness to fit into a specific loudness comfort zone. When a production is done, our adaptive leveler uses classifiers to also calculate the integrated loudness and loudness range of dialog and music sections separately. This way it is possible to just compare the dialog LRA and loudness of complex productions. Assessing the LRA and loudness of dialog and music separately. Conclusion Getting audio dynamics right is not easy. Yet, it is an important thing to keep in mind, because focusing on loudness normalization alone is not enough. In fact, hitting the loudness target often has less impact on the listening experience than level differences, i.e. audio dynamics. If the dynamic range is too small, the audio can be tiring to listen to, whereas a bigger dynamic range can make a program more interesting, but might not work in loud environments, such as a noisy train. Therefore, a good mix adapts the audio dynamic range according to the target listening environment (different loudness comfort zones in cinema, at home, in a car) and according to the nature of the content (radio feature, movie, podcast, music, etc.). Furthermore, because the definition of the loudness range / LRA is purely statistical, only speech programs give reliable LRA values that are comparable. More "intelligent" algorithms are in development, which use classifiers to decide which signals should be included and excluded from the dynamic range measurement. If you understand German, take a look at our presentation about audio dynamic processing in podcasts for further information: Full Article Audio
s Winter Stand Up Paddling on Horsetooth Reservoir By feedproxy.google.com Published On :: Wed, 19 Feb 2020 23:34:52 +0000 I love paddling on the Horsetooth Reservoir in cold season. Boat ramps are closed, no power boat traffic, usually quiet and calm. Snow and ice can enhance scenery. A great time to paddle, train, relax or photograph. The Horsetooth stays […] Full Article SUP trip reports cold water Colorado Horsetooth Horsetooth Reservoir photography winter
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
s Our WFH Best Practices By feedproxy.google.com Published On :: Fri, 20 Mar 2020 08:00:00 -0400 Our first remote office opened in 2007 when a designer and a developer left our HQ office and moved to Durham. Ever since we've been fine-tuning our ability to collaborate across locations. Today, we have team members across the country in our four offices, and we have fully remote employees in Charleston, Kansas City, New York City, Dallas, and Charlottesville. Because of the coronavirus outbreak, a lot of people recently started working from their homes across the world, the country, and Viget. We wanted to share some of our best practices for being great teammates and doing great work, regardless of locale, and we’d love to hear yours in the comments. Communicate Often and Write It Down We want every person at Viget to be informed and connected. We do this in a few ways. We have a company Knowledge Base, which contains critical information including HR policies, office processes, brand guidelines, project resources, etc. We also have a well-organized Google Drive that everyone can access. 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. My favorite communication tool we use, however, is our Internal Lab Report. Every week, we create a Google Doc with HR updates, birthdays, upcoming events we’re attending, relevant publicity we or a client received, and timely updates on projects, sales, and recruiting. This report allows the entire team to have the same information, regardless of PTO schedules, and it provides a record that can be referenced weeks, months, or years later. I have also found our Slack habits really helpful. We try to make our availability easily known, mostly via a passive Slack status. We each update our status daily, sometimes multiple times, so people can see if we’re working from home, out of the office for an appointment, in a meeting, or offline for a personal phone call. We also have a few Slack Channels we use very specifically to announce PTO, important announcements, and recently, one that is specific to the updating coronavirus situation. My work from home station. Figure Out Your Boundaries This looks different for everyone and can be an ever-changing target. Understanding your boundaries requires you to be honest with yourself – Are you easily distracted? Can you successfully work in pajama pants? Will your dog actually allow you to get work done? Does working from the couch result in good work, or do you need a designated work spot? For some, working from home requires setting boundaries to ensure the work gets done. For others, working from home requires setting a start and stop times to ensure you don’t overwork yourself. Viget has a flexible work policy, so many of us work from home fairly often and have gotten our routines set up. As such, we have written about this before! Check out Trevor’s article about working remotely.Show Your Face When I first started at Viget, I’d never worked anywhere that used a Google Hangout for nearly every meeting. At first, I was tempted to call into meetings and leave the camera off because I found it exposing. Now, I can’t imagine not using it, and I’ve even embraced it in my personal life with friends and family. I realized the value in face-to-face conversations even in virtual form, the ability to see body language, and the connection you establish when you see each other's faces — even if your hair isn't perfect or you haven't arranged your plants just-so in the view behind you. Whenever possible, use your camera during a meeting. It increases trust, communication, and in my personal-not-backed-by-science-opinion, lightness, which frankly, I think we can all use a bit more of right now. Here's a screen shot from our Saint Patrick's Day Happy Hour. Create Shared Experiences As a company with project teams often distributed across our four locations, cross-office experiences are vital to our culture, and we’ve spent years working to keep our remote offices in sync. A few of our ongoing group activities include a monthly virtual Book Club, our weekly full-team Free Lunch Friday tradition, Donut for Slack, and, of course, our Pointless Weekends. The current global health crisis now requires almost all of the company to work remote, so we’ve gotten creative with our attempts to increase non-project time together, in order to keep up the vibes we’ve worked hard to create. What we’ve recently started: Last Weekend this Morning - Monday mornings, we have an optional virtual coffee, where anyone who’d like to chat can join and share the latest gardening lesson or bingeable tv show. It lets us start our week off as we would when we’re all in the office — saying hello to each other.Virtual Happy Hours - We are a company that likes to socialize, and a bit of distance doesn’t stop us. This week, we set up an after-hours Happy Hour for St. Patrick’s Day.Daily Lunch Table- If you’ve ever visited our HQ office in Falls Church, you’ll notice our large kitchen table. We have an informal tradition of gathering around noon to eat together, whether it’s just a couple folks or the whole team. We now do this lunch virtually. So far, we’re mostly taking turns discussing who is eating what, and of course, sharing said recipes. I crowdsourced some ideas from the Viget team, and here are some noteworthy takeaways: "In remote meetings, minimize all your other windows and be fully present. It’s easy to allow your attention to accidentally drift if you see a new Slack channel light up, especially if you’re in a larger meeting. Suddenly, you find yourself multitasking. Treat the meeting as if you were there in person: unless you’re taking notes, minimize your other tabs, and give the conversation your full attention." - Paul Koch “I try to reach out to more folks I don’t consistently work with. Since there’s less interaction in general, I want to be more intentional about staying connected.” - Laura Sweltz “Good habits are hard to form and bad habits are hard to break, and it’s often hard to find the right time to make a change. Most of us are experiencing a disruption to our usual behaviors right now, but that doesn’t have to be entirely bad. Be deliberate now and when this is over, we might all end up with some new work habits worth keeping.” - Emily Bloom “I’ve found it helpful to create a physical space similar to the one I had at work. While this isn’t exactly possible, small things like setting up a laptop stand and second screen make it so I’m less likely to get distracted and wander to the couch or kitchen (aka the snack danger zone.).” - Aubrey Lear “It’s easy to get stuck in one spot all day, so be proactive about moving around, or creating excuses to do so. Whether that’s making yourself a cup of coffee, eating lunch away from your computer, or going for a quick walk outside for some fresh air. This will help reduce the risk of going stir crazy.” -Zach Robbins True to Viget form, our remote work is all about “Progress, Not Perfection.” While remote collaboration is ingrained in our company, we’re looking for opportunities to fine-tune our approach and improve our habits. We’d love to hear from you: What are your best practices? Lessons learned? Full Article Process
s CLI Equivalents for Common MAMP PRO and Sequel Pro Tasks By feedproxy.google.com Published On :: Thu, 26 Mar 2020 00:00:00 -0400 Working on website front ends I sometimes use MAMP PRO to manage local hosts and Sequel Pro to manage databases. Living primarily in my text editor, a terminal, and a browser window, moving to these click-heavy dedicated apps can feel clunky. Happily, the tasks I have most frequently turned to those apps for —starting and stopping servers, creating new hosts, and importing, exporting, deleting, and creating databases— can be done from the command line. I still pull up MAMP PRO if I need to change a host's PHP version or work with its other more specialized settings, or Sequel Pro to quickly inspect a database, but for the most part I can stay on the keyboard and in my terminal. Here's how: Command Line MAMP PRO You can start and stop MAMP PRO's servers from the command line. You can even do this when the MAMP PRO desktop app isn't open. Note: MAMP PRO's menu icon will not change color to reflect the running/stopped status when the status is changed via the command line. Start the MAMP PRO servers: /Applications/MAMP PRO.app/Contents/MacOS/MAMP PRO cmd startServers Stop the MAMP PRO servers: /Applications/MAMP PRO.app/Contents/MacOS/MAMP PRO cmd stopServers Create a host (replace host_name and root_path): /Applications/MAMP PRO.app/Contents/MacOS/MAMP PRO cmd createHost host_name root_path MAMP PRO-friendly Command Line Sequel Pro Note: if you don't use MAMP PRO, just replace the /Applications/MAMP/Library/bin/mysql with mysql. In all of the following commands, replace username with your user name (locally this is likely root) and database_name with your database name. The -p (password) flag with no argument will trigger an interactive password prompt. This is more secure than including your password in the command itself (like -pYourPasswordHere). Of course, if you're using the default password root is not particular secure to begin with so you might just do -pYourPasswordHere. Setting the -h (host) flag to localhost or 127.0.0.1 tells mysql to look at what's on localhost. With the MAMP PRO servers running, that will be the MAMP PRO databases. # with the MAMP PRO servers running, these are equivalent: # /Applications/MAMP/Library/bin/mysql -h 127.0.0.1 other_options # and # /Applications/MAMP/Library/bin/mysql -h localhost other_options /Applications/MAMP/Library/bin/mysql mysql_options # enter. opens an interactive mysql session mysql> some command; # don't forget the semicolon mysql> exit; Create a local database # with the MAMP PRO servers running # replace `username` with your username, which is `root` by default /Applications/MAMP/Library/bin/mysql -h localhost -u username -p -e "create database database_name" or # with the MAMP PRO servers running # replace `username` (`root` by default) and `database_name` /Applications/MAMP/Library/bin/mysql -h localhost -u username -p # and then enter mysql> create database database_name; # don't forget the semicolon mysql> exit MAMP PRO's databases are stored in /Library/Application Support/appsolute/MAMP PRO/db so to confirm that it worked you can ls /Library/Application Support/appsolute/MAMP PRO/db # will output the available mysql versions. For example I have mysql56_2018-11-05_16-25-13 mysql57 # If it isn't clear which one you're after, open the main MAMP PRO and click # on the MySQL "servers and services" item. In my case it shows "Version: 5.7.26" # Now look in the relevant MySQL directory ls /Library/Application Support/appsolute/MAMP PRO/db/mysql57 # the newly created database should be in the list Delete a local database # with the MAMP PRO servers running # replace `username` (`root` by default) and `database_name` /Applications/MAMP/Library/bin/mysql -h localhost -u username -p -e "drop database database_name" Export a dump of a local database. Note that this uses mysqldump not mysql. # to export an uncompressed file # replace `username` (`root` by default) and `database_name` /Applications/MAMP/Library/bin/mysqldump -h localhost -u username -p database_name > the/output/path.sql # to export a compressed file # replace `username` (`root` by default) and `database_name` /Applications/MAMP/Library/bin/mysqldump -h localhost -u username -p database_name | gzip -c > the/output/path.gz Export a local dump from an external database over SSH. Note that this uses mysqldump not mysql. # replace `ssh-user`, `ssh_host`, `mysql_user`, `database_name`, and the output path # to end up with an uncompressed file ssh ssh_user@ssh_host "mysqldump -u mysql_user -p database_name | gzip -c" | gunzip > the/output/path.sql # to end up with a compressed file ssh ssh_user@ssh_host "mysqldump -u mysql_user -p database_name | gzip -c" > the/output/path.gz Import a local database dump into a local database # with the MAMP PRO servers running # replace `username` (`root` by default) and `database_name` /Applications/MAMP/Library/bin/mysql -h localhost -u username -p database_name < the/dump/path.sql Import a local database dump into a remote database over SSH. Use care with this one. But if you are doing it with Sequel Pro —maybe you are copying a Craft site's database from a production server to a QA server— you might as well be able to do it on the command line. ssh ssh_user@ssh_host "mysql -u username -p remote_database_name" < the/local/dump/path.sql For me, using the command line instead of the MAMP PRO and Sequel Pro GUI means less switching between keyboard and mouse, less opening up GUI features that aren't typically visible on my screen, and generally better DX. Give it a try! And while MAMP Pro's CLI is limited to the essentials, command line mysql of course knows no limits. If there's something else you use Sequel Pro for, you may be able to come up with a mysql CLI equivalent you like even better. Full Article Code Front-end Engineering Back-end Engineering
s Scurry: A Race-To-Finish Scavenger Hunt App By feedproxy.google.com Published On :: Thu, 26 Mar 2020 13:58:00 -0400 We have a lot of traditions here at Viget, many of which you may have read about - TTT, FLF, Pointless Weekend. There are others, but you have to be an insider for more information on those. Pointless Weekend is one of our favorite traditions, though. It’s been around over a decade and some pretty fun work has come out of it over the years, like Storyboard, Baby Bookie, and Short Order. At a high level, we take 48 hours to build a tool, experiment, or stunt as a team, across all four of our offices. These projects are entirely separate from our client work and we use them to try out new technologies, explore roles on the team, and stress-test our processes. The first step for a Pointless Weekend is assembling the teams. We had two teams this year, with a record number of participants. You can read about TrailBuddy, what the other team built, here. The Scurry team was split between the DC and Durham offices, so all meetings were held via Hangout. Once we were assembled, we set out to understand the constraints and the goals of our Pointless Project. We went into this weekend with an extra pep in our step, as we were determined to build something for the upcoming Viget 20th anniversary TTT this summer. Here’s what we knew we wanted: An activity all Vigets could do together, where they could create memories, and share broadly on socialSomething that we could use in a spotty network at C Lazy U Ranch in ColoradoA product we can share with others: corporate groups, families and friends, schools, bachelor/ette parties We landed on a scavenger hunt native app, which we named Scurry (Scavenger + Hurry = Scurry. Brilliant, right?). There are already a few scavenger apps available, so we set out to create something that was Quick and easy to set up huntsFree and intuitive for usersA nice combination of trivia and activitiesSocial! We wanted to enable teams to share photos and progress One of the main reasons we have Pointless Weekends is to test out new technologies and processes. In that vein, we tried out Notion as our central organizing tool - we used it for user journeys, data modeling, and even writing tickets, which we typically use Github for. We tested out Notion as our primary tool, writing tickets and tracking progress. When we built the app, we needed to prepare for spotty network service, as internet connectivity isn’t guaranteed at C Lazy U Ranch – where our Viget20 celebration will be. A Progressive Web Application (PWA) didn't make sense for our tech requirements, so we chose the route of creating a native application. There are a number of options available to build native applications. But, as we were looking to make as much progress as possible in 48-hours, we chose one of our favorite frameworks: React Native. React Native allows developers to build true, cross-platform native applications, using some of our favorite technologies: javascript, the React framework, and a native-specific variant of CSS. We decided on the turn-key solution Expo. Expo has extra tooling allowing for easy development, deployment, and debugging. This is a snap shot of our app and Expo. Our frontend developers were able to immediately dive in making screens and styling components, and quickly made the mockups in Whimsical a reality. On the backend, we used the supported library to connect to the backend datastore, Firebase. Firebase is a hosted solution for data storage, with key features built-in like authentication, realtime updates, and offline support. Our backend developer worked behind the frontend developers hooking those views up to live data. Both of these tools, Expo and Firebase, were easy to use and allowed us to focus on building a working application quickly, rather than being mired in setup or bespoke solutions to common problems. Whimsical is one of our favorite tools for building out mockups of an app. We made impressive progress in our 48-hour sprint, but there’s still some work to do. We have some additional features we hope to add before TTT, which will require additional testing and refining. For now, stay tuned and sign up for our newsletter. We’ll be sure to share when Scurry is ready for the world! Full Article News & Culture
s Together We Flourish, Remotely By feedproxy.google.com Published On :: Thu, 09 Apr 2020 08:00:00 -0400 Like many other companies, Viget is working through the new challenge of suddenly being a fully-distributed company. We don’t know how long it will last or every challenge that will arise because of these unfortunate circumstances, but we know the health and well-being of our people is paramount. As Employee Engagement Manager, I feel inspired by these new challenges, eager to step up, and committed to seeing what good can come of this. Now more than ever, we want to maintain the culture that has sustained us over the last 20 years – a culture that I think is best captured by our mantra, “do great work and be a great teammate.” As everyone is adjusting to new work environments, schedules, and distractions, I am adjusting my approach to employee engagement, and the People Team is looking for new ways to nurture and protect the culture we treasure. The backbone of being a great teammate is knowing each other and caring about each other. For years the People Team has focused on making sure people who work at Viget are known, accepted, and cared about. From onboarding to events to weekly and monthly touchpoints, we invest in coworkers knowing each other. On top of that, we have well-appointed offices where people like to be, and friendships unfold over time. Abruptly becoming fully distributed makes it impossible for some of these connections to happen organically, like they would have around the coffee machine and the lunch tables. These microinteractions between colleagues in the same office, the hellos when you get off the elevator or the “what’d you get up to this weekend” chit chat near the seltzer refrigerator, all add up. We realize more than ever how valuable those moments are, and I know I will feel extra grateful for them when we are all back together.Until that time, we are working to make sure everyone at Viget feels connected, safe, healthy, and most importantly, together, even when we are physically apart. We are keeping up our weekly staff meetings and monthly team lunches, and we just onboarded a new hire last week as thoroughly as ever. There are some other, new ways we’re sparking connections, too. New ways we're sparking connections: Connecting IntentionallyWe are making the most of the tools that we’ve been using for years. New Slack channels have spun up, including #exercise, where folks are sharing how they are making do without a gym, and #igotyou, a place where folks can post where they’ve found supplies in stock as grocery stores are being emptied at an alarming pace.Remote Lunch TablesWe have teammates in three different time zones, on different project teams, and at different stages of life. We’ve created two virtual lunch tables, one at 12PM EST and one at 12PM MST, where folks can join with or without their lunches and with or without their kids, partners, or pets. There are no rules or structure, just an opportunity to chat and see a friendly face as a touchpoint to your day.Last Weekend This MorningCatching up Monday morning is a great way to kick off your week. Historically, I’ve done this from my desk over coffee as I greet folks coming off the elevator (I usually have the privilege of sitting at our front desk). I now do this from my desk, at home, over coffee as folks pop in or out of our Zoom call. One upshot of the new normal is I can “greet” anyone who shows up, not just people who work from my same office. Again, no structure, just a way to start our week, together.Munch MadnessYes, you read that right. Most of the sports world is enjoying an intermission. Since our CEO can’t cheer on his beloved Cavaliers and our VP of Design can’t cheer on his Gators, we’ve created something potentially much better. A definitive snack bracket. There is a minimal time commitment and folks with no sports knowledge can participate. The rules are simple: create and submit your bracket, ranking who you believe will win each snack faceoff. Then as we move through the rounds, vote on your favorite snacks. The competition has already sparked tons of conversation and plenty of snack hot takes. Want to start a munch-off of your own? Check out our bracket as a starting point.Virtual Happy HoursSigning off for the day and shutting down your machine is incredibly important for maintaining a work-life balance. Casually checking in, unwinding, and being able to chat about your day is also important. We have big, beautiful kitchens in each of our offices, along with casual spaces where at the end of any given day you can find a few Vigets catching up before heading home. This is something we don’t want to miss! So we’re setting up weekly happy hours where folks can hop in and say hi to each other face-to-face. We’ve found Zoom to be a great platform so we can see the maximum number of our teammates possible. Like all of our other events, it’s optional. There is also an understanding that your roommate, kid, significant other, or pet might show up on screen (and are welcome!). No one is shamed for multitasking and we encourage our teammates to join as they can. So far we’ve toasted new teammates, played a song or two, and up next we’ll play trivia. At the end of the day, we are all here for one reason: to do great work. Our award-winning work is made possible by the trust we’ve built within our teams. Staying focused and accountable to ourselves and our clients is what drives our motivation to continue to show up and do our best. In our new working environment, it is crucial that we can both stay connected and productive; a lot of teammates are stepping up to support one another. Here are a few ways we are continuing to foster our “do great work” mantra. New ways we're fostering great work: Staying in TouchThe People Team is actively touching base with every employee. Our focus is on their health, productivity, and connection. These 1:1s have given us a baseline for how we can provide the best support for our team, from making sure they're aware of flexible work options to setting them up with the tools they need to be successful. We’ve delivered chairs, monitors, and helped troubleshoot in-home wifi issues. We are committed to making sure every Viget is set up for success.Sharing is CaringWe’re no stranger to remote teams. We have four offices across the U.S. and a handful of full-time remote folks, and we’ve leaned on our inside experts to share their expertise on remote work. Most recently, ourData & Analytics Director, who has been working remotely full time for five years, gave a presentation on best practices for working from home. His top tips for working from home include: Minimize other windows in remote meetings.Set a schedule and avoid midday chores.Take breaks away from the screen.Plan your workday on your shared calendar.Be mindful of Slack and social media as a distraction.Use timers.Keep your work area separate from where you relax.Pretend that you’re still working from work.Experiment and figure out what works for you. Our UX Research Director also stepped up to share her expertise to aid in adjusting to our new working conditions. She led a microclass on remote facilitation where she shared best practices and went over tools that support remote collaboration. Some of the tools she highlighted included Miro, Mural, Whimsical, and Jamboard. During the microclass she demonstrated use of Whimsical’s voting feature, which makes it easy for distributed groups to establish discussion topic priorities.Always PreparedHaving all of our project materials stored in the Cloud in a consistent, predictable way is a cornerstone of our business continuity plan. It is more important than ever for our team to follow the established best practices and ensure that project files are accessible to the full Viget team in the event of unplanned time off. Our VP of Client Services is leading efforts to ensure everyone is aware of and following our established guidelines with tools like Drive, Slack, Github, and Figma. Our priorities are that clients’ needs are met, quality is high, and timelines are honored. As the pandemic unfolds, our approach to employee engagement will evolve. We have more things in the works to build and maintain connections while distributed, including trivia and game nights, book clubs, virtual movie nights, and community service opportunities, just to name a few. No matter what we’re doing or what tool we’re using to connect, we’ll be in it together: doing great work, being great teammates, and looking forward. Full Article News & Culture
s A Viget Glossary: What We Mean and Why it Matters - Part 1 By feedproxy.google.com Published On :: Tue, 21 Apr 2020 08:00:00 -0400 Viget has helped organizations design and develop award-winning websites and digital products for 20 years. In that time, we’ve been lucky to create long-term relationships with clients like Puma, the World Wildlife Fund, and Privia Health, and, throughout our time working together, we’ve come to understand each others’ unique terminology. But that isn’t always the case when we begin work with new clients, and in a constantly-evolving industry, we know that new terminology appears almost daily and organizations have unique definitions for deliverables and processes. Kicking off a project always initiates a flurry of activity. There are contracts to sign, team members to introduce, and new platforms to learn. It’s an exciting time, and we know clients are anxious to get underway. Amidst all the activity, though, there is a need to define and create a shared lexicon to ensure both teams understand the project deliverables and process that will take us from kickoff to launch. Below, we’ve rounded up a few terms for each of our disciplines that often require additional explanation. Note: our definitions of these terms may differ slightly from the industry standard, but highlight our interpretation and use of them on a daily basis. User ExperienceResearchIn UX, there is a proliferation of terms that are often used interchangeably and mean almost-but-subtly-not the same thing. Viget uses the term research to specifically mean user research — learning more about the users of our products, particularly how they think and behave — in order to make stronger recommendations and better designs. This can be accomplished through different methodologies, depending on the needs of the project, and can include moderated usability testing, stakeholder interviews, audience research, surveys, and more. Learn more about the subtleties of UX research vocabulary in our post on “Speaking the Same Language About Research”.WireframesWe use wireframes to show the priority and organization of content on the screen, to give a sense of what elements will get a stronger visual treatment, and to detail how users will get to other parts of the site. Wireframes are a key component of website design — think of them as the skeleton or blueprint of a page — but we know that clients often feel uninspired after reviewing pages built with gray boxes. In fact, we’ve even written about how to improve wireframe presentations. We remind clients that visual designers will step in later to add polish through color, graphics, and typography, but agreeing on the foundation of the page is an important and necessary first step. PrototypesDuring the design process, it’s helpful for us to show clients how certain pieces of functionality or animations will work once the site is developed. We can mimic interactivity or test a technical proof of concept by using a clickable prototype, relying on tools like Figma, Invision, or Principle. Our prototypes can be used to illustrate a concept to internal stakeholders, but shouldn’t be seen as a final approach. Often, these concepts will require additional work to prepare them for developer handoff, which means that prototypes quickly become outdated. Read more about how and when we use prototypes. Navigation Testing (Treejack Testing)Following an information architecture presentation, we will sometimes recommend that clients conduct navigation testing. When testing, we present a participant with the proposed navigation and ask them to perform specific tasks in order to see if they will be able to locate the information specified within the site’s new organization. These tests generally focus on two aspects of the navigation: the structure of the navigation system itself, and the language used within the system. Treejack is an online navigation testing tool that we like to employ when conducting navigation tests, so we’ll often interchange the terms “navigation testing” with “treejack testing”.Learn more about Viget’s approach to user experience and research. Full Article Strategy Process
s Pursuing A Professional Certification In Scrum By feedproxy.google.com Published On :: Wed, 22 Apr 2020 08:00:00 -0400 Professional certifications have become increasingly popular in this age of career switchers and the freelance gig economy. A certification can be a useful way to advance your skill set quickly or make your resume stand out, which can be especially important for those trying to break into a new industry or attract business while self-employed. Whatever your reason may be for pursuing a professional certificate, there is one question only you can answer for yourself: is it worth it? Finding first-hand experiences from professionals with similar career goals and passions was the most helpful research I used to answer that question for myself. So, here’s mine; why I decided to get Scrum certified, how I evaluated my options, and if it was really worth it. A shift in mindset My background originates in brand strategy where it’s typical for work to follow a predictable order, each step informing the next. This made linear techniques like water-fall timelines, completing one phase of work in its entirety before moving onto the next, and documenting granular tasks weeks in advance helpful and easy to implement. When I made the move to more digitally focused work, tasks followed a much looser set of ‘typical’ milestones. While the general outline remained the same (strategy, design, development, launch) there was a lot more overlap with how tasks informed each other, and would keep informing and re-informing as an iterative workflow would encourage. Trying to fit a very fluid process into my very stiff linear approach to project planning didn’t work so well. I didn’t have the right strategies to manage risks in a productive way without feeling like the whole project was off track; with the habit of account for granular details all the time, I struggled to lean on others to help define what we should work on and when, and being okay if that changed once, or twice, or three times. Everything I learned about the process of product development came from learning on the job and making a ton of mistakes—and I knew I wanted to get better. Photo by Christin Hume on Unsplash I was fortunate enough to work with a group of developers who were looking to make a change, too. Being ‘agile’-enthusiasts, this group of developers were desperately looking for ways to infuse our approach to product work with agile-minded principles (the broad definition of ‘agile’ comes from ‘The Agile Manifesto’, which has influenced frameworks for organizing people and information, often applied in product development). This not only applied to how I worked with them, but how they worked with each other, and the way we all onboarded clients to these new expectations. This was a huge eye opener to me. Soon enough, I started applying these agile strategies to my day-to-day— running stand-ups, setting up backlogs, and reorganizing the way I thought about work output. It’s from this experience that I decided it may be worth learning these principles more formally. The choice to get certified There is a lot of literature out there about agile methodologies and a lot to be learned from casual research. This benefitted me for a while until I started to work on more complicated projects, or projects with more ambitious feature requests. My decision to ultimately pursue a formal agile certification really came down to three things: An increased use of agile methods across my team. Within my day-to-day I would encounter more team members who were familiar with these tactics and wanted to use them to structure the projects they worked on.The need for a clear definition of what processes to follow. I needed to grasp a real understanding of how to implement agile processes and stay consistent with using them to be an effective champion of these principles.Being able to diversify my experience. Finding ways to differentiate my resume from others with similar experience would be an added benefit to getting a certification. If nothing else, it would demonstrate that I’m curious-minded and proactive about my career. To achieve these things, I gravitated towards a more foundational education in a specific agile-methodology. This made Scrum the most logical choice given it’s the basis for many of the agile strategies out there and its dominance in the field. Evaluating all the options For Scrum education and certification, there are really two major players to consider. Scrum Alliance - Probably the most well known Scrum organization is Scrum Alliance. They are a highly recognizable organization that does a lot to further the broader understanding of Scrum as a practice.Scrum.org - Led by the original co-founder of Scrum, Ken Schwaber, Scrum.org is well-respected and touted for its authority in the industry. Each has their own approach to teaching and awarding certifications as well as differences in price point and course style that are important to be aware of. SCRUM ALLIANCE Pros Strong name recognition and leaders in the Scrum fieldOffers both in-person and online coursesHosts in-person events, webinars, and global conferencesProvides robust amounts of educational resources for its membersHas specialization tracks for folks looking to apply Scrum to their specific disciplineMembers are required to keep their skills up to date by earning educational credits throughout the year to retain their certificationConsistent information across all course administrators ensuring you'll be set up to succeed when taking your certification test. Cons High cost creates a significant barrier to entry (we’re talking in the thousands of dollars here)Courses are required to take the certification testCertification expires after two years, requiring additional investment in time and/or money to retain credentialsDifficult to find sample course material ahead of committing to a courseCourses are several days long which may mean taking time away from a day job to complete them SCRUM.ORG Pros Strong clout due to its founder, Ken Schwaber, who is the originator of ScrumOffers in-person classes and self-paced optionsHosts in-person events and meetups around the worldProvides free resources and materials to the public, including practice testsHas specialization tracks for folks looking to apply Scrum to their specific disciplineMinimum score on certification test required to pass; certification lasts for lifeLower cost for certification when compared to peers Cons Much lesser known to the general public, as compared to its counterpartLess sophisticated educational resources (mostly confined to PDFs or online forums) making digesting the material challengingPractice tests are slightly out of date making them less effective as a study toolSelf-paced education is not structured and therefore can’t ensure you’re learning everything you need to know for the testLack of active and engaging community will leave something to be desired Before coming to a decision, it was helpful to me to weigh these pros and cons against a set of criteria. Here’s a helpful scorecard I used to compare the two institutions. Scrum Alliance Scrum.org Affordability ⚪⚪⚪⚪ Rigor⚪⚪⚪⚪⚪ Reputation⚪⚪⚪⚪⚪ Recognition⚪⚪⚪⚪ Community⚪⚪⚪⚪ Access⚪⚪⚪⚪⚪ Flexibility⚪⚪⚪⚪ Specialization⚪⚪⚪⚪⚪⚪ Requirements⚪⚪⚪⚪ Longevity⚪⚪⚪⚪ For me, the four areas that were most important to me were: Affordability - I’d be self-funding this certificate so the investment of cost would need to be manageable.Self-paced - Not having a lot of time to devote in one sitting, the ability to chip away at coursework was appealing to me.Reputation - Having a certificate backed by a well-respected institution was important to me if I was going to put in the time to achieve this credential.Access - Because I wanted to be a champion for this framework for others in my organization, having access to resources and materials would help me do that more effectively. Ultimately, I decided upon a Professional Scrum Master certification from Scrum.org! The price and flexibility of learning course content were most important to me. I found a ton of free materials on Scrum.org that I could study myself and their practice tests gave me a good idea of how well I was progressing before I committed to the cost of actually taking the test. And, the pedigree of certification felt comparable to that of Scrum Alliance, especially considering that the founder of Scrum himself ran the organization. Putting a certificate to good use I don’t work in a formal Agile company, and not everyone I work with knows the ins and outs of Scrum. I didn’t use my certification to leverage a career change or new job title. So after all that time, money, and energy, was it worth it?I think so. I feel like I use my certification every day and employ many of the principles of Scrum in my day-to-day management of projects and people. Self-organizing teams is really important when fostering trust and collaboration among project members. This means leaning on each other’s past experiences and lessons learned to inform our own approach to work. It also means taking a step back as a project manager to recognize the strengths on your team and trust their lead.Approaching things in bite size pieces is also a best practice I use every day. Even when there isn't a mandated sprint rhythm, breaking things down into effort level, goals, and requirements is an excellent way to approach work confidently and avoid getting too overwhelmed.Retrospectives and stand ups are also absolute musts for Scrum practices, and these can be modified to work for companies and project teams of all shapes and sizes. Keeping a practice of collective communication and reflection will keep a team humming and provides a safe space to vent and improve. Photo by Gautam Lakum on Unsplash Parting advice I think furthering your understanding of industry standards and keeping yourself open to new ways of working will always benefit you as a professional. Professional certifications are readily available and may be more relevant than ever. If you’re on this path, good luck! And here are some things to consider: Do your research – With so many educational institutions out there, you can definitely find the right one for you, with the level of rigor you’re looking for.Look for company credits or incentives – some companies cover part or all of the cost for continuing education.Get started ASAP – You don’t need a full certification to start implementing small tactics to your workflows. Implementing learnings gradually will help you determine if it’s really something you want to pursue more formally. Full Article News & Culture Project Management
s 5 things to Note in a New Phoenix 1.5 App By feedproxy.google.com Published On :: Fri, 24 Apr 2020 13:44:00 -0400 Yesterday (Apr 22, 2020) Phoenix 1.5 was officially released ???? There’s a long list of changes and improvements, but the big feature is better integration with LiveView. I’ve previously written about why LiveView interests me, so I was quite excited to dive into this release. After watching this awesome Twitter clone in 15 minutes demo from Chris McCord, I had to try out some of the new features. I generated a new phoenix app with the —live flag, installed dependencies and started a server. Here are five new features I noticed. 1. Database actions in browser Oops! Looks like I forgot to configure the database before starting the server. There’s now a helpful message and a button in the browser that can run the command for me. There’s a similar button when migrations are pending. This is a really smooth UX to fix a very common error while developing. 2. New Tagline! Peace-of-mind from prototype to production This phrase looked unfamiliar, so I went digging. Turns out that the old tagline was “A productive web framework that does not compromise speed or maintainability.” (I also noticed that it was previously “speed and maintainability” until this PR from 2019 was opened on a dare to clarify the language.) Chris McCord updated the language while adding phx.new —live. I love this framing, particularly for LiveView. I am very excited about the progressive enhancement path for LiveView apps. A project can start out with regular, server rendered HTML templates. This is a very productive way to work, and a great way to start a prototype for just about any website. Updating those templates to work with LiveView is an easier lift than a full rebuild in React. And finally, when you’re in production you have the peace-of-mind that the reliable BEAM provides. 3. Live dependency search There’s now a big search bar right in the middle of the page. You can search through the dependencies in your app and navigate to the hexdocs for them. This doesn’t seem terribly useful, but is a cool demo of LiveView. The implementation is a good illustration of how compact a feature like this can be using LiveView. 4. LiveDashboard This is the really cool one. In the top right of that page you see a link to LiveDashboard. Clicking it will take you to a page that looks like this. This page is built with LiveView, and gives you a ton of information about your running system. This landing page has version numbers, memory usage, and atom count. Clicking over to metrics brings you to this page. By default it will tell you how long average queries are taking, but the metrics are configurable so you can define your own custom telemetry options. The other tabs include process info, so you can monitor specific processes in your system: And ETS tables, the in memory storage that many apps use for caching: The dashboard is a really nice thing to get out of the box and makes it free for application developers to monitor their running system. It’s also developing very quickly. I tried an earlier version a week ago which didn’t support ETS tables, ports or sockets. I made a note to look into adding them, but it's already done! I’m excited to follow along and see where this project goes. 5. New LiveView generators 1.5 introduces a new generator mix phx.gen.live.. Like other generators, it will create all the code you need for a basic resource in your app, including the LiveView modules. The interesting part here is that it introduces patterns for organizing LiveView code, which is something I have previously been unsure about. At first glance, the new organization makes sense and feels like a good approach. I look forward to seeing how this works on a real project. Learn More We're hiring Application Developers in our Boulder, Chattanooga, Durham, Falls Church and Remote (U.S. Only) offices. Learn more and introduce yourself. Conclusion The 1.5 release brings more changes under the hood of course, but these are the first five differences you’ll notice after generating a new Phoenix 1.5 app with LiveView. Congratulations to the entire Phoenix team, but particularly José Valim and Chris McCord for getting this work released. Full Article Code Back-end Engineering
s A Viget Glossary: What We Mean and Why It Matters - Part 2 By feedproxy.google.com Published On :: Tue, 28 Apr 2020 10:09:00 -0400 In my last post, I defined terms used by our UX team that are often confused or have multiple meanings across the industry. Today, I’ll share our definitions for processes and deliverables used by our design and strategy teams. Creative Brand Strategy In our experience, we’ve found that the term brand strategy is used to cover a myriad of processes, documents, and deliverables. To us, a brand strategy defines how an organization communicates who they are, what they do and why in a clear and compelling way. Over the years, we’ve developed an approach to brand strategy work that emphasizes rigorous research, hands-on collaboration, and the definition of problems and goals. We work with clients to align on a brand strategy concept and, depending on the client and their goals, our final deliverables can range to include strategy definition, audience-specific messaging, identity details, brand elements, applications, and more. Take a look at the brand strategy work we’ve done for Fiscalnote, Swiftdine, and Armstrong Tire. Content Strategy A content strategy goes far beyond the words on a website or in an app. A strong content strategy dictates the substance, structure, and governance of the information an organization uses to communicate to its audience. It guides creating, organizing, and maintaining content so that companies can communicate who they are, what they do, and why efficiently and effectively. We’ve worked with organizations like the Washington Speakers Bureau, The Nature Conservancy, the NFL Players Association, and the Wildlife Conservation Society to refine and enhance their content strategies. Still confused about the difference between brand and content strategy? Check out our flowchart. Style Guide vs. Brand Guidelines We often find the depth or fidelity of brand guidelines and style guides can vary greatly, and the terms can often be confused. When we create brand guidelines, they tend to be large documents that include in-depth recommendations about how a company should communicate their brand. Sections like “promise”, “vision”, “mission”, “values”, “tone”, etc. accompany details about how the brand’s logo, colors and fonts should be used in a variety of scenarios. Style guides, on the other hand, are typically pared down documents that contain specific guidance for organizations’ logos, colors and fonts, and don’t always include usage examples. Design System One question we get from clients often during a redesign or rebrand is, “How can I make sure people across my organization are adhering to our new designs?” This is where a design system comes into play. Design systems can range from the basic — e.g., a systematic approach to creating shared components for a single website — all the way to the complex —e.g., architecting a cross-product design system that can scale to accommodate hundreds of different products within a company. By assembling elements like color, typography, imagery, messaging, voice and tone, and interaction patterns in a central repository, organizations are able to scale products and marketing confidently and efficiently. When a design system is translated into code, we refer to that as a parts kit, which helps enforce consistency and improve workflow. Comps or Mocks When reviewing RFPs or going through the nitty-gritty of contracts with clients, we often see the terms mocks or comps used interchangeably to refer to the static design of pages or screens. Internally, we think of a mock-up as a static image file that illustrates proof-of-concept, just a step beyond a wireframe. A comp represents a design that is “high fidelity” and closer to what the final website will look like, though importantly, is not an exact replica. This is likely what clients will share with internal stakeholders to get approval on the website direction and what our front-end developers will use to begin building-out the site (in other words, converting the static design files into dynamic HTML, CSS, and JavaScript code). If you're interested in joining our team of creative thinkers and visual storytellers who bring these concepts to life for our clients, we’re hiring in Washington, D.C. Durham, Boulder and Chattanooga. Tune in next week as we decipher the terms we use most often when talking about development. Full Article Strategy Process
s Unsolved Zoom Mysteries: Why We Have to Say “You’re Muted” So Much By feedproxy.google.com Published On :: Wed, 29 Apr 2020 09:36:00 -0400 Video conference tools are an indispensable part of the Plague Times. Google Meet, Microsoft Teams, Zoom, and their compatriots are keeping us close and connected in a physically distanced world. As tech-savvy folks with years of cross-office collaboration, we’ve laughed at the sketches and memes about vidconf mishaps. We practice good Zoomiquette, including muting ourselves when we’re not talking. Yet even we can’t escape one vidconf pitfall. (There but for the grace of Zoom go I.) On nearly every vidconf, someone starts to talk, and then someone else says: “Oop, you’re muted.” And, inevitably: “Oop, you’re still muted.” That’s right: we’re trying to follow Zoomiquette by muting, but then we forget or struggle to unmute when we do want to talk. In this post, I’ll share my theories for why the You’re Muted Problems are so pervasive, using Google Meet, Microsoft Teams, and Zoom as examples. Spoiler alert: While I hope this will help you be more mindful of the problem, I can’t offer a good solution. It still happens to me. All. The. Time. Skip the why and go straight to the vidconf app keyboard shortcuts you should memorize right now. Why we don't realize we’re muted before talking Why does this keep happening?!? Simply put: UX and design decisions make it harder to remember that you’re muted before you start to talk. Here’s a common scenario: You haven’t talked for a bit, so you haven’t interacted with the Zoom screen for a few seconds. Then you start to talk — and that’s when someone tells you, “You’re muted.” We forget so easily in these scenarios because when our mouse has been idle for a few seconds, the apps hide or downplay the UI elements that tell us we’re muted. Zoom and Teams are the worst offenders: Zoom hides both the toolbar with the main in-app controls (the big mute button) and the mute status indicator on your video pane thumbnail.Teams hides the toolbar, and doesn't show a mute status indicator on your video thumbnail in the first place. Meet is only slightly better: Meet hides the toolbar, and shows only a small mute status icon in your video thumbnail. Even when our mouse is active, the apps’ subtle approach to muted state UI can make it easy to forget that we’re muted: Teams is the worst offender: The mute button is an icon rather than words.The muted-state icon's styling could be confused with unmuted state: Teams does not follow the common pattern of using red to denote muted state.The mute button is not differentiated in visual hierarchy from all the other controls.As mentioned above, Teams never shows a secondary mute status indicator. Zoom is a bit better, but still makes it pretty easy to forget that you’re muted: Pros:Zoom is the only app to use words on the mute button, in this case to denote the button action (rather than the muted state).The muted-state icon’s styling (red line) is less likely to be confused with the unmuted-state icon.Cons:The mute button’s placement (bottom left corner of the page) is easy to overlook.The mute button is not differentiated in visual hierarchy from the other toolbar buttons — and Zoom has a lot of toolbar buttons, especially when logged in as host.The secondary mute status indicator is a small icon.The mute button’s muted-state icon is styled slightly differently from the secondary mute status indicator. Potential Cons:While words denote the button action, only an icon denotes the muted state. Meet is probably the clearest of the three apps, but still has pitfalls: Pros:The mute button is visually prominent in the UI: It’s clearly differentiated in the visual hierarchy relative to other controls (styled as a primary button); is a large button; and is placed closer to the center of the controls bar.The muted-state icon’s styling (red fill) is less likely to be confused with the unmuted-state icon.Cons:Uses only an icon rather than words to denote the muted state.Unrelated Con:While the mute button is visually prominent, it’s also placed next to the hang-up button. So in Meet’s active state you might be less likely to forget you’re muted … but more likely to accidentally hang up when trying to unmute. 😬 I know modern app design leans toward minimalism. There’s often good rationale to use icons rather than words, or to de-emphasize controls and indicators when not in use. But again: This happens on basically every call! Often multiple times per call!! And we’re supposed to be tech-savvy!!! Imagine what it’s like for the tens of millions of vidconf newbs. I would argue that “knowing your muted state” has turned out to be a major vidconf user need. At this point, it’s certainly worth rethinking UX patterns for. Why we keep unsuccessfully unmuting once we realize we’re muted So we can blame the You’re Muted Problem on UX and design. But what causes the You’re Still Muted Problem? Once we know we’re muted, why do we sometimes fail to unmute before talking again? This one is more complicated — and definitely more speculative. To start making sense of this scenario, here’s the sequence I’m guessing most commonly plays out (I did this a couple times before I became aware of it): The crucial part is when the person tries to unmute by pressing the keyboard Volume On/Off key. If that’s in fact what’s happening (again, this is just a hypothesis), I’m guessing they did that because when someone says “You’re muted” or “I can’t hear you,” our subconscious thought process is: “Oh, Audio is Off. Press the keyboard key that I usually press when I want to change Audio Off to Audio On.” There are two traps in this reflexive thought process: First, the keyboard volume keys control the speaker volume, not the microphone volume. (More specifically, they control the system sound output settings, rather than the system sound input settings or the vidconf app’s sound input settings.)In fact, there isn’t a keyboard key to control the microphone volume. You can’t unmute your mic via a dedicated keyboard key, the way that you can turn the speaker volume on/off via a keyboard key while watching a movie or listening to music. Second, I think we reflexively press the keyboard key anyway because our mental model of the keyboard audio keys is just: Audio. Not microphone vs. speaker. This fuzzy mental model makes sense: There’s only one set of keyboard keys related to audio, so why would I think to distinguish between microphone and speaker? So my best guess is hardware design causes the You’re Still Muted Problem. After all, keyboard designs are from a pre-Zoom era, when the average person rarely used the computer’s microphone.If that is the cause, one potential solution is for hardware manufacturers to start including dedicated keys to control microphone volume: Video conference keyboard shortcuts you should memorize right now Let me know if you have other theories for the You’re Still Muted Problem! In the meantime, the best alternative is to learn all of the vidconf app keyboard shortcuts for muting/unmuting: MeetMac: Command(⌘) + DWindows: Control + DTeamsMac: Command(⌘) + Shift + MWindows: Ctrl + Shift + MZoomMac: Command(⌘) + Shift + AWindows: Alt + AHold Spacebar: Temporarily unmute Other vidconf apps not included in my analysis: Cisco Webex MeetingsMac: Ctrl + Alt + MWindows: Ctrl + Shift + M GoToMeeting Mac: No keyboard shortcut? Windows: Ctrl + Alt + A Bonus protip from Jackson Fox: If you use multiple vidconf apps, pick a keyboard shortcut that you like and manually change each app’s mute/unmute shortcut to that. Then you only have to remember one shortcut! Full Article Process User Experience
s A Parent’s Guide to Working From Home, During a Global Pandemic, Without Going Insane By feedproxy.google.com Published On :: Thu, 30 Apr 2020 15:06:00 -0400 Though I usually enjoy working from Viget’s lovely Boulder office, during quarantine I am now working from home while simultaneously parenting my 3-year-old daughter Audrey. My husband works in healthcare and though he is not on the front lines battling COVID-19, he is still an essential worker and as such leaves our home to work every day. Some working/parenting days are great! I somehow get my tasks accomplished, my kid is happy, and we spend some quality time together. And some days are awful. I have to ignore my daughter having a meltdown and try to focus on meetings, and I wish I wasn’t in this situation at all. Most days are somewhere in the middle; I’m just doing my best to get by. I’ve seen enough working parent memes and cries for help on social media to know that I’m not alone. There are many parents out there who now get to experience the stress and anxiety of living through a global pandemic while simultaneously navigating ways to stay productive while working from home and being an effective parent. Fun isn’t it? I’m not an expert on the matter, but I have found a few small things that are making me feel a bit more sane. I hope sharing them will make someone else’s life easier too. Truths to Accept First, let’s acknowledge some truths about this new situation we find ourselves in: Truth 1: We’ve lost something. Parents have lost more than daycare and schools during this epidemic. We’ve lost any time that we had for ourselves, and that was really valuable. We no longer have small moments in the day to catch up on our personal lives. I no longer have a commute to separate my work duties from my mom duties, or catch up with my friends, or just be quiet. Truth 2: We’re human. The reason you can’t be a great employee and a great parent and a great friend and a great partner or spouse all day every day isn’t because you’re doing a bad job, it’s because being constantly wonderful in all aspects of your life is impossible. Pick one or two of those things a day to focus on. Truth 3: We’re all doing our best. This is the most important part of this article. Be kind to yourselves. This isn’t easy, and putting so much pressure on yourself that you break isn’t going to make it any easier. Work from Home Goals Now that we’ve accepted some truths about our current situation, let’s set some goals. Goal 1: Do Good Work At Viget, and wherever you work, with kids or without we all want to make sure that the quality of our work stays up throughout the pandemic and that we can continue to be reliable team members and employees to the best of our abilities. Goal 2: Stay Sane We need to figure out ways to do this without sacrificing ourselves entirely. For me, this means fitting my work into normal work hours as much as possible so that I can still have some downtime in the evenings. Goal 3: Make This Sustainable None of us knows how long this will last but we may as well begin mentally preparing for a long haul. Work from Home Rules Now, there are some great Work from Home Rules that apply to everyone with or without kids. My coworker Paul Koch shared these with the Viget team a Jeremy Bearimy ago and I agree this is also the foundation for working from home with kids. When you’re in a remote meeting, minimize other windows to stay focusedSet a schedule and avoid chores*Take breaks away from the screenPlan your workday on the calendar+Be mindful of Slack and social media as a distractionUse timers+Keep your work area separate from where you relaxPretend that you’re still WFWExperiment and figure out what works for you In the improv spirit I say “Yes, AND….” to these tips. And so, here are my adjusted rules for WFH while kiddos around: These have both been really solid tools for me, so let’s dig in. Daily flexible schedule for kids Day Planning: Calendars and Timers A few small tweaks and adjustments make this even more doable for me and my 3-year-old. First- I don’t avoid chores entirely. If I’m going up and down the stairs all day anyway I might as well throw in a load of laundry while I’m at it. The more I can get done during the day means a greater chance of some down time in the evening. Each morning I plan my day and Audrey’s day: My Work Day:Audrey's DayIdentify times of day you are more likely to be focus and protect them. For me, I know I have a block of time from 5-7a before Audrey wakes up and again during “nap time” from 1-3p.I built a construction paper “schedule” that we update and reorganize daily. We make the schedule together each day. She feels ownership over it and she gets to be the one who tells me what we do next.Look at your calendar first thing and make adjustments either in your plans or move meetings if you have to.I’m strategic about screen time- I try to schedule it when I have meetings. It also helps to schedule a physical activity before screen time as she is less likely to get bored.Make goals for your day: Tackle time sensitive tasks first. Take care of things that either your co-workers or clients are waiting on from you first, this will help your day be a lot less stressful. Non-time sensitive tasks come next- these can be done at any time of day.We always include “nap time” even though she rarely naps anymore. This is mostly a time for us both to be alone. When we make the schedule together it also helps me understand her favorite parts of the day and reminds me to include them. Once our days are planned, I also use timers to help keep the structure of the day. (I bought a great alarm clock for kids on Amazon that turns colors to signal bedtime and quiet time. It’s been hugely worth it for me.) Timers for Me:Timers for Audrey:More than ever, I rely on a time tracking timer. At Viget we use Harvest to track time, and it has a handy built in timer, but there are many apps or online tools that could help you keep track of your time as well.Audrey knows what time she can come out of her room in the morning. If she wakes up before the light is green she plays quietly in her room.I need a timer because the days and hours are bleeding together- without tracking as I go it would be really hard for me to remember when I worked on certain projects or know for certain if I gave Viget enough time for the day.She knows how long “nap time” is in the afternoon.Starting and stopping the timer helps me turn on and off “work mode”, which is a helpful sanity bonus.Perhaps best of all I am not the bad guy! “Sorry honey, the light isn’t green yet and there really isn’t anything mommy can do about it” is my new favorite way to ensure we both get some quiet time. Work from Home Rules: Updated for Parents Finally, I have a few more Work from Home Rules for parents to add to the list: Minimize other windows in remote meetingsSet a schedule and fit in some chores if time allowsTake breaks away from the screenSchedule both your and your kids’ daysBe mindful of Slack and social media as a distractionUse timers to track your own time and help your kids understand the dayKeep your work area separate from where you relaxPretend that you’re still WFWExperiment and figure out what works for youBe prepared with a few activitiesEach morning, have just ONE thing ready to go. This can be a worksheet you printed out, a coloring station setup, a new bag of kinetic sand you just got delivered from Amazon, a kids dance video on YouTube or an iPad game. Recently I started enlisting my mom to read stories on Facetime. The activity doesn’t have to be new each day but (especially for young kids) it has to be handy for you to start up quickly if your schedule changesClearly communicate your availability with your team and project PMsLife happens. Some days are going to be hard. Whatever you do, don’t burn yourself out or leave your team hanging. If you need to move a meeting or take a day off, communicate that as early and as clearly as you can.Take PTO if you canNone of us are superheroes. If you’re feeling overwhelmed- take a look at the next few days and figure out which one makes the most sense for you to take a break.Take breaks to be alone without doing a taskWork and family responsibilities have blended together, there’s almost no room for being alone. If you can find some precious alone time don’t use it to fold laundry or clean the bathroom. Just zone out. I think we all really need this. Last but not least, enjoy your time at home if you can. This is an unusual circumstance and even though it’s really hard, there are parts that are really great too. If you have some great WFH tips we’d love to hear about them in the comments! Full Article Process News & Culture
s So You've Written a Bad Design Take By feedproxy.google.com Published On :: Tue, 05 May 2020 08:00:00 -0400 So you’ve just written a blog post or tweet about why wireframes are becoming obsolete, the dangers of “too accessible” design, or how a certain style of icon creates “cognitive fatigue.” Your post went viral, but now you’re getting ratioed by rude people on the Internet. That sucks! You were just trying to start a conversation and you probably didn’t deserve all that negativity (except for you, “too accessible” guy). Most likely, you made one of these common mistakes: 1. You made generalizations about “design” You, a good user-centered designer, know that you are not your user. Nor are you every designer. First of all, let's acknowledge that there is no universal definition of design. Even if we narrow it down to software design, it’s still hard to make generalizations. Agency, in-house, product, startup, enterprise, non-profit, website, app, connected hardware, etc. – there are a lot of different work contexts and cultures for people with “designer” in their titles. "The Design Industry" is not a thing, but even if it were, you don't speak for it. Don’t assume that the kind of design work you do is the universal default. 2. You didn’t share enough context There are many great design books and few great design blog posts. (There are, to my knowledge, no great design tweets, but I am open to your suggestions.) Writing about design is not well suited to short formats, because context plays such an important role and there’s always a lot of it to cover. Writing about your work should include as much context as you would include if you were presenting your portfolio for a job interview. What kind of organization did you work for? Who was your client and/or your stakeholders? What was the goal of the project? Your timeline? What was the makeup of your team? What were the notable business rules and constraints? How are you defining effectiveness and success? Without these kinds of details, it’s not possible for other designers to know if what you’ve written is credible or applicable to them. 3. You were too certain A blog post doesn’t need to be a dissertation. It’s okay to share hunches and anecdotes, but give the necessary caveats. And if you're making claims about science, bruh, you gotta cite your sources. Be humble in your takes. Your account of what worked for you and why is more valuable to your peers than making sweeping claims and reheating the same old arguments. Be prepared to be told you’re wrong, and have the humility to realize that your perspective is just your perspective. Real conversations, like good design, are built on feedback and diverse viewpoints. — Together, we can improve the discourse in our information ecosystems. Don't generalize. Give context. Be humble. Full Article Design & Content User Experience
s Should you use Userbase for your next static site? By feedproxy.google.com Published On :: Wed, 06 May 2020 08:00:00 -0400 During the winter 2020 Pointless Weekend, we built TrailBuddy (working app coming soon). Our team consisted of four developers, two project managers, two front-end developers, a digital-analyst, a UXer, and a designer. In about 48 hours, we took an idea from Jeremy Field’s head to a (mostly) working app. We broke up the project in two parts:. First, a back-end that crunches trail, weather, and soil data. That data is exposed via a GraphQL API for a web app to consume. While developers built the API, I built a static front end using Next.js. Famously, static front-ends don’t have a database, or a concept of “users.” A bit of functionality I wanted to add was saving favorite trails. I didn’t want to be hacky about it, I needed some way to add users and a database. I knew it’d be hard for the developers to set this up as part of the API, they had their hands full with all the #soil-soil-soil-soil-soil (a slack channel dedicated solely to figuring out our soil data problem—those were plentiful.) I had been looking for an excuse to use Userbase, and this seemed like as good a time as any. A textbook Userbase use case “When would I use it?” The Usebase site lists these reasons: If you want to build a web app without writing any backend code. If you never want to see your users' data. If you're tired of dealing with databases. If you want to radically simplify your GDPR compliance. And if you want to keep things really simple. This was a perfect fit for my problem. I didn’t want to write any more backend code for this. I didn’t want to see our user’s data, I don’t care to know anyone’s favorite trails.* A nice bonus to not having users in our backend was not having to worry about keeping their data safe. We don’t have their data at all, it’s end-to-end encrypted by Userbase. We can offer a reasonable amount of privacy for free (well for the price of using Userbase: $49 a year.) I am not tired of dealing with databases, but I’d rather not. I don’t think anyone doesn’t want to simplify their GDPR compliance. Finally, given our tight timeline I wanted nothing more than to keep things really simple. A sign up form that I didn't have to write a back-end for Using Userbase Userbase can be tried for free, so I set aside thirty minutes or so to do a quick proof of concept to make sure this would work out for us. I made an account and followed their Quickstart. Userbase is a fundamentally easy tool to use, but their quickstart is everything I’d want out of a quickstart: Written in the most vanilla way possible (just HTML and vanilla JS). This means I can adapt it to my needs, in this case React using Next.js Easy to follow, it does the most barebones tour of the functionality you can expect to get out of the SDK (software development kit.) In other words it is quick and it is a start It has a live demo and code samples you can download and run yourself It didn’t take long after that to integrate Userbase into our app with more help from their great docs. I debated whether to add code samples of what we did here, and I didn’t because any reader would be better off using the great quickstart and docs Userbase provides—they are that clear, and that good. Depending on your use case you’ll need to adapt the examples to your needs, for us the trickiest things were creating a top level authentication context to manage users in the app, and a custom hook to encapsulate all the logic for setting, updating, and deleting favourite trails in the app. Userbase’s SDK worked seamlessly for us. A log in form that I didn't have to write a back-end for Is Userbase for you? Maybe. I am definitely a fan, so much so that this blog post probably reads like an advert. Userbase saved me a ton of time in this project. It reminded me of “The All Powerful Front End Developer” talk by Chris Coyer. I don’t fully subscribe to all the ideas in that talk, but it is nice to have “serverless” tools like Userbase, and all the new JAMstacky things. There are limits to the Userbase serverless experience in terms of scale, and control. Obviously relying on a third party for something always carries some (probably small) risk—it’s worth noting Usebase includes a note on their pricing page that says “You can host it yourself always under your control, or we can run it for you for a full serverless experience”—Still, I wouldn’t hesitate this to use in future projects. One of the great things about Viget and Pointless Weekend is the opportunity to try new things. For me that was Next.js and Userbase for Trailbuddy. It doesn’t always work out (in fact this is my first pointless weekend where a risk hasn’t blown up in my face) but it is always fun. Getting to try out Userbase and beginning to think about how we may use it in the future made the weekend worthwhile for me, and it made my job on this project much more enjoyable. *I will write a future post about privacy conscious analytics in TrailBuddy when I’ve figured that out. I am looking into Fathom Analytics for that. Full Article Code Front-end Engineering
s Global Gitignore Files Are Cool and So Are You By feedproxy.google.com Published On :: Wed, 06 May 2020 08:00:00 -0400 Setting it up First, here's the config setup you need to even allow for such a radical concept. Define the global gitignore file as a global Git configuration: git config --global core.excludesfile ~/.gitignore If you're on OSX, this command will add the following config lines in your ~/.gitconfig file. [core] excludesfile = /Users/triplegirldad/.gitignore Load that ~/.gitignore file up with whatever you want. It probably doesn't exist as a file yet so you might have to create it first. Harnessing its incredible power There are only two lines in my global gitignore file and they are both fairly useful pretty much all the time. $ cat ~/.gitignore TODO.md playground This 2 line file means that no matter where I am, what project I'm working on, where in the project I'm doing so, I have an easy space to stash notes, thoughts, in progress ideas, spikes, etc. TODO.md More often than not, I'm fiddling around with a TODO.md file. Something about writing markdown in your familiar text editor speaks to my soul. It's quick, it's easy, you have all the text editing tricks available to you, and it never does anything you wouldn't expect (looking at you auto-markdown-formatting editors). I use one or two # for headings, I use nested lists, and I ask for nothing more. Nothing more than more TODO.md files that is! In practice I tend to just have one TODO.md file per project, right at the top, ready to pull up in a few keystrokes. Which I do often. I pull this doc up if: I'm in a meeting and I just said "oh yeah that's a small thing, I'll knock it out this afternoon". I'm halfway through some feature development and realize I want to make a sweeping refactor elsewhere. Toss some thoughts in the doc, and then get back to the task at hand. It's the end of the day and I have to switch my brain into "feed small children" mode, thus obliterating everything work-related from my short term memory. When I open things up the next day and know exactly what the next thing to dive into was. I'm preparing for a big enough refactor and I can't hold it all in my brain at once. What I'd give to have an interactive 3D playground for brain thoughts, but in the meantime a 2D text file isn't a terrible way to plan out dev work. playground Sometimes you need more than some human words in a markdown file to move an idea along. This is where my playground directory comes in. I can load this directory up with code that's related to a given project and keep it out of the git history. Because who doesn't like a place to play around. I find that this directory is more useful for long running maintenance projects over fast moving greenfield ones. On the maintenance projects, I tend to find myself assembling a pile of scripts and experiments for various situations: The client requests a one-time obscure data export. Whip up some CSV generation code and save that code in the playground directory. The client requests a different obscure data export. Pull up the last time you did something vaguely similar and save yourself the startup time. A batch of data needs to be imported just once. Might as well stash that in the chance that "just once" is actually "just a few times". Kicking the tires on an integration with a third party service. Some of these playground files end up being useful more times than I can count (eg: the ever-changing user_export.rb script). Some items get promoted into application code, which is always fun. But most files here serve their purpose and then wither away. And that's fine. It's a playground, anything goes. Wrapping up Having a personal space for project-specific notes and code has been helpful to me over the years as a developer on multiple projects. If you have your own organizational trick, or just want to brag about how you memorize everything without any markdown files, let me know in the comments below! Full Article Code
s What happens if my visa is refused or cancelled due to my character? By feedproxy.google.com Published On :: Wed, 04 Dec 2019 07:16:08 +0000 If you have your visa refused or cancelled, you need to get expert advice a soon as possible. Strict time limits apply to drafting submissions and appeals. A visa refusal or cancellation can limit the type or visas you can apply for in the future or even prohibit you from applying for any visa to […] The post What happens if my visa is refused or cancelled due to my character? appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Visa Cancellation cancelled visa character issues character test character visa conviction criminal conduct criminal conviction criminal record minister's delegate ministerial direction 65 refused visa substantial criminal record visa cancelled visa refusal visa refused
s New regional visas for Australia By feedproxy.google.com Published On :: Fri, 06 Dec 2019 00:41:45 +0000 The Australian Government has introduced two new regional visas which requires migrants to commit to life in regional Australia for at least three years. This new visa opens to the door to permanent residency for overseas workers from a wider range of occupations than before — including such occupations as real estate agents, call centre […] The post New regional visas for Australia appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Work & Skilled Visas permanent residence Permanent Visa points-tested migrants regional australia regional employers Regional Occupation List SKILLED EMPLOYER SPONSORED REGIONAL VISA skilled work regional visa subclass 191 Subclass 485 subclass 491 subclass 494 temporary graduate visa
s Occupations that may be taken off or put onto the skilled migration occupation lists By feedproxy.google.com Published On :: Tue, 17 Dec 2019 03:27:50 +0000 The Department of Employment, Skills, Small and Family Business is considering removing the following occupations from the Skilled Migration Occupation Lists (Skills List) in March 2020: Careers Counsellor Vehicle Trimmer Business Machine Mechanic Animal Attendants and Trainers Gardener (General) Hairdresser Wood Machinist Massage Therapist Community Worker Diving Instructor (Open Water) Gymnastics Coach or Instructor At […] The post Occupations that may be taken off or put onto the skilled migration occupation lists appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Work & Skilled Visas Aged or Disabled Carer Animal Attendants and Trainers Baker Business Machine Mechanic Careers Counsellor Community Worker Corporate Treasurer Diving Instructor (Open Water) Fitter and Turner Gardener (General) Gymnastics Coach Gymnastics Instructor Hairdresser Horse Trainer Massage Therapist Nursing Support Worker occupations list Pastrycook Personal Care Assistant Poultry Farmer skilled migration Vehicle Trimmer Wood Machinist
s Australia is recruiting – New Global Talent Visa By feedproxy.google.com Published On :: Tue, 14 Jan 2020 06:54:24 +0000 Australia has introduced a streamlined, priority visa pathway for highly skilled and talented individuals to work and live permanently in Australia. The Government and industry has recognised there is growing competition for talent around the globe and to compete we must have a pathway that leads to certainty for people wishing to come to Australia. […] The post Australia is recruiting – New Global Talent Visa appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Work & Skilled Visas agricultural business australian immigration cyber security Digital technologies employement Financial technology global talent visa jobs Medical technologies Migration Australia talent visa urban development work work visa
s Visa cancelled due to incorrect information given or provided to the Department of Home Affairs By feedproxy.google.com Published On :: Wed, 19 Feb 2020 05:56:21 +0000 It is a requirement that a visa applicant must fill in or complete his or her application form in a manner that all questions are answered, and no incorrect answers are given or provided. There is also a requirement that visa applicants must not provide incorrect information during interviews with the Minister for Immigration (‘Minister’), […] The post Visa cancelled due to incorrect information given or provided to the Department of Home Affairs appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Visa Cancellation 1703474 (Refugee) [2017] AATA 2985 cancel a visa cancelledvi sa Citizenship and Multicultural Affairs Department of Home Affairs migration act 1958 minister for immigration NOICC notice of intention to consider cancellation Sanaee (Migration) [2019] AATA 4506 section 109 time limits
s Coronavirus (COVID-19) and Visas for Australia By feedproxy.google.com Published On :: Tue, 17 Mar 2020 00:35:01 +0000 The World Health Organization has announced that Coronavirus (COVID-19) is a pandemic. The migration situation is changing rapidly throughout Australia. As an Australian citizen or permanent resident, can I still enter Australia? There is no restriction on Australian citizens or permanent residents entering Australia at this stage. However, those arriving in Australia will be required […] The post Coronavirus (COVID-19) and Visas for Australia appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Immigration News australia coronvirus australian migration corona virus covid-19 immigration Australia no further stay No further stay waiver conditions 8503 No further stay waiver conditions 8534 No further stay waiver conditions 8535 offshore visa onshore visa permanent resident travel bans virus australia
s Australia’s global talent visa for individuals and businesses By feedproxy.google.com Published On :: Mon, 06 Apr 2020 05:48:19 +0000 In late 2019 the Australian Government launched the Global Talent – Independent program which offers a streamlined, priority visa pathway for highly skilled and talented individuals to work and live permanently in Australia. There are two streams. The first is the Global Talent Independent Program (GTI) and the second is the Global Talent Employer Sponsored (GTES). […] The post Australia’s global talent visa for individuals and businesses appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Work & Skilled Visas AgTech existing skilled visa programs FinTech Global Talent Employer Sponsored Global Talent Independent Program GTES GTES agreement GTI highly-skilled niche positions job opportunities Medium-term stream MedTech niche job overseas workers Short-term stream skilled employee skilled worker Temporary skill shortage TSS
s What can I do if I am on a working holiday or seasonal worker visa in the Coronavirus (COVID-19) crisis? By feedproxy.google.com Published On :: Tue, 14 Apr 2020 01:10:49 +0000 Seasonal Worker Programme and Pacific Labour Scheme workers can extend their stay for up to 12 months to work for approved employers as long as pastoral care and accommodation needs of workers are met to minimise health risks to visa holders and the community. Approved employers under the Seasonal Worker Programme and Pacific Labour Scheme […] The post What can I do if I am on a working holiday or seasonal worker visa in the Coronavirus (COVID-19) crisis? appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Student Visas 444 visa access superannuation Acting Minister Tudge agricultural workers Australian welfare payment Coronavirus covid-19 department of education international students JobKeeper payment labour market testing new zealand citizens pacific labour scheme seasonal worker programme seasonal worker visa student visa temporary skilled visa visa application commitment visa holders visa status WHM worker visa working holiday working holiday makers
s Employer sponsored temporary work visas (482 and 457) and Coronavirus (COVID-19) By feedproxy.google.com Published On :: Thu, 16 Apr 2020 20:10:00 +0000 If you’re a Temporary Skill Shortage visa holder – what should you do if you have been stood down or your work hours are reduced by your employer? The Australian Government has announced that Temporary Skill Shortage visa holders who have been stood down, but not laid off, will maintain their visa validity and businesses […] The post Employer sponsored temporary work visas (482 and 457) and Coronavirus (COVID-19) appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Employer Sponsored Visas AGEE Australian Government Endorsed Agreement Event breach visa conditions business employers Coronavirus covid-19 covid-19 pandemic temporary activity visa employer obligations Employer sponsored temporary work visa extend your visa extended visa labour agreement nominated salary reduced work hours sc 408 sc 457 sc 482 stood down subclass 408 Subclass 457 subclass 482 Temporary skill shortage TSS visa conditions visa holder visa validity
s Student visa holders and New Zealand citizens in Australia and the Coronavirus (COVID-19) crisis? By feedproxy.google.com Published On :: Sun, 19 Apr 2020 20:30:00 +0000 International students who have been in Australia for longer than 12 months who find themselves in financial hardship will be able to access their Australian superannuation. The Government will undertake further engagement with the international education sector who already provide some financial support for international students facing hardship. International students working in supermarkets will have […] The post Student visa holders and New Zealand citizens in Australia and the Coronavirus (COVID-19) crisis? appeared first on Visa Australia - Immigration Lawyers & Registered Migration Agents. Full Article Student Visas aged care Australian welfare payments Coronavirus covid-19 extended hours international students JobKeeper payment new zealand citizens nurses special category subclass 444 subclass 444 visa conditions working hours
s What’s New in Recipe Card Blocks Free & PRO By feedproxy.google.com Published On :: Thu, 16 Jan 2020 14:49:30 +0000 It’s been a few months since the release of the Recipe Card Blocks PRO plugin, and our team continued to release new updates constantly for both versions of the plugin: Free & PRO. As we’ve released many major updates for both versions in the past months, let’s make a quick overview of the most important changes and new features we’ve […] Full Article Plugins
s Reel 3.0: New Color Schemes, Portfolio Styles & More! By feedproxy.google.com Published On :: Mon, 17 Feb 2020 08:13:49 +0000 We’re very excited to announce a new major update for our Reel theme. The new 3.0 version brings new color schemes and many improvements to the Portfolio Showcase widget. What’s new in 3.0? 5 New Color Schemes + 2 New Theme Styles Full-width header option New styles & options for Portfolio Showcase widget 5 New Color Schemes After long research […] Full Article News
s 7 Best WordPress Membership Plugins to Generate Recurring Revenue By feedproxy.google.com Published On :: Fri, 28 Feb 2020 14:55:24 +0000 Do you want to turn your WordPress blog into a membership site? Businesses around the globe use this model to sell their physical products or offer exclusive digital content, and many of them are super successful. CopyBlogger, a site with content marketing lessons, offers premium courses to members and they’re currently an eight-figure business. Meanwhile, the owner of the razor […] Full Article Plugins
s Social Icons Widget 4.0 — Now With a Social Icons Block for Gutenberg Included By feedproxy.google.com Published On :: Tue, 03 Mar 2020 21:07:29 +0000 In 2015 we launched Social Icons Widget by WPZOOM with the intent to provide WordPress users with a simple and easy-to-use widget for adding social links to their websites. With over 100k installs at the moment and continuous positive feedback from the users, it kept us motivated to constantly improve and keep updating this free plugin. Now, to keep the […] Full Article Plugins
s Meet the Remote Workplaces of the WPZOOM Team By feedproxy.google.com Published On :: Thu, 26 Mar 2020 15:55:21 +0000 The world turned upside down lately, forcing the majority of people to work from their homes. For the WPZOOM team, working remotely is not something new. Some of our team members have been working remotely since they joined us, others had the experience of both working from home and from the office (hello, Pavel). However, we’ve gone completely remote, without […] Full Article News
s 9 Things You Can Do To Your WordPress Website During Quarantine By feedproxy.google.com Published On :: Tue, 07 Apr 2020 18:15:25 +0000 If you’d have told us at WPZOOM about the current situation we find ourselves in six months ago, we wouldn’t have believed you. It’s all we can see if we turn on the TV and it’s clear right now, humanity has taken a break. Worrying about loved ones, ensuring we stay safe, and for heaven’s sake, stay inside. Staying inside […] Full Article News
s Presence 2.0: Beaver Builder Integration, Dark Skin & More! By feedproxy.google.com Published On :: Wed, 08 Apr 2020 13:05:07 +0000 Great news for the users of Presence — our multipurpose theme. We have finally released the long-awaited 2.0 version, which features major changes and improvements. What’s new in Presence 2.0? Beaver Builder Integration Dark Skin New Demo: Organic Shop New Typography and Colors options in the Customizer New Templates in Page Builder Beaver Builder Integration If you have followed recent […] Full Article Theme Updates
s If You’re Using Beaver Builder Lite, You Need This Addon By feedproxy.google.com Published On :: Wed, 15 Apr 2020 16:22:52 +0000 Hey there, I’m Ben, and I’m a guest author here at WPZOOM. Today I thought I’d share with you my experience of one of their rather awesome plugins, an addon for Beaver Builder. I know the team at WPZOOM are big fans of Beaver Builder, why not? It’s a great page builder with an excellent feature set; chances are if […] Full Article Plugins
s How to Create an Online Ordering Page for Restaurants with WooCommerce By feedproxy.google.com Published On :: Fri, 24 Apr 2020 07:42:25 +0000 Until recently it was something normal for any restaurant to have a well-maintained website. Even so, it seems that for many restaurants this was something difficult to achieve. In these difficult times, for many restaurant owners and other businesses in this field, owning just a simple website is no longer enough. If you still want to remain in business you […] Full Article Tutorials
s 20+ Best WordPress Video Themes for 2020 By feedproxy.google.com Published On :: Wed, 06 May 2020 18:43:07 +0000 If you’re a video producer or vlogger looking to set up your own video website to showcase your content, you’ll most likely need one that reflects your own unique style. You’ll need to think about the gallery options you’d want, color schemes, customizations, and the type of business you’re running. You should also consider the different technology you’ll need to […] Full Article WP Themes
s Herbert Labs By feedproxy.google.com Published On :: Fri, 08 May 2020 08:52:01 +0000 Full Article Inspiration siteinspire Web