5 Commits

Author SHA1 Message Date
naomi 85f80fb159 feat: break down how I turn each step into code
Node.js CI / Lint and Test (push) Failing after 20s
2025-12-10 12:11:05 -08:00
naomi bbac528845 feat: add syntax highlighting and fix code alignment 2025-12-10 11:46:41 -08:00
naomi 07aa12a042 feat: add post about thinking algorithmically
Node.js CI / Lint and Test (push) Successful in 45s
2025-12-10 11:32:29 -08:00
naomi fba7ca4d50 chore: remove sonar workflow
Node.js CI / Lint and Test (push) Successful in 1m33s
2025-10-31 14:53:44 -07:00
naomi f1f6bfcee5 feat: add learning in public post
Code Analysis / SonarQube (push) Failing after 20s
Node.js CI / Lint and Test (push) Has been cancelled
2025-10-31 14:52:44 -07:00
8 changed files with 530 additions and 48 deletions
-34
View File
@@ -1,34 +0,0 @@
name: Code Analysis
on:
push:
branches:
- main
jobs:
sonar:
name: SonarQube
steps:
- name: Checkout Source Files
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarCube Scan
uses: SonarSource/sonarqube-scan-action@v4
timeout-minutes: 10
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: "https://quality.nhcarrigan.com"
with:
args: >
-Dsonar.sources=.
-Dsonar.projectKey=blog
- name: SonarQube Quality Gate check
uses: sonarsource/sonarqube-quality-gate-action@v1
with:
pollingTimeoutSec: 600
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: "https://quality.nhcarrigan.com"
+1
View File
@@ -16,6 +16,7 @@
"react-dom": "^19.0.0",
"react-markdown": "9.0.3",
"reading-time": "1.5.0",
"rehype-highlight": "7.0.2",
"rehype-raw": "7.0.0",
"remark-gfm": "4.0.0"
},
+54
View File
@@ -26,6 +26,9 @@ importers:
reading-time:
specifier: 1.5.0
version: 1.5.0
rehype-highlight:
specifier: 7.0.2
version: 7.0.2
rehype-raw:
specifier: 7.0.0
version: 7.0.0
@@ -1602,6 +1605,9 @@ packages:
hast-util-from-parse5@8.0.3:
resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
hast-util-is-element@3.0.0:
resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
hast-util-parse-selector@4.0.0:
resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
@@ -1614,12 +1620,19 @@ packages:
hast-util-to-parse5@8.0.0:
resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==}
hast-util-to-text@4.0.2:
resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==}
hast-util-whitespace@3.0.0:
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
hastscript@9.0.1:
resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
highlight.js@11.11.1:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
hosted-git-info@2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@@ -1896,6 +1909,9 @@ packages:
loupe@3.1.2:
resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
lowlight@3.3.0:
resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
@@ -2374,6 +2390,9 @@ packages:
resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==}
hasBin: true
rehype-highlight@7.0.2:
resolution: {integrity: sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==}
rehype-raw@7.0.0:
resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
@@ -2751,6 +2770,9 @@ packages:
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
unist-util-find-after@5.0.0:
resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
unist-util-is@6.0.0:
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
@@ -4651,6 +4673,10 @@ snapshots:
vfile-location: 5.0.3
web-namespaces: 2.0.1
hast-util-is-element@3.0.0:
dependencies:
'@types/hast': 3.0.4
hast-util-parse-selector@4.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -4701,6 +4727,13 @@ snapshots:
web-namespaces: 2.0.1
zwitch: 2.0.4
hast-util-to-text@4.0.2:
dependencies:
'@types/hast': 3.0.4
'@types/unist': 3.0.3
hast-util-is-element: 3.0.0
unist-util-find-after: 5.0.0
hast-util-whitespace@3.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -4713,6 +4746,8 @@ snapshots:
property-information: 7.1.0
space-separated-tokens: 2.0.2
highlight.js@11.11.1: {}
hosted-git-info@2.8.9: {}
html-url-attributes@3.0.1: {}
@@ -4972,6 +5007,12 @@ snapshots:
loupe@3.1.2: {}
lowlight@3.3.0:
dependencies:
'@types/hast': 3.0.4
devlop: 1.1.0
highlight.js: 11.11.1
lru-cache@10.4.3: {}
magic-string@0.30.17:
@@ -5676,6 +5717,14 @@ snapshots:
dependencies:
jsesc: 0.5.0
rehype-highlight@7.0.2:
dependencies:
'@types/hast': 3.0.4
hast-util-to-text: 4.0.2
lowlight: 3.3.0
unist-util-visit: 5.0.0
vfile: 6.0.3
rehype-raw@7.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -6179,6 +6228,11 @@ snapshots:
trough: 2.2.0
vfile: 6.0.3
unist-util-find-after@5.0.0:
dependencies:
'@types/unist': 3.0.3
unist-util-is: 6.0.0
unist-util-is@6.0.0:
dependencies:
'@types/unist': 3.0.3
+377
View File
@@ -0,0 +1,377 @@
---
title: "How to Think Algorithmically"
date: "2025-12-10"
summary: "A structured approach to programmatic problem solving."
---
If you've ever seen me help someone with their code, you may have noticed my unusual approach. I *never* have them start by looking at their code. Instead, I ask them to explain their logic. What are they trying to accomplish? How do they think it should work?
This is not because I am lazy or trying to make things difficult. It is because I have learned, through years of teaching and debugging, that **most coding problems are not actually coding problems - they are logic problems**.
## The Problem with Starting with Code
When you sit down at your keyboard and immediately start typing, you are trying to solve two problems at once. You are figuring out what you want to do, and figuring out how to make the computer do it.
It's like trying to learn English by writing Shakespearian poetry. Sounds messy, right?
Let's say you are trying to write a FizzBuzz algorithm. If you start with code instead of logic, you might write something like...
```javascript
for (let i = 1; i <= 100; i++) {
if (i % 3 === 0) {
console.log("Fizz");
}
if (i % 5 === 0) {
console.log("Buzz");
}
// ... wait, what about FizzBuzz?
}
```
You have already hit a problem, and you haven't even finished writing the code yet! If you had worked out the logic *first*, instead of jumping right into code, you would have been able to identify this problem without mucking around with the syntax.
## The Algorithmic Thinking Approach
Instead of starting with code, start with plain language. Write out your instructions. Do so one step at a time, as if you were explaining to Naomi (who will do exactly what you say and nothing more).
Let's use FizzBuzz as an example. Here is how I would break it down:
1. First, I look at the number.
2. Is the number divisible by three?
3. If it is, I say "Fizz"!
4. Is the number divisible by five?
5. If it is, I say "Buzz"!
6. Is the number divisible by three AND five?
7. If it is, I say "FizzBuzz"!
8. If I have said nothing at all, I say the number.
Now, here is the crucial part: **I test this logic manually before I write any code**. What happens if the number is 3? What should happen? What about 2? 5? 7? 15?
1. First, I look at the number. The number is 3.
2. Is the number divisible by three? Yes, 3 is divisible by three.
3. If it is, I say "Fizz"! Okay, "Fizz"
Saying a word ends my logical flow. I've said what I need to say, so I'm done.
Since we are expected to say "Fizz" when we see 3, this makes sense. What about 5?
1. First, I look at the number. The number is 5.
2. Is the number divisible by three? No, 5 is not divisible by three.
3. If it is, I say "Fizz"! It is not, so I do not say anything.
4. Is the number divisible by five? Yes, 5 is divisible by five.
5. If it is, I say "Buzz"! Okay, "Buzz".
Again, our logic looks correct. When I see 5, I *should* say "Buzz". What about 7?
1. First, I look at the number. The number is 7.
2. Is the number divisible by three? No, 7 is not divisible by three.
3. If it is, I say "Fizz"! It is not, so I do not say anything.
4. Is the number divisible by five? No, 7 is not divisible by five.
5. If it is, I say "Buzz"! It is not, so I do not say anything.
6. Is the number divisible by three AND five? No, 7 is not divisible by three or five.
7. If it is, I say "FizzBuzz"! It is not, so I do not say anything.
8. If I have said nothing at all, I say the number. Okay, 2.
Yep, that all looks right. When I see 2, I *should* say 2. What about 15?
1. First, I look at the number. The number is 15.
2. Is the number divisible by three? Yes, 15 is divisible by three.
3. If it is, I say "Fizz"! Okay, "Fizz"
WAIT! That's an issue! When I see 15, I *should* say "FizzBuzz". Oh no!
Because saying something ends my logic, I need to check for three AND five before I check them individually - the "three and five" condition can never be reached.
So I fix my logic:
1. First, I look at the number.
2. Is the number divisible by three AND five?
3. If it is, I say "FizzBuzz"!
4. Otherwise, is the number divisible by three?
5. If it is, I say "Fizz"!
6. Otherwise, is the number divisible by five?
7. If it is, I say "Buzz"!
8. Otherwise, I say the number.
Now I test again: 3? "Fizz" âś“. 5? "Buzz" âś“. 15? "FizzBuzz" âś“. 2? 2 âś“.
**ONCE THE LOGIC IS SOUND AND ALL OF MY MANUAL TESTS WORK, THEN I WRITE CODE.**
This approach serves two critical purposes:
1. I figure out the logic independently from the code, so I am not juggling both logic and syntax.
2. If my app does not work, I can look for an error in the code because I know the logic is sound (since I tested that before writing any code).
## The Importance of Precision
Computers are like children who will do only and exactly what you say. They cannot infer your intent. They cannot read between the lines. They will follow your instructions to the letter, even when those instructions lead to nonsense.
I learned this lesson recently while helping someone solve a pyramid-building problem. They were trying to build a pyramid out of a character, with a specified number of rows. Their initial instructions were something like:
1. Look at the string.
2. Look at the integer.
3. Write the string.
4. Go to the next line.
5. Write the same string from before again.
6. Add two more of the same single string beside it.
7. Repeat until you have the same number of rows as the integer.
When I followed these instructions precisely, I got:
```
x
xxx
xxxxx
xxxxxxx
xxxxxxxxx
```
But that is not a pyramid! A pyramid should be centred, like:
```
x
xxx
xxxxx
xxxxxxx
xxxxxxxxx
```
The instructions were missing a crucial detail: the spacing. But more importantly, they were imprecise. "Add two more of the same single string beside it" - beside what? Where? The instructions assumed I would understand the intent, but a computer (or a very literal Naomi following instructions) would not.
After several iterations, we refined the instructions to be precise:
1. Look at the string. It is what we want the pyramid to be built by.
2. Look at the integer. It is the amount of rows we want.
3. Add a number of spaces equal to the integer, and then write the string.
4. Go to the next line.
5. Write the same spaces string from before again, but get rid of one space, and write the string.
6. Add two more of the same single string beside it.
7. Write the whole space and string again from the last row, get rid of one space again, and add two more of the same string.
8. Repeat step 7 until you have the same number of rows as the integer.
Now, when I follow these instructions precisely, I get the correct pyramid. The logic is sound. **Only then** do we start thinking about how to translate this into code.
## Translating Logic to Code
Once your logic is sound and tested, translating it to code becomes much simpler. You are no longer trying to figure out what to do - you already know that. You are just figuring out how to express it.
Let us go back to the pyramid example. We have our logic:
1. Look at the string and integer.
2. For each row, calculate the number of spaces and the number of characters.
3. Print the spaces, then the characters.
4. Move to the next row.
Now we can think about the code structure.
First, let's define our function:
```javascript
function pyramid(characterToBuildPyramidWith, numOfRows) {
}
```
What are our steps?
- We need a loop to iterate through rows.
- For each row, we gotta know how many spaces to use. We use less spaces in each row.
- For each row, we gotta know how many characters to use. We use more characters in each row.
- Finally, print our result.
Okay, let's cretae a loop to iterate through the number of rows. Sounds like a great usecase for a standard `for` loop.
```javascript
function pyramid(characterToBuildPyramidWith, numOfRows) {
for (let row = 0; row < numOfRows; row++) {
}
}
```
We're using `row` instead of `i`, so it's less confusing.
Now for each row (so each iteration), we gotta know how many spaces to use. Thankfully, we've already sorted that out in our logic:
> Add a number of spaces equal to the integer
> Write the whole space and string again from the last row, get rid of one space again
So we start with `numOfRows` spaces, and for each iteration we can decrement the number of spaces by one. I think, then, that we could do `numOfRows - row`. Let's put that in a variable so we don't lose track.
```javascript
function pyramid(characterToBuildPyramidWith, numOfRows) {
for (let row = 0; row < numOfRows; row++) {
const spaces = " ".repeat(numOfRows - row);
}
}
```
Alright, now the number of characters. Again, we can refer back to our paper logic:
> Write the same spaces string from before again, but get rid of one space, and write the string.
> Write the whole space and string again from the last row, get rid of one space again, and add two more of the same string.
Okay, so we start with one character, and add two more for every iteration. That would be... `row` times two, but add one to account for the initial character.
```javascript
function pyramid(characterToBuildPyramidWith, numOfRows) {
for (let row = 0; row < numOfRows; row++) {
const spaces = " ".repeat(numOfRows - row);
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
}
}
```
Finally, our last step:
> Finally, print our result.
We can print things with a `console.log` statement. Let's print our spaces followed by our characters.
```javascript
function pyramid(characterToBuildPyramidWith, numOfRows) {
for (let row = 0; row < numOfRows; row++) {
const spaces = " ".repeat(numOfRows - row);
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
console.log(spaces + characters);
}
}
```
Time to double check our work! Let's call our function:
```javascript
function pyramid(characterToBuildPyramidWith, numOfRows) {
for (let row = 0; row < numOfRows; row++) {
const spaces = " ".repeat(numOfRows - row);
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
console.log(spaces + characters);
}
}
pyramid("x", 5);
```
Checking the console, I see:
```txt
x
xxx
xxxxx
xxxxxxx
xxxxxxxxx
```
That looks like a pyramid! But hang on... It looks like we've shifted it one space too far. Let's go back to our logic on paper, because our logic is off (so we don't want to touch the code yet).
1. Look at the string. It is what we want the pyramid to be built by.
2. Look at the integer. It is the amount of rows we want.
3. Add a number of spaces equal to the integer, and then write the string.
4. Go to the next line.
5. Write the same spaces string from before again, but get rid of one space, and write the string.
6. Add two more of the same single string beside it.
7. Write the whole space and string again from the last row, get rid of one space again, and add two more of the same string.
8. Repeat step 7 until you have the same number of rows as the integer.
AHA! Our issue is in step 3.
> 3. Add a number of spaces equal to the integer, and then write the string.
By adding the number of spaces equal to the integer, we've failed to account for the initial pyramid character. Essentially, we need to add one less space.
So we update our logic **first**:
1. Look at the string. It is what we want the pyramid to be built by.
2. Look at the integer. It is the amount of rows we want.
3. Add a number of spaces equal to the integer **less one**, and then write the string.
4. Go to the next line.
5. Write the same spaces string from before again, but get rid of one space, and write the string.
6. Add two more of the same single string beside it.
7. Write the whole space and string again from the last row, get rid of one space again, and add two more of the same string.
8. Repeat step 7 until you have the same number of rows as the integer.
## When Logic Breaks During Coding
I see it all the time. You have worked out your logic, tested it manually, and it looks perfect. You start translating it to code, and halfway through, you realize it's not perfect at all.
Maybe you cannot figure out how to achieve a specific step. Maybe you discover an edge case you did not consider. Maybe the logic just... does not work the way you thought it would.
**Stop coding immediately.**
I know, I know. Your instinct is to keep typing, to try to fix it in code, to hack around the problem. But resist that urge. If your logic needs revision, that is a logic problem, not a code problem. And logic problems should be solved on paper, not in your editor.
Step away from your keyboard. Go back to your plain English instructions. Walk through them again manually. Where does it break? What did you miss? What assumption did you make that turned out to be wrong?
Let us say you are working on that pyramid problem, and while coding you realize: "Wait, how do I know how many spaces to remove each time? Do I start with the full number of spaces, or one less?"
Instead of trying to figure this out in code, go back to your logic:
1. Add a number of spaces equal to the integer, and then write the string.
2. Go to the next line.
3. Write the same spaces string from before again, but get rid of one space, and write the string.
Test it manually: if the integer is 5, I start with 5 spaces. Then I go to the next line and have 4 spaces. Then 3 spaces. Then 2 spaces. Then 1 space. Then 0 spaces. That makes sense!
Now you can go back to your code with clarity. You know that for row 0, you need `numOfRows - 0 - 1` spaces (which is 4 for 5 rows). For row 1, you need `numOfRows - 1 - 1` spaces (which is 3). The pattern is clear because you worked it out in logic first.
Okay, pretend we've tested our change manually (I am sparing you from reading through that process again), and it works. Now we can update our code to reflect our logic change:
```javascript
function pyramid(characterToBuildPyramidWith, numOfRows) {
for (let row = 0; row < numOfRows; row++) {
// Notice how this is the ONLY change I made. We aren't changing anything that isn't updated in the logic on paper.
const spaces = " ".repeat(numOfRows - row - 1);
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
console.log(spaces + characters);
}
}
pyramid("x", 5);
```
And we get:
```txt
x
xxx
xxxxx
xxxxxxx
xxxxxxxxx
```
**WE'VE DONE IT!!!!!**
The key principle here is: **if you discover a logic problem while coding, you have not discovered a coding problem. You have discovered that your logic was incomplete.** Fix the logic first, test it manually, and then return to the code.
This might feel inefficient. You might think "I am so close, let me just fix this one thing in code." But I promise you: fixing logic in code is like trying to repair the foundation of a house while you are painting the walls. It will not work, and you will make a bigger mess.
## The Benefits of This Approach
When you think algorithmically first, you gain several advantages:
**You catch logic errors early.** Instead of debugging why your code does not work, you debug why your logic does not work - and logic is much easier to debug than code.
**You separate concerns.** Logic and syntax are two different problems. Solve them separately, and you will solve them more effectively.
**You build confidence.** When your code does not work, you know it is a syntax issue, not a logic issue. That narrows down your debugging significantly.
**You communicate better.** When you can explain your logic in plain English, you can explain it to teammates, ask for help more effectively, and document your code more clearly.
**You learn faster.** By focusing on logic first, you develop stronger problem-solving skills that transfer across languages and technologies.
## The Takeaway
The next time you have to write some code, don't write the code! Do this:
1. Write out your logic in plain English, step-by-step.
2. Test that logic by hand, using multiple test cases.
3. Ideally, you've touched every "branch" in your logical breakdown.
3. Edit and adjust the logic when test cases fail.
4. Once all of your manual test cases pass your hand-written logic, you can finally begin translating it into code.
You will find that your code is cleaner, your bugs are fewer, and your problem-solving skills are stronger. And hey - if you can explain your logic to me in plain English and it works, then translating it to code is just a matter of syntax. And syntax is the easy part!
> đź’ˇ Remember: computers are children who will do only and exactly what you say. Be precise, be thorough, and test your logic before you write your code.
+59
View File
@@ -0,0 +1,59 @@
---
title: "Learning In Public"
date: "2025-10-31"
summary: "Why Naomi hates answering DMs"
---
If you have ever tried to DM me, there is a very good chance that I advised you to ask me the question in a server instead. This is NOT just because I hate DMs - though I do, because running multiple prolific communities means I am absolutely buried in DM request. No, this is actually for YOUR benefit.
Because when I redirect you to a public community instead of my DMs, I am encouraging you to **learn in public**. But why is learning in public so important? Well, there are a number of reasons. Let's explore some!
## Single Source of Truth
When you ask me a question in DMs, I implicitly become the single source of truth. Whatever answer I provide you is *hopefully* accurate, but I am wrong way more often than I am right (even this article should be taken with a grain of salt). But the burden of fact checking my answer now falls entirely on you.
Consider a DM where you ask me "What is the time complexity of a merge sort?". And let's pretend I say it is `O(n log n)`. It might be, it might not be, I'm honestly not sure - even after looking it up. BUT my lack of knowledge isn't the point here. The point is that whatever information I give you is now your burden to confirm.
What if you asked me that question in a public server? I'll give you the same answer: `O(n log n)`. But now because this is a PUBLIC conversation, Jeremy could chime in and say "Actually it's `O(n)` and here is a source". The burden of fact checking has shifted off your shoulders, because the entire community can now weigh in and call out my incorrect answer. And *generally* the collective knowledge of a group will be more accurate than the isolated knowledge of an individual.
## Helping Others Grow
Here's another benefit! I presume that, like many people, you agonised about reaching out to ask me your question. Let's pretend you asked me "How do I centre this `div`?". I cannot speak to your emotions, but I *can* state that it is rather common for developers (especially those in their early learning stages) to be afraid of, embarrassed by, or too shy to ask questions.
The fact that you worked up the courage to ask the question should be celebrated! It can be super duper scary! But when you ask me that question in DMs, *no one else can see it*. Instead, if you ask that question in a server, you and I can have our conversation in a public forum. And maybe Danny had the same question, but was too uncomfortable to ask it. Your initiative has now sparked a conversation from which Danny, and anyone else in the community, can potentially benefit.
## Networking!
If you regularly follow this blog, you probably saw my [post about networking](https://blog.nhcarrigan.com/post/networking) and how it is vital, especially in our current economic downturn. Did you know, though, that asking questions in public IS a networking opportunity??
We've already written at length about how a DM is completely isolated, so let's skip right to the part where you ask me the question publicly. This time, you ask me about the considerations between choosing JavaScript or Python. This is a "juicy" question; that is, questions like this are great catalysts for some in-depth discussions. And that's exactly what we do in this scenario - we have a killer discussion, with multiple people chiming in.
During this discussion, you've effectively demonstrated your ability to learn, curiosity for new information, and technical proficiency all at once. And because this happened in public, someone like Jessica might see the conversation thread. And maybe her team has an opening for a junior developer. That conversation could very well be the spark that leads her to reach out to you for a referral for that role! You never know who is reading a conversation.
## Building a Portfolio
Now, a lot of my work happens on Discord. Which is not the best platform, because it's not indexed by search engines. But EVEN SO, your public conversations can become part of your portfolio! I have conversations waaaaaay back from when I first started my learning journey that I still look back on fondly years later. Because those conversations serve as a lovely reminder of where I started, and thus how far I have come.
But your conversations aren't just beneficial for your own self-actualisation! They're also a great demonstration of your long-term growth and commitment to your craft. If you have spent the last five years engaging in increasingly technical conversations, asking progressively more in-depth questions, and engaging in more complex discourse... then that's something you can leverage on your portfolio to show your own evolution!
And if your conversations are on an indexable platform, like the [freeCodeCamp forum](https://forum.freecodecamp.org), then you even get some free exposure through search engine results!
## Confidence is Key!
I've been scared to ask questions before too. I promise it gets easier. Now I'm running my mouth all day asking questions about everything! But I'm only confident enough to do so because I started asking those questions at the *beginning of my learning journey*. I've gone through all of the "oh god what if people think I'm completely incompetent" anxieties over and over again. And it turns out... No one has ever thought that.
BUT! I know you won't believe me. Just like I didn't believe the folks who told me the same thing in my initial learning. I can tell you it's okay until I am blue in the face, but the most powerful confirmation comes from *experiencing it yourself*. So asking your "silly" questions NOW, when you are still in your first steps of learning to code, will better prepare you to be comfortable asking those questions on the job - where it is VITAL that you are comfortable doing so!
## Learning by Teaching
I, personally, am a HUGE fan of the Socratic Method. SO MUCH SO that I formally adopted it as our [instructional approach at freeCodeCamp](https://www.freecodecamp.org/news/how-to-help-someone-with-their-code-using-the-socratic-method/). I think that there is a lot of value in being guided to reach the solution through your own cognitive reasoning.
Part of that process, then, requires you to explain your understanding along the way. In having to explain your understanding, you are effectively teaching others! In fact, when you do this in public there is a significant chance someone will chime in to ask questions about bits they didn't understand. Which then causes you to dive into your explanation further. And every time you have to break something down and convey it in a way someone else can understand, you strengthen your own competencies!
Not only is that a win for everyone, but being challenged to articulate your thoughts can help you better succeed in your professional career. Part of our work as developers involves explaining our ideas to others - some audiences are technical, and some are not. But all audiences need to be able to understand you. So getting that experience NOW just further positions you for success in your career.
## The Takeaway
I know I rambled on and on. I do that. I'm always yapping. So here's the key takeaway I want you to carry with you forever:
The next time you want to hit that "Send DM" button, consider all of these benefits you will lose out on by asking me a question privately instead of in a public community.
+27
View File
@@ -54,3 +54,30 @@ figcaption {
@apply text-center;
@apply italic;
}
pre {
@apply text-left;
@apply bg-gray-100;
@apply p-2;
@apply rounded-md;
@apply border;
@apply border-gray-300;
@apply overflow-x-auto;
@apply whitespace-pre-wrap;
@apply break-words;
@apply text-sm;
@apply font-mono;
}
code:not(pre code) {
@apply text-sm;
@apply font-mono;
@apply bg-gray-100;
@apply p-1;
@apply rounded-md;
@apply border;
@apply border-gray-300;
@apply overflow-x-auto;
@apply whitespace-pre-wrap;
@apply break-words;
}
+10 -13
View File
@@ -11,19 +11,18 @@ import type { JSX, ReactNode } from "react";
import "./globals.css";
// eslint-disable-next-line new-cap -- This is a function call.
const inter = Inter({ subsets: [ "latin" ] });
const inter = Inter({ subsets: ["latin"] });
const metadata: Metadata = {
description:
"The personal musings of a transfem software engineer.",
description: "The personal musings of a transfem software engineer.",
openGraph: {
images: "https://cdn.nhcarrigan.com/og-image.png",
},
title: "Naomi's Blog",
title: "Naomi's Blog",
twitter: {
card: "summary_large_image",
card: "summary_large_image",
images: "https://cdn.nhcarrigan.com/og-image.png",
site: "@naomi_lgbt",
site: "@naomi_lgbt",
},
};
@@ -48,14 +47,12 @@ const RootLayout = ({
strategy={"afterInteractive"}
type="text/javascript"
></Script>
<link href="https://cdn.nhcarrigan.com/logo.png" rel="icon" sizes="any" />
<link
href="https://cdn.nhcarrigan.com/logo.png"
rel="icon"
sizes="any"
/>
<body className={inter.className}>
{children}
</body>
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css"
></link>
<body className={inter.className}>{children}</body>
</html>
);
};
+2 -1
View File
@@ -7,6 +7,7 @@
import Markdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import remarkGfm from "remark-gfm";
import rehypeHighlight from "rehype-highlight";
import type { JSX } from "react";
import { Rule } from "@/components/rule";
import { getPostData } from "@/lib/posts";
@@ -34,7 +35,7 @@ const Page = async({
<h2 className="text-center">{post.data.summary}</h2>
<p className="text-center">{`A ${post.data.readtime}.`}</p>
<Rule />
<Markdown rehypePlugins={[ rehypeRaw ]} remarkPlugins={[ remarkGfm ]}>
<Markdown rehypePlugins={[ rehypeRaw, rehypeHighlight ]} remarkPlugins={[ remarkGfm ]}>
{post.content}
</Markdown>
<Rule />