With the Australia Day (and Indian Republic Day) falling on a Thursday I got a long weekend by taking the Friday off. Me, Parvathy (my wife) and Gautham (my son) decided to head off to Coffs Harbour, which is a six-hour drive from Sydney. We started off at six, Thursday morning.
This was the first time Parvathy, and I was doing a road trip this long with Gautham and had no idea what to expect. Gautham was wide awake from the start of the trip till we reached Coffs Harbour. But it was all right traveling with him. The trip was also the first since he was fully toilet-trained. We did stop at 3 places on the way but were happy to do that. We stopped for breakfast at Hungry Jack’s, Beresfield and had quick burger, fries and hash brown. We continued to have this same breakfast throughout the trip, for it was fast and enabled to get on with the day quickly. Deciding, ordering and eating at a cafe is much more time-consuming. After two more stops, we reached Coffs Harbour by two in the noon. Since both me and Parvathy are trying to eat healthy (since a month), we decided to keep our lunch light. Mostly we had carrots, cucumber, and some nuts. For Gautham, we usually got something on the way.
We headed straight to Royal Palms Motor Inn and dropped our bags and quickly freshened up. The weather forecast said it would rain, but luckily there was no rain and was a pleasant climate. We headed off straight to Jetty Beach, where we spent the rest of our day. The beach was calm and had a great walk by the side of it. The sand looked like a mirror, and in the beginning, Gautham was even cautious not to break it. We enjoyed the time there and stayed there till five. After having a wash down at the beach showers, we headed back to the hotel. Gautham fell asleep the moment we got into the car. We reached the hotel and stayed in the car till seven so not to disturb his sleep. Once he woke up, we headed off to Bombay Brasserie, an Indian restaurant right next to the hotel. We usually prefer other food option while eating outside to try different cuisine. But during the trip, we stuck to Indian hotels as Gautham often ends up eating more from there, as it was similar to food at home. We had a nice tandoori platter, Nan, rice and ice-cream. By half past eight, we reached back at the hotel, had a bath and went to sleep by ten.
Day 2 (Friday)
We all slept in a bit late today and woke up by seven. Luckily Parvathy was up and ready by then. After a quick fresh up, we started off to Dorrigo. Picked up our breakfast burgers on the way and headed off straight to Dorrigo. It was just over an hours drive from the hotel and a scenic one too. Dorrigo has a lot of attractions, but we just did the Skywalk Lookout, Wonga Walk, Walk with The Birds Boardwalk and Dangar Falls. We spent half a day there covering all these. The lookout and the walks were superb. It was a pleasant walk in the forest as it had rained the night before. By the time we headed back, Gautham was fast asleep after having a delicious cake with cream and juice. Woolgoolga was the next stop and was around one and half hours away. By three in the evening, we hit the beach. By five we headed back to the hotel. On the way, we drove through Emerald beach to the hotel. After a quick fresh up we set out for dinner by six. We tried a different Indian restaurant today and ate to our full. By ten we hit the bed.
Day 3 (Saturday)
I woke up at half past five and went for a run. I ran by the boat jetty to jetty beach and through the Coffs Coast State Park. The route was scenic, and I enjoyed it.By seven I was at the hotel and got ready to checkout. We checked out by eight, grabbed a Boost smoothie and burger and headed off to Sawtell beach. It was a hot day, and the sun was already up and high. We just had a quick walk by the beach side and headed straight to Nambucca heads as we wanted to spend more time there. The walk by the Nambucca river is excellent. You can see the river meeting the sea here, and it is a beautiful sight. The river is calm and up to waist height and we can easily walk. We spent around two hours there and started our way back home at around one in the noon. It is around six hours drive, and with a couple of stops along the way, we reached home by eight in the evening.
It was a good three-day break and completely disconnected from work and social media. It was refreshing, and the drive was great too. This was our first long drive after coming to Sydney and enjoyed it.
I have been using Snagit for over one and half years and been loving it. Snagit gives you a way to create and edit screenshots or record videos to show a process, provide detailed feedback, or share information with the people who need it most. It tucks away neatly to the side of your screen and is there up and ready when you want to grab a screen capture or record a quick video. The screen capture is easily triggered using keyboard shortcuts (Ctrl + Alt + S by default). Once captured, it takes you to the Snagit editor where you can add a lot more details to the captured image.
Some of the features that I often use are:
- Blur (or Redact): Use to hide or disguise sensitive information. Often my screenshots contain sensitive content which I want to blur.
- Step: Add a series of numbers or letters to label steps or items in a capture. This feature helps in guiding a step by step process in a screenshot.
- Crop: Common feature in all image editors.
- Spotlight & Magnify: Magnify, blur or dim a selected area of the picture. This feature is useful to highlight specific parts of the image.
- Callouts, Text, and Arrows: Again pretty much standard with most image editors.
Snagit has been a great fit for blogging and makes creating screenshots easy. Communicating with images is much faster with these great features. If you take a lot of screenshots give Snagit a try, you will love it!
Often when coding, I need to move pieces of code up or down. It could be a group of lines of code or an entire function that I need to shift up or down. In earlier versions of Visual Studio, I had to select the lines of code, cut them from current place, move the cursor to the desired position and paste it. That’s a lot of keystrokes for getting a simple thing done. In the latest versions of Visual Studio (I am currently on VS2015) we can use Alt + Up/Down to move the selection up or down. This also works for the current line without selecting it.
Hope this helps to move code around faster!
Often when writing code or in code review discussions it comes up - ‘Should I be doing a null check here?.’ and we start off long discussions. Like in most cases, there is no definite answer to this. In this post let us examine some of the pros and cons of having defensive checks and how and when we can avoid it to make the code more readable.
Let’s see an example to explore more. The below code aggregated details from different repository classes and returns a combined model. I have kept this simple with just three dependencies.
1 2 3 4 5 6 7 8
As you see, there are no null checks on any of the values returned from external dependencies. The code expects all calls to be successful with no exceptions - ‘happy path’ scenario. The problem is when an error happens; the exception stack trace will look like something below.
1 2 3
We will not be able to tell which of the values was null, making it hard to debug the error. We have to manually go through the code checking how each of the dependencies retrieves values and check which one possibly was null. Debugging takes a lot of time and might be difficult depending on the complexity of the dependencies. The advantage of the above code though is that it is readable and there is noise in the code.
Let us now modify the above example to see how it would be to add defensive code and check for nulls.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
The defensive checks added for guarding against invalid values makes the code harder to read. Defensive checks are there for incoming parameters as well and validate if they are null/default value (for Guid). However when an error happens the stack trace will mention the name of the property which was null. Debugging is fast and easy and makes the exception message useful. But we don’t want our code filled with defensive checks like this.
Team Conventions and Practices
Let us dig a bit deeper into why we had to put in the defensive checks in the first place. We had to check for null on person since the repository decided to return a null when it could not find the person given an id. Does it even make sense or add any value in returning a null reference from the repository? Unless the business works in a way that there is a high possibility of something returning null this does not add any value. Even in cases like that, we should revert to other options which we will see in a while. When most of the time we expect a person to exists, it is better for the repository to throw an exception right away that the person does not exist. If the validations and the defensive checks are performed at the boundaries, then we do not need to do a null check anymore when getting a person or any similar functions.
1 2 3 4 5 6 7 8 9 10 11
For cases where there are possibilities of a value existing or not you can resort to Stronger Code Contracts. Using the Maybe type to indicate a value might or might not be present is a good way to force defensive checks. Maybe type ensures that any consumer of the code handles the case where the object does not exist. Readability of the code also improves in this case.
If you have noticed in the above code when checking for null’s, I checked the Email property for null as well. Setting up team conventions that properties cannot be null, help reduce defensive checks for it. You could use various techniques to ensure properties are not null like setting a default value for the property in the constructor, Null object pattern, checking for null’s when setting property values or modeling the object in a way that optional parameters are not direct properties on the object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
With the updated repository code and the property changes, we can rewrite the original code much similar as it was before introducing the defensive checks. The guard clauses at the start of the function, checking for the parameters is still important. Validating for input parameters helps find the problems earlier in the code stack and follows the fail fast pattern. It helps us find exactly where the null was introduced and address the issue faster. The defensive code is at the beginning of the function and can be easily skipped over while reading. If you are not that keen to write this on all functions, you can also write some helper classes which Validates a list of parameters (params). I prefer the explicit check and used to skipping over them when reading code.
1 2 3 4 5 6 7 8 9 10 11
Value Objects and Defensive Coding
Let us now look at other ways to improve defensive checks on properties. Modeling properties as Value Objects helps contain the defensive code within the property. Like in the above case where email cannot be null, the checks to make sure that it is a valid email can be within the Email class. Containing this logic in the class removes the need for the rest of the code to check for it. If an email object exists, it will be valid. It is the same with names, date ranges, money, etc. The lesser we expose primitive type properties, the less defensive code we need to write. It also removes the problems of checking string.IsNullOrEmpty at some places and just for nulls at others.
Though this is not an extensive examination of all possible cases, we have still seen some common scenarios. Defensive coding is required. It is about striking a balance and making code contracts stronger to convey the intent. The defensive checks are within the classes responsible for the object and exist at a central place. It removes the need to check for it elsewhere in the code. This is a simple application of Encapsulation. So the next time you check for null make sure it is where it should be!
Getting fit is one of the goals that I have set for myself this year. I have started running since mid of December and also controlling my diet.
- Have Parvathy (my wife) support me throughout.
- Running 1-2 times a week
- No carbs till Dinner: Smoothie, Veggies, and nuts till dinner. Dinner is Chappathi and curry (mostly vegetables).
- 150+ Pushups Daily, spread across the day
- No Sugar
I was around 95 kilos when I started out in December. At the time of writing, I weigh 82 kilos. Yes, I have lost 13 kilos over the past one and half months. This is the first time I have seen such drastic changes in my body, and I believe it’s because of the strict diet more than anything. Below are the various aspects of what I have been following.
I started with running once a week. But now I am so into it I try to run two to three times a week. I use Runtastic to track my runs. Last week I purchased the premium plan for Runtastic and looking forward to starting one of their 10k training plans and runtastic results on days that I do not run. I use a Bose SoundSport in-ear audio only headphones headphones (the cheapest in their range) for music during the runs. Luckily Bose was running a half price on those models when I purchased.
I do push-ups every day and get 150+ (25 * 6+) every day. I split this out throughout the day - 75 before I head off to work and 75 once back. I get enough time in the morning to space it at 30-minute intervals as I wake up at four. I plan to replace push-ups with Runtastic Results starting next week.
Breakfast (7:30 am): Green Smoothie (+ eggs on days that I run) or Avocado and eggs. Lunch (12 pm): Raw vegetables (Carrot, Cucumber, spinach, kale, beetroot, corn, sprouts) Dinner (6:30 pm: Wheat Dosa or Chappathi + Vegetable Curry Snacks: Anytime I feel hungry I have one of these - Nuts (Almonds, walnuts, sunflower seeds, etc.), Carrot, Banana and Peanut butter. Usually, I end up having just the nuts at around 10 30 in the morning.
When eating out, I keep an eye on carbs and other junk. Try to eat grilled instead of fried. Usually, we eat out on weekends as we will be traveling places. We usually have a hearty lunch on weekends. Parvathy and I decided to have fruits for dinner on those days. I try to take fruits that contain less sugar like kiwi, berries, etc. But we do have apples, mangoes, watermelon, etc. but in moderation. The fruit choices are more driven by what’s available at the place I live now.
Sugar: I try my best to avoid it fully. To start with I quit tea and coffee. Believe me, I was a tea addict and I needed lots of it. It was hard, but then Parvathy quit it one day, and I got inspired by her. I still remember that last tea I took when I decided I am having no more of it. It’s hard but doable!. I don’t have any ice-cream, fruit juice, carbonated drinks, energy drinks, pastries, etc.
We used to spend a lot of our weekends in shopping malls till a while back. We decided to change that to more of outdoor activities. So it’s either the beach, boating, parks, walks, etc. This has increased our general activity levels and help burn extra calories. And mostly I have ‘an extra weight’ to carry around; you can tell that from the photos :). Gautham also enjoys these outdoor activities, and there’s more for him to learn in each of those short trips. On weekdays we go for a walk after dinner, shop around for groceries, etc. and run any other errands so that we are free during weekends.
With the new routine, I now feel great to be back in shape. I have never been this light since a long time, and I am happy to be in clothes that I had locked up in my bags. Since the new routine takes an hour out of my morning routine I have to optimize myself further to keep up with blogging, videos and learning new things. I am still trying to find a balance but for this. Hoping to continue with this new routine.
As a .NET developer, I spent the majority of my time in Visual Studio. Knowing to navigate fast within the IDE or quickly find what I want is important. Many times finding specific settings or navigating to individual windows can take a while, especially if you are not familiar with it and don’t know exactly where to look. Visual Studio has a quick launch toolbar that is designed exactly for this. Be it opening the Package Manager Console or changing the font style you can use the quick launch to search and navigate to it.
You can use Quick Launch to quickly search and execute actions for IDE assets such as options, templates, menus. You can’t use Quick Launch to search for code and symbols. The Quick Launch search box is located at the top-right corner of the menu bar and is accessible by choosing the Ctrl+Q keys.
The added advantage is that you can use the quick launch bar to learn new keyboard shortcuts. Searching for an item also shows the keyboard shortcut for it next to it. Over time you can remember the direct keyboard shortcut and avoid quick launch as well.
Knowing the tools that you use is an important part of development. Able to navigate fast within the IDE enables to remove any time wasted poking around the IDE. Use that time to read and write code.
How many times have you had to navigate down a long chain of function calls to find out that some code deep down was changing the value of an object passed to it? The change could either be setting the value to null or modifying the value in itself. When passing around reference types, it’s easy to run into this situation very often. This happens not just when debugging existing code, but also when looking at the code we have just finished writing. Maintaining state transitions and object state based on the order in which functions are invoked on them can soon become confusing and buggy. So the best way is to try and avoid them in the first place.
What is state Mutation
The process of changing the value of a variable or an object over time after creation is called mutation. In simpler terms when you are changing the value of an object, you are mutating the state. I am sure that everyone would have had some time getting their head around the below statement when starting off with programming (I did)
By second nature (depending on the programming languages one is exposed to e.g. csharp, java, etc.) you would say the above statement is perfectly fine and not think twice about anything. But show it to someone who is new to programming. They will find it hard to understand those two statements, the same phase that we have all gone through. ‘=’ has turned into an assignment operator while it is an equality operator in mathematics. There are languages where ‘=’ still stands for equality (like FSharp). In the example above the value of x is mutated - it is changed from 1 to 2.
The process of actually changing a variable’s value over time, within a single context, is called mutation.
Risks of Mutation
Mutable types can pose risks when passing a mutable value as function parameters or when returning mutable values from functions.
Passing Mutable Value
Let us take a simple example below. I have a list of integers, and I want to check if the first item of the incoming list and the sorted one are same. I have a simple sort method which implements Bubble sort. What do you think will be the output?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Yes, it prints out the message that the First item is in place. Before getting into the details of the issue, let us set our expectations correct. When calling the Sort method, we do not expect it to change the contents of the original list. Given that the function’s signature is that of a Query (returns a value), we expect it not to create any side effects). According to Command Query Separation (CQS) by Bertrand Meyer in Object Oriented Software Construction
Every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, Asking a question should not change the answer. More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.
Applying CQS means that any method can either be a Query or a Command. A command changes the state of the system but does not return a value (void). A query does not change the state of the system and returns a value and should be idempotent. Such functions are also referred to as pure functions. The above Sort function only partially confirms to being a query. It does return the same output given the same input, the sorted list. But it changes the state of the system and has side effects - it mutates the list passed. The issue in the implementation of the Sort is that it casts the list passed in as IList
This kind of change is only possible if the development team owns the Sort function. If this is a third-party library that you are consuming then the only way to avoid the problem will be to send in a copy of the list. Even trying to pass the list AsReadOnly will not work here. Check it out if you are not sure why.
The above solution does not imply that every time we need to pass in a list to a function we should defensively copy it (using ToList). It depends. Within a development team, there can be a convention that it sticks to CQS principle. In case of exceptions, make sure that it is communicated to everyone. Communication to developers is done best by naming the function to reflect that or adding a comment that shows up in the IDE intellisense (if any). For code that you consume from third parties or open sources make sure you understand well how the library behaves and check the documentation before using it. Ensure you have unit tests asserting the assumptions and behavior in all cases.
Returning Mutable Values
Let us take an example to see the possible effects of returning mutable values from a function. Below is a configuration helper class which returns a configuration object. The helper method is used in three different places of the application shown as config1, config2, config3. In one of the cases, the business logic requires the Duration value to be twice that in configuration. Since the real configuration helper reaches out to the database for its values, it was decided to cache the values after the first call. The ConfigurationHelper uses ‘Singleton Pattern to achieve the caching Below is the implementation. Do you see any problems?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
The first caller will get the configuration value 1, as expected. The second caller also gets the configuration value 1, but it goes on to set the value as two times, so it becomes 2. The third caller, which does not have any idea of the second caller or its specific business requirements also gets the configuration value as 2. They get a wrong configuration because the second caller updated the same object that the ConfigurationHelper holds. Again this is a side effect of how the ConfigurationHelper returns the configuration. There are two or more ways to solve this problem. The ConfigurationHelper class can return a new instance of the Configuration class every time someone requests for it. To return a new instance requires removing the private variable and the conditional check associated with it. Removing the check is similar to the defensive copying that we discussed in the previous example and also every call to get the configuration, now needs to hit the database. One could argue that only one caller mutates the object and it is unnecessary to create a new instance for the rest. We can remove the public setter’s on the Configuration class properties. Without a setter, the second caller cannot change the Duration property of the Configuration class. Removing the setter means that we add a constructor as well to take in the parameters that it requires as below.
1 2 3 4 5 6 7 8 9
The above ensures that nobody can change the value of the configuration object once created. So the second caller can longer assign the new duration value to the same object. If it wants to continue using a configuration object it needs to create a new Configuration object with the new duration. If there are more properties on the configuration object you can create extension methods like WithDuration to create a new Configuration class copying all the values as is from the old object and replace just the Duration.
1 2 3 4 5 6 7
As we have seen the above two cases, mutation can cause undesired effects unless those are intended for. It does not mean that mutating is bad and you should stop it immediately. But if you start writing your code using immutable types, Value Objects, etc. you will slowly move to a point where you no longer need to mutate values. When you do not mutate state, it is easier to reason about code. You no longer need to wade through those method calls to find who is changing the value of a property. Immutability is one of the key features of functional languages and changes how programs are written. You take away most of the problems involved in multi-threading when a function can no longer mutate the state of the object. So the next time you make change check if you are changing the state of the object, think twice and see if you can find a way around!
I have been using Cmder as my command line for around two years and been loving it. I am not a super user of the command line, but try to use it more and more.
Cmder is a software package created out of pure frustration over the absence of good console emulator on Windows. It is based on ConEmu with major config overhaul, comes with a Monokai color scheme, and a custom prompt layout.
This is not right with Windows 10, as there is a new command prompt which has a lot more features. I have not yet thought of moving to that as Cmder has been working well for me.
Installation and setting up
Cmder is open source and free to download from Cmder.net. One of the advantages of Cmder is its portability. You can carry it with you on a USB stick or in the Cloud, so all your settings can go anywhere you go. Installation is simple, all you need to do is download the latest release, extract the archive and run Cmder executable. Check out the documentation if you face any difficulties.
Features I Like
Able to paste into the console using the Windows shortcut Ctrl + V is one of the key things that got me started with this command line tool. It also supports most of the other text traversal keyboard shortcuts of Windows.
Cmder supports multiple console tabs within a window. Tabs makes having multiple consoles open and managing them easy. All tab manipulation has associated keyboard shortcuts making it even faster. When creating a new tab, using Ctrl + T, you can choose to run different predefined tasks on command line startup. You can also set the user and user rights to run them as. Setting up the predefined tasks is under Settings -> Startup->Tasks. I have added custom tasks for PowerShell, and Visual Studio developer command prompt as that is what I use mostly.
1 2 3
Alias is one of the key features that keeps me to Cmder. You can create short commands to map to longer commands. Aliases avoid typing long commands every time you want to perform that action. You can see all existing aliases by running alias command. I use this feature a lot. Most of the git commands are aliases, so I do not have to type them every time. For e.g., when on a git repository I can type gs to run git status. You can also pass arguments to alias. To do a git commit with a message I run gc The commit message. Aliases support optional parameters through the $1-9 or the $*.
To define a alias alias gs=git status. Below are some of the alias examples.
1 2 3 4 5 6
Check out the video for a walk-through of the setup and its usage. Cmder allows to get things done fast and looks great. Try it out to see if it works for you.
Screencast helps to connect with people in a different way and adds a personal touch (sound and visual). It makes learning new things faster, by seeing it in action. Most of the fine details (which can be missed while writing a blog post) get captured in screencasting and this helps in better understanding. I have been long wanting to create screencasts and start a YouTube channel. Finally, this happened in 2016 and here is how the recording experience went.
A screencast is a digital recording of computer screen output, also known as a video screen capture, often containing audio narration.
I chose to do my first screencast as a slide share presentation, as it was something that I was comfortable with. Since there are not many videos on Azure Key Vault and I have been blogging extensively about it, I didn’t have to think twice about the topic. I scripted the whole presentation, to every word that I would say. Scripting for a video is different from writing a blog post as it has to be conversational with a video. Also, there are a lot more details that need to be covered and talked about as it is all visible on the recording.
Since I did not have an external monitor I wanted a presentation application that allows presenter notes and syncs them across multiple devices. This would allow me to record the screen and read off the presenter notes side by side. Slides had exactly what I wanted. It allows to add presenter notes for each slide and allows remote controlling the presentation from multiple devices. So I can launch it as a full-screen presentation on my laptop for recording screen and have an iPad or mobile launch the same presentation as a presenter where the notes show up. This helped me follow the script while recording the video. It would have been much easier with multiple monitors, but I just did not want to get one just for this and I have been trying to get used with a single screen. Alternatively, I could have taken a printout of the script.
An external microphone is absolutely necessary to record your sound well. The microphone that comes built into the laptop is not suited for recording good quality audio. It picks a lot more of the background noises, room noise, typing etc and creates a lot of disturbance in the recording. There are a lot of options available when it comes to getting an external microphone. Most of the microphones are either Condenser Mics or Dynamic Mics. Microphones also have different connectivity options like XLR, USB etc. For a home recording setup USB is easier to get started with so I decided to get one with a USB connectivity.
I got the Rode Podcaster with a boom arm and shock mount. The Rode Podcaster is a dynamic USB mic and is a popular choice amongst many people out there. It’s a bit higher on the price side (depends on your budget though) but delivers great value. It cuts off most of the room noise and takes in only your voice which is exactly what I wanted. You need to get really close into the mic, so a boom arm helps.
Choosing the software was much easier than getting the microphone. Adobe Premiere or Camtasia are the most popular screen recording software’s in the windows world. I have a lot of friends already using Camtasia and was happy with it. So I decided to stick with Camtasia and bought a license (Thanks to Readify’s Software Allowance, I did not have to spend a lot from my pocket).
For recording audio, I use Audacity, which is an open source software and available free of cost. I am yet to learn some audio processing techniques and for now just use noise removal, amplify and compression. Also since the Rode microphone does not pick a lot of external noise the audio did not require much processing. At first, I tried recording with a Samson GO mic but felt that it picked it a lot more room noise and it needed a lot more audio processing.
With the hardware and software sorted now comes the hardest part of it all - Recording!!. I knew there would be difficulties along the way, but never thought it would be this hard. After reading around I understood that a popular technique that people use for recording is to record the audio and video separately for webcasts/screen recordings. I decide to take the same approach but just that did it in the wrong order (which I found after the first recording). For my first video I did the video first and the audio later. This meant that I recorded my screen performing all the slide movements and the code sample demo and then tried to fit the audio onto it. This was the biggest mistake in my complete recording, but I realized it only towards the end of the recording. Recording video was easy but fitting in the sound to it was hard. I had to do multiple (innumerous) takes and have to stop so often every now and then. And since I am yet to learn how to talk naturally when in front of a microphone, my voice was all over the place. Some bits had more bass, some a bit low others high, some fast others slow. I struggled with it for a long time and finally somehow got to get it all together. But though it was nowhere close to the quality that I set out for or would love to have in videos that I watch, I decided to ship it. For the second recording, I recorded the audio first and then fitted in the video onto it. This was so much easier and I have a more consistent voice in that, though there is a noticeable change in the middle.
I am planning to do more recordings in the upcoming months so that I get more comfortable with it. If it hurts, do it more often. Kindly leave your feedback on the videos.
I prefer to use the keyboard to navigate within sites I use frequently. Keyboard enables to navigate faster within site and perform tasks quicker. The Logitech MX Master mouse provides a lot of capabilities to navigate. But I find the keyboard faster to perform repetitive actions - like posting a new status update on social media sites, managing tasks in Jira, TFS online, GitHub, responding to emails, Todoist, etc. Finding keyboard shortcuts on these various sites can itself be a daunting task. One might need to google to get the shortcuts or find the relevant documentation on the site. Luckily most of the popular sites today display a pop-up modal with all the keyboard shortcuts for the site when pressing Shift + ?. Note that this might not work on all the sites out there. But for most of the common ones that I use l, I find it working.
So the next time you spend a lot of time on a website try hitting Shift + ? to look for supported keyboard shortcuts.