This post documents a solution for the following error I encountered in a React TypeScript project that was using Redux:
No overload matches this call.
Overload 1 of 2, '(props: ProviderProps<Action> | Readonly<ProviderProps<Action>>): Provider<Action>', gave the following error.
Type '{ children: Element; store: Store<{ readonly [$CombinedState]?: undefined; } & { repos: ReposState; }, Action>; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Provider<Action>> & Readonly<ProviderProps<Action>>'.
Property 'children' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Provider<Action>> & Readonly<ProviderProps<Action>>'.
Overload 2 of 2, '(props: ProviderProps<Action>, context: any): Provider<Action>', gave the following error.
React is a JavaScript framework used to build web apps. Redux is an open-source library used to manage the state of an application, and is often used along with React JS.
In this context, the Redux <Provider> component is used to pass application state along to its children components. It is best practice to wrap the entirety of your app in the <Provider> component, and pass the store object into it as an argument (property):
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { Provider } from 'react-redux';
import App from './App';
import { store } from './state';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
In my project, this was producing an error on the <Provider> component that said “No overload matches this call.” I knew this must have something to with the argument(s) being passed along.
At first I thought it might have something to do with my store object, but that was not it. I was able to resolve this roadblock by explicitly passing a ProviderProps object into the Provider component.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { Provider, ProviderProps } from 'react-redux';
import App from './App';
import { store } from './state';
const providerProps: ProviderProps = {
store: store,
};
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<Provider {...providerProps}>
<App />
</Provider>
</React.StrictMode>
);
This worked because the store object is explicitly typed in the ProviderProps object. This ensures that it matches the type expected by the Provider component. Ultimately, it was a TypeScript error. TypeScript was not able to infer the store type correctly.
A common coding challenge that you may encounter will ask you to write a function that returns the Fibonacci sequence, up to the nth number (which is provided as an argument). Below is a solution, along with some commentary about the topic. This challenge is a great exercise in problem solving.
Fibonacci numbers
The sequence starts with 0 and 1, and the next number in the sequence is always the sum of the previous two numbers. The first few terms of the sequence are:
Since this series follows a known pattern, we can write code to generate it up to a specified position.
In mathematics, the Fibonacci sequence is a sequence in which each number is the sum of the two preceding ones. Numbers that are part of the Fibonacci sequence are known as Fibonacci numbers.
These numbers were first described in ancient Indian mathematics. They are named after the Italian mathematician Leonardo of Pisa, also known as Fibonacci, who introduced the sequence to Western European mathematics in his 1202 book Liber Abaci. Fibonacci numbers are also strongly related to the golden ratio. In computer science, these numbers can be applied to programming algorithms related to search, data structures, and graphs.
Recursion
In programming, recursion is an important concept. Recursion is when a function calls itself. Writing code that generates the Fibonacci sequence requires recursion. Here is an example in JavaScript:
function fibonacci(n) {
if (n < 2){
return 1;
}else{
return fibonacci(n-2) + fibonacci(n-1);
}
}
console.log(fibonacci(7)); // Returns 21
If you ask this function for 0 or 1 terms, it will simply return 1. It is the condition that will ultimately stop the recursion. Anything above that, it will have to call itself recursively. What exactly is happening there? This Stack Overflow thread does a great job stepping though the logic and illustrating each iteration.
When I decorate the code from above with console log statements and collect the results into an array, it becomes obvious:
function fibonacci(n) {
console.log("Iterating on n = " + n)
if (n <= 1) {
console.log("n is: "+n)
return [0, 1].slice(0, n + 1);
} else {
const fib = fibonacci(n - 1);
console.log("fib is: "+fib)
console.log("iterating on " + n)
fib.push(fib[fib.length - 1] + fib[fib.length - 2]);
return fib;
}
}
You can see it iterates all the way down, starting at the desired argument of term numbers, and ending with 1. Once it gets to the bottom, it starts going back up. On each subsequent round, it adds a new number to the result array by summing the previous two numbers.
I asked ChatGPT to rewrite this code for me, and this is how it was cleaned up:
function fibonacci(n) {
if (n <= 1) {
return [0, 1].slice(0, n + 1);
} else {
var sequence = fibonacci(n - 1);
sequence.push(sequence[sequence.length - 1] + sequence[sequence.length - 2]);
return sequence;
}
}
This function has an exponential time complexity. It can be very slow for larger values of n.
Memoization and Cacheing
This challenge is often followed with a request to make it “more performant”. I mentioned above that our solution has “exponential time complexity”. Its algorithmic efficiency can be described as O(2^n) in Big O notation.
Every call (while n is greater than 1) results in two additional recursive calls, one with n-1 and another with n-2. Each of those calls then results in two more recursive calls, and so on, resulting in a binary tree of recursive calls.
The performance of this code can be improved by implementing memoization. Memoization is when we store the results of our function call. On subsequent calls, our application can look up answers it previously calculated without have to do the work again.
function fibonacci2(n, memo = {}) {
if (n in memo) {
console.log("we used the memo on: " + n)
return memo[n];
}
if (n <= 1) {
return [0, 1].slice(0, n + 1);
} else {
const fib = fibonacci2(n - 1, memo);
fib.push(fib[fib.length - 1] + fib[fib.length - 2]);
memo[n] = fib;
return fib;
}
}
memo = {}
console.log(fibonacci2(7, memo));
console.log(fibonacci2(15, memo));
On each iteration we save the results to an array called memo. When we use the function, we first check to see if the answer we want is already stored in our cache. Our course, the work still needs to be done the first time around, but never again – making computation much faster in the future. You can see that my 2nd call can start where the results of the previous call left off:
By using memoization, this implementation of the Fibonacci function has a time complexity of O(n). Another way to improve the performance of our code, without using memoization, is to use a loop:
function fibonacci(n) {
var sequence = [0, 1];
for (var i = 2; i <= n; i++) {
sequence.push(sequence[i-1] + sequence[i-2]);
}
return sequence;
}
The choice between memoization or a loop depends on the specific requirements and constraints of the use-case. While the time complexity of a loop-based solution is still O(n), it can be faster than the memoization approach for small or medium-sized values of n. If simplicity and readability are a higher priority, or if memory usage is a concern, a loop-based solution may be a better option.
Memoization is considered a “dynamic programming” technique. Dynamic programming involves solving sub-problems once and storing the results for future reference, which can significantly improve the efficiency of the overall solution.
On this website (this very one you are reading) I have a resume page. On it, I display a timeline styled with CSS. I use the border-radius property to create circles for the years on that timeline. The years connect between <div> elements that represent my work experience.
It looks great (at least, I think so). Except on mobile. Specifically, on Android running Chrome. The circle appears oblongly squished.
I could not recreate this bug on my laptop, even when I used Chrome Developer Tools to simulate mobile. Not being able to reproduce a bug consistently is a very frustrating experience.
USB debugging
I would have to use remote debugging via Chrome DevTools. The first step was to enable “Developer Options” on my Android device. I was using a S21 Galaxy Ultra. On this device I navigated to “Settings” -> “About Phone” -> “Software information”. Then I triple tapped the “Build number” and received a toast message “Developer mode activated”. This feels familiar, as it has been a similar process on previous Android devices that I have owned. I’d post a picture of my software information screen, but am worried that some of the data could be used maliciously by strangers on the internet.
“Developer options” was revealed in my “Settings” app. From there, I could turn on “USB debugging”
Now, I could connect my Android to my MacBook. From my MacBook, I opened Chrome and navigated to chrome://inspect/#devices
As long as my Android also had Chrome running, I could see my device listed with any open browser tabs. Clicking “inspect” opened a new window on my laptop that mirrored my cellphone’s screen. When I scrolled on one, it reflected on the other.
CSS Solution
I could inspect elements from the developer tools panel. This was exactly what I needed to debug the problem. And, the fix ended up being pretty easy. Here’s the original, relevant CSS:
The issue was ultimately with the width and height properties. The circles look correct on my desktop browser because the width and height rendered to nearly identical – 64px by 66px. To get a circle with CSS you need an element with the same height and width (the greater the difference, the less even and more stretched the circle appears), and then set the border-radius to 50%. On Android, that same element was being rendered as 64px by 85px. This was most probably happening because the height was not being explicitly defined.
As a remedy, I hard-coded the width and height properties. I changed the unit of measurement to pixels for both.
This fixed the circle from being stretched. But, now the text was not centered that way that it should be.
That was happening because of the line-height property. Since it was set without a unit of measure, most browsers would interpret it to mean a multiplier of the current font-size. And, the font-size was also using a relative unit of measure, em. Right away, that was a code smell. It was a browser issue, where along the way values were not being calculated as expected.
On mobile, the font-size was being calculated to 20.8px. On desktop, the font-was was being calculated to 16px. I fixed this by changing the line-height value to an absolute unit of measure:
A palindrome is a word (or a string of characters) that can be read identically either forwards or backwards. Examples include:
racecar
madam
mom
level
civic
kayak
rotavator
The logic for determining a palindrome is simple. Take the input, reverse it, and then compare it to the original. PHP even has a built-in operation, strrev(), to reverse strings. We can write a function to judge if an input string is a palindrome:
During an interview, for a role as a Software Engineer, I was asked “Given a string, determine if you can make it a palindrome by removing at most 1 character.”
To solve that challenge, I can loop through the string while increasing the value of a counter variable. On each iteration, I’d remove a single character (whose index is determined by the count), reverse the result, and then compare it.
I use PHP’s substr() function to get the each half of “the new string with one character removed.” The first division starts from the beginning (zero index) and continues up until the counter determined position (zero on the first loop, one on the second, and so on). The second part starts one step past the iterative count, and finishes with the string’s end. This results is the original input with a single letter deleted.
To illustrate how this works, I printed out the concatenation each time. You can see that the program continues until the result is a palindrome.
Although this works, reversing the string each time is costly. It reduces the algorithmic efficiency, making the solution “not scalable.” How can we decide if a string is a palindrome without reversing it?
Validating a palindrome using recursion
Judging a string to be a palindrome can be done using recursion. In programming, recursion is when a function calls itself.
Before we worry about removing any characters like we did above, we need a new function to verify a palindrome without reversing it:
function determinePalindromeRecursively($value){
if ((strlen($value) < 2)){
// echo "true \n";
return true;
}else{
if (substr($value,0,1) == substr($value,(strlen($value) - 1),1)){
echo substr($value,1,strlen($value) - 2) . "\n";
return determinePalindromeRecursively(substr($value,1,strlen($value) -2));
}else{
// echo " Not a Palindrome";
return false;
}
}
}
This method compares the first and last characters of the input. If they match, our code will remove them and pass the updated $value back around to itself, recursively. This continues until we get down to a single letter, or less – when we know that the original string was a palindrome.
To get the first character, we tell the substr() method to take the $value, start at the beginning (zero index), and collect a single element: substr($value,0,1)
To get the last character, we tell the substr() method to take the $value, start at the end (the string’s length minus one), and collect a single element: substr($value,(strlen($value) – 1),1)
To remove both the first and last letters, we tell substr() to start just past the first element (represented by an index of 1), and to collect the string’s length worth of characters minus two.
Notice that on each recursive loop, the string loses the front and back symbols.
Now, remember the original challenge: “Given a string, determine if you can make it a palindrome by removing at most 1 character.”
All that is left is to use our recursive function in tandem with removing a single character per loop.
Give it a try, refactor my code, and see if you can solve this problem in a different way. There are other computer science puzzles about palindromes that you can apply this logic towards. Have fun!
Programming and meditation have a lot in common. Both demand focus and concentration and can enhance your ability to think clearly and solve problems.
When you program, you are constantly thinking critically and solving problems. You must be able to debug your code when something goes wrong, pay close attention to the little things, and think rationally. This can be mentally difficult since it calls for intense focus and concentration.
Focus and concentration can be enhanced through the practice of meditation. It can entail sitting in quiet while concentrating on your breath or a mantra, which is a particular word or phrase. This can assist with distraction removal and strengthen your capacity for sustained attention.
I started meditating early in my career as a programmer. Having had an interest in Buddhism, the tangental practice of meditation was appealing as a self-care ritual. I didn’t anticipate the impact its benefits would have on my skill, motivation, and focus. These necessary attributes compounded as my practice grew.
Meditation can help reduce stress and anxiety. This is important for programmers, as the work can be challenging. The ability to stay calm and focused in the face of stress can be invaluable in the programming world.
I had always been a workhorse, spending hours upon hours coding and debugging. Meditating for just a few minutes a day helped me to clear my mind and focus on the task at hand. I discovered I could sleep better and was less irritable.
As I continued to meditate, I found that my productivity increased, and I was able to tackle problems that previously seemed insurmountable with ease. My coding was more precise and effective. I was able to think more imaginatively and provide fresh ideas for problems.
I was so impressed with the benefits of meditation that I began to teach it to my colleagues. They also discovered that it made people more productive and happier at work.
Writing as a Meditation Practice
In another post, Reading Habits for Programmers, I discuss the benefits of practicing focus to improve coding skills. I mention that “ifreading benefits your coding ability, then meditation does too”. I would go as far as to say that reading is a form of meditation. Any time we intentionally shift our focus from scattered to laser-like, we are practicing mindfulness. Note-taking and blogging is a great way to do that too.
Writing about how the world seems through your own particular lens fosters mindfulness and appreciation. It keeps your mind grounded in this realm. Journaling is an important ritual that I practice daily, but it is hard to take note of and digest everything that happens in our lives. Doing it here is a way that I can highlight the stuff that has truly touched me.
To get philosophical about it, I think that what’s really out there and what we experience might be very different things. Like how a the experience of a computer screen showing a beautifully drawn graphical user interface never hints at the reality of computer boards directing electrical circuits to represent the information we see. Our notion of reality is a digital simulation instigated by the sensory input interpreted through our senses.
Walking meditation (kinhin) is another form that has helped get my through challenging times. Solutions, both to engineering problems as well as life obstacles, reveal themselves mid-stride. Stress relief can be induced by physical activity. Fresh air and blood flow are good for the brain. Light exercise is the necessary distraction that gives our mind space to breathe.
Mindfulness
Our senses keep us plugged into reality. They instantly create a connection to the present. Paying attention is the only way to experience this moment in life. If you’re feeling distracted, panicked, or out-of-touch with reality, try taking time to intentionally notice the things that stimulate you.
Setting out a short period of time each day to sit quietly and concentrate on your breathing might serve as a simple way to include meditation & mindfulness into your regular schedule. There are numerous styles of meditation, so it’s worthwhile to try out different techniques to determine which ones suit you.
Though they may appear unrelated, programming and meditation have more in common than you may imagine. Making meditation & mindfulness a daily habit can help you focus better, manage stress and anxiety, and become a better programmer.
Even under the richest of experiential excitement, without mindfulness there is no participation with, nor illusion of, reality. If you mindlessly read a book, you might as well have not read it. If you day-dream during a movie, you may know as much about the plot as someone who has never saw it. The same is true for life in its entirety. Don’t miss out – pay attention.
You can train yourself to get better at paying attention. The better you get at it, the more you will experience the richness of vibrancy of this world. The two best techniques I have found for this is: meditation and reading.
For a recent side project I was tasked with enhancing an existing HTML table. That table displayed search results. The records were dynamic, populated by an AJAX call after the “search” button was pressed. One of the requests was to let users click on the column headers to sort the table. Each click would organize the data, toggling ascending and descending, based on the column values.
My first idea was to use a front-end library. I love abstractions, and hate reinventing the wheel. I’ve used the DataTables jQuery plug-in before, and thought it might be a good fit. All I had to do was include two CDN file references – one for CSS styles and another for JavaScript functionality. After that, I could select the table by ID and call a single function:
This added quick and easily out-of-the-box functionality, with bells and whistles.
It seemed great, but the extras that it added, such as pagination and front-end search were unnecessary, and actually got in the way of the design specification. Those might be easy enough to clean up by passing options into the method call, or even with a bit of custom CSS, but still seemed like overkill.
Further, the DataTables library would occasionally throw errors about an “incorrect column count”, depending on what results my back-end provided. That was because the data model, and possible front-end actions for this app were more complex that you might think. The HTML wasn’t strictly semantic and the information wasn’t just tabular.
The more I thought about it, the more I felt that plain vanilla JavaScript should be enough to get the job done. And, since we’re living in the future, I decided to ask an AI chat-bot called ChatGPT.
I asked “How can I use jQuery to sort an HTML table by a specific column?”
It told me that “You can use the sort method of JavaScript arrays combined with the map method to sort an HTML table by a specific column,” and gave me a specific code example!
I was very impressed. Here is the JavaScript code it provided:
<script>
$(document).ready(function() {
var table = $('#myTable tbody tr').get();
table.sort(function(a, b) {
var A = $(a).children('td').eq(1).text();
var B = $(b).children('td').eq(1).text();
if(A < B) {
return -1;
}
if(A > B) {
return 1;
}
return 0;
});
$.each(table, function(index, row) {
$('#myTable').children('tbody').append(row);
});
});
</script>
I added this code to a click-handler in my app, after adjusting the element selectors. Although it worked (kind of), it did not operate quite as I expected. It only performed the sort on a single column, and did not alternate the order on each click.
I continued to ask the chat-bot more questions, making refinements to the functionality. I wanted the code to toggle between ascending and descending on each click. Also, I figured it could be nice to avoid jQuery completely and just use basic JS.
Eventually, it told me “To toggle between ascending and descending order when sorting the table, you can keep track of the current sorting order for each column in a separate array”. Below, you can see the full code implementation:
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
text-align: left;
padding: 8px;
border-bottom: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
th {
background-color: #4CAF50;
color: white;
cursor: pointer;
}
td:first-child {
font-weight: bold;
}
td:nth-child(3), td:nth-child(4) {
text-transform: capitalize;
}
#search-input {
padding: 8px;
margin-bottom: 12px;
width: 100%;
box-sizing: border-box;
border: 2px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
#search-input:focus {
outline: none;
border-color: #4CAF50;
}
</style>
<input type="text" id="search-input" placeholder="Search breeds...">
<button>Search</button>
<table id="dog-table">
<thead>
<tr>
<th>Breed</th>
<th>Origin</th>
<th>Size</th>
<th>Temperament</th>
</tr>
</thead>
<tbody>
<tr>
<td>Labrador Retriever</td>
<td>Canada</td>
<td>Large</td>
<td>Friendly, outgoing, and active</td>
</tr>
<tr>
<td>German Shepherd</td>
<td>Germany</td>
<td>Large</td>
<td>Loyal, confident, and courageous</td>
</tr>
<tr>
<td>Poodle</td>
<td>France</td>
<td>Small to Large</td>
<td>Intelligent, elegant, and proud</td>
</tr>
<tr>
<td>Bulldog</td>
<td>England</td>
<td>Medium</td>
<td>Determined, friendly, and calm</td>
</tr>
<tr>
<td>Beagle</td>
<td>England</td>
<td>Small to Medium</td>
<td>Cheerful, determined, and friendly</td>
</tr>
</tbody>
</table>
<script>
// Get the table element
const table = document.querySelector('table');
// Get the header row and its cells
const headerRow = table.querySelector('thead tr');
const headerCells = headerRow.querySelectorAll('th');
// Get the table body and its rows
const tableBody = table.querySelector('tbody');
const tableRows = tableBody.querySelectorAll('tr');
// Initialize sort order for each column
let sortOrders = Array.from(headerCells).map(() => null);
// Attach a click event listener to each header cell
headerCells.forEach((headerCell, index) => {
headerCell.addEventListener('click', () => {
// Extract the column index of the clicked header cell
const clickedColumnIndex = index;
// Toggle the sort order for the clicked column
if (sortOrders[clickedColumnIndex] === 'asc') {
sortOrders[clickedColumnIndex] = 'desc';
} else {
sortOrders[clickedColumnIndex] = 'asc';
}
// Sort the rows based on the values in the clicked column and the sort order
const sortedRows = Array.from(tableRows).sort((rowA, rowB) => {
const valueA = rowA.cells[clickedColumnIndex].textContent;
const valueB = rowB.cells[clickedColumnIndex].textContent;
const sortOrder = sortOrders[clickedColumnIndex];
const compareResult = valueA.localeCompare(valueB, undefined, { numeric: true });
return sortOrder === 'asc' ? compareResult : -compareResult;
});
// Rebuild the table in the sorted order
tableBody.append(...sortedRows);
});
});
</script>
Using predictive language models as a coding assistant is very helpful. I can’t wait to see what other uses we find for this technology, especially as it gets better.
The benefits of reading are well documented and enumerated. If you are a programmer, reading helped get you to were you are. Of course, as with any intellectual pursuit, consuming prosaic knowledge is a pre-requisite to success.
Having the time to read, think, and write is a luxury. It’s a habit that that many people claim they can’t afford. And ironically, those are the people that could benefit from it the most. Like strength training, it is something I’ve habituated myself to do daily.
Reading makes you a better software engineer, not because of the information ingested, but because of the byproduct mental skill built as a result. Reading, regardless of the subject matter, is strength training for your mind. It is a neighbor to meditation and mindfulness in regards to brain health.
And, to make the connection explicit: if reading benefits your coding ability, then meditation does too. I’m not the only one that thinks that meditation will make you a better programmer. Reading, and writing, can be meditative pursuits that afford the benefits enjoyed by mystics and monks, engineers and enigmatics*. Consuming knowledge is, in many ways, a programmer’s primary function. Let’s delve into the realms of reading and writing that act as superpowers in molding our intellect and efficiency.
Reading
Literacy seems to date back nearly five-thousand years. It might be even older. I wouldn’t be surprised if the timeline of civilization and humanity turns out to be much longer than what is currently accepted by historians and scholars. Reading and writing are low-tech, non-electrical, super powers that define and augment what it means to be a modern human. Like meditation, reading changes the brain’s physical structure.
Reading is a skill. Even if you “know how to read”, true literacy is highly perishable. Amber Peterson from The NCTE writes, “literacy is the way that we interact with the world around us”. Following the video-game, simulation theory, analogy – being literate is the opposite of being an “NPC” in real life.
This type of literacy flexes same brain muscles as mindfulness. It is the kind of mindfulness that allows us to actually experience life, or what Sam Harris calls “waking up”. Even if you live a very long time, if you were a mindlessly zombie the entire ride, then it might as well not even have happened.
Filmmaker Stephen Apkon is quoted as saying “True literacy is always a two-way transaction. We don’t just consume; we produce. We don’t just read; we write.”
Spoken communication already feels magical. From an alien perspective, it seems I can sing sounds to export my thoughts and ideas into another person’s mind. Writing, then, is an evolution of this transcendent practice that allows brain data to be store, shipped, and unzipped without a livestream.
Listening
Audiobooks unlock a new way to consume written words. Many people find it easier than reading. I think that is because it requires less focus. If I listened to a book, can I say that I have “read” that book? My opinion is “yes”, but does that mean that I can say that I have also “read” a podcast? Do we need new terminology to better describe our world?
I can get through a publication more quickly by listening. But, does that forsake the benefits of increased focus that I discussed above? Entrepreneur Naval Ravikant tweeted, “Listening to books instead of reading them is like drinking your vegetables instead of eating them.”
I love that analogy. It’s still good for you, but there is clearly something missing. And, how Faustianly modern it is to prefer a more processed option in favor of palatability. In another tweet, Naval says, “Reading is more efficient when at rest. Audio is more efficient when in motion.”
I agree, and reserve Audiobooks for when I am moving – walking, exercising at the gym, or even driving. Brian Tracy, author and top business-speaker, said “You can become one of the smartest and most knowledgeable people in your field by turning traveling time into learning time; by turning your car into a mobile classroom,”
I first discovered this concept of a “university on wheels” around 2008 after listening to one of my first-ever Audiobooks, “The Phoenix Transformation“. Around that time I had just finished college, and was trying to figure out what to do with my life. My primary source of income was delivering pizza, so I was on the road a lot, alone in my car.
This was before smartphones were popular, and as a poor young person, I could not afford a stand-alone MP3 player. I was able to download books and other audio programs (Tony Robbins changed my life), and burn them onto blank CD-R disks. A single book might be ten CDs long. If I heard something impactful or if there was an exercise prompt by the author, I would pull over and scribble my thoughts down onto a blank “guest check” pad, sparking the origins of my hypergraphia.
Tips, Tricks, and Recommendations
I recommend reading and writing every day. I like to have two or three physical books that I switch between at home. The Kindle app is my electronic option for when I’m out and have a few minutes to kill. My Audible account keeps multiple audiobooks queued that I can switch between at the gym or on long walks. Here is a list of the books that I listened to in 2020:
Read multiple books, and start new ones before you’ve finished them. Don’t worry about putting a book down and never picking it up again: Life is too short to finish books that you don’t like. Audible allows audiobook returns and refunds credits for reuse.
There’s so much content available, it is hard to decide where to direct your focus. As a rule, I try to not read any new books – meaning, I won’t read material that has been recently published. As a soft rule, I like books that have been released at least five years ago.
I avoid read popular books and best-sellers. I’m excited by obscure material containing alternative, even radical, ideas. If you only read the same books as everyone else, you will only have the same ideas that everyone else is having.
Reading will make you a better writer and content producer. Niall Ferguson mentions that quality books tend to have a thousand-to-one ratio; meaning the author has read about a thousand words on the subject for every one word written.
Niall continues about the compounding benefits of reading: “You’ve got to get that reading speed up early, and then you just have to read and read and read. And it is cumulative, not only in the sense that you get better at reading, but in a fascinating way the knowledge that you imbibe from books is cumulative.”
I am a slow reader. And, I am okay with that. I spend lots of time, in between sentences, thinking and contemplating. My advice is to not try reading faster, but instead to read for longer amounts of time. Like anything worth pursuing, it is about putting the hours in. “Reading is the quiet time in which you reflect and learn,” says author Ryan Holiday.
Writing
The best reading habit that I can recommend to you is to write while you read. A professor once told me: If you don’t have a pen in your hand, you’re not really studying. It ensures that you stay focused and engaged, and trains your mind to not wander. I have mentioned before that writing is “calisthenics for the brain“.
Digital devices, like the Kindle, make it easy to highlight text and take notes. After each page, I like to jot down a synopsis or any tangental thoughts that were sparked in the past few minutes. I don’t read fast. I record and define any unfamiliar words, and keep lists of unique phrases and idioms.
If I really like a new word, I’ll rewrite it and what it means, multiple times. Sometimes, I’ll rewrite sentences that just sound nice, or have a musical quality to them. Then, I’ll try to author my own in a similar style.
Taking notes is a challenge when I listen to audiobooks. Audible provides a feature allowing listeners to bookmark audio clips, and add text comments. Periodically, I’ll audit my collection and transcribe my favorites into a journal.
Journaling To Be A Better Writer (And Programmer)
Private journaling is vital to my process of writing publicly (blogging). I write a lot of stuff that I never publish. And that is the point – it is a personal practice that makes everything public-facing better. That idea is inspired by Kevin Kelly who has said, “I write primarily to find out what I’ve been thinking, and I don’t know until I write it”. The common wisdom is that you should think first, and then write – but to me it is obvious that the reverse is true. Spilling lots of ideas down onto a page is how I get started.
Note taking, making lists, and other kinds of journaling are powerful tools for being prolific. Learning how to make and take good notes requires practice. Simple bullet point lists are an easy way to start. Morning journal pages serve as a long-form translation of the lists I scribble mixed with a stream-of-consciousness narration. I try to write something every single day – no zero days. That’s how I get the noise out of my head. It crystalizes the nebulas storm that rages within my “monkey mind” – a concept I borrow from Tim Ferriss.
The magic always happens when I go back to old scrap and put the editor hat on. I have multiple physical notebooks, and use Evernote on my digital devices. I jot down thoughts, copy ideas while I read, write down new word definitions, and try to fill an entire page with free-flow journaling each day. Organizing all of these sources has become a series of techniques I use to keep finding inspiration.
Digesting the messy ball of words is aided by adding lots of visual cues. I use different colored pens, add drawings and doodles. I lay index cards out on an empty space and take a photo. Volume is the important variable in this quality algorithm. Getting as much down on paper as you can is always the best first step to getting value out of the writing process.
A coder’s diary
Taking notes about the coding challenges you’ve solved and the technical knowledge you’ve learned cements it. Even if you never read your notes again, the act of taking pen to paper will deepen the grooves in your mental records. You should consider keeping a blog for this reason. Having an archive of your experiences expounded, with the ability to search keywords, is invaluable. I include code examples, screenshots, relevant links and quotes, and a story to add context.
That compliments my main point: writing prose will ultimately make you a better programmer. Coding is a discipline nearer to writing then it ever will be to mathematics. That seems counterintuitive to the uninitiated.
This blog acts as my technical log that I can back reference when I encounter a familiar problem. As time passes, and new projects take hold of your attention, it’s easy to forget how you did something, even a few months ago. If you also have a similar blog about tech send me a link – I’d love to read through it!
Note Taking & Processing
There is an art and skill to note taking. It is a neighbor to journaling. When I have the urge and energy to do work, but I am not sure where to begin, I hit my notebooks as step number one.
My process has evolved. I start with physical writing as my primary note taking method. I use a notebook and I use index cards. Eventually (at least months, sometimes longer), I revisit hand-written notes and “process” them. That “process” involves re-reading and commenting on them in their existing form. I move the important (and positive) things to Evernote. I have organized my Evernote in multiple Notebooks. My pipeline looks like: index cards -> notebook -> Evernote -> blog
I use Twitter as a public diary for single sentences, ideas, and quotes that won’t fit any where else.
Since this post is a WIP (work-in-progress), I’ll leave unpolished notes below. That way I can continue refining my thoughts on this subject as time goes on.
– The psychological benefit of writing out negative feelings, and later destroying the paper. (“Burn after writing”)
– Looking back on goals. Reviewing old budgets, and feeling gratitude for where I am now
– Doodling and drawing skills
Writer Kurt Vonnegut said about his process: “When I write, I feel like an armless, legless man with a crayon in his mouth”
I discovered a bug in a web app that I built a few years ago. It was difficult to debug because it only happened intermittently. As any programmer knows, issues that can’t be reproduced consistently (and locally) present the most pain. Ultimately, it was causing database records to be created in double – but only when certain conditions evaluated true in the app state.
I’ll get into the code fix in another post. Here, I’ll show you how I cleaned up the database. This application has over ten-thousand data records in production. The first thing I did before messing around was to export a back-up of the prod DB. That was only me being extra careful – I already have a nightly job that dumps the entire production database as a .sql file to an S3 bucket. Taking an export on the fly is easy through phpMyAdmin.
Step one is to identify duplicates and store them in a temporary table, using a GROUP BY clause. In MySQL (and most other SQL-based database systems),GROUP BY is used to group rows from a table based on one or more columns.
The duplicate rows that I am interested in have all identical values, except for their primary keys. I can group those rows (and put them into a new, temporary, table) by including all of the table columns names (except the primary key) in my SQL statement. You can list those names in phpMyAdmin with this command:
SHOW COLUMNS FROM `records`;
My tables have quite a few columns. Instead of copy/pasting each field name, I used SQL code to list them out together. This was possible by leveraging the INFORMATION_SCHEMA database, a special system database that provides metadata about the database server itself in MySQL. I could retrieve the column names and then concatenate them into a single string using the GROUP_CONCAT function:
SELECT GROUP_CONCAT(column_name SEPARATOR ', ') AS column_list
FROM information_schema.columns
WHERE table_schema = 'bjjtracker'
AND table_name = 'records';
The result displayed as abbreviated until I selected “Full texts” from the options menu (highlighted below)
I could now copy/paste that column_list into my SQL statement. Remove the primary key field (usually the first one), or else no duplicates will be found (unless your use-case involves records having repeated primary key values, which is a less likely scenario).
CREATE TABLE TempTable AS
SELECT userid, type, date, beltrank, medal, weight, notes, created_date, style -- List all columns except the primary key
FROM `records`
GROUP BY userid, type, date, beltrank, medal, weight, notes, created_date, style -- Group by all columns except the primary key
HAVING COUNT(*) > 1; -- Indicates their is more than one record with exactly matching values
Now we have a new table that contains records that are duplicative in our original table. Step 2 is to delete the duplicates from the original table.
DELETE FROM `records`
WHERE (userid, type, date, beltrank, medal, weight, notes, created_date, style) IN (
SELECT userid, type, date, beltrank, medal, weight, notes, created_date, style
FROM TempTable
);
Don’t forget to delete that temporary table before you leave:
DROP TEMPORARY TABLE IF EXISTS TempTable;
Dealing with NULL values
On the first table I used this on, everything worked as expected. On a subsequent run against another table, zero rows were deleted even though my temp table contained duplicate records. I deduced that it was because of NULL values causing the comparison to not work as expected. I figured that I had to handle NULL values explicitly using the IS NULL condition on each field.
DELETE FROM recordsdetails
WHERE
(userid IS NULL OR userid,
recordid IS NULL OR recordid,
detailtype IS NULL OR detailtype,
technique IS NULL OR technique,
reps IS NULL OR reps,
partnername IS NULL OR partnername,
partnerrank IS NULL OR partnerrank,
pointsscored IS NULL OR pointsscored,
pointsgiven IS NULL OR pointsgiven,
taps IS NULL OR taps,
tappedout IS NULL OR tappedout,
result IS NULL OR result,
finish IS NULL OR finish,
created_date IS NULL OR created_date)
IN (
SELECT userid, recordid, detailtype, technique, reps, partnername, partnerrank, pointsscored, pointsgiven, taps, tappedout, result, finish, created_date
FROM TempTable
);
But yet, I still got zero rows being deleted. This time though, I was seeing a warning. It complained: “Warning: #1292 Truncated incorrect DOUBLE value”
This suggests that there is a data type mismatch or issue in the comparison involving numeric and string values. My guess is that the IS NULL handling was causing type conversion issues. To remedy this, I wrote a more explicit query by combining the AND and OR conditions.
DELETE FROM recordsdetails
WHERE
(userid IS NULL OR userid IN (SELECT userid FROM TempTable)) AND
(recordid IS NULL OR recordid IN (SELECT recordid FROM TempTable)) AND
(detailtype IS NULL OR detailtype IN (SELECT detailtype FROM TempTable)) AND
(technique IS NULL OR technique IN (SELECT technique FROM TempTable)) AND
(reps IS NULL OR reps IN (SELECT reps FROM TempTable)) AND
(partnername IS NULL OR partnername IN (SELECT partnername FROM TempTable)) AND
(partnerrank IS NULL OR partnerrank IN (SELECT partnerrank FROM TempTable)) AND
(pointsscored IS NULL OR pointsscored IN (SELECT pointsscored FROM TempTable)) AND
(pointsgiven IS NULL OR pointsgiven IN (SELECT pointsgiven FROM TempTable)) AND
(taps IS NULL OR taps IN (SELECT taps FROM TempTable)) AND
(tappedout IS NULL OR tappedout IN (SELECT tappedout FROM TempTable)) AND
(result IS NULL OR result IN (SELECT result FROM TempTable)) AND
(finish IS NULL OR finish IN (SELECT finish FROM TempTable)) AND
(created_date IS NULL OR created_date IN (SELECT created_date FROM TempTable));
That worked! With a cleaned database, it was time to figure out what was causing the bug in the first place, and to fix the problem.
Clones in quiet dance; Copies of our code converge; Echoes of our souls;
A Digital Transformation Case Study: Boosting Restaurant Sales with Custom Web Development and Online Ordering Integration
Client background & challenge
When I was younger I worked as a pizza delivery driver. Years later, the pizzeria where I once worked commissioned me to build their website. They were busier than ever thanks to online ordering (GrubHub, Seamless, UberEats), but were getting hit with high service fees.
They wanted their own website to be able to take orders for food online and send a notification to their iPad. That way they could avoid using apps like GrubHub that charged additional fees.
Project overview & execution
I used a service called GloriaFood that provides ready-made website templates, a secure payment process, and a messaging system. It integrates with Stripe for processing payments. There is an iPad app that receives push notifications when new orders are placed. The website builder required no code, and had a ton of options. I was able to register the pizzeria’s domain name directly though the admin portal, and generate a sales optimized website with hosting all setup. It was “seamless” – pun intended!
There are also options for integrating their ordering UI with an existing website, a Facebook page, or a dine-in QR code. The an option to publish a custom app required an additional cost per month.
I even traveled to this restaurant’s physical location, selected and purchased a tablet computer for them, installed the GloriaFood app to receive orders, and connected it to their mobile printer.
It’s amazing how much I was able to accomplish without writing a single line of code. The most technical part of this project was setting up a Stripe account and putting the API keys into the GloriaFood admin panel. GloriaFood is a product by Oracle, a company that specializes in providing a wide range of software and hardware products and services.
Print Design
As an extra part of this project, I designed a business card with a QR code linking to the new website. The business owner planned to give this to customers who ordered through other food ordering apps such as GrubHub, Seamless, UberEats, and Slice.
Results
Sales Increase
Since the launch of the new website, the restaurant has witnessed a notable surge in online orders, marking a 25% increase. This substantial rise not only signifies a successful digital transformation but also illustrates the growing customer preference for a seamless, direct ordering experience. The intuitive interface and easy navigation on the restaurant’s website have played a strong role in attracting and retaining customers, driving a higher volume of online orders and significantly contributing to the restaurant’s revenue growth.
Cost Savings
Transitioning from third-party ordering platforms like GrubHub, Seamless, and UberEats to a self-hosted online ordering system through has led to big cost savings. Third-party platforms usually charge hefty commissions, which eat into the restaurant’s profits and inflate prices for customers. With the new website, the restaurant has eliminated these intermediary costs, ensuring better profitability while also offering customers more competitive pricing.
Customer Feedback
The feedback received from both the restaurant management and its customers has been overwhelmingly positive. The restaurant staff has praised the streamlined process, which has simplified order management and allowed for a smoother operation during busy hours.