<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jacob Aloysious</title><link>https://jacobaloysious.in/author/jacob-aloysious/</link><atom:link href="https://jacobaloysious.in/author/jacob-aloysious/index.xml" rel="self" type="application/rss+xml"/><description>Jacob Aloysious</description><generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><lastBuildDate>Sat, 26 Sep 2026 00:00:00 +0000</lastBuildDate><image><url>https://jacobaloysious.in/author/jacob-aloysious/avatar_hub5d1c1a9cf07cfd313ce97c2dfe0179c_402758_270x270_fill_q90_lanczos_center.jpg</url><title>Jacob Aloysious</title><link>https://jacobaloysious.in/author/jacob-aloysious/</link></image><item><title>An AI-First Second Brain for Engineering Teams: My Talk at KLA</title><link>https://jacobaloysious.in/post/ai-first-second-brain-kla-conference/</link><pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/ai-first-second-brain-kla-conference/</guid><description>&lt;p>I had the opportunity to speak at &lt;strong>
&lt;a href="https://www.kla.com/" target="_blank" rel="noopener">KLA&lt;/a>&amp;lsquo;s Engineering Conference&lt;/strong>, an event attended by &lt;strong>800–1,000 engineers&lt;/strong>, about a problem that sits underneath much of our engineering work: remembering enough of the right context to make the next decision well.&lt;/p>
&lt;p>KLA serves the semiconductor industry with process-control, inspection, and metrology technologies. That made it a fitting setting for a conversation about preserving context across complex engineering work.&lt;/p>
&lt;p>My talk, &lt;strong>“AI-First Second Brain for Engineering Teams,”&lt;/strong> explored how AI can help preserve that context without turning every conversation, incident, or provisional idea into permanent truth.&lt;/p>
&lt;p>I had a &lt;strong>90-minute slot&lt;/strong>. The talk itself lasted &lt;strong>75 minutes&lt;/strong>, followed by &lt;strong>more than 30 minutes of Q&amp;amp;A&lt;/strong>, taking the session beyond its allotted time. There was a lot of enthusiasm for the topic, and it was encouraging to see that interest continue into the discussion.&lt;/p>
&lt;p>The message I wanted to leave with the audience was simple: AI can do much of the work of organizing and maintaining memory. People still need to decide what is safe to share, what deserves to be remembered, and when an old lesson applies to a new situation.&lt;/p>
&lt;p>&lt;img src="conference-stage.jpg" alt="Presenting AI-First Second Brain for Engineering Teams at KLA&amp;rsquo;s Engineering Conference">&lt;/p>
&lt;p>&lt;em>On stage at KLA&amp;rsquo;s NEOTERIX 2026 Engineering Conference in Chennai.&lt;/em>&lt;/p>
&lt;h2 id="the-work-before-the-work">The work before the work&lt;/h2>
&lt;p>Think about a difficult engineering issue. The logs are in one place. Someone else has the physical observation. The reason for an old design choice is buried in a discussion. A workaround exists in the memory of an engineer who happens to be unavailable.&lt;/p>
&lt;p>Before anyone can investigate properly, the team has to reconstruct the story.&lt;/p>
&lt;p>I described this in the talk as engineering archaeology. We are searching for what happened, who understood it, which assumptions mattered, and whether the previous solution is still relevant. The information may exist, but it is not yet a usable starting point.&lt;/p>
&lt;p>That reconstruction carries a &lt;strong>memory tax&lt;/strong>. Engineers pay it when debugging an unfamiliar failure. Managers pay it when recovering an unowned commitment. Leaders pay it when trying to understand whether a team has learned something reusable or simply closed another issue.&lt;/p>
&lt;p>The questions differ, but the dependency is similar: useful action waits for context. Adding more documents does not automatically reduce that delay. A larger collection can also make it harder to distinguish current guidance from an abandoned experiment.&lt;/p>
&lt;h2 id="what-i-mean-by-a-second-brain">What I mean by a second brain&lt;/h2>
&lt;p>For this talk, a second brain meant a maintained body of context that helps a team continue its work. It includes decisions and their rationale, incident history, runbooks, known limitations, and commitments that need follow-through.&lt;/p>
&lt;p>The useful distinction is between storing information and maintaining it. A stored note can remain available long after its assumptions have expired. Maintained knowledge has a visible source, an owner, a verification state, and a reason to revisit it. It can be corrected or retired.&lt;/p>
&lt;p>The recurring flow in the talk was:&lt;/p>
&lt;p>&lt;strong>Capture → Govern → Surface → Decide&lt;/strong>&lt;/p>
&lt;p>Capture brings in relevant observations. Governance determines what may persist and who can use it. Retrieval surfaces the right material with its supporting evidence. A person then makes the decision with enough context to understand the consequences.&lt;/p>
&lt;p>This also changes how I think about expert dependency. An experienced engineer&amp;rsquo;s judgment is valuable, but their availability should not be the only route to the team&amp;rsquo;s history. Shared memory can give another engineer the sources, reviewed guidance, and prior investigations needed to make progress.&lt;/p>
&lt;p>It does not reproduce the expert. It preserves a better starting position for whoever is doing the work next.&lt;/p>
&lt;h2 id="give-ai-the-maintenance-work">Give AI the maintenance work&lt;/h2>
&lt;p>A large part of the talk concerned the division of responsibility. AI is useful for extracting candidate decisions, linking related cases, drafting summaries, noticing stale guidance, and bringing open questions back for review.&lt;/p>
&lt;p>Those tasks consume attention, especially when context is scattered across messages, meetings, documents, and alerts. An assistant can prepare the material continuously, leaving people with smaller, more specific decisions to make.&lt;/p>
&lt;p>In the personal workflow I described, Google Chat is the interaction surface, MyClaw is the agent runtime, and human-readable Markdown in Google Drive holds durable memory. The runtime coordinates tools, policies, and scheduled work; the underlying model is one component of that system.&lt;/p>
&lt;p>The particular products matter less than the arrangement. People need somewhere to review and correct proposed memory. Durable records need to remain understandable outside a single chat session. Cases, decisions, and approved knowledge need different lifecycles.&lt;/p>
&lt;p>A useful record should explain where it came from, who owns it, when it was checked, and what would make it questionable again. That gives the next reader a way to assess it instead of accepting a confident summary at face value.&lt;/p>
&lt;h2 id="five-loops-that-keep-memory-useful">Five loops that keep memory useful&lt;/h2>
&lt;p>I organized the maintenance work into five recurring loops. Together, they turn a collection of notes into something a team can keep using.&lt;/p>
&lt;p>&lt;strong>1. Capture decisions for review.&lt;/strong> After an architecture discussion, the assistant can extract the decision, its rationale, and the condition under which it should be revisited. A person can store, edit, or skip the proposal. Recording the reason matters: without it, a future team may preserve a decision after the original constraint has disappeared.&lt;/p>
&lt;p>&lt;strong>2. Assist with incidents.&lt;/strong> During an investigation, the assistant can surface a relevant playbook, its source, its verification state, and recent changes. The engineer chooses the next action. The assistant can preserve the checkpoint so the next handoff does not restart the investigation from scratch.&lt;/p>
&lt;p>&lt;strong>3. Draft weekly updates.&lt;/strong> Actual activity can become a draft of delivered work, ongoing work, risks, and next steps. Human review remains part of publication. This is valuable because an update should reflect what happened, including uncertainty, rather than merely sound complete.&lt;/p>
&lt;p>&lt;strong>4. Check freshness.&lt;/strong> Guidance should return for review when time passes, a dependency changes, or an original assumption stops holding. AI can identify those triggers. An owner decides whether the record remains valid, needs correction, or should be archived.&lt;/p>
&lt;p>&lt;strong>5. Propose reusable knowledge.&lt;/strong> Several cases may suggest a pattern worth preserving. The assistant can prepare a narrow proposal with evidence and limitations. A named owner reviews it before it becomes guidance for others.&lt;/p>
&lt;p>These loops make maintenance a recurring responsibility. They also give the human reviewer a concrete question to answer at each step.&lt;/p>
&lt;p>&lt;img src="conference-speaker.jpg" alt="Speaking about governed engineering memory at KLA&amp;rsquo;s Engineering Conference">&lt;/p>
&lt;p>&lt;em>Discussing how AI can preserve context while keeping consequential decisions with people.&lt;/em>&lt;/p>
&lt;h2 id="a-resolved-case-is-not-automatically-reusable-knowledge">A resolved case is not automatically reusable knowledge&lt;/h2>
&lt;p>This was one of the most important distinctions in the talk. A fix can be correct for one incident and misleading when generalized.&lt;/p>
&lt;p>A case records what happened under particular conditions. Reusable knowledge makes a broader claim: under these conditions, this diagnostic or action is worth considering again. Moving between the two requires evidence, scope, limitations, and ownership.&lt;/p>
&lt;p>For example, a recovery procedure might have worked with one configuration. Before it becomes a runbook recommendation, someone needs to ask what actually explains the recovery, which prerequisites matter, and when the procedure should not be used.&lt;/p>
&lt;p>The same applies to AI-generated summaries. Fluent language can hide how narrow the original evidence was. Promotion should therefore be an explicit action, with a reviewer responsible for the claim that future engineers will inherit.&lt;/p>
&lt;p>Most cases can remain cases. Their history is still useful. Only selected lessons need to become shared guidance, and that guidance needs a path back to its supporting evidence.&lt;/p>
&lt;p>&lt;img src="cases-are-not-knowledge.png" alt="Cases remain traceable in case history; only narrow, verified learning enters the Team Brain after owner review">&lt;/p>
&lt;p>&lt;em>Many cases, few promotions: reusable guidance needs verified evidence, a source trail, and an owner.&lt;/em>&lt;/p>
&lt;h2 id="making-the-boundaries-concrete-with-a-field-issue-demo">Making the boundaries concrete with a field-issue demo&lt;/h2>
&lt;p>I tailored the demo to KLA’s semiconductor engineering context: how AI could support an end-to-end workflow from a field issue to a tested code fix, with human approval at the consequential steps. The scenario is fictional and illustrates the proposed approach. The presenter application is a deterministic simulation backed by local artifacts and tests. It does not operate production equipment, call a live model, or deploy changes to an external system.&lt;/p>
&lt;p>I see this as a practical example of &lt;strong>forward-deployed engineering&lt;/strong>: working from a specific customer use case and shaping the AI solution around that customer’s environment. Here, the problem is moving from a semiconductor field issue to an actionable engineering investigation. The design follows the evidence available at the tool, the restrictions on sharing it, and the engineer’s responsibility for the fix. That customer context determines where AI can help and where human judgment must remain.&lt;/p>
&lt;p>&lt;img src="kla-ai-automation-workflow-clean.png" alt="Demo workflow: an OnTool Agent prepares a sanitized context packet, a human approves sharing, and an Engineering Agent prepares a tested fix using the same approved Team Brain">&lt;/p>
&lt;p>&lt;em>The automation workflow presented at KLA: raw evidence stays local, only an approved packet crosses the boundary, and an engineer reviews and ships the proposed fix.&lt;/em>&lt;/p>
&lt;p>The scenario follows evidence from a tool-side investigation to an engineering diagnosis. An on-tool agent prepares a sanitized packet while restricted raw evidence stays local. The packet must be reviewed and approved before it crosses the boundary to the engineering side.&lt;/p>
&lt;p>One deliberate step is attempting the transfer too early. The system refuses it. That refusal makes the permission boundary visible: information being useful does not, by itself, authorize sharing it.&lt;/p>
&lt;p>On the engineering side, the approved packet is combined with shared knowledge, code, and tests. The example concerns a settle gate that checks position while motion is still unstable. The workflow prepares a diagnostic experiment and a proposed runtime and test change. The engineer retains responsibility for reviewing and shipping the change through the normal process.&lt;/p>
&lt;p>A second gate appears after the simulated resolution. The workflow refuses to promote the finding into reusable knowledge until an owner approves it. The later cold-start view shows what another engineer could inherit months afterward: a scoped diagnostic path, evidence, ownership, and review conditions.&lt;/p>
&lt;p>This is the behavior I wanted the demo to make tangible. Better context can shorten the route to an investigation, while explicit gates preserve responsibility for sharing, software changes, and future reuse.&lt;/p>
&lt;p>In a real implementation, those gates also require technical enforcement through credentials, isolation, network controls, validation, and audit records. A prompt alone cannot provide that boundary.&lt;/p>
&lt;h2 id="memory-about-people-needs-its-own-limits">Memory about people needs its own limits&lt;/h2>
&lt;p>Engineering context includes people, and that requires care. Remembering an agreed follow-up can help a team. Turning an impression into a lasting judgment about a colleague can cause harm.&lt;/p>
&lt;p>The manager workflow in the materials separates fragments into three outcomes: remember, keep uncertain, or reject. A professional commitment may be appropriate to retain. A conditional statement must keep its condition. A speculative personal judgment should not become durable memory.&lt;/p>
&lt;p>Consider the difference between “I can review this if the release work finishes” and “I will review this.” Removing the condition changes the commitment. An assistant that compresses the first statement into the second has created an inaccurate expectation, even if its summary reads naturally.&lt;/p>
&lt;p>That is why visibility and correction matter. People should be able to inspect the source of a remembered claim, correct it, and understand the boundary around its use. Useful continuity depends on restraint as much as recall.&lt;/p>
&lt;h2 id="start-with-one-decision-that-keeps-losing-context">Start with one decision that keeps losing context&lt;/h2>
&lt;p>My proposed starting point was a small, thirty-day pilot around one recurring problem. Choose a decision where the team repeatedly reconstructs history, then define what better continuity would look like.&lt;/p>
&lt;p>A recurring incident, an architecture decision log, or a handoff process could be a suitable starting place. Give it one owner, a clear boundary around what may be stored, and a measurable outcome.&lt;/p>
&lt;p>The build path in the talk moves through four stages: define the job and stop rules, wire the workflow and failure handling, ground retrieval and human review, then add ongoing ownership and operational checks.&lt;/p>
&lt;p>The tests should cover the memory contract as well as answer quality. Does the workflow reject unreviewed material? Does it preserve conditional language? Can a person correct a record? Does promotion require approval? Can the system show where its guidance came from?&lt;/p>
&lt;p>Measure whether the next engineer reaches a justified decision sooner, whether handoffs lose less context, or whether fewer investigations restart unnecessarily. Counting stored notes or generated summaries tells us little about those outcomes.&lt;/p>
&lt;h2 id="what-i-wanted-engineers-to-take-away">What I wanted engineers to take away&lt;/h2>
&lt;p>Speaking at KLA&amp;rsquo;s Engineering Conference was an opportunity to connect AI with a familiar engineering challenge: continuity across people, incidents, and time.&lt;/p>
&lt;p>The promise of a second brain is practical. It can help a team recover the rationale behind a choice, resume an investigation, and reuse an earned lesson with its limits intact. Reaching that point requires ongoing maintenance and deliberate human ownership.&lt;/p>
&lt;p>My closing question was: &lt;strong>Where does your team pay its highest memory tax?&lt;/strong>&lt;/p>
&lt;p>That is where I would start. Find the context that repeatedly disappears, preserve it with evidence and boundaries, and see whether the next decision improves.&lt;/p>
&lt;p>The
&lt;a href="https://github.com/jacobaloysious/second-brain-talk" target="_blank" rel="noopener">talk repository&lt;/a> contains the slide deck, speaker notes, and demo materials for exploring the approach in more detail.&lt;/p></description></item><item><title>Bringing My Blog Back with Codex Computer Use</title><link>https://jacobaloysious.in/post/bringing-my-blog-back-with-codex/</link><pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/bringing-my-blog-back-with-codex/</guid><description>&lt;p>My blog&amp;rsquo;s source code was sitting in GitHub. My domain, &lt;strong>jacobaloysious.in&lt;/strong>, was registered with GoDaddy. I had a Vercel account ready to use. Somewhere in the background, an old AWS setup was still involved.&lt;/p>
&lt;p>The goal sounded simple: publish the blog from GitHub using Vercel and make it accessible through my own domain.&lt;/p>
&lt;p>This time, I asked Codex to help do the work through Computer Use. Instead of following a deployment tutorial and switching between dashboards myself, I let it inspect the browser, configure the deployment, and trace the domain setup. I stayed involved when access or missing context required my input.&lt;/p>
&lt;p>It turned into a useful exercise in both AI-assisted work and remembering how my own website was wired together.&lt;/p>
&lt;h2 id="1-get-computer-use-working">1. Get Computer Use working&lt;/h2>
&lt;p>The first obstacle appeared before deployment even began. Although I was signed in to GitHub, Vercel, and GoDaddy in Chrome, Codex could not initially connect to my browser.&lt;/p>
&lt;p>The Computer Use setting showed:&lt;/p>
&lt;blockquote>
&lt;p>Disabled by your organization or unavailable in your region.&lt;/p>
&lt;/blockquote>
&lt;p>The message alone did not establish the cause. We checked the available setup guidance, but did not conclusively diagnose why the setting was disabled. I subsequently enabled Computer Use and asked Codex to continue.&lt;/p>
&lt;p>Once access was working, Codex could inspect my existing signed-in Chrome tabs and interact with the account dashboards.&lt;/p>
&lt;p>The first lesson: being signed in to a website and giving an assistant access to that browser are separate steps.&lt;/p>
&lt;h2 id="2-inspect-the-existing-hugo-project">2. Inspect the existing Hugo project&lt;/h2>
&lt;p>My Hugo source lived in a private GitHub repository.&lt;/p>
&lt;p>Codex inspected the project and its existing GitHub Actions workflow. That revealed several details that mattered for the new deployment:&lt;/p>
&lt;ul>
&lt;li>The site used Hugo with the Academic theme.&lt;/li>
&lt;li>The theme was included as a Git submodule.&lt;/li>
&lt;li>The existing build pinned a specific Hugo Extended version.&lt;/li>
&lt;li>A custom icon was copied into the theme before building.&lt;/li>
&lt;li>The previous workflow published the generated &lt;code>public&lt;/code> directory to AWS S3.&lt;/li>
&lt;/ul>
&lt;p>Reading the old workflow gave us a starting point for a compatible build. There was no need to combine a hosting migration with a theme or Hugo upgrade.&lt;/p>
&lt;h2 id="3-import-the-repository-into-vercel">3. Import the repository into Vercel&lt;/h2>
&lt;p>In the Vercel dashboard, Codex opened &lt;strong>Add New → Project&lt;/strong>, selected GitHub, and selected my blog repository.&lt;/p>
&lt;p>Vercel already had access to the repository, so it could import the private project without making the source code public.&lt;/p>
&lt;p>The project configuration was:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Setting&lt;/th>
&lt;th>Value&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Framework preset&lt;/td>
&lt;td>Hugo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Root directory&lt;/td>
&lt;td>Repository root&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Source branch&lt;/td>
&lt;td>The production branch&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Environment variable&lt;/td>
&lt;td>&lt;code>HUGO_VERSION&lt;/code>, matching the existing build&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Build output&lt;/td>
&lt;td>&lt;code>public&lt;/code> through the Hugo preset&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>We overrode the build command to preserve the existing theme setup. The build initialized the Git submodules, copied my custom icon into the theme, and generated the static site with the intended production URL.&lt;/p>
&lt;p>A simplified example of the Hugo generation step is:&lt;/p>
&lt;pre>&lt;code class="language-sh">hugo --minify --baseURL https://example.com/
&lt;/code>&lt;/pre>
&lt;p>Use your own domain in place of &lt;code>example.com&lt;/code>, and include any preparation steps required by your theme.&lt;/p>
&lt;h2 id="4-deploy-and-check-the-actual-website">4. Deploy and check the actual website&lt;/h2>
&lt;p>The first Vercel deployment succeeded. The blog became available at its Vercel-provided address.&lt;/p>
&lt;p>Codex then opened the deployed site and checked more than the deployment success message. The homepage displayed my biography, profile image, styling, and recent posts. It also opened the &lt;strong>Leadership - Buy In | Meetings&lt;/strong> article and verified that its content loaded.&lt;/p>
&lt;p>At this point, the hosting part was working. The Vercel project was connected to GitHub so future pushes to the production branch could trigger new deployments.&lt;/p>
&lt;h2 id="5-add-the-custom-domain-in-vercel">5. Add the custom domain in Vercel&lt;/h2>
&lt;p>Next, Codex added &lt;code>jacobaloysious.in&lt;/code> to the project&amp;rsquo;s production environment.&lt;/p>
&lt;p>We kept the address without &lt;code>www&lt;/code> as the main domain. Codex also added &lt;code>www.jacobaloysious.in&lt;/code> and configured a &lt;strong>308 permanent redirect&lt;/strong> to &lt;code>jacobaloysious.in&lt;/code>.&lt;/p>
&lt;p>Vercel supplied the DNS records needed for this project:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Type&lt;/th>
&lt;th>Name&lt;/th>
&lt;th>Destination&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>A&lt;/td>
&lt;td>&lt;code>@&lt;/code>&lt;/td>
&lt;td>The IP address provided by Vercel&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CNAME&lt;/td>
&lt;td>&lt;code>www&lt;/code>&lt;/td>
&lt;td>The CNAME target provided by Vercel&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The destinations are intentionally generalized here. Use the exact records displayed in your own Vercel dashboard.&lt;/p>
&lt;h2 id="6-discover-the-old-aws-connection">6. Discover the old AWS connection&lt;/h2>
&lt;p>I expected the next step to be editing DNS in GoDaddy. Instead, GoDaddy showed that the domain&amp;rsquo;s DNS was managed by &lt;strong>Amazon Route 53&lt;/strong>.&lt;/p>
&lt;p>That explained why registering the domain with GoDaddy did not mean GoDaddy controlled its active DNS records.&lt;/p>
&lt;p>The services had different jobs:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Service&lt;/th>
&lt;th>Role in this setup&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>GitHub&lt;/td>
&lt;td>Stored the Hugo source and content&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Vercel&lt;/td>
&lt;td>Built and hosted the website&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>GoDaddy&lt;/td>
&lt;td>Registered the domain; later became its DNS provider&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>AWS&lt;/td>
&lt;td>Previously supplied Route 53 DNS and the S3 deployment destination&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Codex initially suggested updating the existing Route 53 records to preserve anything else using that DNS zone. I clarified that I no longer used the AWS setup and wanted the website routed to Vercel.&lt;/p>
&lt;p>That context mattered: it allowed us to replace the old nameserver delegation instead of requiring access to AWS.&lt;/p>
&lt;h2 id="7-move-dns-management-back-to-godaddy">7. Move DNS management back to GoDaddy&lt;/h2>
&lt;p>Codex selected GoDaddy&amp;rsquo;s default nameservers and completed the confirmation flow, moving DNS management back to GoDaddy.&lt;/p>
&lt;p>Once the GoDaddy DNS records became available, Codex made two changes:&lt;/p>
&lt;ol>
&lt;li>Replaced the parked &lt;code>@&lt;/code> A record with the IP address supplied by Vercel.&lt;/li>
&lt;li>Changed the &lt;code>www&lt;/code> CNAME to the target supplied by Vercel.&lt;/li>
&lt;/ol>
&lt;p>GoDaddy confirmed that both records were saved successfully.&lt;/p>
&lt;p>Changing DNS and retiring the previous hosting setup are separate tasks. A migration should also include a review of old deployment workflows, credentials, and billable resources.&lt;/p>
&lt;h2 id="8-investigate-vercels-invalid-configuration-warning">8. Investigate Vercel&amp;rsquo;s “Invalid Configuration” warning&lt;/h2>
&lt;p>After saving the records, Vercel still showed &lt;strong>Invalid Configuration&lt;/strong> for both domain names.&lt;/p>
&lt;p>It was tempting to assume we had entered something incorrectly. Codex compared the saved GoDaddy records with Vercel&amp;rsquo;s required values and ran public DNS checks.&lt;/p>
&lt;p>The records matched, but the public lookups were still reaching the old AWS nameservers. Those servers refused the queries, and the lookups returned &lt;code>SERVFAIL&lt;/code>.&lt;/p>
&lt;p>So there were two different states:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>In GoDaddy:&lt;/strong> the new nameservers and Vercel records were saved.&lt;/li>
&lt;li>&lt;strong>In the public DNS checks:&lt;/strong> the old AWS delegation was still being used.&lt;/li>
&lt;/ul>
&lt;p>Vercel could not verify the custom domain while those lookups were failing. A browser check also failed to resolve the domain, so we could not yet verify HTTPS on the custom address.&lt;/p>
&lt;p>GoDaddy advised that most DNS updates take effect within an hour, but global propagation can take up to 48 hours. Saving a DNS change is not the same as every resolver seeing it immediately.&lt;/p>
&lt;h2 id="9-verify-the-domain-and-go-live">9. Verify the domain and go live&lt;/h2>
&lt;p>After the DNS changes propagated, the domain was verified and the blog became accessible at &lt;strong>
&lt;a href="https://jacobaloysious.in" target="_blank" rel="noopener">jacobaloysious.in&lt;/a>&lt;/strong>.&lt;/p>
&lt;p>The completed setup:&lt;/p>
&lt;ul>
&lt;li>The Hugo blog was deployed and working on its Vercel address.&lt;/li>
&lt;li>GitHub was connected to Vercel for future deployments.&lt;/li>
&lt;li>The main domain and &lt;code>www&lt;/code> redirect were configured in Vercel.&lt;/li>
&lt;li>GoDaddy had accepted the nameserver change and saved the required records.&lt;/li>
&lt;li>The custom domain was verified and the website was live at &lt;code>jacobaloysious.in&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>The earlier &lt;strong>Invalid Configuration&lt;/strong> warning was an intermediate state during the migration. Once the DNS change took effect, the main goal was complete: readers could use my own domain to access the blog hosted on Vercel.&lt;/p>
&lt;h2 id="what-i-learned-from-using-computer-use">What I learned from using Computer Use&lt;/h2>
&lt;p>The most useful part was watching Codex carry context across several services. It read the old build workflow, applied those details in Vercel, discovered the Route 53 dependency in GoDaddy, and used DNS checks to explain the remaining warning.&lt;/p>
&lt;p>It also exposed where my input was necessary. I had to enable browser access and explain that AWS was no longer part of the intended setup. The assistant could inspect the dashboards, but it could not infer that decision from a nameserver entry alone.&lt;/p>
&lt;p>There were practical limits too. Browser pages needed time to load, some interactions needed another attempt, and a successful save did not guarantee an immediately working domain. Verification remained part of the job.&lt;/p>
&lt;p>For me, this was a concrete example of AI helping with an operational task: taking an existing website, understanding enough of its history to deploy it, and working through the connections between source code, hosting, registration, and DNS.&lt;/p>
&lt;p>My blog is now live at &lt;strong>
&lt;a href="https://jacobaloysious.in" target="_blank" rel="noopener">jacobaloysious.in&lt;/a>&lt;/strong>, with the content in GitHub, hosting on Vercel, and domain registration and DNS managed through GoDaddy. The old AWS nameserver dependency has been replaced.&lt;/p>
&lt;p>For future posts, the publishing flow is simple: update the content in GitHub, push to the production branch, and let Vercel build and deploy the site.&lt;/p></description></item><item><title>Leadership - Buy In | Meetings</title><link>https://jacobaloysious.in/post/leadership_buyin_meeting/</link><pubDate>Tue, 13 Feb 2024 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/leadership_buyin_meeting/</guid><description>&lt;p>Frequently, we find ourselves in leadership meetings, whether they are for making decisions or providing guidance. In such situations, I always remind myself or advise my colleagues to consider the following:&lt;/p>
&lt;ol>
&lt;li>Establish the purpose and context upfront&lt;/li>
&lt;li>Collaborate with the affected audience proactively&lt;/li>
&lt;li>Be Open to feedbacks&lt;/li>
&lt;/ol>
&lt;h4 id="establish-the-context-and-purpose">Establish the Context and Purpose&lt;/h4>
&lt;p>Clearly express your purpose from the beginning; whether you&amp;rsquo;re seeking guidance, a decision, or simply engaging in a brainstorming session.&lt;/p>
&lt;p>Strive for direct communication and don&amp;rsquo;t take offense at potentially blunt questions. These questions may be aimed at streamlining the presentation by skipping slides for which the audience already has context.&lt;/p>
&lt;p>Leadership is often impatient, preferring a quicker pace than anticipated. It&amp;rsquo;s not crucial to reach the end of the slides; instead, be prepared for interruptions during the presentation.&lt;/p>
&lt;p>Leadership&amp;rsquo;s time is incredibly valuable, underscoring the necessity of thorough preparation, especially with supporting data. When it comes to incorporating data into presentations, refrain from including them on slides simply because you possess them—use them as supplementary evidence.&lt;/p>
&lt;h4 id="collaborate-with-the-affected-audience">Collaborate with the affected audience:&lt;/h4>
&lt;p>Certain proposals we put forth may have repercussions on other departments within the organization; for instance, implementing automation to address customer issues could potentially impact the operations team.&lt;/p>
&lt;p>Expect challenging questions and feedback when delving into the territories or crossing boundaries of other groups. A more effective strategy is to collaborate with the affected group in advance, before the leadership meeting. Acknowledge the potential impact, and seek initial input on the proposed solutions. The objective is to prevent any confrontations during the leadership meeting, especially if an impacted leader feels offended by the proposal.&lt;/p>
&lt;h4 id="be-open-to-feedbacks">Be Open to feedbacks&lt;/h4>
&lt;p>Higher the hierarchical level, the more diverse the leader&amp;rsquo;s staff is likely to be. Depending on the specific audience, one might face differing challenges or potential criticism.&lt;/p>
&lt;p>Be attentive to inquiries such as, &lt;strong>&amp;ldquo;What problem are we exactly trying to solve?&amp;quot;&lt;/strong> This suggests that although the problem has been stated, there is a need for further clarification. Either the leader may not grasp the issue, or they may not perceive it as a problem. In such instances, avoid being defensive or revisiting the problem slides; instead, seek to understand the underlying intent behind the questions—simply ask.&lt;/p>
&lt;p>Maintain openness—what matters most is resolving the problem. The solution doesn&amp;rsquo;t necessarily have to align with the one you initially proposed.&lt;/p></description></item><item><title>Covid Travel - India to SG - Dec'21</title><link>https://jacobaloysious.in/post/vlog_india-to-sg-travel/</link><pubDate>Wed, 08 Dec 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/vlog_india-to-sg-travel/</guid><description>&lt;p>Chennai to Singapore: (Non-VTL AirIndia 0346)&lt;/p>
&lt;p>&lt;strong>Date:&lt;/strong> 06/Dec/2021 Monday&lt;/p>
&lt;h4 id="documents-required">Documents Required:&lt;/h4>
&lt;p>&lt;strong>Had to take a printout of all&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Tickets&lt;/li>
&lt;li>RT-PCR Test Result&lt;/li>
&lt;li>Visa Doc&lt;/li>
&lt;li>SG Arrival Card&lt;/li>
&lt;li>SG Arrival Swab Test confirmation with QR code&lt;/li>
&lt;li>Passport&lt;/li>
&lt;li>Entry Approval&lt;/li>
&lt;/ol>
&lt;h4 id="chennai">Chennai:&lt;/h4>
&lt;ul>
&lt;li>At the entrance - documents check&lt;/li>
&lt;li>A new document from AI was given to fill in the visa details&lt;/li>
&lt;li>AirIndia counter, again same set of documents check.&lt;/li>
&lt;li>Complimentary Face-shield and Mask from AI; at immigration entry&lt;/li>
&lt;li>Immigration - Standard - Only Passport/Visa check&lt;/li>
&lt;li>You are expected to wear a mask and face shield in the flight&lt;/li>
&lt;/ul>
&lt;h4 id="singapore-sg">Singapore (SG):&lt;/h4>
&lt;ul>
&lt;li>No face shield required, but Mask is mandatory&lt;/li>
&lt;li>Temperature check&lt;/li>
&lt;li>Guided directly into immigration lobby&lt;/li>
&lt;li>Immigration: Documents Check - All + Biometric and Photo&lt;/li>
&lt;li>Guided to Swab Test&lt;/li>
&lt;li>Verification of your Swab Test booking and barcode generated&lt;/li>
&lt;li>Guided to Swab test counters - there were multiple of them (10+)&lt;/li>
&lt;li>Take the Swab test&lt;/li>
&lt;li>Guided: Exit the airport - Taxi stand or Arrival Pickup&lt;/li>
&lt;li>Go to your SHN facility&lt;/li>
&lt;/ul>
&lt;h4 id="note">Note:&lt;/h4>
&lt;ul>
&lt;li>SG airport was well organised and guided - Impressive 😍&lt;/li>
&lt;li>No shopping is possible at SG airport&lt;/li>
&lt;li>Toilets are accessible after immigration&lt;/li>
&lt;li>At SG it took me less than 1hr&lt;/li>
&lt;li>Install TraceTogether App and register/enable it after immigration&lt;/li>
&lt;/ul>
&lt;h4 id="recommendation">Recommendation:&lt;/h4>
&lt;ul>
&lt;li>Carry a Pen&lt;/li>
&lt;li>Go early to the airport (4hrs) as the document check takes a lot of time.&lt;/li>
&lt;li>Carry a face shield - personal the complimentary one wasn&amp;rsquo;t comfortable.&lt;/li>
&lt;li>Ensure you book the SG Arrival Swab Test in advance&lt;/li>
&lt;/ul>
&lt;h4 id="links">Links:&lt;/h4>
&lt;p>Swab Test Registration:
&lt;a href="https://safetravel.changiairport.com/en.html?source=ca#/">https://safetravel.changiairport.com/en.html?source=ca#/&lt;/a>&lt;/p>
&lt;h4 id="4-hours-in-the-airport-me-my-tea-and-my-kindle-">4 hours in the Airport: Me, My Tea and My Kindle 😆&lt;/h4>
&lt;p>Book:
&lt;a href="https://www.goodreads.com/book/show/29780253-born-a-crime" target="_blank" rel="noopener">Born a Crime: Stories From a South African Childhood Trevor Noah&lt;/a>&lt;/p>
&lt;p>&lt;img src="travel-1.jpg" alt="alt Components" title="TeaandKindle">&lt;/p>
&lt;h4 id="almost-empty-airport---guess-that-was-the-only-flight-scheduled">Almost empty airport - guess that was the only flight scheduled&lt;/h4>
&lt;p>&lt;img src="travel-2.jpg" alt="alt Components" title="Chennai Airport - Empty">&lt;/p>
&lt;h4 id="both-mask-and-faceshield-was-mandatory-">Both Mask and Faceshield was Mandatory 😦&lt;/h4>
&lt;p>&lt;img src="travel-3.jpg" alt="alt Components" title="AI Flight">&lt;/p></description></item><item><title>PKCE</title><link>https://jacobaloysious.in/post/tech_pkce/</link><pubDate>Fri, 03 Dec 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_pkce/</guid><description>&lt;p>
&lt;a href="https://jacobaloysious.in/post/tech_oauth/" title="OAuth">Prerequisite: OAuth2.0&lt;/a>&lt;/p>
&lt;p>PKCE is pronounced as &amp;lsquo;pixie&amp;rsquo;. PKCE - Proof Key for Code Exchange =&amp;gt;
&lt;a href="https://www.youtube.com/watch?v=5cQNwifDq1U" target="_blank" rel="noopener">Credits&lt;/a>&lt;/p>
&lt;h3 id="concepts">Concepts:&lt;/h3>
&lt;h4 id="what-is-confidential-client">What is Confidential Client?&lt;/h4>
&lt;p>Any backend application written in languages like .Net, Java, NodeJS can be considered as Confidential Client. As they have the ability to &amp;ldquo;store variables&amp;rdquo; in our case Secret Keys - without exposing them to the end user - as the code is running on the server side. The secret key would be used to generate the Access Token in the OAuth Flow.&lt;/p>
&lt;h4 id="what-is-public-client">What is public Client?&lt;/h4>
&lt;ol>
&lt;li>
&lt;p>Any Single Page Application (SPA), where all the code is downloaded to the users browser would be considered a Public Client. Coz: the secret key cannot be securely stored as the hacker could do a &amp;ldquo;view source code&amp;rdquo; and look at the secret key which is usually in plain text/string format.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Another example are Mobile Apps - the user can download and de-compile/reverse engineer - the application and find the secret key.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="why-do-you-need-pkce">Why do you need PKCE?&lt;/h3>
&lt;p>Once the secret key is available - the hacker can impersonate as the Client and generate the access token (note: clientID is public and secret key is private). Once the access token is available - the hacker can access lot more confidential information about the user. So the existing
&lt;a href="https://jacobaloysious.in/post/tech_oauth/" title="OAuth">OAuth2.0&lt;/a> model is not secure for both SPA and mobile apps. To solve this challenge -
&lt;a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc7636.txt.pdf" target="_blank" rel="noopener">PKCE&lt;/a> was introduced.&lt;/p>
&lt;h4 id="oauth-20-normal-flow">OAuth 2.0 Normal Flow:&lt;/h4>
&lt;p>&lt;img src="oauth-normal-flow.jpg" alt="alt Components" title="OAuth2.0 Normal Flow">&lt;/p>
&lt;h4 id="pkce-flow">PKCE Flow:&lt;/h4>
&lt;p>&lt;img src="pkce-flow-2.jpg" alt="alt Components" title="PKCE Flow">&lt;/p>
&lt;h3 id="what-is-new-in-pkce">What is new in PKCE?&lt;/h3>
&lt;ol>
&lt;li>In the PKCE flow: Instead of a constant Secret Key - Everytime an OAuth flow is initiated - &lt;strong>A new &amp;ldquo;Secret Key&amp;rdquo;&lt;/strong> is generated and Hashed.&lt;/li>
&lt;li>Hash is shared with the Authentication Server(AS) when requesting for the Temporary Code. AS would remember this Hash value.&lt;/li>
&lt;li>When the client request for the Access Token - it sends the newly generated &amp;ldquo;Secret Key&amp;rdquo; - the AS would check, if the secret matches the Hash (it already remembers - #2).&lt;/li>
&lt;/ol>
&lt;h3 id="reference">Reference:&lt;/h3>
&lt;p>
&lt;a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc7636.txt.pdf" target="_blank" rel="noopener">RFC7636&lt;/a>,
&lt;a href="https://www.youtube.com/watch?v=aU9RsE4fcRM" target="_blank" rel="noopener">Oauth Hack&lt;/a>,
&lt;a href="https://www.youtube.com/watch?v=5cQNwifDq1U" target="_blank" rel="noopener">What&amp;rsquo;s the difference between Confidential and Public clients&lt;/a>&lt;/p></description></item><item><title>Designated Authentication - OAuth2.0</title><link>https://jacobaloysious.in/post/tech_oauth/</link><pubDate>Thu, 02 Dec 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_oauth/</guid><description>&lt;p>
&lt;a href="https://www.youtube.com/watch?v=996OiexHze0" target="_blank" rel="noopener">OAuth2.0 and OpenID&lt;/a> - is one of the best videos (62 mins) on this topic - Highly recommended. This blog is just a quick summary (4 mins read) of it.&lt;/p>
&lt;h3 id="what-is-oauth">What is OAuth?&lt;/h3>
&lt;p>OAuth is a security standard where you give one application permission to access your data from another application i.e. you authorized one application to use data from another application on your behalf, without giving them your username and password. The steps to grant permission(s) or consent is often reffered to as authorization or delegated authorization. Permissions are scoped e.g. client can be given access to read your GMail contacts but cannot Read/Write your email. OAuth is not exactly used for user identification (who loggged in), instead its used to access API&amp;rsquo;s for resources like gmail contact list.&lt;/p>
&lt;p>&lt;img src="access-card-example.jpg" alt="alt Components" title="Access Card Example">&lt;/p>
&lt;ul>
&lt;li>You check-in to a hotel.&lt;/li>
&lt;li>At the front desk - You give your details like Passport and Reservation&lt;/li>
&lt;li>Front Desk would in turn - give you the Key Card i.e. Access Token&lt;/li>
&lt;li>You can use the Key Card to access your reserved Room&lt;/li>
&lt;/ul>
&lt;p>Here, the Front Desk is the Authentication Server - the key card is your Access token used to acess your Room (Resources API). The API doesn&amp;rsquo;t really care who is accessing the Resource as long as they have the access token.&lt;/p>
&lt;h3 id="oauth-terminologies">OAuth Terminologies:&lt;/h3>
&lt;p>Lets assume you are giving Yelp access to your Gmail account contacts..&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Resource Owner:&lt;/strong> Represent you the owner of the gmail account; who can give permission/authorize.&lt;/li>
&lt;li>&lt;strong>Client&lt;/strong>: Represent Yelp i.e. the application which would like to perform action on behalf of you.&lt;/li>
&lt;li>&lt;strong>Authorization Server:&lt;/strong> One who validates the gmail uname/password and authenticate - in this case &lt;em>accounts.google.com&lt;/em>. Resource owner will already have an account with this server (gmail).&lt;/li>
&lt;li>&lt;strong>Resource Server:&lt;/strong> Server (API) which has the actual content/resources like contact list in this case &lt;em>contacts.google.com&lt;/em>. Which client would talk to get the actual data.&lt;/li>
&lt;li>&lt;strong>Authorization Grant:&lt;/strong> Once authenticated an &lt;em>Authorizatiion Code&lt;/em> or temporary code is sent back to he client. So, the client has been granted relevant access to the resource owners gmail contacts. This is short lived, this is used to inturn get the access token (long lived).&lt;/li>
&lt;li>&lt;strong>Redirect URI:&lt;/strong> Also known as Callback. It is the URI to which the response of Authentication #5 should be sent back to client #2&lt;/li>
&lt;li>&lt;strong>Access Token:&lt;/strong> Token/Key used by the Client to access all the resources of the owner; based on the authorized permissions.&lt;/li>
&lt;li>&lt;strong>Response Type&lt;/strong>: The type of information the client would like to receive e.g: code (authorization code)&lt;/li>
&lt;li>&lt;strong>Scope:&lt;/strong> Granular permission the client wants acess to like Read Contact, Read Profile basic info.&lt;/li>
&lt;li>&lt;strong>Consent:&lt;/strong> Whether the client can be given permission to access the requested information.&lt;/li>
&lt;li>&lt;strong>ClientID:&lt;/strong> Unique ID of the client, which is used to talk to the authorization server.&lt;/li>
&lt;li>&lt;strong>Client Secret:&lt;/strong> Secret Key - only the client and the auth server shares. Helps Client and Resource Server to share information secretly behind the scenes.&lt;/li>
&lt;/ol>
&lt;h3 id="oauth-flow">OAuth Flow:&lt;/h3>
&lt;h4 id="prerequisite">Prerequisite:&lt;/h4>
&lt;p>Client and the Authorization Server should establish a working relationship. Both the &amp;ldquo;ClientID (AppID)&amp;rdquo; and &amp;ldquo;Client Secret(AppSecret)&amp;rdquo; are generated by the Authorization Server. The client ID would be used to uniquely identify the client. Its the responsibility of the client to ensure the &amp;ldquo;ClientSecret&amp;rdquo; is kept secret and its only know by client and authorization server. As there are the only means for the Auth Server to verify the client.&lt;/p>
&lt;h4 id="actual-flow">Actual Flow:&lt;/h4>
&lt;p>In this example, Yelp would want to authenticate a user based on GMail Authentication, and access Profile/Contacts information.&lt;/p>
&lt;p>&lt;img src="oauth-code-flow.jpg" alt="alt Components" title="OAuth Code Flow">&lt;/p>
&lt;ol>
&lt;li>Client(Yelp) would make a request to Authenticate - to &amp;ldquo;Autorization Server&amp;rdquo; (accounts.google.com); as part of the request:
&lt;ol>
&lt;li>&amp;ldquo;RedirectURI&amp;rdquo; is set to a callback URL of the client &amp;ldquo;yelp.com/callback&amp;rdquo;&lt;/li>
&lt;li>&amp;ldquo;Respose Type&amp;rdquo; is set to &amp;ldquo;Code&amp;rdquo;, so a auth code is sent back as response to 1.a&lt;/li>
&lt;li>&amp;ldquo;Client ID&amp;rdquo; and &amp;ldquo;Scope&amp;rdquo; (Profile/Contacts)&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Auth Server pops up a dialog (mostly) - where user gets to enter the GMail credentials (uname/pass) and authenticate&lt;/li>
&lt;li>Auth Server shows up a consent form - list the info access requested (like contacts, profile) - user gets to choose Yes or NO&lt;/li>
&lt;li>Once concent(Yes) is given - an &amp;ldquo;Auth Code&amp;rdquo; is generated and sent back to the the client - to specifiied callback/redirectURI.&lt;/li>
&lt;li>Then, the client sends the &amp;ldquo;Auth Code + ClientID + ClientSecret&amp;rdquo; to &amp;ldquo;Authorization Server&amp;rdquo; and gets back an &amp;ldquo;Access Token&amp;rdquo;&lt;/li>
&lt;li>Using the &amp;ldquo;Access Token&amp;rdquo;, Client can contact the resource server (contacts.google.com) to get the actual resources (profile, contacts) of the user.&lt;/li>
&lt;/ol>
&lt;p>Reference: &lt;a href="https://www.youtube.com/watch?v=aU9RsE4fcRM">https://www.youtube.com/watch?v=aU9RsE4fcRM&lt;/a>&lt;/p></description></item><item><title>WebFinger</title><link>https://jacobaloysious.in/post/tech_webfinger/</link><pubDate>Wed, 01 Dec 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_webfinger/</guid><description>&lt;p>&lt;em>This blog contain just snips - a detailed explanation is available in the Reference links..&lt;/em>&lt;/p>
&lt;h3 id="background">Background:&lt;/h3>
&lt;p>Twitter started the project called
&lt;a href="https://blueskyweb.org/" target="_blank" rel="noopener">Bluesky&lt;/a> with a goal to build a social web. As part of it,
&lt;a href="https://www.w3.org/TR/activitypub/" target="_blank" rel="noopener">ActivityPub&lt;/a> a decentralized social networking protocol was built - which uses WebFinger in the background.&lt;/p>
&lt;h3 id="what-is-webfinger">What is WebFinger:&lt;/h3>
&lt;p>WebFinger is used to discover information about people or other entities on the Internet that are identified by a URI using standard Hypertext Transfer Protocol (HTTP) methods over a secure transport. A WebFinger resource returns a JavaScript Object Notation (JSON) object describing the entity that is queried.&lt;/p>
&lt;h3 id="key-items-to-note">Key Items to Note:&lt;/h3>
&lt;p>WebFinger protocol is used to request information about an entity identified by a query target (a URI).&lt;/p>
&lt;p>A WebFinger request is an HTTPS request to a WebFinger resource.&lt;/p>
&lt;p>A WebFinger resource is a well-known URI&lt;/p>
&lt;p>A WebFinger resource is always given a query target, which is another URI that identifies the entity whose information is sought.
GET requests to a WebFinger resource convey the query target in the &amp;ldquo;resource&amp;rdquo; parameter of the WebFinger URI’s query string&lt;/p>
&lt;p>The path component of a WebFinger URI MUST be the well-known path &lt;strong>&amp;quot;/.well-known/webfinger&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>The WebFinger resource returns a JSON Resource Descriptor (JRD) as the resource representation to convey information about an entity on the Internet&lt;/p>
&lt;p>The use of HTTPS is REQUIRED to ensure that information is not modified during transit.
Clients MUST verify that the certificate used on an HTTPS connection is valid and accept a response only if the certificate is valid.&lt;/p>
&lt;p>The Registration Template:&lt;/p>
&lt;ul>
&lt;li>Property Identifier:&lt;/li>
&lt;li>Link Type:&lt;/li>
&lt;li>Description:&lt;/li>
&lt;li>Reference:&lt;/li>
&lt;li>Notes: [optional]
The &amp;ldquo;Property Identifier&amp;rdquo; must be a URI that identifies the property being registered.&lt;/li>
&lt;/ul>
&lt;h4 id="example">Example:&lt;/h4>
&lt;p>Suppose Lia wishes to authenticate with a web site she visits using OpenID Connect. She would provide the web site with her OpenID Connect identifier, say &lt;a href="mailto:lia@example.com">lia@example.com&lt;/a>. The visited web site would perform a WebFinger query looking for the OpenID Connect provider. Since the site is interested in only one particular link relation, the WebFinger resource might utilize the &amp;ldquo;rel&amp;rdquo; parameter&lt;/p>
&lt;p>&lt;strong>Request:&lt;/strong>&lt;/p>
&lt;pre>&lt;code> GET /.well-known/webfinger?
resource=acct%3Alia%40example.com&amp;amp;
rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer
HTTP/1.1
Host: example.com
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Response:&lt;/strong>&lt;/p>
&lt;pre>&lt;code> HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/jrd+json
{
&amp;quot;subject&amp;quot; : &amp;quot;acct:lia@example.com&amp;quot;,
&amp;quot;links&amp;quot; :
[
{
&amp;quot;rel&amp;quot; : &amp;quot;http://openid.net/specs/connect/1.0/issuer&amp;quot;,
&amp;quot;href&amp;quot; : &amp;quot;https://openid.example.com&amp;quot;
}
]
}
&lt;/code>&lt;/pre>
&lt;p>Since the &amp;ldquo;rel&amp;rdquo; parameter only serves to filter the link relations returned by the resource, other name/value pairs in the response, including any aliases or properties, would be reeturned. Also, since support for the &amp;ldquo;rel&amp;rdquo; parameter is not guaranteed, the client must not assume the &amp;ldquo;links&amp;rdquo; array will contain only the requested link relation.&lt;/p>
&lt;h4 id="take-ways">Take ways:&lt;/h4>
&lt;p>The specification is rather simple as it uses JSON as the data model for all the communication. Almost, all languages provide support for handling JSON. Validation is still not part of the spec - So both validation and handling attack should be the responsiblity for the client.&lt;/p>
&lt;h4 id="references">References:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc7033.txt.pdf" target="_blank" rel="noopener">WebFinger Protocol&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://bluesky-community.net/" target="_blank" rel="noopener">Bluesky&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://gitlab.com/bluesky-community1/decentralized-ecosystem/-/blob/master/protocols/activitypub.md" target="_blank" rel="noopener">ActivityPub&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.w3.org/TR/activitypub/" target="_blank" rel="noopener">W3 ActivityPub&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Engineering Manager - 5yrs</title><link>https://jacobaloysious.in/post/diary_engineering_manager/</link><pubDate>Sat, 27 Nov 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_engineering_manager/</guid><description>&lt;p>I have been an engineering manager since 2016 i.e. 5+ yrs, as I write this blog. More often, I have thought to myself as - what is my role as an engineering manager. This is just a brain dump and not an exhaustive list and not in any specific order.&lt;/p>
&lt;h4 id="technical">Technical:&lt;/h4>
&lt;ul>
&lt;li>Solid understanding of the requirements and architecture - team deliverables&lt;/li>
&lt;li>Reasonable overall breath and few focussed depth - understanding of the design&lt;/li>
&lt;li>Ensure the testing stratergy (Automated and Manual) - has appropriate coverage&lt;/li>
&lt;li>Quality: Follow best known practices of Software Engineering like Test Driven Development, CI/CD.&lt;/li>
&lt;/ul>
&lt;h4 id="talent-for-each-team-member">Talent: For each team member&lt;/h4>
&lt;ul>
&lt;li>Strength and weakness&lt;/li>
&lt;li>Short term and mid term - development focus areas&lt;/li>
&lt;li>Mentor or coach&lt;/li>
&lt;li>Training Needs&lt;/li>
&lt;/ul>
&lt;h4 id="team">Team:&lt;/h4>
&lt;ul>
&lt;li>Onboarding plan for new hires&lt;/li>
&lt;li>Understanding of Cross functional teams - that your team colloborates with&lt;/li>
&lt;li>Clarity on the ownership overlap between your team and cross functional team&lt;/li>
&lt;li>Updated: skill and ownership matrix&lt;/li>
&lt;/ul>
&lt;h4 id="hiring">Hiring:&lt;/h4>
&lt;ul>
&lt;li>Estimate the # of new hires - required for you team ~1yr timeframe&lt;/li>
&lt;li>Clear job(s) description of all new positions&lt;/li>
&lt;li>Work closely with Talent Acquition team on filtering resumes, scheduling and debriefing Sessions&lt;/li>
&lt;li>Identify buddy to help the new member settle in&lt;/li>
&lt;/ul>
&lt;h4 id="roadmap">Roadmap:&lt;/h4>
&lt;ul>
&lt;li>Clear understanding of the division&amp;rsquo;s roadmap and business priorities&lt;/li>
&lt;li>Project roadmap - that your team would be working on ~6 to 12months.&lt;/li>
&lt;li>Project Plan/Schedule for the projects: in progress and next one in pipeline&lt;/li>
&lt;li>Identifying technical debt in your functional area&lt;/li>
&lt;li>Functional roadmap to pay off technical debt&lt;/li>
&lt;li>New technologies that your team shall pay attension to&lt;/li>
&lt;li>Technical conferences your team can attend/follow&lt;/li>
&lt;/ul></description></item><item><title>WASM Cloud</title><link>https://jacobaloysious.in/post/tech_wasm_cloud/</link><pubDate>Fri, 26 Nov 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_wasm_cloud/</guid><description>&lt;h4 id="what-is-wasm-cloud-trying-to-solve">What is WASM Cloud trying to solve?&lt;/h4>
&lt;p>Lets ask - what a typical &amp;ldquo;Development Iteration&amp;rdquo; look like?&lt;/p>
&lt;ol>
&lt;li>Start of with your Napkin Drawings - conceptual vision of what is it you want to build&lt;/li>
&lt;li>Initial Prototype, prove that it works&lt;/li>
&lt;li>Then, Figure out how to scale&lt;/li>
&lt;/ol>
&lt;p>The challenge is between #2 and #3 there is more often a &lt;strong>complete rewrite&lt;/strong>. As the author claims- Virtually nothing from prototype is written in a way it is scalable.&lt;/p>
&lt;p>The goal of the project is to &lt;strong>&amp;ldquo;Ship Napkins to Production&amp;rdquo;&lt;/strong> directly.&lt;/p>
&lt;ol>
&lt;li>Draw your conceptual map of how your application should look like&lt;/li>
&lt;li>Fill in the blanks with your business logic and just push it - boom!!&lt;/li>
&lt;li>Don&amp;rsquo;t worry about any of the non-sense in between.&lt;/li>
&lt;li>Remove all the boiler plate and let developer write only Business logic.&lt;/li>
&lt;/ol>
&lt;h4 id="how-is-this-achived">How is this achived?&lt;/h4>
&lt;p>Using the &lt;strong>&amp;ldquo;Actor Model&amp;rdquo;&lt;/strong> and the out of the box boilerplate infrastructure.
Personally, I a fan of Actor Model, as its easy to just write a function which has a single responsibility. If you have ever worked with Threads and IPC(Interprocess communication) - you would know the overheads that come in managing them. With the Actor model you have an input queue, an output queue and the function in between. Developer shall write only the function. Function would read from the input queue, process and write it to the output queue. The infrastructure should take care of running the actor, as a thread or process and also manage the input/output queue, data transfer, serialization etc. One of the popular implementation of Actor model is
&lt;a href="https://akka.io/" target="_blank" rel="noopener">AKKA&lt;/a>.&lt;/p>
&lt;p>From the authors:&lt;/p>
&lt;blockquote>
&lt;p>The creators of wasmCloud believe that we can not only change the way developers build software for the better, but make it easier to secure, deploy, maintain, observe, and upgrade that software as well–all while reducing the amount of boilerplate we have to copy and paste.&lt;/p>
&lt;/blockquote>
&lt;h4 id="example">Example:&lt;/h4>
&lt;p>Lets look at their
&lt;a href="https://wasmcloud.dev/app-dev/create-actor/generate/" target="_blank" rel="noopener">Hello World&lt;/a> example.&lt;/p>
&lt;p>Interesting snippets:&lt;/p>
&lt;pre>&lt;code> #[derive(Debug, Default, Actor, HealthResponder)]
#[services(Actor, HttpServer)]
struct HelloActor {}
/// Implementation of HttpServer trait methods
#[async_trait]
impl HttpServer for HelloActor {
//Actual Impl
}
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;em>HelloActor&lt;/em> is the name of your actor&lt;/li>
&lt;li>The two lines with &amp;ldquo;#&amp;rdquo; above the actor name igenerate - at compile time - nearly all of the scaffolding needed to build an actor.&lt;/li>
&lt;li>The &lt;em>HealthResponder&lt;/em> term generates a function that automatically responds to health check queries from the &lt;em>wasmCloud&lt;/em> host.&lt;/li>
&lt;li>The &lt;em>#[services(&amp;hellip;)]&lt;/em> line declares the servicesthat your actor implements, and generates message handling code for those interfaces.&lt;/li>
&lt;li>All actors implement the &lt;em>Actor&lt;/em> interface.&lt;/li>
&lt;li>The &lt;em>HttpServer&lt;/em> entry declares that the actor will also implement that interface, and requires an implementation of that trait’s method: handle_request.&lt;/li>
&lt;/ul>
&lt;h4 id="conclusion">Conclusion:&lt;/h4>
&lt;p>I am fan of distributed computing: designing and writing scalable application. Maybe the concept of wasmCloud doing the heavy lifting sounds easy; but I belive its a very hard problem. Coz: when we actually get our hands dirty with actual application design - challenges like: managing states, versioning, schema management/registry, idempotency, trade offs w.r.t CAP theorm, heterogeneous system etc..all comes in. Also, given what Docker + Kubernetes eco system already provides - finding the right architecture to use wasmCloud would be a challenge. But this is definitely a place lot of things can be improved and room for optimization. Star&amp;rsquo;ed the project for now, will be following it closely.&lt;/p>
&lt;p>Reference:
&lt;a href="https://wasmcloud.dev/" target="_blank" rel="noopener">WASM Cloud&lt;/a>,
&lt;a href="https://github.com/wasmCloud/wasmCloud" target="_blank" rel="noopener">GitHub&lt;/a>&lt;/p></description></item><item><title>Rubber Duck Debugging</title><link>https://jacobaloysious.in/post/tech_rubber_duck_debugging/</link><pubDate>Wed, 24 Nov 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_rubber_duck_debugging/</guid><description>&lt;p>I have been in a similar situation multiple times - where in I was stuck on a problem. To get a solution, I would want to reach out for help. So, I would start to write it down - as it could post it in StackOverflow or send it as an email to my friend/colleague. While I am writing the problem down, I try to set the context and elaborate on the problem statement - after few iteration/reformatting/edits - its strange that I would have found the solution. Oops-What happened???&lt;/p>
&lt;p>Stepping back and looking at it, what had happened is - while we try to explain the problem to someone (in writing) - we try to remove all the clutter and focus on the actual problem - with the intent to keep the &lt;strong>email shorter and digestable components&lt;/strong>, so that the audience/reader is not overwhelmed. But, in the process we have a better clarity of the core (only) problem we are trying to solve. When that clarity comes up, more often we get closer to the solution.&lt;/p>
&lt;p>BTW: I never knew, there was a name for it - &lt;strong>&amp;ldquo;Rubber Duck Debugging&amp;rdquo;&lt;/strong> until I heard it from
&lt;a href="https://twitter.com/shanselman" target="_blank" rel="noopener">scott hanselman&lt;/a> in one of his podcast. And there is a website
&lt;a href="https://rubberduckdebugging.com/" target="_blank" rel="noopener">rubberduckdebugging&lt;/a> for it.&lt;/p>
&lt;p>Snip from the site:&lt;/p>
&lt;blockquote>
&lt;ol>
&lt;li>Place rubber duck on desk and inform it you are just going to go over some code with it, if that’s all right.&lt;/li>
&lt;li>Explain to the duck what your code is supposed to do, and then go into detail and explain your code line by line.&lt;/li>
&lt;li>At some point you will tell the duck what you are doing next and then realise that that is not in fact what you are actually doing. The duck will sit there serenely, happy in the knowledge that it has helped you on your way.&lt;/li>
&lt;/ol>
&lt;/blockquote>
&lt;p>Well, I had to buy one rubber duck, as I wasn&amp;rsquo;t able to negotiate to lease one with my 7yr old daughter 😉&lt;/p>
&lt;p>The next time you get stuck on a hard issue, take a moment and write down exactly whats going wrong as if you were going to explain it to someone else, you may just notice exactly where you are going wrong and even if you dont, at least you have a question all ready for submission to StackOverflow&amp;hellip;&lt;/p></description></item><item><title>Software Enthusiast - Getting Started</title><link>https://jacobaloysious.in/post/tech_getting_started/</link><pubDate>Wed, 24 Nov 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_getting_started/</guid><description>&lt;p>I have been asked this question multiple times. I would like to be a software enthusiast and where do I get started. Thanks to my Friend to help put this together&lt;/p>
&lt;h3 id="books">Books:&lt;/h3>
&lt;h4 id="coding">Coding:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/clean-code-a/9780136083238/" target="_blank" rel="noopener">Clean Code: A Handbook of Agile Software Craftsmanship&lt;/a> *&lt;/li>
&lt;/ul>
&lt;h4 id="unit-testing">Unit Testing:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.manning.com/books/the-art-of-unit-testing-second-edition" target="_blank" rel="noopener">The Art of Unit Testing, 2nd Edition&lt;/a> *&lt;/li>
&lt;/ul>
&lt;h4 id="design">Design:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/design-patterns-elements/0201633612/" target="_blank" rel="noopener">Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a>*&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/head-first-design/9781492077992/" target="_blank" rel="noopener">Head First Design Patterns, 2nd Edition&lt;/a> *&lt;/li>
&lt;/ul>
&lt;h4 id="solid-principles">SOLID principles:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://cleancoders.com/" target="_blank" rel="noopener">Clean Coders: Level up your code&lt;/a> *&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/" target="_blank" rel="noopener">Clean Architecture: A Craftsman’s Guide to Software Structure and Design&lt;/a> *&lt;/li>
&lt;/ul>
&lt;h4 id="refactoring">Refactoring:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/refactoring-improving-the/9780134757681/" target="_blank" rel="noopener">Refactoring: Improving the Design of Existing Code&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/working-effectively-with/0131177052/" target="_blank" rel="noopener">Working Effectively with Legacy Code&lt;/a>&lt;/li>
&lt;/ul>
&lt;h4 id="architecture">Architecture:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/" target="_blank" rel="noopener">Clean Architecture: A Craftsman’s Guide to Software Structure and Design&lt;/a> *&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/" target="_blank" rel="noopener">Designing Data-Intensive Applications&lt;/a> *&lt;/li>
&lt;li>
&lt;a href="https://martinfowler.com/architecture/" target="_blank" rel="noopener">Software Architecture Guide&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/building-microservices/9781491950340/" target="_blank" rel="noopener">Building Microservices&lt;/a>
&lt;em>*must read books&lt;/em>&lt;/li>
&lt;/ul>
&lt;h2 id="keeping-up-with-ever-evolving-tech-space">Keeping up with ever evolving tech Space:&lt;/h2>
&lt;h3 id="youtube-channels-to-follow">Youtube channels to follow&lt;/h3>
&lt;ul>
&lt;li>
&lt;a href="https://www.youtube.com/c/NDCConferences" target="_blank" rel="noopener">NDC Conferences&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.youtube.com/c/GotoConferences" target="_blank" rel="noopener">GOTO Conferences&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.youtube.com/nctv" target="_blank" rel="noopener">InfoQ&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="twitter-handles-to-follow">Twitter handles to follow:&lt;/h3>
&lt;ul>
&lt;li>
&lt;a href="https://twitter.com/allenholub" target="_blank" rel="noopener">allenholub&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/ploeh" target="_blank" rel="noopener">ploeh&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/jbogard" target="_blank" rel="noopener">jbogard&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/mfeathers" target="_blank" rel="noopener">mfeathers&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/GeePawHill" target="_blank" rel="noopener">GeePawHill&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/Grady_Booch" target="_blank" rel="noopener">Grady_Booch&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/shanselman" target="_blank" rel="noopener">shanselman&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/KentBeck" target="_blank" rel="noopener">KentBeck&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/martinfowler" target="_blank" rel="noopener">martinfowler&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/unclebobmartin" target="_blank" rel="noopener">unclebobmartin&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/ansonhorton" target="_blank" rel="noopener">Anson Horton&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/madstorgersen?lang=en" target="_blank" rel="noopener">Mads Torgersen&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/joboccara" target="_blank" rel="noopener">Jonathan Boccara&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/thecleancoders" target="_blank" rel="noopener">Clean Coders&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/davidfowl" target="_blank" rel="noopener">David Fowler&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/John_Papa" target="_blank" rel="noopener">John Papa&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/spolsky" target="_blank" rel="noopener">Joel Spolsky&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/robconery" target="_blank" rel="noopener">Rob Conery&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/codinghorror" target="_blank" rel="noopener">Jeff Atwood&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/migueldeicaza" target="_blank" rel="noopener">Miguel “mask and vax” de Icaza&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/haacked" target="_blank" rel="noopener">Boom Haackalacka&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://twitter.com/shanselman" target="_blank" rel="noopener">Scott Hanselman&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="podcasts--blogs-to-follow">Podcasts &amp;amp; blogs to follow:&lt;/h3>
&lt;ul>
&lt;li>
&lt;a href="https://www.dataengineeringpodcast.com/" target="_blank" rel="noopener">The Data Engineering Podcast&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.hanselminutes.com/" target="_blank" rel="noopener">Hanselminutes&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.thoughtworks.com/insights/podcasts/technology-podcasts/all-episodes" target="_blank" rel="noopener">Technology podcast: all episodes | Thoughtworks&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://netflixtechblog.com/" target="_blank" rel="noopener">Netflix TechBlog&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.thoughtworks.com/en-in/radar" target="_blank" rel="noopener">Technology Radar | An opinionated guide to technology frontiers | Thoughtworks&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://engineering.fb.com/" target="_blank" rel="noopener">Facebook Engineering Blog&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://engineeringblog.yelp.com/" target="_blank" rel="noopener">Yelp Engineering Blog&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://eng.uber.com/" target="_blank" rel="noopener">Uber Engineering Blog&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Reverse ETL</title><link>https://jacobaloysious.in/post/tech_reverse_etl/</link><pubDate>Sun, 14 Nov 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_reverse_etl/</guid><description>&lt;p>While listening to
&lt;a href="https://www.dataengineeringpodcast.com/reverse-etl-and-customer-data-platforms-episode-235/" target="_blank" rel="noopener">Podcast&lt;/a> stumbled upon this term of Reverse-ETL.&lt;/p>
&lt;p>First lets align on a few basic terminologies:&lt;/p>
&lt;h4 id="what-is-a-data-warehouse-dw">What is a Data Warehouse (DW):&lt;/h4>
&lt;p>Data Warehouse centralizes and consolidates data from multiple sources like application log files and transaction applications. Orgainzation use DW to gain valuable insights from data, which can improve decision making by building a historical record of data. It can be considered the single source of truth.&lt;/p>
&lt;h4 id="what-is-etl">What is ETL&lt;/h4>
&lt;p>&lt;img src="ETL.jpg" alt="alt Components" title="ETL">
ETL Stands for &lt;em>Extract Transform and Load&lt;/em>. ETL is a data integration process that combines data from multiple data sources into a single, consistent data store that is loaded into a data warehouse or other target system.&lt;/p>
&lt;h4 id="what-is-reverse-etl">What is Reverse ETL&lt;/h4>
&lt;p>&lt;img src="ReverseETL.jpg" alt="alt Components" title="Reverse ETL">
Reverse ETL is the process of copying data from a central data warehouse to operational systems of record, including but not limited to SaaS tools used for growth, marketing, sales and support.&lt;/p>
&lt;h3 id="discussion">Discussion:&lt;/h3>
&lt;p>Hang On! this doesn&amp;rsquo;t make sense - why should someone do ETL and then Reverse it? Coz, just ETL in itself - is a HUGE infrastructure to both develop and maintain - why would I manage both. Well, as always devil is in the details.&lt;/p>
&lt;p>Lets see an example from
&lt;a href="https://hightouch.io" target="_blank" rel="noopener">Hightouch&lt;/a>
&lt;img src="example.jpg" alt="alt Components" title="Example">&lt;/p>
&lt;p>&lt;strong>Reasoning&lt;/strong>(&lt;em>by Hightouch&lt;/em>):&lt;/p>
&lt;blockquote>
&lt;p>Reverse ETL is necessary because your data warehouse — the platform you bought to eliminate data silos — has ironically become a data silo. Without reverse ETL, your business’s core definitions only live in the warehouse.&lt;/p>
&lt;/blockquote>
&lt;p>More detailed information like use cases are avaialble in this blog
&lt;a href="https://hightouch.io/blog/reverse-etl/" target="_blank" rel="noopener">Reverse ETL&lt;/a>&lt;/p>
&lt;h3 id="conclusion">Conclusion:&lt;/h3>
&lt;p>The intent here seems to bridge the knowlege gap, that comes in due to data warehouse. Say: If a business user is so used to a particular platform/tech like SalesForce, the user would prefer the analystic output/data to be available in their platform. Incase of Data Warehouse, the SalesForce business user should understand and learn the new ways to access the data and its corresponding schema in the DW; and also learn the access mechanisms like scripts, sql etc.. With Reverse ETL, it creates a comfortable/known space for the user as all the &amp;ldquo;Actionable Data&amp;rdquo; from the analytics are available in their platform. So, sure it makes sense.&lt;/p>
&lt;p>Only challenge, I see as an organization is - the effort in maintaining both ETL and Reverse ETL infrastructure. Any changes in the DW schema - should be notified to both the teams and the deliverables should be synced up - to avoid any broken pipelines.&lt;/p>
&lt;p>Reference:
&lt;a href="https://www.oracle.com/in/database/what-is-a-data-warehouse/" target="_blank" rel="noopener">DataWarehouse&lt;/a>&lt;/p></description></item><item><title>Access Control - Casbin</title><link>https://jacobaloysious.in/post/tech_casbin/</link><pubDate>Sun, 31 Oct 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_casbin/</guid><description>&lt;p>I was trying to read about RBAB (Role-Based Access Control) and ABAC(Attribute-Based Access Control); after some reading - I realized, as a software engineer - it&amp;rsquo;s way more easier when you get to read code - So, I started to search for open source project which implements access control infrastructure, and stumbled upon
&lt;a href="https://casbin.org/" target="_blank" rel="noopener">Casbin&lt;/a>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>Snip from Readme:&lt;/em> In Casbin, an access control model is abstracted into a CONF file based on the &lt;strong>PERM metamodel (Policy, Effect, Request, Matchers)&lt;/strong>. So switching or upgrading the authorization mechanism for a project is just as simple as modifying a configuration. You can customize your own access control model by combining the available models. For example, you can get RBAC roles and ABAC attributes together inside one model and share one set of policy rules.&lt;/p>
&lt;/blockquote>
&lt;p>The interesting part here is how Casbin - has designed the whole system behind a simple yet flexible configuration file and grammars to describe predicates. Intent of this blog is - just to get you curious about Casbin. Casbin has reasonally good documentation on their site.&lt;/p>
&lt;p>&lt;em>ProTip:&lt;/em> Best way to understand an open source is to start with the test cases, look at each test case - review the context and assert statements.&lt;/p>
&lt;p>Lets look at a simple
&lt;a href="https://github.com/jacobaloysious/pycasbin/blob/master/examples/rbac_model.conf" target="_blank" rel="noopener">RBAC Model Config&lt;/a>&lt;/p>
&lt;pre>&lt;code>[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) &amp;amp;&amp;amp; r.obj == p.obj &amp;amp;&amp;amp; r.act == p.act
&lt;/code>&lt;/pre>
&lt;p>
&lt;a href="https://github.com/jacobaloysious/pycasbin/blob/master/examples/rbac_policy.csv" target="_blank" rel="noopener">RBAC_Policy.CSV&lt;/a>&lt;/p>
&lt;pre>&lt;code>p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin
&lt;/code>&lt;/pre>
&lt;p>Basically there are four parts: Request, Policy, Matcher and Effect.
&lt;a href="https://casbin.org/docs/en/how-it-works" target="_blank" rel="noopener">Ref&lt;/a>&lt;/p>
&lt;p>&lt;strong>Request:&lt;/strong> Defines the parameter &lt;em>name&lt;/em> and &lt;em>order&lt;/em> which we should provide for access control matching function. This enables the code/model to be setup when the data is read from the source.&lt;/p>
&lt;p>&lt;strong>Policy:&lt;/strong> It&amp;rsquo;s the Access stratergy. This is how our internal system is designed. It defines the name and order of the fields in the &lt;em>Policy rule document&lt;/em>.&lt;/p>
&lt;p>&lt;strong>Matchers:&lt;/strong>: This is similar to a predicate function - which shall describe if the request allowed. Rules which help us to match the request and the policy.&lt;/p>
&lt;p>&lt;strong>Effect:&lt;/strong> It&amp;rsquo;s useful, when there are multiple patterns which would match and you would need to make a decision. There are defaults, here you get to override both allow and deny defaults. Refer:
&lt;a href="https://casbin.org/docs/en/syntax-for-models#policy-effect" target="_blank" rel="noopener">PolicyEffect&lt;/a>.&lt;/p>
&lt;h4 id="inheritance">Inheritance:&lt;/h4>
&lt;ul>
&lt;li>If A has role B, B has role C, then A has role C. This transitivity is infinite for now&lt;/li>
&lt;li>Casbin doesn&amp;rsquo;t distinguish role from user in its RBAC. They are all treated as strings.&lt;/li>
&lt;/ul>
&lt;pre>&lt;code>p, data2_admin, data2, read
g, alice, data2_admin
&lt;/code>&lt;/pre>
&lt;p>In the above example,&lt;/p>
&lt;ul>
&lt;li>data2_admin has read access to data2&lt;/li>
&lt;li>alice inherits/is a member of role data2_admin. alice here can be a user, resource or a role.&lt;/li>
&lt;/ul>
&lt;p>
&lt;a href="https://github.com/jacobaloysious/pycasbin/blob/master/tests/rbac/test_role_manager.py" target="_blank" rel="noopener">test_role_manager.py&lt;/a>&lt;/p>
&lt;pre>&lt;code> rm = get_role_manager()
#1
rm.add_link(&amp;quot;u1&amp;quot;, &amp;quot;g1&amp;quot;)
rm.add_link(&amp;quot;u3&amp;quot;, &amp;quot;g2&amp;quot;)
self.assertTrue(rm.has_link(&amp;quot;u1&amp;quot;, &amp;quot;g1&amp;quot;))
self.assertFalse(rm.has_link(&amp;quot;u1&amp;quot;, &amp;quot;g2&amp;quot;))
self.assertCountEqual(rm.get_roles(&amp;quot;u1&amp;quot;), [&amp;quot;g1&amp;quot;])
self.assertCountEqual(rm.get_roles(&amp;quot;u2&amp;quot;), [&amp;quot;g1&amp;quot;])
#2
rm.add_link(&amp;quot;u1&amp;quot;, &amp;quot;g1&amp;quot;, &amp;quot;domain1&amp;quot;)
self.assertTrue(rm.has_link(&amp;quot;u1&amp;quot;, &amp;quot;g1&amp;quot;, &amp;quot;domain1&amp;quot;))
self.assertFalse(rm.has_link(&amp;quot;u1&amp;quot;, &amp;quot;g1&amp;quot;, &amp;quot;domain2&amp;quot;))
&lt;/code>&lt;/pre>
&lt;h4 id="what-casbin-does-not-do">What Casbin does NOT do:&lt;/h4>
&lt;ul>
&lt;li>Authentication (aka verify username and password when a user logs in)&lt;/li>
&lt;li>manage the list of users or roles.&lt;/li>
&lt;/ul>
&lt;p>Reference:
&lt;a href="https://github.com/jacobaloysious/pycasbin" target="_blank" rel="noopener">Casbin&lt;/a>&lt;/p></description></item><item><title>Premortem</title><link>https://jacobaloysious.in/post/diary_premortem/</link><pubDate>Sun, 31 Oct 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_premortem/</guid><description>&lt;p>
&lt;a href="https://hbr.org/2007/09/performing-a-project-premortem" target="_blank" rel="noopener">Gary Klein - HBR&lt;/a> - this article was quite intersting. I belive, this could be one of the procedures for thinking in organization - to help alleviate or provide feedback to quality of thinking.&lt;/p>
&lt;blockquote>
&lt;p>Unlike a typical critiquing session, in which project team members are asked what might go wrong, the premortem operates on the assumption that the “patient” has died, and so asks what did go wrong. The team members’ task is to generate plausible reasons for the project’s failure.&lt;/p>
&lt;/blockquote>
&lt;p>It&amp;rsquo;s beautiful as an idea: Coz, when people are coming close to a decision, it becomes very difficult to raise doubts or raise questions. As, there is fear that person would be tagged as someone who is slowing down the whole group - when the group is about to make a decision. And may at times, that person is perceived as annoying and want to get rid of them or ignore and move on. &lt;strong>This premortem legitimizes that sort of descent and that sort of doubt; not just legitimizes it - but also rewards it.&lt;/strong>&lt;/p>
&lt;p>BTW: I dont think its going to prevent people from making mistakes. But it would certainly allow people to possible loop holes to think through before making a safer decision.&lt;/p></description></item><item><title>One Percent - Per Day</title><link>https://jacobaloysious.in/post/diary_one_percent_improvement/</link><pubDate>Sat, 09 Oct 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_one_percent_improvement/</guid><description>&lt;p>Born and Brought in a middle class family in India. We are often set a goal to become the number one in the class - both by family and teachers. It is all about, topping the exams, getting the highest score, getting rank #1. All you need to do is study hard(er) to become #1. Every parent has the opinion - their child can be the best and always do what ever it takes like pay for additional tution&amp;rsquo;s [&lt;em>though its way above they could afford&lt;/em>], to ensure there is no roadblocks. Comparing against fellow class mates, talking about stories of students who woke up at 4.30am in 5th grade, and got rank #1. At the end of the day you get competitive and you can go as far as the best student in your class (you know). Choosing to burnout or not is not an option.&lt;/p>
&lt;p>Many at times we fail to understand, what we are doing is trying to push - so that we become better than &lt;strong>someone else&lt;/strong>. But, later in my carrer I have come to this realization that - You don&amp;rsquo;t need to compete with someone - The only person you need to compete with &lt;strong>is yourself&lt;/strong>.&lt;/p>
&lt;p>You actually, don&amp;rsquo;t really need to compete - just try to &lt;strong>become 1% better&lt;/strong> than your yesterday self. Thanks to the book - Atomic Habits- I wish I had read this book 20yrs back.&lt;/p>
&lt;p>What has changed in me is - I wake up, look at the mirror and say - what have I done yesterday to make myself 1% better. Then, what am I going to do today to make myself 1% better.&lt;/p>
&lt;p>Many at times, we are so sucked into our daily lives, we fail to realize this. We are busy being busy and only at the end of the year - focal cycle - we try to retrospect and see what went well and what could have been better. But, there are two issues here 1) It&amp;rsquo;s too late feedback 2) the goal we set for the entire year - are too ambitious. But, by taking things one day at a time and having a goal of 1% improvement - which is achiveable, will enable us to be better prepared with minimum motivation.&lt;/p>
&lt;p>For me 1% could be as simple as : reading 10pages of a book[tech, leadership], watching a tech podcast, writing a blog, online course, going to gym, badminton. Improvment is always both Mind or Body. As long as you cautiously spend time for these - you are learning/improving.&lt;/p>
&lt;p>Note: learning is a continous process, it take time and its a never ending journey.&lt;/p>
&lt;p>Happy learning!&lt;/p></description></item><item><title>Bitmap Indexed Storage</title><link>https://jacobaloysious.in/post/tech_bitmaped_indexed_storage/</link><pubDate>Sat, 10 Jul 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_bitmaped_indexed_storage/</guid><description>&lt;p>Always been facinated by the ways - data structure&amp;rsquo;s can enable better storage and faster queries.&lt;/p>
&lt;p>BitMapped Indexed Storage - is useful while using &lt;strong>Columnar Databases&lt;/strong> - where per column data is stored together.&lt;/p>
&lt;p>Often the number of &lt;strong>distinct&lt;/strong> values in a column is small compared to the total number of rows. In the below example: column &lt;em>sex&lt;/em> there are only two distinct value &lt;em>Female or Male&lt;/em> in the given table - the cardinality is really low.&lt;/p>
&lt;p>In such cases: We can now take a column with &lt;em>n&lt;/em> distinct values and turn it into &lt;em>n&lt;/em> separate bitmaps: one bitmap for each distinct value, with one bit for each row. The bit is 1 if the row has that value, and 0 if not.&lt;/p>
&lt;p>Picture is worth a thousand words.. here we you go..&lt;/p>
&lt;p>&lt;img src="dbimage.jpg" alt="alt Components" title="Work">&lt;/p>
&lt;p>Fantastic Query performance&amp;hellip; As the amount of data read from disk on to the memory is less - improved Disk Throughput.
As always, solution are for a specific problem. If you wanna do a range query, then this solution might not the best.&lt;/p>
&lt;p>If &lt;em>n&lt;/em> is very small, those bitmaps can be stored with one bit per row. But if &lt;em>n&lt;/em> is bigger, there will be a lot of zeros in most of the bitmaps (&lt;em>sparse&lt;/em>). In that case, the bitmaps can additionally be run-length encoded or might not be recommened.&lt;/p>
&lt;p>Reference:
&lt;a href="https://www.goodreads.com/book/show/23463279-designing-data-intensive-applications" target="_blank" rel="noopener">Designing Data-Intensive Applications, by Martin Kleppmann &lt;/a>&lt;/p></description></item><item><title>Five Ideals of Software Development</title><link>https://jacobaloysious.in/post/diary_5_ideals_of_software/</link><pubDate>Sun, 04 Jul 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_5_ideals_of_software/</guid><description>&lt;p>&lt;strong>Credits:&lt;/strong> Most of the text below are &amp;ldquo;Verbatim&amp;rdquo; notes from the book
&lt;a href="https://www.goodreads.com/book/show/44333183-the-unicorn-project" target="_blank" rel="noopener">The Unicorn Project, by Gene Kim&lt;/a>.&lt;/p>
&lt;p>There are times, when you read a book - it strikes you really hard/well and you would like to share it with as many people you would like. Since this blog of mine is public - I decided to put it here so that it would help someone/someday.&lt;/p>
&lt;p>Here are Five Ideals:&lt;/p>
&lt;h4 id="1-locality-and-simplicity">1. Locality and Simplicity:&lt;/h4>
&lt;p>Design things so that we have locality in our systems and the organizations that build them. And we need simplicity in everything we do. The last place we want complexity is internally, whether its in our code, in our organization or in our process. Rate at which a software team can add new features can improve only when - we pay down technical debt as a part of daily work and a good automated test suite to catch the failures.&lt;/p>
&lt;p>Remember: the &amp;ldquo;S&amp;rdquo; in the
&lt;a href="https://en.wikipedia.org/wiki/SOLID" target="_blank" rel="noopener">SOLID&lt;/a> Principles - Single Responsiblitity.&lt;/p>
&lt;h4 id="2-focus-flow-and-joy">2. Focus, Flow and Joy:&lt;/h4>
&lt;p>Its all about how our daily work feels. Is our work marked by boredom and waiting for other people to get things done on our behalf? Do we blindly work on small pieces of the whole, only seeing the outcomes of our work during a deployment when everything blows up, leading to firefighthing, punishment and burn out? Or do we work in small batches, ideally single-piece flow, getting fast and continual feedback on our work? These are the conditions that allow for focus and flow, challenge, learning, discovery, mastering our doman, and even joy.&lt;/p>
&lt;p>Remember: Test Driven Development(TDD) and Continous Integration (CI)&lt;/p>
&lt;blockquote>
&lt;p>The process of stopping a system when a defect was suspected originates back to the original Toyota System Corporation to something called Jidoka. The idea behind Jidoka is that by stopping the system you get an immediate opportunity for improvement, or find a root cause, as opposed to letting the defect move further down the line and be unresolved.&lt;/p>
&lt;/blockquote>
&lt;h4 id="3-improvement-of-daily-work">3. Improvement of Daily Work:&lt;/h4>
&lt;p>Reflect upon what the
&lt;a href="https://itrevolution.com/kata/" target="_blank" rel="noopener">Toyota Andon cord&lt;/a> teaches us about how we must elevate improvment of daily work over daily work itself.&lt;/p>
&lt;p>Remember:
&lt;a href="https://martinfowler.com/books/refactoring.html" target="_blank" rel="noopener">Refactoring, by Martin Fowler&lt;/a>&lt;/p>
&lt;h4 id="4-psychological-safety">4. Psychological Safety:&lt;/h4>
&lt;p>Where we make it safe to talk about problems, because solving problems requires prevention, which requires honesty, and honesty requires the absence of fear. In manufacturing, psychological safety is just as important as physical safety. A culture of fear where everyone is afraid to share the bad news - will only have a negative impact.&lt;/p>
&lt;p>One of the Value of KLA (my current employer) is &amp;ldquo;HFC: Honesty, Forthright and Consistency&amp;rdquo; - which I greatly admire.&lt;/p>
&lt;h4 id="5-customer-focus">5. Customer Focus:&lt;/h4>
&lt;p>Question ruthlessly whether something actually matters to our customers, as in, are they willing to pay us for it or is it only of value to our functional silo.&lt;/p>
&lt;p>Remember the 80:20 Rule.&lt;/p>
&lt;blockquote>
&lt;p>According to Standish’s research and more recent estimates, 20 percent of software features are often used, while 50 percent of features are hardly ever or never used. The remaining 30 percent of features are used infrequently. (For package applications, like Microsoft Office, Standish found that just five percent of features are used.)
&lt;a href="https://www.standishgroup.com/sample_research_files/Modernization.pdf" target="_blank" rel="noopener">Ref&lt;/a>&lt;/p>
&lt;/blockquote></description></item><item><title>Book - Making of a Manager, by Julie Zhuo</title><link>https://jacobaloysious.in/post/book_makingofamanager/</link><pubDate>Sun, 20 Jun 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/book_makingofamanager/</guid><description>&lt;p>If you are a newly promoted manager and struggling to figure out what the job is like. Don&amp;rsquo;t worry you are not alone - this book is exclusively only for you - go get a copy and keep it on your table (I have mine). Having read multiple books about management and leadership; also attending relevant sessions - nothing really &lt;strong>stuck&lt;/strong> to me like this book. Maybe there is a reason, I could connect.&lt;/p>
&lt;p>&lt;strong>Trivia:&lt;/strong> The author - Julie Zhuo is the VP, Product Design at Facebook, having successfully worked her way up the ranks.&lt;/p>
&lt;p>In this book, Julie - I would call her an &lt;em>accidental manager&lt;/em>; becomes a manager at the age of 25, just because the size of her team was growing. She wasn&amp;rsquo;t prepared - she had no idea where to start and what to do and most importantly what she should NOT be doing. She juggles her way through trying to be a good manager and fighting her inner conflicts (read soul) - which was still an individual contributor(IC). And this was exactly where, I was able to connect to Julie and her book. As, I was a IC - who loved to code (time flies when I was coding) - excitement/feeling of making a feature work was awesome.&lt;/p>
&lt;blockquote>
&lt;p>Hard Truth: The roles and responsiblities of a Manager vs IC is completely different - you cannot do both. Well if you are doing it - then you are a superhuman!&lt;/p>
&lt;/blockquote>
&lt;p>I was trying to do both for years, and it wasn&amp;rsquo;t scaling up. I was signing up for features and assiging bugs to myself - and it was hard to balance the time between the needs of the actual role(/team) vs my own code deliverables.&lt;/p>
&lt;p>Well, don&amp;rsquo;t get me wrong. I dont mean, you should stop coding when you become a manager. I still code (mostly on weekends), but just that - we need to understand, that its NOT your primary responsibility. My guidance: the code you work on, should not be in the critical path and there are no depenencies (someone waiting for you to deliver).&lt;/p>
&lt;p>I have been a manager for just over 5yrs as of today(Jun/2021). So, I might not have lot of experience. But this book definetly made a difference for someone like me who became a Manager being an IC.&lt;/p>
&lt;p>It&amp;rsquo;s an easy to read book - you might feel like Julie is sitting on the other side of the table and talking to you - a live mentorship 😉. You can learn a lot from this book, irrespective of the team size you are leading (big or small).&lt;/p>
&lt;p>Few Key Take aways:&lt;/p>
&lt;h4 id="manager-are-made-not-born">Manager are Made not Born:&lt;/h4>
&lt;p>This was an interesting revelation for me 😉. This is a skill that you could really work on - if you find the roles and responsibilities motivating/interesting. Julie talks about 3 important things: 1) Purpose 2) People and 3) Process - the why, the who and the how. A great mananger constantly asks herself how she can influence these levers to improve her teams outcomes.&lt;/p>
&lt;ul>
&lt;li>Why: Your team knows what success looks like and cares about achieving it. Success would be embody both - self (career) and for the product (company).&lt;/li>
&lt;li>Who: Does the team have the right skill set and the motivation. Trust and coaching to their strengths.&lt;/li>
&lt;li>How: Establishing guidance for principles and rationals behind decicion making.&lt;/li>
&lt;/ul>
&lt;h4 id="art-of-feedback">Art of feedback:&lt;/h4>
&lt;p>&lt;strong>Avoid:&lt;/strong> It&amp;rsquo;s time for our Annual Performance Review. Here is how you have been doing for the past year.
&lt;strong>Aspire:&lt;/strong> Can I share some feedback for you from that meeting this morning.&lt;/p>
&lt;p>Giving feedback as often as possible, keeping it as specific as possible, clarifying what success looks/feels like and finally suggesting next steps. In case of cirtical/bad feedback - don&amp;rsquo;t do a &amp;ldquo;compliment sandwich&amp;rdquo; - as the most important focus point, which acutally matter could be missed.&lt;/p>
&lt;h4 id="hiring-well">Hiring Well:&lt;/h4>
&lt;ul>
&lt;li>Hiring is not a &lt;strong>problem&lt;/strong> to be solved but an oppurtunity to build the future of your organization.&lt;/li>
&lt;li>Hiring is &lt;strong>Your&lt;/strong> responsiblity. No recruiter can possibly know what an ideal candidate looks like for &lt;strong>your&lt;/strong> team. So, ensure you describe your ideal candidate as precisely as you can.&lt;/li>
&lt;/ul>
&lt;p>I would stop here - and recommend you to go read the book. There are lots of interesting observations and recommendations - which you could try out of the box. Read it, you can thank me later 😆&lt;/p>
&lt;h3 id="highly-recommended">Highly Recommended!!&lt;/h3>
&lt;p>
&lt;a href="https://www.goodreads.com/en/book/show/38821039-the-making-of-a-manager" target="_blank" rel="noopener">the-making-of-a-manager&lt;/a>&lt;/p></description></item><item><title>Sqlite - Blunders</title><link>https://jacobaloysious.in/post/tech_sqlitedb/</link><pubDate>Sat, 05 Jun 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_sqlitedb/</guid><description>&lt;h3 id="what-is-sqlite">What is Sqlite:&lt;/h3>
&lt;blockquote>
&lt;p>SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. SQLite is the most used database engine in the world.
SQLite is built into all mobile phones and most computers and comes bundled inside countless other applications that people use every day. More Info:
&lt;a href="https://www.sqlite.org/index.html" target="_blank" rel="noopener">SQLite&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h2 id="my-learning">My Learning:&lt;/h2>
&lt;p>Sqlite is a fantastic embedded database - light weight, easy to use and almost Zero Configuration. I would prefer to call it ZMQ of DataBase 😉&lt;/p>
&lt;h3 id="blunder">Blunder:&lt;/h3>
&lt;p>As part of our design: we had to persist a bunch of parametric information per user session (few MBs). This information is not required outside the user session. But, it would be reused when the user comes back. Session - is local running on a windows box. We decided to use sqlite as our backend persistence mechanism; as there was no installation or specific configuration required to set sqlite up.&lt;/p>
&lt;p>Since there are parallel read write happening, we had to use the
&lt;a href="https://sqlite.org/wal.html" target="_blank" rel="noopener">WAL: Write Ahead Logging&lt;/a> journal mode.&lt;/p>
&lt;p>We did couple of blunders:&lt;/p>
&lt;h4 id="blunder-1---insert-one-at-a-time">Blunder #1 - Insert ONE at a time&lt;/h4>
&lt;ol>
&lt;li>When an action occured - we opened the db connection, inserted record and closed it.&lt;/li>
&lt;li>We didn&amp;rsquo;t want to keep the connection open, throughout the session - as there were chances of software crash - which could potentially corrupt he database.&lt;/li>
&lt;li>But as time went by, the number of actions became HUGE (order of millions - automated). At this point - Opening and closing the connection for every action, started to hurt us (&lt;em>high latency and low throughtput&lt;/em>). Coz, the time taken to open and close a connection (~300ms) was adding up.&lt;/li>
&lt;/ol>
&lt;p>Solution:
&lt;strong>Microbatching&lt;/strong>: Batched about 500 actions together - open the connection once, inserted all 500 actions in one shot and closed - Transaction. Worst case, we would loose less than 500 actions, and that tradeoff was acceptable.&lt;/p>
&lt;h4 id="blunder-2---mounted-drive">Blunder #2 - Mounted Drive:&lt;/h4>
&lt;ol>
&lt;li>The db had to be persisted on a mounted Linux drive (&lt;em>there are reason for this, I won&amp;rsquo;t go into details&lt;/em>).&lt;/li>
&lt;li>As the session started - the app created a sqliteDB directly on the mounted drive and started inserting.&lt;/li>
&lt;li>Since we were using WAL mode - there were temporary files getting created and deleted on the mounted drive during every transaction.&lt;/li>
&lt;li>As time went by - the reliablity of the drive/driver went down, and retries didn&amp;rsquo;t help keep up. The throughput significantly got impacted and multiple errors started showing up.&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="mounted_drive.jpg" alt="alt Components" title="Mounted Drive">&lt;/p>
&lt;p>&lt;strong>Solution:&lt;/strong> During the session, create the db in a &lt;strong>local (temp) drive&lt;/strong>, and end of sesssion copy it into the mounted drive. Similarly, when session restarts - copy from mounted drive on to a new temp location and consume it; and copy it back on completion.&lt;/p>
&lt;p>&lt;img src="temp_drive.jpg" alt="alt Components" title="Temp Drive">&lt;/p>
&lt;blockquote>
&lt;p>Never EVER - read or write an Sqlite Database from a mounted Drive. It usually works, but when it doesn&amp;rsquo;t - its a nightmare.&lt;/p>
&lt;/blockquote>
&lt;h4 id="blunder-3---lazy-load">Blunder #3 - Lazy Load:&lt;/h4>
&lt;ol>
&lt;li>When a specific information was required - we opened the db connection, executed the &amp;ldquo;select&amp;rdquo; query and return the results.&lt;/li>
&lt;li>Again: We didn&amp;rsquo;t want to keep the connection open, throughout the session - as there were chances of software crash - which could potentially corrupt he database.&lt;/li>
&lt;li>The read was implemented in a &amp;ldquo;Lazy - On demand&amp;rdquo; fashion - so that &lt;strong>only&lt;/strong> the minimum required information was read on demand.&lt;/li>
&lt;li>Reading only the required info is an ideal design - why would we ever read more that what is required? GraphQL - is a good example of how to design minimilistic API.&lt;/li>
&lt;li>But the challenge in our (specific) case: was the number of reads - it was about 600reads in less than 50 milliseconds. And each one had to open and close the connection (which takes ~50ms).&lt;/li>
&lt;li>Since it was a high throughput system, the overhead of lazy read was slowing down the entire software.&lt;/li>
&lt;/ol>
&lt;p>Solution: &lt;strong>PreFetch Require Information&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Since we knew the sequence in which the actions are performed, we redesigned the query to read &lt;strong>&amp;ldquo;more&amp;rdquo;&lt;/strong> records than required.&lt;/li>
&lt;li>Then created an in memory cache [index/map] to hold the data and filter based on Client Query.&lt;/li>
&lt;li>Read from DB would occur only if there is a cache miss.&lt;/li>
&lt;li>The cache was a rolling buffer with LRU (Least Recently Used) and a watermark (memory or count), so that the RAM didn&amp;rsquo;t explode.&lt;/li>
&lt;li>When a new read from DB was required, if the cache is full - we delete the oldest item and read from DB and add it to cache.&lt;/li>
&lt;li>No change to the Client API. Only the Data Acess Layer changed. 😉&lt;/li>
&lt;/ul>
&lt;h3 id="conclusion">Conclusion:&lt;/h3>
&lt;p>As always on hindsight, the solution looks trivial and obvious. Since, we were using Sqlite for the first time and initially didn&amp;rsquo;t reallize the data could grow exponentially - had to learn (Adapt) the hard way. Esp, when these are running in production - you need scheme&amp;rsquo;s to manage old vs new verisons of software (read, backward compatibility).&lt;/p></description></item><item><title>Concurrent Dictionary and Delay - C#</title><link>https://jacobaloysious.in/post/tech_concruent_dictionary/</link><pubDate>Sun, 30 May 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_concruent_dictionary/</guid><description>&lt;p>Reference:
&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=net-5.0" target="_blank" rel="noopener">ConcurrentDictionary&lt;/a>&lt;/p>
&lt;p>In a high throuput and low latency enviorment - we had a peice of code in the critical path - which helped in throttling. After version #2.0 of the software was released (internally) - we saw the througput has gone down significantly almost 3X - compared to previous Version #1.0 - 4mins to 11 minutes.&lt;/p>
&lt;p>We looked at the history/change sets between the versions: it was huge, 100s of commits and software was running with 100s of threads - on a 2Milliion LOC software stack. So, we were unsure which peice of code nor thread - was causing the delay. We were all over the place, trying to see if its a system issue or memory trend or some fragmentation vs memory/back pressure vs excess logging etc&amp;hellip;. And, after 3 day (yes: 3days slog) - we found its a delay caused by the &lt;strong>ConcurrentDictionary&lt;/strong> class!!! 😳&lt;/p>
&lt;p>It was an unpleasant suprise, since we didn&amp;rsquo;t expect such a huge delay cause due to a &lt;em>.Net Framework class&lt;/em>.&lt;/p>
&lt;h4 id="1-version-10--4mins">1. Version 1.0: [4mins]&lt;/h4>
&lt;p>One API with its backing data store with one Dictionary.&lt;/p>
&lt;pre>&lt;code> private Dictionary&amp;lt;int, User&amp;gt; userInfos;
public List&amp;lt;User&amp;gt; GetUsers() {
return userInfos.Values;
}
&lt;/code>&lt;/pre>
&lt;h4 id="2-version-20--11-minutes">2. Version 2.0: [11 minutes]&lt;/h4>
&lt;p>In version #2: We changed the data store, which was holding the user info from a simple dictionary to a two level &lt;em>ConcurrentDictionay&lt;/em>.&lt;/p>
&lt;p>There was some obvious reason for using &lt;em>ConcurrentDictionay&lt;/em> - I won&amp;rsquo;t go into the details. But, after changing the data store- we ended up blindly updating all usages to consume from the new data store.&lt;/p>
&lt;p>And the API (GetUsers) implementation was updated, interface remained the same - but: it was in the critical path.&lt;/p>
&lt;pre>&lt;code> private ConcurrentDictionary&amp;lt;int, ConcurrentDictionary&amp;lt;int, User&amp;gt;&amp;gt; userInfos;
public List&amp;lt;User&amp;gt; GetUsers(){
var users = new List&amp;lt;User&amp;gt;();
for(var userGroup in userInfos.Values){
for(var user in userGroup.Values){
users.add(user)
}
return users;
}
}
&lt;/code>&lt;/pre>
&lt;h4 id="3-version-30--4-minutes">3. Version 3.0: [4 minutes]&lt;/h4>
&lt;p>After looking into the usages &lt;strong>&amp;ldquo;in the critical path&amp;rdquo;&lt;/strong> - we only required the count of the active user groups.&lt;/p>
&lt;p>So, we wrote another API to just return the count. With this change, we were able to bring it back the throughput back to #Version 1.0. Huff!! 😌&lt;/p>
&lt;pre>&lt;code> private ConcurrentDictionary&amp;lt;int, ConcurrentDictionary&amp;lt;int, User&amp;gt;&amp;gt; userInfos;
public List&amp;lt;User&amp;gt; GetActiveUserGroups(){
return userInfos.Count;
}
&lt;/code>&lt;/pre>
&lt;h3 id="learning">Learning:&lt;/h3>
&lt;p>On highsight, the fix looks trivial and straight forward. But the challenge was the huge debugging effort to find the root cause. And little did we suspect a .Net Framework class can cause such a huge delay and slow down overall execution time. It was a great learning for us as a team - involved in debugging. BTW, we are talking about a code base of about few Million lines of code.&lt;/p>
&lt;p>BTW: Concurrent dictionary exists for a reason: Usage of it as our data store was the right choice.&lt;/p>
&lt;blockquote>
&lt;p>Represents a thread-safe collection of key/value pairs that can be accessed by multiple threads concurrently.&lt;/p>
&lt;/blockquote>
&lt;p>If a class should be thread safe, then there has to be a lock/Mutex implemented. A lock has its own tradeoff in terms of execution time (Thread Scheduling, Prempt etc..) - so think carefully on its usages.&lt;/p></description></item><item><title>Parallel Processing with Constraints</title><link>https://jacobaloysious.in/post/tech_context_parallel_process/</link><pubDate>Sat, 15 May 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_context_parallel_process/</guid><description>&lt;p>An interesting senario, I recently encountered - have tried to tear down the context to get to the solution early, and avoid nitty gritty (boring) details. Also, example showns only 2 threads.&lt;/p>
&lt;h3 id="context">Context:&lt;/h3>
&lt;p>Different Actions (like: 1,2,3) from Cutomers (like Mr.A, Miss.B..) are pushed into a stream/queue from an external component. &lt;strong>&amp;ldquo;$&amp;rdquo;&lt;/strong> denotes end/last action from a customer.
A thread can 1) Process each action 2) Generate aggregated views for each customer per session - and then write it to the sink. The processing threads are started when the session starts and a user cannot reenter the session once done.&lt;/p>
&lt;p>note: all threads mentioned are background and long running.&lt;/p>
&lt;h3 id="constraints">Constraints:&lt;/h3>
&lt;p>Aggregation can be triggered only after all the actions are processed. i.e processing of action A1, A2, A3 should be done - before aggregation &amp;ldquo;A$&amp;rdquo; of A is triggered.&lt;/p>
&lt;h2 id="1-single-thread">1. Single Thread&lt;/h2>
&lt;p>Well, this is a no brainer. We have one thread which reads (pull) from the stream/queue and process one item from the queue at a time. All constraints can be managed with a global context inside the thread.&lt;/p>
&lt;p>&lt;img src="SingleThread.jpg" alt="alt Components" title="SingleThread">&lt;/p>
&lt;p>Below is a code which runs inside the Thread.&lt;/p>
&lt;pre>&lt;code> # {name, [actions]}
customer = {}
def read_from_stream(name, action):
if action=='$':
aggregate(name)
else:
process(name, action)
def process(name, action)
result = process_the_custom_action(action)
cusomter[name].append(result)
def aggregate(name):
action_results = cutomer[name]
view = gen_agg_view(action_results)
write_to_sink(view)
# remove customer from tracking
del customer[name]
def process_the_custom_action(action):
#Heavy lifting operation
return result
&lt;/code>&lt;/pre>
&lt;h2 id="2-pull-model---parallel-processing">2. Pull Model - Parallel Processing&lt;/h2>
&lt;p>Later we realized, the function &lt;strong>processing_the_custom_action&lt;/strong> is heavy lifting and takes more CPU. So, we were not able to keep up, with the incoming data rate. So, the memory increased drastically and triggers garbage collection and slow down actual code execution.&lt;/p>
&lt;p>So, we decided to introduce multiple threads to read from the queue. Same code as above - executed in multiple threads. Each thread would pop (PULL) one item from the queue, process it and then pop the next item. Just to be explicit: one item from the queue is processed by only one of the threads, but which thread (order) gets which item is not guranteed.&lt;/p>
&lt;p>&lt;img src="MultiThreadPullModel.jpg" alt="alt Components" title="PullModel">&lt;/p>
&lt;p>This design had a major challenge in ensuring the constraints are honored.&lt;/p>
&lt;p>In the above example: Aggregation for customer &amp;ldquo;A$&amp;rdquo; should be triggered only after last action &amp;ldquo;A3&amp;rdquo; is done. But &amp;ldquo;A$&amp;rdquo; and &amp;ldquo;A3&amp;rdquo; are processed in two different threads i.e. A3 by Thread #1; A$ by Thread #2. How would Thread #2 know A3 processing is done?? 😞&lt;/p>
&lt;p>If we really need to go with this approach and also honor the constraints - then there should be &lt;strong>broadcast events fired&lt;/strong> and all threads subscribed to it. Each thread should subscribe and do individual book keeping for all customers being processed across all the threads (dependency across threads, coupling..huff!!) 😰&lt;/p>
&lt;p>&lt;strong>Pros:&lt;/strong>
If any of the thread is killed in between. The data loss would be minimal i.e only the customers already read by that specific thread in the past and not completed. As all NEW data would be processed by one of the threads alive.&lt;/p>
&lt;h2 id="3-push-model---parallel-processing">3. Push Model - Parallel Processing&lt;/h2>
&lt;p>To ensure, we honor the constraint and also enable parallel processing. We introduced a load_balancer, called it a &lt;strong>distributor module&lt;/strong>.&lt;/p>
&lt;p>&lt;img src="MultiThreadPushModel.jpg" alt="alt Components" title="PushModel">&lt;/p>
&lt;h4 id="distributor-module">Distributor Module:&lt;/h4>
&lt;ul>
&lt;li>Would have reference to all the available processing threads.&lt;/li>
&lt;li>Each thread would have a corresponding queue. So, No_Of_Threads equals No_Of_Queueus.&lt;/li>
&lt;li>Each queue would have an index, which range from 0 to No_of_threads.
&lt;blockquote>
&lt;p>0 &amp;lt; Queue_Index &amp;lt; No_Of_Threads&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>Once an item is read - it generates a hash using the &amp;ldquo;name&amp;rdquo; of the customer. (like: SHA256)&lt;/li>
&lt;li>On the HASH we apply a MOD using the No_Of_Threads available and get the queue index
&lt;blockquote>
&lt;p>Queue_Index = hash(customer_name) % No_Of_Threads&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>Push the item to the corresponding queue_index&lt;/li>
&lt;/ul>
&lt;p>With this approach, we ensured - &lt;strong>same customer items are always processed by the same thread&lt;/strong>. So, there are no cross talks across threads or external dependency.
We could increase or decrease the number of threads used (obviously: before a session starts not in-between), based on a configuration or heuristics.&lt;/p>
&lt;pre>&lt;code> #### Distributor Module
def read_from_stream(name, action):
# Generate hashkey using customer name.
# Mod using the number of threads. No_Of_Thread == No_Of_Queues
queue_index = hash(name) % No_Of_Threads
publish(queue_index, name, action)
def publish(queue_index, name, action):
# get the queue reference using the index
queue = queues[queue_index]
# add the item into corresponding queue
queue.push(name, action)
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Cons:&lt;/strong>
The biggest cons: If a thread is killed for what ever reason. All the customers past and future once - which would be queue/allocated to the thread would be dropped. But in the pull model, it would have dropped only a handful sitting inside (past) the thread. Well we could handle this dynamically - like have a &lt;strong>heart beat&lt;/strong> mechanism and update the &amp;ldquo;No_Of_Thread&amp;rdquo; and get it working - just that it would be another infra.&lt;/p>
&lt;h4 id="conclusion">Conclusion:&lt;/h4>
&lt;p>There are pros and cons to both approaches.&lt;/p>
&lt;blockquote>
&lt;p>More Infra == More Code == More Maintainability == More to Debug == More room for bugs to creep in.&lt;/p>
&lt;/blockquote>
&lt;p>Trying to keep it simple while keeping the tradeoffs minimal is the key. In our case; we went with the push approach - as the chances of a thread crash was minimal and also we added some defensive coding and drop an item safely if required.&lt;/p>
&lt;h4 id="reference">Reference:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.manning.com/books/big-data" target="_blank" rel="noopener">Storm Model, by Nathan Marz&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Choreography vs Orchestration</title><link>https://jacobaloysious.in/post/tech_choreography/</link><pubDate>Sun, 02 May 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_choreography/</guid><description>&lt;p>I have been getting into this debate quite often; which approach is preferred - Choreography vs Orchestrator. As always, it depends - Here is my take on it&amp;hellip;&lt;/p>
&lt;h3 id="modules">Modules:&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>App:&lt;/strong> Like an UI module, where user trigger&amp;rsquo;s an action like:Create an account&lt;/li>
&lt;li>&lt;strong>Action #N:&lt;/strong> Specific modules, which has one specific action to be performed like: sending email, mail atm cards - once an account is created.&lt;/li>
&lt;li>&lt;strong>Coordinator:&lt;/strong> Module, which handles/triggers all the downstream actions (#n) - when an event is recived from App.&lt;/li>
&lt;/ul>
&lt;h1 id="orchestrator">Orchestrator&lt;/h1>
&lt;p>&lt;img src="orchestration.jpg" alt="alt Components" title="Orchestrator">&lt;/p>
&lt;p>Here the coordinator is the orchestrator - which has the knowledge of the business rules - like: what are the set of actions that need to be performed when a specific event occured. If you observe, the arrows are pointing from coordinator towards actions. So, the coordinator need to understand the details of each and every API (per Actions) - their base URL/REST end points. And if each of them takes in differnt params - then all this information would sit inside the coordinator module.&lt;/p>
&lt;p>The cooridnator has become the central brain. And now it has tight coupling with all the Actions. And if a new action should be added, we will have changes to the coordinator module. After a point of time - this module will become the &amp;ldquo;God like&amp;rdquo; service. And every new Actions team would have to come to coordinator team (more meetings/discussion/followps) - to have their action integrated with the coordinator. Any changes to the coordinator module would become extremely hard - as there is so much coupling. And in addition failures of each action should be handled with special case - adding more and more actions specific details/code into the coordinator module.&lt;/p>
&lt;p>On deployment and version management: If there are specific changes to an Actions - URI or params. Either the action module - can never depricate their existing uri and params, as it is used by coordinator module. Or, coordinator module would have to understand the versions (of action) and act accordingly. Both can get a bit too messy. And choosing one or either of them - would require some tradeoffs (debates) to be made somewhere.&lt;/p>
&lt;p>BTW: When we are just starting of - coordinator might be the easiest way to get things done (read, move faster). But as we scale out - we should look for approaches which would enable better decoupling.&lt;/p>
&lt;p>&lt;strong>Pros:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Better control in coordinating the Action modules&lt;/li>
&lt;li>Handling failures would be easiers - in one place&lt;/li>
&lt;li>One place to look at the flow chart&lt;/li>
&lt;li>Good for transaction driven and places where actions are not idempotenent&lt;/li>
&lt;/ul>
&lt;h1 id="choreography">Choreography:&lt;/h1>
&lt;p>&lt;img src="choreography.jpg" alt="alt Components" title="Choreography">&lt;/p>
&lt;p>In this approach, lets take a broker like KAFKA as an example. When a new event is created its publised to a KAFKA queue with a specific TOPIC. There could be multiple subscribers (actions) - which would subscribe to the topic. The subscribers have their specific logics and subscibe to specific topics. At any point of time, any new actions can be added into the system without the knowledge of the App module. Look at the red arrows - there are NO arrow pointing from App towards specific Actions - so app doesn&amp;rsquo;t have any dependency on Action. We could also have custom subscribers (Actions) - which would run a pipeline for the data science team - this would enable us to generate observability data on the loads and trends.&lt;/p>
&lt;p>Deploy: In this approach both app and action moudles can be indeopendently deployed and upgraded. The schema registry would have the contract details - topic vs the payloads.&lt;/p>
&lt;p>&lt;strong>Schema Registry:&lt;/strong>
Every payload schema: should be published in the schema repository. We can use libraries like &amp;ldquo;Protocol Buffers&amp;rdquo; or &amp;ldquo;Apache Avro&amp;rdquo; for describing payload schemas.&lt;/p>
&lt;p>&lt;strong>Cons:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Handling errors might become very tricky. You would need an external monitoring infrastructure to track this.&lt;/li>
&lt;li>If there are depenencies across actions - then you should think twice on using this pattern. Though there are ways to solve it - like: using sub topics.&lt;/li>
&lt;li>Debugging can become a bit more hard. Needs distributed tracing to correlate/debug.&lt;/li>
&lt;/ul>
&lt;h1 id="conclusion">Conclusion:&lt;/h1>
&lt;p>Personal preference is to lean towards choreographed approach - as they are more loosely coupled and are more flexibble and amenable to change. Again: it all depends on your use case - if you are building a low latency system - which should catch errors and react to it really fast based on lots of buisinees logic, then orchestrator might be a better approach.&lt;/p>
&lt;h2 id="references">References:&lt;/h2>
&lt;p>
&lt;a href="https://samnewman.io/books/building_microservices/" target="_blank" rel="noopener">Book : Building Microservices by Sam Newman&lt;/a>&lt;/p></description></item><item><title>Feature Toggle - Nightmares</title><link>https://jacobaloysious.in/post/tech_feature_toggle/</link><pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_feature_toggle/</guid><description>&lt;p>We were working on a custom algorithm to optimally grab images given a list of area. Every image grabbed is written into an object store with a generated hashkey. The haskkey can be used to query the recorded data - when we would like to play them back.&lt;/p>
&lt;p>Software was a monolith and the algorithm was shipped with it. So, any new fixes would be shipped with the new software versions and user would be able to playback the same recorded data.&lt;/p>
&lt;pre>&lt;code>def customAlgorithm():
locations = []
# actual algo...
return locations;
&lt;/code>&lt;/pre>
&lt;p>A day came when we - rolled out a bug fix in the algorithm. But, we broke the backward compatiblity 😟. Users had lots of existing recorded data which they wanted to playback. Since the algorithm had changed - the generated &lt;strong>hashkeys&lt;/strong> didn&amp;rsquo;t match the ones in the object store.&lt;/p>
&lt;p>We thought its proabaly a one off scenario: so we added a feature toggle - user will have to &lt;strong>manually&lt;/strong> (pain) figure out - which version the data was recorded on and update the toggle config (xml) and rerun.&lt;/p>
&lt;pre>&lt;code>def customAlgorithm():
locs = []
if version == '1.0':
locs = oldAlgo()
else:
locs = newAlgo()
return locs
&lt;/code>&lt;/pre>
&lt;p>And - Well there was another bug fix:&lt;/p>
&lt;pre>&lt;code>def customAlgorithm():
locs = []
if version == '1.0':
locs = Algo_1_0()
else if version == ''2.0':
locs = Algo_2_0()
else:
locs = latestAlgo()
return locs
&lt;/code>&lt;/pre>
&lt;p>And yeah the story went on for one more iteration and we had to STOP!!!! 😓 It was already becoming a nightmare to mantain the code.&lt;/p>
&lt;p>It wasn&amp;rsquo;t just manually figuring out the toggle which was creating pain - but to enable code reuse, the algorthm had to be refactored multiple times - so that parts of the algorithm can be reused across versions. In addition to that the number of test suites we had to manage had gone up significantly, as there were multiple users each one using different version - and oh yeah there were version specific fixes released as patches 😟&lt;/p>
&lt;p>Finally we decided to write all the &lt;strong>metadata&lt;/strong> - related to recording - into an embedded database. And on playback we get the information from the database and not by re-running the code/algorithm.&lt;/p>
&lt;p>On hindsight: the database feels like it an obvious solution, right? well the devil is in the details - in our case it about effort(read, time). The playback infrastructure based on database took ~8 weeks to build -first version. It had to handle numerous (10s) use cases. Previously, we only had one flow to be maintained i.e the flow which ran the use cases + algo shipped. But now we have to manage &lt;strong>TWO&lt;/strong> different flows - one for recording and one for playback (x) No_Of_Use_Cases.&lt;/p>
&lt;p>Its almost 3yrs since we rolled out this solution to production. When we look back it was a very good decision to build two different workflows 😍. Code is more structured and maintainable.&lt;/p>
&lt;p>At times - short term goal/fix takes priority. But, its always good to step back and look at the pain points and have an item in your backlog to find a better solution. The priority should be driven based on feedback: remember the 80/20 rule&lt;/p>
&lt;blockquote>
&lt;p>80 percent of customers only use 20 percent of the features in the software they’ve bought.&lt;/p>
&lt;/blockquote>
&lt;p>BTW: the database schema has changed a lot - with the addition of multiple use cases. Which also needs version management 😉 And evey new use case discussion now has two parts to be discussed - some problems are good to have (read, tradeoffs).&lt;/p>
&lt;p>Ref:
&lt;a href="https://martinfowler.com/articles/feature-toggles.html" target="_blank" rel="noopener">Feature Toggle&lt;/a>&lt;/p></description></item><item><title>Side Cars</title><link>https://jacobaloysious.in/post/tech_sidecars/</link><pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_sidecars/</guid><description>&lt;h2 id="idea">Idea&lt;/h2>
&lt;p>Add additional functionality into an existing application, with minimal or zero code changes to the exiting application. Also, the package can be consume by any software - irrespective of the language or framework (heterogeneous) it is written in.&lt;/p>
&lt;h2 id="how">How?&lt;/h2>
&lt;p>Using side cars pattern - : I/O(
&lt;a href="https://zeromq.org" target="_blank" rel="noopener">ZMQ&lt;/a>) + Topic (intent) + Data(
&lt;a href="https://developers.google.com/protocol-buffers" target="_blank" rel="noopener">ProtoBuf&lt;/a>) + Impl(Subscriber of topic).&lt;/p>
&lt;p>&lt;img src="sidecar.jpg" alt="alt Components" title="SideCarBase Window Images">&lt;/p>
&lt;p>DAPR framework from Microsoft Azure team – uses a similar design - runs side car. Dapr is a portable, event-driven runtime that makes it easy for developers to build resilient, micro service stateless and stateful applications that run on the cloud and edge and embraces the diversity of languages and developer frameworks.&lt;/p>
&lt;p>We could use the Side Car for adding functionalities like resource monitoring, logging, log aggregation, configurations, observability (telemetry /feature trends) etc.. Once we get the sidecar installed - we could keep adding new functionality as it independently developed and deployed. The features in the sidecar could be turned on or off based on options.&lt;/p>
&lt;p>Say as an organization: we decided to use cloud solutions for telemetry and internal tools decide to push data to the cloud - this solution might need a security layer - which would implement both gov and corp policies. This common implemenation of policies could be sitting inside the side cars and can be deployed on to all machine where the internal tools runs. And any update made to the policies would be transparent to the application - as the side cars would be independently deployed and maintained.&lt;/p>
&lt;h2 id="how-is-it-different-from-a-microservice-with-rest-api">How is it different from a Microservice with REST API?&lt;/h2>
&lt;p>Microservice doesn’t really care about the client. But here the side car is tightly coupled and tracks everything about the main application – including say: killing the application if the resource used is above the threshold - so that the tool PC doesn’t require a restart.&lt;/p>
&lt;h2 id="where-should-it-be-used">Where should it be used?&lt;/h2>
&lt;p>Only for non-critical operation - as the latency will be high.&lt;/p>
&lt;h3 id="reference">Reference:&lt;/h3>
&lt;ul>
&lt;li>
&lt;a href="https://dapr.io/" target="_blank" rel="noopener">DAPR&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.magalix.com/blog/the-sidecar-pattern" target="_blank" rel="noopener">Blog&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar" target="_blank" rel="noopener">MSSideCar&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Badminton - BG66 Ultimax String</title><link>https://jacobaloysious.in/post/badminton_bg66string/</link><pubDate>Sun, 21 Mar 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/badminton_bg66string/</guid><description>&lt;p>It&amp;rsquo;s been around 3-4yrs since I started playing badminton. Have heard friends discussing about different types of badminton strings - but personally never felt a need to take a deep look at any of them. I was always using the standard - BG65 string; its so durable - I never changed them for more than a year 😉&lt;/p>
&lt;p>After C19 break joined a new team of players. I am an intermediate player - but felt my game was very sluggish. I initially thought due to the C19 break - my game was completely off. But later realized that; there is a difference in the skill of the new players - they were really good. In my previous team, the rallys were really shot ~6, but here it went to almost 16 - it was also tiring.&lt;/p>
&lt;p>I definitely had to do something, to not just move up my game - but atleast match the skill of the players. BTW, I am not a trained player (never been to coaching). One of my friend recommened - to try changing the string and see if it make a difference.&lt;/p>
&lt;p>Below are some basic about badminton string. On a 10000 feet level: Common badminton strings’ diameters range from 0.65mm to 0.70mm. There are two types of strings - &amp;ldquo;Thick&amp;rdquo; and &amp;ldquo;Thin&amp;rdquo; ones. I won&amp;rsquo;t go into detail of each one, there are ton&amp;rsquo;s of materials out there.&lt;/p>
&lt;p>&lt;img src="string-type.jpg" alt="alt StringTypes" title="StringTypes">&lt;/p>
&lt;p>Below are the specs for B66 Ultimax:
&lt;img src="B66-Specs.jpg" alt="alt Specs" title="Specs">&lt;/p>
&lt;p>This was the only string my friend recommened - since he was an advanced player; I decided to blindly take his recomendation. This is a very thin string (0.65mm) - and a bit on the expensive side.&lt;/p>
&lt;p>There are two important things to notice - &lt;strong>Durability&lt;/strong> and &lt;strong>Control&lt;/strong>. It has the lowest durability among Yonex string - you might have to change then every few weeks 😟. But, It has the best control/power 😍&lt;/p>
&lt;p>Honestly: Within a week, I was able to see a &lt;strong>huge&lt;/strong> difference in my game. I was able to return smashes with much better control and clears did reach the 3rd court - previously, it usually landed in the mid court and we get a killer smash return. And finally, much better control of my short serve and drives. After using it for a month - I am just loving it. I have now changed all my 3 rackets with the same string.&lt;/p>
&lt;p>Finally: If you are really looking to up your game. Try out different strings, in my case B66 Ultimax worked - you might find a different one. But, keep looking and trying.&lt;/p>
&lt;p>&lt;em>side kick:&lt;/em>
&lt;a href="https://en.wikipedia.org/wiki/Taufik_Hidayat" target="_blank" rel="noopener">Taufik Hidayat&lt;/a> was using BG66 Ultimax.&lt;/p>
&lt;p>Next string on my list to try is
&lt;a href="http://yonexusa.com/products/aerosonic/" target="_blank" rel="noopener">Aerosonic&lt;/a> - worlds thinnest string.&lt;/p></description></item><item><title>MongoDB - Hybrid Schema</title><link>https://jacobaloysious.in/post/tech_mogodb-hybridschemadesign/</link><pubDate>Sun, 14 Mar 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_mogodb-hybridschemadesign/</guid><description>&lt;p>I recently ran into a situation where in we have a session and each Session produces a lot of messages (sync) and each message has an associated timestamp and order.
This is similar to a blog post (session) and its comments (messages).&lt;/p>
&lt;p>Since the messages are unbounded (not sure how many would be produced). In my initial design - I had a separate collection for Messages. Each Session would have one corresponding MessageW (wrapper) document and each MesssageW document would have an array of messages (acutal messages).&lt;/p>
&lt;p>With all the available data I had - the size of the MessageW document never went above 1MB - so we were all good. But unfortunately, we had a new use case which broke this assumption 😟. The session was running for hours and there was tons of messages getting generated and yes - we hit the 16MB ceiling 😓.&lt;/p>
&lt;p>Obvious solution was to create to create a new one doucment for every new message. So, that we never hit the size limit (16MB) of a mongoDB document. But, since we are looking at unbounded message - there could huge (million message docs) number of documents.&lt;/p>
&lt;p>So, we choose to go with the &lt;strong>Hybrid Approach&lt;/strong>&lt;/p>
&lt;p>In the hybrid approach, we go with our initial option - where we have a MessageW (wrapper) document - which has an array of Messages. Then we add a constrain on the document i.e. the size of the array should not be more than a given arbitary number. For every new message we increment the &lt;em>count&lt;/em>. If the number count crossed the constraint - then create a new MessageW document, inc the page number and also update the Session (&lt;em>NumberOfMsgPages&lt;/em>). The reader would get the &lt;em>NumberOfMsgPages&lt;/em> and read backwards - until he hit page 0. Voila!! 😍&lt;/p>
&lt;p>&lt;strong>Important Items to note:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Session Object : will have a &lt;em>NumberOfMsgPages&lt;/em> property&lt;/li>
&lt;li>MessageW Object: would have a &lt;em>Page&lt;/em> and &lt;em>Count&lt;/em> property.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Operators:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/reference/operator/update/inc/" target="_blank" rel="noopener">$inc&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/reference/operator/update/set/" target="_blank" rel="noopener">$set&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/reference/operator/query/lt/" target="_blank" rel="noopener">$lt&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-upsert" target="_blank" rel="noopener">upsert&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Since: A code is worth a thousand words. Here is the code 😊&lt;/p>
&lt;pre>&lt;code> public void InsertMessage(Message message, ObjectId parentId)
{
var builder = Builders&amp;lt;Message&amp;gt;.Filter;
// Find MessageObject: given parentId and CurrentPageNo
// And: Constraint: Number of messages is less than 1000.
var filter = builder.Eq(&amp;quot;parentId&amp;quot;, parentId)
&amp;amp; builder.Lt(&amp;quot;Count&amp;quot;, 1000)
&amp;amp; builder.Eq(&amp;quot;Page&amp;quot;, CurrentMessagePageCount);
// Try and Insert into existing Message Document array And Increment the Count.
var update = Builders&amp;lt;Message&amp;gt;.Update
.AddToSet(x =&amp;gt; x.Messages, message)
.Inc(&amp;quot;Count&amp;quot;, 1);
// If the constraint with &amp;quot;Count&amp;quot; matches.
// ModifiedCount would be greater than Zero
var result = MsgCollection.UpdateOne(filter, update);
if (result.IsAcknowledged)
{
if(result.ModifiedCount== 0)
{
// Increment the Page count
CurrentMessagePageCount += 1;
// Update: NumberOfMsgPages in Session Collection
var sessionFilter = Builders&amp;lt;MySession&amp;gt;.Filter.Eq(&amp;quot;_id&amp;quot;, parentId);
var updateSession = Builders&amp;lt;MySession&amp;gt;.Update
.Inc(&amp;quot;NumberOfMsgPages&amp;quot;, 1);
SessionsCollection.UpdateOne(sessionFilter, updateSession);
// Find MessageObject: given parentId and CurrentPageNo-which is obviously not found.
// So, we will use &amp;quot;IsUpsert=true&amp;quot; to add a new document.
// And: Number of messages is less than 20.
var filter2 = builder.Eq(&amp;quot;parentId&amp;quot;, parentId)
&amp;amp; builder.Eq(&amp;quot;Page&amp;quot;, CurrentMessagePageCount);
// Try: Insert into existing Message And Increment the Count
var update2 = Builders&amp;lt;Message&amp;gt;.Update
.AddToSet(x =&amp;gt; x.Messages, message)
.Set(&amp;quot;Page&amp;quot;, CurrentMessagePageCount)
.Inc(&amp;quot;Count&amp;quot;, 1);
MsgCollection.UpdateOne(filter2, update2, new UpdateOptions() { IsUpsert = true });
}
}
}
&lt;/code>&lt;/pre>
&lt;p>A obvious reaction after reading the code is - Ok, whats the big deal here?&lt;/p>
&lt;p>Lets take a code walk through: (think how would you achive this in your traditional SQL DB&amp;rsquo;s)&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Code never check if the MessageW document &lt;strong>exits&lt;/strong> before Update.&lt;/p>
&lt;ul>
&lt;li>How did it work: &lt;strong>&lt;em>&amp;ldquo;$IsUpsert=true&amp;rdquo;&lt;/em>&lt;/strong> is the magic word.&lt;/li>
&lt;li>&lt;em>$IsUpsert=True&lt;/em>: MongoDB would internally insert a &lt;strong>new&lt;/strong> document - if the document doesn&amp;rsquo;t exists.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Updating &lt;strong>counter&lt;/strong> is happening inside MongoDB:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;em>$inc&lt;/em>&lt;/strong> mongoDB operator - increments a specific field - in our case &lt;em>count&lt;/em>&lt;/li>
&lt;li>Hence, Client doesn&amp;rsquo;t have to read the document to know the actual count and then increment/update.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Constraint Check:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;em>$lt&lt;/em>&lt;/strong> MongoDB operator would handle the constraints.&lt;/li>
&lt;li>Update goes through if the constraint is met.&lt;/li>
&lt;li>As part of the result, we could check if any doc was modified&lt;/li>
&lt;li>Cool part - the second half of the code runs only once in 1000 inserts&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>How did we come up with the arbitary constraint number? well, I dont think we have a thumb rule here. Since we don&amp;rsquo;t track the actual document size - you would have to look at your data and come up with the sizing.&lt;/p>
&lt;p>BTW, I am new to MongoDB and learning. If there are better approaches - feel free to write back to me. Thanks.&lt;/p>
&lt;p>Reference:
&lt;a href="https://www.oreilly.com/library/view/mongodb-applied-design/9781449340056/" target="_blank" rel="noopener">MongoDB Applied Design Patterns, by Rick Copeland&lt;/a>&lt;/p></description></item><item><title>MongoDB Tit Bits</title><link>https://jacobaloysious.in/post/tech_mogodb-titbits/</link><pubDate>Sun, 07 Mar 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_mogodb-titbits/</guid><description>&lt;p>While I am getting started with MongoDB for my new project. Here are the few quick notes - based on my readings so far:&lt;/p>
&lt;p>One Key Takeaway:&lt;/p>
&lt;blockquote>
&lt;p>Data accessed together should be stored together&lt;/p>
&lt;/blockquote>
&lt;h4 id="wiredtiger">WiredTiger:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/core/wiredtiger/" target="_blank" rel="noopener">WiredTiger&lt;/a> is the default storage engine for mongo db&lt;/li>
&lt;li>It stores documents and indexes on disk&lt;/li>
&lt;li>In memory cache stores some doc and frequency used index - working set
&lt;ul>
&lt;li>50% of (RAM -1 GB) Or, 256MB&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="massive-arrays">Massive Arrays:&lt;/h4>
&lt;ul>
&lt;li>Max Document size is 16MB&lt;/li>
&lt;li>Index performance on arrays decreases as array size increases&lt;/li>
&lt;li>
&lt;a href="https://www.mongodb.com/blog/post/building-with-patterns-the-extended-reference-pattern" target="_blank" rel="noopener">Extended Reference pattern&lt;/a>: where we duplicate some and not all data&lt;/li>
&lt;/ul>
&lt;h4 id="index">Index:&lt;/h4>
&lt;ul>
&lt;li>Each index is atleast 8KB&lt;/li>
&lt;li>Index take up storage - One File for each collection and one file for each Index (WiredTiger impl)&lt;/li>
&lt;li>Write performance as index needs to updated&lt;/li>
&lt;li>Limit each collection to 50 Index max&lt;/li>
&lt;li>Do: Add index for frequently supported queries - improves read performance&lt;/li>
&lt;li>Don’t: Create unnecessary indexes - reduce performance and takes up space&lt;/li>
&lt;/ul>
&lt;h4 id="bloated-documents">Bloated Documents:&lt;/h4>
&lt;ul>
&lt;li>Do: Data accessed together should be stored together&lt;/li>
&lt;li>Don’t: bloat your document with related data that is not accessed to gether&lt;/li>
&lt;li>Data that is related to each other should NOT necessarily stored together&lt;/li>
&lt;li>Remove bloat from frequently used documents - it can be inmemory wire tiger cache&lt;/li>
&lt;li>Data Duplication is OK (depends!)
&lt;ul>
&lt;li>Summary document and Details document - ref via links&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="case-incentive-query">Case Incentive Query:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/reference/operator/query/regex/" target="_blank" rel="noopener">$regex&lt;/a> queries are case &lt;em>insensitive&lt;/em> but not performant&lt;/li>
&lt;li>Non-$regex queries are case &lt;em>sensitive&lt;/em>&lt;/li>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/reference/collation/" target="_blank" rel="noopener">Collation&lt;/a>:
&lt;ul>
&lt;li>Language specific rules for MongoDB for string comparison&lt;/li>
&lt;li>Strength ranges from 1-5&lt;/li>
&lt;li>Strength 1-2 will give you case insensitive&lt;/li>
&lt;li>Query: {&amp;ldquo;first_name&amp;rdquo;: {$regex: /Jacob/i }} - case insensitive&lt;/li>
&lt;li>Query: {&amp;ldquo;first_name&amp;rdquo;: &amp;ldquo;Jacob&amp;rdquo;} - case sensitive&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="accessing---separate-data-together">Accessing - Separate data together:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/" target="_blank" rel="noopener">$lookup&lt;/a>:
&lt;ul>
&lt;li>Is used to join data from more than one collection&lt;/li>
&lt;li>Great for rarely used queries or analytical queries (batch run overnight)&lt;/li>
&lt;li>Very slow and resource intensive&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="upserthttpswwwmongodbtutorialorgmongodb-crudmongodb-upsert">
&lt;a href="https://www.mongodbtutorial.org/mongodb-crud/mongodb-upsert/" target="_blank" rel="noopener">Upsert&lt;/a>:&lt;/h4>
&lt;ul>
&lt;li>Upsert is a combination of update and insert. Upsert performs two functions:
&lt;ul>
&lt;li>Update data if there is a matching document.&lt;/li>
&lt;li>Insert a new document in case there is no document matches the query criteria.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Personally: I found this very interesting, as for my use cases - I dont need to track if the document already exist.&lt;/li>
&lt;/ul>
&lt;p>I understand - the blog looks a bit navive (read, nothing interseting), sry I am just getting started. BTW, I plan to write a follow blog - deep dive on my specific use cases and data modelling.&lt;/p>
&lt;h4 id="reference">Reference:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.youtube.com/channel/UCK_m2976Yvbx-TyDLw7n1WA" target="_blank" rel="noopener">MongoDB Channel&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.mongodbtutorial.org/" target="_blank" rel="noopener">MongoDB Tutorial&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Goals - Yr 2021</title><link>https://jacobaloysious.in/post/diary_goals-2021/</link><pubDate>Sun, 17 Jan 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_goals-2021/</guid><description>&lt;p>Being in the IT industry for more than a decade:&lt;/p>
&lt;ul>
&lt;li>Start of the year: &lt;strong>&amp;ldquo;Goal setting&amp;rdquo;&lt;/strong> - you align with your manager on how the year is gona possibly look like&lt;/li>
&lt;li>End of the year: &lt;strong>&amp;ldquo;Self Assessment&amp;rdquo;&lt;/strong> - your retrospective of how the year was. Followed by &lt;strong>&amp;ldquo;Performance Feedback&amp;rdquo;&lt;/strong> - comments from your peers and manager.&lt;/li>
&lt;/ul>
&lt;p>This is really good - a proven/well established process - which works!&lt;/p>
&lt;p>On personal front - I have never thought about setting personal goals. Well Hang on! - what about &lt;em>New Yr Resolution&lt;/em>? 😜 Oh ya; it just never worked - why? it never had a system. As a huge fan of
&lt;a href="https://jamesclear.com/atomic-habits" target="_blank" rel="noopener">Atomic Habits&lt;/a> book - here is a blog from the author on
&lt;a href="https://jamesclear.com/goals-systems" target="_blank" rel="noopener">Goals-Systems&lt;/a> - which talks about the system. Below is a snip from it:&lt;/p>
&lt;blockquote>
&lt;p>If you want better results, then forget about setting goals. Focus on your system instead - James Clear&lt;/p>
&lt;/blockquote>
&lt;p>In business - goals are usually based on
&lt;a href="https://www.mindtools.com/pages/article/smart-goals.htm" target="_blank" rel="noopener">SMART&lt;/a>.&lt;/p>
&lt;p>But: 3 criteria&amp;rsquo;s for &lt;strong>MY&lt;/strong> personal goals:&lt;/p>
&lt;ul>
&lt;li>It should be a Compass&lt;/li>
&lt;li>Be honest about what I want&lt;/li>
&lt;li>Measure the Gain not the Gap
&lt;a href="http://www.strategiccoach.com/go/gapandgain" target="_blank" rel="noopener">ref&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Seriously!! how can you be foccussed on achieving a goal if you are not SMART?&lt;/p>
&lt;blockquote>
&lt;p>well - I would prefer to love and embrace the Journey that the actual destination.&lt;/p>
&lt;/blockquote>
&lt;p>Now lets set some goals:&lt;/p>
&lt;h2 id="fitness">Fitness:&lt;/h2>
&lt;p>I started around end of last yr (2020) - but due to the vacation/Christmas season (fantastic food at home 😋) and my fracture - had to drop it (well, &lt;em>stop blaming - you could have done better!&lt;/em> 😉). This year I plan to restart and give it a honest try.&lt;/p>
&lt;h4 id="system">System:&lt;/h4>
&lt;ul>
&lt;li>Signed up to
&lt;a href="https://www.fittr.com/" target="_blank" rel="noopener">Fittr&lt;/a>&lt;/li>
&lt;li>Enrolled under a Coach - Mr.HR in Fittr
&lt;ul>
&lt;li>Quantified Nutrition and Workout plan&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Have a buddy - Mr.P&lt;/li>
&lt;li>Blocked 1hr of time on my calender every day for workout&lt;/li>
&lt;/ul>
&lt;p>Hopefully Fittr&amp;rsquo;s system would be able to track my progress and my coach w/ guidance.
Expectation: I should be able to look back every month and see some progress. Progress could be anything - starting from loosing weight, to getting in shape, to ripped (ripped! seriously? be honest😁). As it stands today - I am in the obese category - any progress todays being healthy is good enough.&lt;/p>
&lt;h2 id="sports">Sports:&lt;/h2>
&lt;p>I have always loved playing sports - like Cricket, Football and now Badminton, Cycling. But never went for coaching or had any planned schedule. But, always dreamt of playing sports every single day in my life! BTW, I don&amp;rsquo;t mean - I should have been a sportsman - I was never good at any of them 😉 - just enjoyed doing it.&lt;/p>
&lt;p>Cricket requires lot of time investment and Football is too injury prone - So my only option is Badminton and Cycling.&lt;/p>
&lt;h4 id="system-1">System:&lt;/h4>
&lt;ul>
&lt;li>Signed up a membership - at a badminton academy close to my house.&lt;/li>
&lt;li>Have a bunch of friends who play only on weekends thanks to
&lt;a href="https://www.booknplay.in/" target="_blank" rel="noopener">Rozo&lt;/a>&lt;/li>
&lt;li>Combine (alternate) Fitness workout with sports - optimizing time.&lt;/li>
&lt;li>Cycling once a week, with Mr.K&lt;/li>
&lt;/ul>
&lt;p>Honestly - just the feel of playing - is all that is required. It has always been a great refresher. Expectation: Sports 2days a week.&lt;/p>
&lt;h2 id="journal">Journal:&lt;/h2>
&lt;p>Started very enthusistically on the
&lt;a href="https://www.youtube.com/watch?v=fm15cmYU0IM" target="_blank" rel="noopener">Bullet Journal&lt;/a> - but dropped it midway 😞.&lt;/p>
&lt;p>Looking back: It was hard to manage, as I was throwing too many things at it - starting from adhoc meetings/calls to escalations. I was religiously following the -
&lt;a href="https://medium.com/the-mission/how-to-stop-procrastinating-by-using-the-2-minute-rule-310fa8495fb9" target="_blank" rel="noopener">2 minutes rule&lt;/a> by David Allen - and the same went into the journal.&lt;/p>
&lt;blockquote>
&lt;p>If it takes less than two minutes, then do it now - David Allen&lt;/p>
&lt;/blockquote>
&lt;p>It was a clutter - and the energy required, at the end of a long day to declutter 😟, lost motivation after a month.&lt;/p>
&lt;h4 id="system-2">System:&lt;/h4>
&lt;ul>
&lt;li>Update Journal before bed&lt;/li>
&lt;li>email follow up: &lt;strong>flag&lt;/strong> it and leave it in outlook.&lt;/li>
&lt;li>Try use
&lt;a href="https://dynalist.io/" target="_blank" rel="noopener">Dynalist&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>This might be an ongoing thing - which I would need to recalibrate throughtout the year. Expectation: Every re-calibration should be an improvement of the previous state.&lt;/p>
&lt;h2 id="blogs">Blogs:&lt;/h2>
&lt;p>Started this last yr(2020). Have not been consistent.&lt;/p>
&lt;h4 id="system-3">System:&lt;/h4>
&lt;ul>
&lt;li>Future Blog list - would be managed in Journal&lt;/li>
&lt;li>Block calendar time once a week - Saturday afternoon&lt;/li>
&lt;li>One blog per week
&lt;ul>
&lt;li>If I missed, will add a &amp;ldquo;&lt;em>No Blog week&lt;/em>&amp;rdquo; blog 😝, keeps me accountable&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="books">Books:&lt;/h2>
&lt;p>For a starter like me - Last year was a fantastic year for books and podcast. I should pinch myself - I read 15 books in total i.e. more than 1 book per month 😍. I wish to continue the same momentum.&lt;/p>
&lt;h4 id="system-4">System:&lt;/h4>
&lt;ul>
&lt;li>Read a non-fiction/non-technical book using Kindle everyday before bed - 10 pages.&lt;/li>
&lt;li>Read a technical book (hard copy) - every day during bfast or lunch.&lt;/li>
&lt;li>Order 2 books every month - lets push the envelope.👍
&lt;ul>
&lt;li>
&lt;a href="https://www.shroffpublishers.com/" target="_blank" rel="noopener">shroff publishers&lt;/a> and Amazon&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="personal-finance">Personal Finance:&lt;/h2>
&lt;p>One thing that I am pathetic is managing my self finance. Mostly I have been lazy (or) coding was more fun.&lt;/p>
&lt;p>I don&amp;rsquo;t plan to make any drastic changes - but just the knowledge of investing and managing - I belive would be useful.&lt;/p>
&lt;h4 id="system-5">System:&lt;/h4>
&lt;ul>
&lt;li>Start reading some finance books&lt;/li>
&lt;li>Gather list of getting started books&lt;/li>
&lt;/ul>
&lt;h2 id="conclusion">Conclusion:&lt;/h2>
&lt;p>Goals are good to know where to go (read Compass). I want to always &lt;strong>look back&lt;/strong> and be happy about the progress made - than being worried about the &lt;strong>Gap that is left&lt;/strong> to achive the goal. Again: enjoy the Journey and the destination would become immaterial.&lt;/p></description></item><item><title>Retrospective - Year 2020</title><link>https://jacobaloysious.in/post/diary_retrospective-2020/</link><pubDate>Fri, 01 Jan 2021 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_retrospective-2020/</guid><description>&lt;p>Happy New Year - 2021&lt;/p>
&lt;h1 id="what-went-well-">What went well 👍&lt;/h1>
&lt;p>This year has been more personal challenges than technical due to the Covid19.&lt;/p>
&lt;h4 id="marathon">Marathon:&lt;/h4>
&lt;p>Ran my first 10K
&lt;a href="https://www.thechennaimarathon.com/" target="_blank" rel="noopener">Marathon, Chennai&lt;/a>. I ran with my wife and we finished together 😍&lt;/p>
&lt;h4 id="blog">Blog:&lt;/h4>
&lt;p>Started this blog - I am super excited about. Had registered this website few years back, but never got a change to blog.&lt;/p>
&lt;h4 id="wfh">WFH:&lt;/h4>
&lt;p>Personally I have always admired how great minds like
&lt;a href="https://www.hanselman.com/" target="_blank" rel="noopener">Scott Hanselmen&lt;/a> manage to work from home - for more than a decade - lead a team and also stay productive. Well : if you need to learn to swim, then you should first throw yourself into the water. In a way, thanks to C19 and forced WFH - I ended up setting up my home office.&lt;/p>
&lt;p>But but but, as Scott says this is NOT remote work its quarantine work 😉. I don&amp;rsquo;t quite belive life would be the same (pre C19 days) again, and I am up for the challenge.&lt;/p>
&lt;h4 id="reading">Reading:&lt;/h4>
&lt;p>One of the best habit I have developed this year - reading books consistently. Read ~15 books (pinch myself, record - usually its 1 or 2) this year. Ensured - I read every single day before I go to bed. Thanks to the book
&lt;a href="https://jamesclear.com/atomic-habits" target="_blank" rel="noopener">Atomic Habits&lt;/a> and my bookmate best friend(Mr.P). When I look back, I feel guilty I didn&amp;rsquo;t start this early - anyway it&amp;rsquo;s never late than ever.&lt;/p>
&lt;h4 id="home-sweet-home">Home Sweet Home:&lt;/h4>
&lt;p>All our plans went into a array due to the lockdown - there was a 2 week mild relaxation, took a risk and we sneaked into our new house. This was a dream come true - we always wanted to move into a community esp for my daughter and here we are.&lt;/p>
&lt;h4 id="niece-s">Niece (s):&lt;/h4>
&lt;p>Happy to welcome the two little ones (T and G) into our extended family - Stay blessed!!&lt;/p>
&lt;h4 id="neck-pain">Neck Pain:&lt;/h4>
&lt;p>6 different doctors (physio, ortho, chiro, homeopathy, ayurveda - you name it) * 1.5 yrs - no luck. Finally met a spine surgeon - took an MRI and figured out it was just &lt;strong>LOW Vitamin D&lt;/strong> damm!! What an AntiClimax 😱. Sometimes we (including the doctor) do complicate things - all that was required was just a simple blood test - patterns can sometimes be misleading (can we use - AI? take care of the Training set).&lt;/p>
&lt;h4 id="hackathon-judge">Hackathon Judge:&lt;/h4>
&lt;p>I was part of the Judging panel for our first 100% virtual hackathon- pinch myself 😎. I was a participant in the last 2 hackathons at KLA - won prizes. But this time I was sitting on the other side of the table - asking question and digesting new solution and prespectives - it was such a wonderful experience.&lt;/p>
&lt;h1 id="what-could-have-been-better-">What could have been better 👎&lt;/h1>
&lt;h4 id="meeting">Meeting:&lt;/h4>
&lt;p>There were days I had ~14 planned meeting in a single day 😞 and an Average of ~9 meeting in a day. This might not be sustainable - I would need to figure out a better way to manage these overheads.&lt;/p>
&lt;h4 id="journal">Journal:&lt;/h4>
&lt;p>Started on Journaling this year - actually tried
&lt;a href="https://bulletjournal.com/" target="_blank" rel="noopener">Bullet Journal&lt;/a>, it was nice. It gave me a good picture to reflect how the day (month) was and also plan what were my important task for the next day - but sadly I wasn&amp;rsquo;t consistent 😦. Yr 2021 - I hope to be better.&lt;/p>
&lt;h4 id="badminton">Badminton:&lt;/h4>
&lt;p>Wanna get back to start playing Badminton regularly - I love the game. After the game your mind is so clear - its my best form of meditation.&lt;/p>
&lt;h3 id="fracture">Fracture:&lt;/h3>
&lt;p>What an end to the year : a hairline fracture on my foot - casted - 4 weeks - home quarantined 😟&lt;/p>
&lt;h4 id="fittr">Fittr:&lt;/h4>
&lt;p>I signed up for
&lt;a href="https://www.fittr.com/" target="_blank" rel="noopener">FITTR&lt;/a> program, but unfortunately - the fracture came in between 😞. Next year I will come back stronger.&lt;/p>
&lt;h1 id="conclusion">Conclusion:&lt;/h1>
&lt;p>2020 was a mixed year with lots of learning both professionally and technically. Looking back - I dont have any real regrets and I hope to have an even better 2021.&lt;/p></description></item><item><title>Docker - DotNet 4.8 - Getting Started</title><link>https://jacobaloysious.in/post/tech_docker_getting_started/</link><pubDate>Wed, 30 Dec 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_docker_getting_started/</guid><description>&lt;p>Source Code:
&lt;a href="https://github.com/jacobaloysious/docker-try-net48" target="_blank" rel="noopener">docker-try-net48&lt;/a>&lt;/p>
&lt;p>&lt;strong>Goal:&lt;/strong> Develop a .Net48 application - coding would happen in the host while its run inside the docker - live&lt;/p>
&lt;p>&lt;em>Prerequisite:&lt;/em>
&lt;a href="https://docs.docker.com/docker-for-windows/install/" target="_blank" rel="noopener">Docker Desktop for windows&lt;/a> is up and running and you are using Windows Containers&lt;/p>
&lt;p>There are tons of documentation online, this is just me getting started.&lt;/p>
&lt;h2 id="base-image">Base Image:&lt;/h2>
&lt;p>There are two base images supported officially by Microsoft for .Net windows application.&lt;/p>
&lt;ul>
&lt;li>Windows Server Core&lt;/li>
&lt;li>Windows Nano Server&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="DotNetContainer.jpg" alt="alt Components" title="Base Window Images">&lt;/p>
&lt;p>In this example: we are gona work on a .Net Framework 4.8 - console application. We would be using the
&lt;a href="https://github.com/microsoft/dotnet-framework-docker/blob/master/src/runtime/4.8/windowsservercore-ltsc2019/Dockerfile" target="_blank" rel="noopener">&lt;strong>DotNet Framework 4.8&lt;/strong>&lt;/a> image which internally uses
&lt;a href="https://hub.docker.com/_/microsoft-windows-servercore" target="_blank" rel="noopener">&lt;strong>servercore:ltsc2019-amd64&lt;/strong>&lt;/a> as base image.&lt;/p>
&lt;p>Let first pull the image, into our local image cache. This would take a while as the size is huge - get yourself a coffee.&lt;/p>
&lt;pre>&lt;code>$docker pull mcr.microsoft.com/dotnet/framework/runtime:4.8
&lt;/code>&lt;/pre>
&lt;p>Once pulled (image is available in your local cache) - you are gona see an entry with Tag &lt;strong>4.8&lt;/strong> in image list&lt;/p>
&lt;pre>&lt;code>$docker image ls
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="PullDotNetImage.jpg" alt="alt Components" title="Pull DotNet Image">&lt;/p>
&lt;h2 id="sample-app">Sample App:&lt;/h2>
&lt;p>Here is a sample app to demostrate the usage. Clone the
&lt;a href="https://github.com/jacobaloysious/docker-try-net48" target="_blank" rel="noopener">repository&lt;/a>. Open the solution &lt;em>jacapp.sln&lt;/em> in VS2019 and compile it. Its a simple app which starts two threads and exits after 10 seconds&lt;/p>
&lt;ul>
&lt;li>One thread - print the count and the thread ID - to the &lt;em>console&lt;/em> every second&lt;/li>
&lt;li>Second thread - write the same count and thread ID - into an &lt;em>output text file&lt;/em> every second&lt;/li>
&lt;/ul>
&lt;p>&lt;em>note:&lt;/em> the output file would be on a volume mounted drive with the host&lt;/p>
&lt;p>&lt;img src="reposcreenshot.jpg" alt="alt Components" title="Repo Content">&lt;/p>
&lt;h2 id="dockerfile">Dockerfile:&lt;/h2>
&lt;p>Let&amp;rsquo;s look at the contents of the dockerfile:&lt;/p>
&lt;ol>
&lt;li>Specify &lt;strong>Base image&lt;/strong> we plan to use - in our case we are gona use the image (4.8 Runtime) we have already downloaded (pulled)&lt;/li>
&lt;li>Specify the &lt;strong>Working Directory&lt;/strong> where all the commands would be run. Think of it as running &lt;code>$CD /d c:/myapp&lt;/code>, before the &lt;em>EntryPoint&lt;/em> is exectuted&lt;/li>
&lt;li>Specify the &lt;strong>Command&lt;/strong> to be executed inside the working directory. In our case its the console app, so we run the output exe &lt;em>jacapp.exe&lt;/em>&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="docker-file.jpg" alt="alt Components" title="Dockerfile Content">&lt;/p>
&lt;h2 id="build-image">Build Image:&lt;/h2>
&lt;p>Let&amp;rsquo;s build a docker image. Run the command from the directory which has the &lt;code>Dockerfile&lt;/code>&lt;/p>
&lt;pre>&lt;code>$docker build -t testapp .
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="docker-build-image.jpg" alt="alt Components" title="Dockerfile Content">&lt;/p>
&lt;p>&lt;img src="test-app-image.jpg" alt="alt Components" title="Test App Image">&lt;/p>
&lt;h2 id="run-image">Run Image:&lt;/h2>
&lt;p>Items to note:&lt;/p>
&lt;ul>
&lt;li>&amp;ndash;name: name of the container image instance&lt;/li>
&lt;li>-v: volume mount; here we mount the output &amp;ldquo;bin&amp;rdquo; directory with a specific directory inside the container &amp;ldquo;c:\myapp&amp;quot; .&lt;/li>
&lt;li>-rm: remove the container instance once the program exits&lt;/li>
&lt;/ul>
&lt;pre>&lt;code>$docker run --name jacinstance1 --rm -v D:\dev\dkr\docker-try-net48\jacapp\bin\Debug:C:\myapp\ testapp
&lt;/code>&lt;/pre>
&lt;h4 id="instance-of-the-containter-running">Instance of the containter running:&lt;/h4>
&lt;p>&lt;img src="jac-instance.jpg" alt="alt Components" title="Run Console Output">&lt;/p>
&lt;h4 id="console-output">Console output:&lt;/h4>
&lt;p>&lt;img src="run-console-output.jpg" alt="alt Components" title="Run Console Output">&lt;/p>
&lt;h4 id="contents-of-the-file-writted-on-the-mounted-drive">Contents of the file writted on the mounted drive:&lt;/h4>
&lt;p>&lt;img src="run-output-file-content.jpg" alt="alt Components" title="Run Console Output">&lt;/p>
&lt;p>Well thats it! We have our application running inside a container - Now we could edit your project (try updating the console output text), compile and directly &lt;code>docker run&lt;/code> the image i.e. NO docker image re-build required!!&lt;/p></description></item><item><title>Code Reviews</title><link>https://jacobaloysious.in/post/tech_code-reviews/</link><pubDate>Sat, 10 Oct 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_code-reviews/</guid><description>&lt;p>While working in a development team; being part of the code review is not an optional thing. Depending on the size of the org/team and the # of features in parallel - I am sure, we will get multiple code review requests in a week.&lt;/p>
&lt;p>I often ask myself, can I provide valuable feedbacks on every review I am part of? Most certainly NO! lets be honest here.&lt;/p>
&lt;p>Then the next question is - why are you added into the review? well I could think of two reasons:&lt;/p>
&lt;ul>
&lt;li>FYI: Let the team know I made this change; there could be depenencies (another developer; working on similar files)&lt;/li>
&lt;li>Status update (stakeholders)&lt;/li>
&lt;/ul>
&lt;h3 id="not-an-active-reviewer">Not an active reviewer:&lt;/h3>
&lt;p>If you think, you don&amp;rsquo;t have the right context to contribute. It&amp;rsquo;s good to be explict and call out - &lt;strong>Sorry, I don&amp;rsquo;t have enough context to add value. I would leave the review to the experts&lt;/strong> and recommend the author to mark you as &lt;strong>Observer&lt;/strong> instead.&lt;/p>
&lt;p>Note: code review is not a place to train; where you discuss and use it as a learning form.&lt;/p>
&lt;h3 id="add-value">Add Value:&lt;/h3>
&lt;p>This is critical and most important objective of a code review. Pointing out each and every spelling mistake and intendation fix - might not add much value; in which case - propose them to run it through a FxCop/style/code analyser utility.&lt;/p>
&lt;p>You absolutely need to be aware of the context before providing feedback 👀. If you are not sure about the specifics, setup a meeting and request the developer to walk you through. At the end of the day - &lt;strong>code is the ground truth&lt;/strong> (irrespective of what was aligned). Few example of real Value could be:&lt;/p>
&lt;ol>
&lt;li>Pointing out specific use cases not handled&lt;/li>
&lt;li>Usage of design principles (SOLID) - coupling/cohesion etc&lt;/li>
&lt;li>Adding: Validation, Logging, Tracablility etc&amp;hellip;&lt;/li>
&lt;li>Handling: Errors, Exception, Leaks, Performance etc..&lt;/li>
&lt;li>Code Coverage, appropriate tests (note: test should also be as clean/maintainable as SUT)&lt;/li>
&lt;/ol>
&lt;h3 id="assumptions">Assumptions:&lt;/h3>
&lt;p>This could at times come back back and bite; I have been there 😕. If you are not sure about a specfic change again: &lt;strong>call out explicitly and confirm - if your understanding is accurate&lt;/strong>.&lt;/p>
&lt;p>As authors - we do want our code to be non ambiguous. But, since there is always a context and depenency in the code - its hard to describe everything. Maybe better naming could help? well: 😏&lt;/p>
&lt;blockquote>
&lt;p>There are only two hard things in Computer Science: cache invalidation and naming things.&amp;ndash; Phil Karlton&lt;/p>
&lt;/blockquote>
&lt;h3 id="no-condescending-words">No Condescending words&lt;/h3>
&lt;p>Thanks to
&lt;a href="https://www.michaelagreiler.com/" target="_blank" rel="noopener">Doctor McKayla&lt;/a> for this.&lt;/p>
&lt;blockquote>
&lt;p>Words such as “just”, “easy”, “only”, or “obvious” can come across belittling and condescending. It’s a good practice to remove those words from your feedback. Most of the time, they do not add any value&amp;hellip;.. research shows that people have a tendency to interpret written language in a negative way.&lt;/p>
&lt;/blockquote>
&lt;p>Personally, I am cautious to ensure my review comments looks like a conversation - than a direct command.&lt;/p>
&lt;h3 id="more-the-number-of-reviewers">More the number of Reviewers:&lt;/h3>
&lt;p>I remember receiving emails like &amp;ldquo;please review my change set&amp;rdquo; sent to a DL which had 30+ developers.
Do you think all 30 members would have all the required context or would &lt;strong>you ensure&lt;/strong> all 30 will follow up and get the context and then do the reivew? Less likely! 🤔&lt;/p>
&lt;p>Maybe there is a perception that more the reviewers; more the # of valuable feedback. But, what if its the other way - every one assumes its someone else responsiblity - zero feedbacks 😟.&lt;/p>
&lt;h3 id="separate-feature-addtion-and-refactoring">Separate Feature Addtion and Refactoring:&lt;/h3>
&lt;p>Many at time its intriguing to refactor the code while we are working on a feature. We should - its always a good practise to &lt;em>clean up&lt;/em> and &lt;em>make it better&lt;/em>.&lt;/p>
&lt;p>My only argument here is: If you have both - the feature implemetation and refactoring in the same changeset (esp on a large code base, spanning files/dependencies) - It becomes a challenge to follow the &lt;strong>actual functional&lt;/strong> change.&lt;/p>
&lt;p>Recomendation: split them into two changeset like
&lt;a href="https://www.michaelagreiler.com/stacked-pull-requests/" target="_blank" rel="noopener">StackedPullRequest&lt;/a>: Personally would prefer (2) followed by (1)&lt;/p>
&lt;ol>
&lt;li>Only refactoring. No feature addtion&lt;/li>
&lt;li>Only feature addition&lt;/li>
&lt;/ol>
&lt;h3 id="unsure-of-the-reviewers">Unsure of the reviewers?&lt;/h3>
&lt;p>If you are already part of the team which maintains the code; no brainer. You are here since you are not sure - simplest tip &lt;strong>Go for history&lt;/strong>.
I have done this more than once; say making a change in deploy scripts maintained by operational team. Look for atleast 2 developers based on change history (again: don&amp;rsquo;t stop with one) of the file(s); secondly: make sure you look at their org structure and see if they belong to the operational team (If I get to deliver and someone else sends me a new review request 😑); finally: just to be sure add their solid line into it (why: well, you are unsure if you would get a response 😜).&lt;/p>
&lt;h3 id="approval-enforced">Approval Enforced:&lt;/h3>
&lt;p>Few companies have strict code review rules like: only a pull request that has 2 or more approvals - would be merged into mainline. I feel this culture/process is awesome; as there is definetly a sens of responsibility and ownership on the part of the reviewers - at the end of the day again (would say it multiple times) &lt;strong>&amp;ldquo;Code is the Ground Truth&amp;rdquo;&lt;/strong> (irrespective; what ever the feature/design document says).&lt;/p>
&lt;h2 id="conclusion">Conclusion:&lt;/h2>
&lt;p>I personally belive, Code review are not optional. Anyday - another pair of eyes would give you a different prespective. While, we as developers are more focused on getting thing done, there are chances of scenarios getting overlooked - effective code review enable us to bridge this gap. This defintely requires commitment and trust between authors and reviewers.&lt;/p>
&lt;p>Building a culture toward delivering quality code with code review as pivot is critical.&lt;/p>
&lt;p>Check out:
&lt;a href="https://www.michaelagreiler.com/" target="_blank" rel="noopener">Doctor McKayla&lt;/a>; there are lots of good content on this topics.&lt;/p></description></item><item><title>Apache Airflow and Regression Monitoring</title><link>https://jacobaloysious.in/post/tech_airflow_reg_monitor/</link><pubDate>Fri, 02 Oct 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_airflow_reg_monitor/</guid><description>&lt;h2 id="introduction">Introduction:&lt;/h2>
&lt;p>Airflow is a platform to programmatically author, schedule and monitor workflows or data pipelines. It was originally developed and open sourced by Airbnb, later joined Apache Software foundation’s incubation program in 2016. Workflow is a sequence of tasks defined around Directed Acyclic Graph(DAGs) – which could be started on a schedule or triggered by an event or using Command line interface. Airflow pipelines are configuration as code (Python), allowing for dynamic pipeline generation. This allows for writing code that instantiate pipelines dynamically.&lt;/p>
&lt;h2 id="components">Components:&lt;/h2>
&lt;p>&lt;img src="airflow_component.jpg" alt="alt Components" title="Airflow Components">&lt;/p>
&lt;h4 id="metadata-db">Metadata DB:&lt;/h4>
&lt;p>Stores information&amp;rsquo;s like job status and task instance status.&lt;/p>
&lt;h4 id="scheduler">Scheduler:&lt;/h4>
&lt;p>Airflow scheduler executes your tasks on an array of workers while following the specified dependencies. The scheduler is the brains behind setting up the workflows in airflow. The execution time begins at DAG start date and repeat every schedule interval.&lt;/p>
&lt;h4 id="web-interface-ui">Web Interface (UI):&lt;/h4>
&lt;p>Airflow ships with a Flask app that tracks all the defined workflows and lets you easily change, start or stop them. The rich user interface makes it easy to visualize pipelines running in production, monitor progress and troubleshoot issues.&lt;/p>
&lt;h4 id="cli">CLI:&lt;/h4>
&lt;p>Airflow has a very rich command line interface that allows to test, run, backfill, describe and clear parts of your DAGs&lt;/p>
&lt;h2 id="concepts">Concepts:&lt;/h2>
&lt;h4 id="dag">DAG:&lt;/h4>
&lt;p>A DAG is the container that is used to organize tasks in a way that reflects their relationship, dependencies and set their execution context and order.&lt;/p>
&lt;h4 id="operators">Operators:&lt;/h4>
&lt;p>Operators are the worker that run the tasks. Workflows are defined by creating a DAG of operators. They are broadly classified into three – Sensors, Operators and Transfers. Airflow provides many prebuild operators for many common tasks and new operators can be created by inheriting BaseOperator class.&lt;/p>
&lt;h4 id="tasks">Tasks:&lt;/h4>
&lt;p>Once an operator is instantiated, its is referred to as a “task”. Each task is user defined and responsible for performing a specific operation in the workflow. Instantiating a task requires providing a unique task_id and DAG container. Task can be python function or external scripts that could be invoked.&lt;/p>
&lt;h2 id="example">Example:&lt;/h2>
&lt;p>&lt;img src="example.jpg" alt="alt Example" title="Example">&lt;/p>
&lt;p>In the example, we show case - how Airflow could be used to express a workflow that can be used to generate the statistics/ report as part of end-to-end regression test suit; which involves multiple systems to work together. A traditional approach would use something very basic like bunch of batch scripts w/o CRON. But the challenge is - it would very easily get tangled and developer would spend a lot of time to figure out where the log files are or what failed and why/who owns what. Airflow helps solves this problem by helping in orchestrating your processes, managing the logs and really good dashboard with visualization of what failed and much more information.&lt;/p>
&lt;p>&lt;img src="code_snippet.jpg" alt="alt CodeSnippet" title="Code Snippt">&lt;/p>
&lt;h2 id="references">References:&lt;/h2>
&lt;ul>
&lt;li>Airflow : &lt;a href="https://airflow.apache.org">https://airflow.apache.org&lt;/a>&lt;/li>
&lt;li>Luigi: &lt;a href="https://luigi.readthedocs.io/en/stable/index.html">https://luigi.readthedocs.io/en/stable/index.html&lt;/a>&lt;/li>
&lt;li>Blog: &lt;a href="https://medium.com/airbnb-engineering/airflow-a-workflow-management-platform-46318b977fd8">https://medium.com/airbnb-engineering/airflow-a-workflow-management-platform-46318b977fd8&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Python Plugins with Topics</title><link>https://jacobaloysious.in/post/tech_python_plugins/</link><pubDate>Sun, 13 Sep 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_python_plugins/</guid><description>&lt;p>Source Code:
&lt;a href="https://github.com/jacobaloysious/pyplugins" target="_blank" rel="noopener">PyPlugins&lt;/a>&lt;/p>
&lt;p>Any infrastructure should always have the capability to extend itself. It would be better if the functionality is added by a contributor - who is not part of the core team. And it doesn&amp;rsquo;t get in the way of core components - development, compilation and deployment.&lt;/p>
&lt;p>The concept of plugin has been around there for quite a while - Visual Studio/VS Code all has plugins (aka extensions). Basic idea here is to add new functionalities - by just deploying a new dll, jar or py modules.&lt;/p>
&lt;p>In this proposal using python, we have a root folder named &lt;strong>Plugins&lt;/strong> - the infra would enumerate the Plugins directory to add functions. The functionalities register themselves with a &lt;strong>Key&lt;/strong> - let’s call them &lt;strong>TOPICS&lt;/strong>.&lt;/p>
&lt;p>Well why &lt;strong>Topics&lt;/strong>? I am borrowing this idea from Messaging Queue infra like
&lt;a href="https://zeromq.org/" target="_blank" rel="noopener">ZMQ&lt;/a> and
&lt;a href="https://kafka.apache.org/" target="_blank" rel="noopener">Kafka&lt;/a>&amp;hellip; So, that we could create a Topic to Function mapping - and we would be able to map caller to a MQ subscriber.&lt;/p>
&lt;p>Let me walk through each component:&lt;/p>
&lt;h4 id="base-class">Base class&lt;/h4>
&lt;p>Base class that each plugin must inherit from; this class exposes couple of items 1) List of Topics 2) Execute Method - which your plugin should implement.&lt;/p>
&lt;pre>&lt;code>class IPlugin(object):
def __init__(self):
self.description = 'UNKNOWN'
self.topics = []
def execute(self, topic, argument):
&amp;quot;&amp;quot;&amp;quot;The method that we expect all plugins to implement. This is the
method that our framework will call
&amp;quot;&amp;quot;&amp;quot;
raise NotImplementedError
&lt;/code>&lt;/pre>
&lt;h4 id="example-plugin--calculate">Example Plugin : Calculate&lt;/h4>
&lt;p>Calculate Plugin - exposes two functionalities: &lt;em>add&lt;/em> and &lt;em>subtract&lt;/em>. For the client its exposed as two topics. The execute function takes in topic and the argument. Based on the topic the respective plugin could dispatch it to sub-functions within the plugin.&lt;/p>
&lt;pre>&lt;code>class CalculatorPlugin(IPlugin):
def __init__(self):
self.description = 'Calculator'
self.topics = ['Add', 'Subtract']
def execute(self, topic, args):
if topic == &amp;quot;Add&amp;quot;:
return self.add(args)
raise Exception (f'Topic: {topic} has no mapping function')
def add(self, args):
count = 0
for index in range(0, len(args)):
count += args[index]
return count
&lt;/code>&lt;/pre>
&lt;h4 id="service-discovery">Service Discovery:&lt;/h4>
&lt;p>The infrastructure would enumerate the plugin base_directory and try find sub class of &lt;strong>IPlugin&lt;/strong>.
Create instance of the sub_class and register to the store: &lt;code>MAP&amp;lt;topic, instance&amp;gt;&lt;/code>. Infra should be able to directly call the &lt;strong>execute&lt;/strong> API, on the instance.&lt;/p>
&lt;pre>&lt;code>class ServiceDiscovery(object):
def __init__(self, plugin_package_dir='plugins'):
self.plugin_package_base_dir = plugin_package_dir
self.plugin_topic_instance_map = {}
self.enumerate_packages()
def enumerate_packages(self, package):
&amp;quot;&amp;quot;&amp;quot;Recursively walk the supplied package to retrieve all plugins
&amp;quot;&amp;quot;&amp;quot;
imported_package = __import__(package, fromlist=['foo'])
for _, pluginname, ispkg in pkgutil.iter_modules(imported_package.__path__, imported_package.__name__ + '.'):
if not ispkg:
plugin_module = __import__(pluginname, fromlist=['foo'])
clsmembers = inspect.getmembers(plugin_module, inspect.isclass)
for (_, c) in clsmembers:
# Only add classes that are a sub class of Plugin, but NOT Plugin itself
if issubclass(c, IPlugin) &amp;amp; (c is not IPlugin):
print(f' Found plugin class: {c.__module__}.{c.__name__}')
cls_instance = c()
for topic in cls_instance.topics:
print(f' Registering Topics: {topic}')
self.plugin_topic_instance_map[topic] = cls_instance
&lt;/code>&lt;/pre>
&lt;h4 id="execution">Execution&lt;/h4>
&lt;p>Now that we have a &lt;code>Map&amp;lt;Topic,instance&amp;gt;&lt;/code>. When a call comes in - it would have a topic and the args. Using the Map, we could get the corresponding instance and call by passing in both the topic and args. This is similar to delegate (&lt;strong>C#&lt;/strong>) or function pointers(in &lt;strong>C&lt;/strong>).&lt;/p>
&lt;pre>&lt;code>class ServiceDiscovery(object):
def __init__(self, plugin_package_dir='plugins'):
...
self.plugin_topic_instance_map = {}
def execute(self, topic, argument):
if topic not in self.plugin_topic_instance_map:
raise Exception (f'Topic: {topic} is not registered')
return self.plugin_topic_instance_map[topic].execute(topic, argument)
&lt;/code>&lt;/pre>
&lt;h4 id="unit-test">Unit Test:&lt;/h4>
&lt;p>Writing unit test is not optional. Well, I am a fan of TDD 😉&lt;/p>
&lt;pre>&lt;code>def test_cal_plugin_add_func(self):
# Arrange
ser_dis = ServiceDiscovery()
# Action
result = ser_dis.execute(&amp;quot;Add&amp;quot;, [1, 2])
# Assert
self.assertEqual(result, 3)
&lt;/code>&lt;/pre>
&lt;h4 id="deployment">Deployment:&lt;/h4>
&lt;p>Adding a new plugin should be as simple as&lt;/p>
&lt;ul>
&lt;li>Copy and paste a new directory under the Plugin base directory&lt;/li>
&lt;li>Directory should have a class which implements &lt;code>IPlugin&lt;/code>&lt;/li>
&lt;/ul>
&lt;h4 id="conclusion">Conclusion:&lt;/h4>
&lt;p>Building a comprehensive plugin infrastructure is non-trivial; look at Visual Studio - you could override pretty much anything, starting from adding intellisese to a new compiler tool chain. Here, we are just look at a small tip - to get started - on having a python based plugin. Always starting off any infra project with the idea of extension in mind - is good to ensure cleaner responsibility separation.&lt;/p>
&lt;p>From the &lt;strong>SOLID&lt;/strong> principle : &lt;strong>O&lt;/strong> -&amp;gt; our software should be Opened for extension but closed for modifications 😍&lt;/p></description></item><item><title>Minimalism is not Starving</title><link>https://jacobaloysious.in/post/vlog_minimalism_is_not_starving/</link><pubDate>Sat, 22 Aug 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/vlog_minimalism_is_not_starving/</guid><description>&lt;p>Getting Started:
&lt;a href="https://www.netflix.com/in/title/80114460" target="_blank" rel="noopener">Netflix Minimalism Documentary&lt;/a>. There are lots of articles and blogs online on Minimalism, so I am not gona give any gyans on it. Just my two cents on its interpretation and how it has helped me in a few ways.&lt;/p>
&lt;p>Let’s begin: Every time I bring up minimalism in a conversation, the initial (read, instinct) reaction has been - come ‘on I work really hard and earn money to be happy and happiness is definitely in getting the best of the things I like - Ok, I agree, the only question I have is - &lt;strong>how many of each?&lt;/strong>&lt;/p>
&lt;p>There is always this strange dilemma of need vs. want. We always want something - not because we need it, just because &lt;em>either it looks good or someone gave good reviews on it&lt;/em>.&lt;/p>
&lt;p>Its hard to acknowledge the fact that we all buy more than our need - unless we go through a declutter exercise. Below is the list of my declutter exercise - Not is any specific order&amp;hellip; just the dump.&lt;/p>
&lt;h3 id="gadgets">Gadgets:&lt;/h3>
&lt;p>Oculus VR headset and Echo Show - BTW, I didn’t buy them both - received as a gift for presenting at an engineering conference. I used the VR headset only &lt;strong>once&lt;/strong> (yes, just once). We never felt good about using it, but neither was I reluctant to give it away. I thought someday I will use it, and after ~1.5yrs - that day never showed up and it was still eating dust. Thanks to minimalism; I had the courage to sell it and bought something I would use every day for my new house. Same with Echo Show, its on it way out.&lt;/p>
&lt;h3 id="stationary">Stationary:&lt;/h3>
&lt;p>Just the intent of de-clutter; i realized - I actually had a pack of pens 10nos (arg! my Frugal Instinct) + pencil(s) + sharpener(s) + rubber(s) lying on my desk - btw, they were my own stock and not my daughters 😉. Similarly, with notebooks: 3 + 1 (rough + Journal) + sticky notes etc..&lt;/p>
&lt;p>&lt;em>&lt;strong>Question&lt;/strong>&lt;/em>: Do I need all of them? Obviously &lt;strong>NO!&lt;/strong>. Now - I just have 1 notebook + 1 pen Period!!
If my pen stops working or I lost my notebook - I will write it down on some digital platform (desktop or mobile -which doesn&amp;rsquo;t feel good), until I buy a new one. Thats Ok.&lt;/p>
&lt;h3 id="headsets">Headset(s):&lt;/h3>
&lt;p>There is a sense of guilt as I type this - I had accumulated almost 5 headsets (all working) and all for the same purpose - attend meetings. Minimalism enabled me to take a note:&lt;/p>
&lt;blockquote>
&lt;p>OnePlus; Anker Soundbuds Slim; JBL Reflect Mini; Sony WH-1000XM3; Bose SoundSport&lt;/p>
&lt;/blockquote>
&lt;p>All 5 of them were lying on my desk. There were times; I kept juggling around with each one - as I wasn&amp;rsquo;t sure which one had charge. On hindsight - I couldn&amp;rsquo;t convince myself, what was so motivating to buy (read upgrade) a new one. It could have been some fancy ad or one bad experience.&lt;/p>
&lt;p>Now I just use &lt;strong>ONE&lt;/strong> and I have the discipline to ensure I charge it each and every day at night - so that it is ready and available for the next day. For now the remaining ones are packed together and tucked away - I might sell it soon.&lt;/p>
&lt;h3 id="shoes">Shoes:&lt;/h3>
&lt;p>I had 5 (2 Running and 3 Badminton) - I don&amp;rsquo;t remember the last time I had played badminton; and about Running? Stop joking. Donated 3 of them and I am left with 2nos (1 each).&lt;/p>
&lt;p>&lt;em>&lt;strong>Question:&lt;/strong>&lt;/em> Why did I buy 3 Badminton shoes? Well, if you have been playing in a club - this is bound to happened (depends on your will power) -as your fellow mates might advise 1) Cushion in your shoe looks very slim, it might not take the impact and damage your knee 2) The grip doesn’t look good, you might slip and hurt yourself etc..They were right, but the point is - There is &lt;strong>ALWAYS&lt;/strong> something better out there; and you will never feel the sense of satisfaction&amp;hellip;&lt;/p>
&lt;h3 id="only-keyboard">Only Keyboard:&lt;/h3>
&lt;p>No mouse? Seriously?- Agree, this might sound a bit weird. I started with putting my mouse in the drawer. It was pretty challenging when starting off - but it’s possible.&lt;/p>
&lt;p>What did I do? Started learning and using &lt;strong>VIM extension&lt;/strong> - like
&lt;a href="https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb?hl=en" target="_blank" rel="noopener">For Chrome&lt;/a> and
&lt;a href="https://marketplace.visualstudio.com/items?itemName=vscodevim.vim" target="_blank" rel="noopener">For VSCode&lt;/a>. Browsing without mouse is a strange feeling, but its awesome - try it out, you might not go back to using a mouse! - also, makes you feel a bit geeky 😁. BTW, how is this related to Minimalism? Well, I had 3 mouse (fear of - it stops working and lockdown 😟)&lt;/p>
&lt;p>How VIM helped me as a developer (read, coding)? I will write a separate blog. BTW, VIM is 30yr old.&lt;/p>
&lt;h3 id="clothes">Clothes:&lt;/h3>
&lt;p>I don’t think anyone can escape this. Buying new clothes for a festival is not optional, and we have quite a few of them + sale. A Sunday evening declutter exercise - to my surprise I was able to get rid of ~60% of my wardrobe (donated), esp. the once which I thought would fit me (read, I will slim down) someday - and it’s been years. Now my cupboard looks very familiar (read neat) - I know exactly how many clothes I have and I can actually see each one of them 😍.&lt;/p>
&lt;p>I have just started off with Minimalism, not sure how far and long - I would get along - But, for now the change it has brought it&amp;hellip; I am really liking it and esp I am &lt;strong>NOT STARVING!!&lt;/strong>&lt;/p></description></item><item><title>VLog - First Bicycle Ride</title><link>https://jacobaloysious.in/post/vlog_first-bicycle-ride/</link><pubDate>Sat, 01 Aug 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/vlog_first-bicycle-ride/</guid><description>&lt;p>Technically it’s my first bicycle ride after ~20 years. I used to drive a lot during my school days. We used to cycle almost everywhere we went - school, tuitions, meet friends, cricket in beach, movies etc..&lt;/p>
&lt;blockquote>
&lt;p>Note: Locally we use Cycle (for Bicycle) and Bike (for motorcycle).&lt;/p>
&lt;/blockquote>
&lt;p>I never really had the motivation anytime recently to buy a Cycle - but I always had a good feeling of driving one (read, old memories).&lt;/p>
&lt;p>Fortunately I got hold of a cycle through a common friend (used one) - and I have to say it was pretty cool - &lt;strong>
&lt;a href="https://scott.sportnetwork.in/scott-aspect-950-mtb-black-bronze-my-2019.html" target="_blank" rel="noopener">Scott Aspect 950&lt;/a>&lt;/strong> an MTB. Honestly I wasn&amp;rsquo;t aware of this brand until I bought them 😉.&lt;/p>
&lt;p>Lot has changed since my cycling days in school. First thing - there were &lt;strong>gears&lt;/strong> and lots of &lt;strong>accessories&lt;/strong> sticking around the cycle - still trying to figure out what each one is for.&lt;/p>
&lt;p>Chennai is usually know for its hot weather. We jokingly comment, Chennai has three beautiful seasons - &lt;strong>Hot, Hotter and Hottest&lt;/strong> 😄.&lt;/p>
&lt;p>You remember those Fridays, where you slog yourself out and don&amp;rsquo;t really remember at what time you went and crashed on bed. The next day when you wake up - you kind of feel blank - It was one such Saturday. Evening around 5pm (Jul/26/2020) - the Chennai weather was unusual, it was cloudy and surprisingly with pleasant breeze - while sipping on my Tea - had a strange feeling to travel with the beautiful clouds.&lt;/p>
&lt;p>I decided to go for a ride. Due to C19 the roads were pretty empty (unusual for Chennai). Before I realized, I had already driven 15 kms; well 15k it’s that long - agree, but for a first timer -it was, I started to feel the strain on my knees. I forgot to carry water 😓 - was kindaa exhausted. In Chennai we have a lot of tea shops (well, they also serve bajji and I love it etc..) - and I am usually OK to go grab one, stand on the road and sip it. But, due to the pandemic, I wasn&amp;rsquo;t very comfortable.&lt;/p>
&lt;p>All that I could do was to just hang in there and think how to get back to home. Well, there were no other options - I have to drive all the way back. It started drizzling and I wasn&amp;rsquo;t prepared for the rains (no rain coat) too 😟. I started to drive back home with multiple pit stops almost every 2kms - luckily it was only drizzling, reached home around ~8pm.&lt;/p>
&lt;p>After I reached home, took a hot shower - ate something - and crashed into my bed and woke up only the next day ~9am. I have to say it was one of the most pleasant feeling I had in decades - &lt;strong>12+ hours of uninterupped sleep&lt;/strong> wow!!. I don&amp;rsquo;t remember the last time I slept so long - it was &lt;strong>DEEP SLEEP&lt;/strong> 😴. It was an unusual feeling; there was body pain - but I felt so good.&lt;/p>
&lt;p>Honestly - Just for the deep sleep - I would do this many more times. I hope, I can cycle for the rest of my life!! - Joy of cycling ❤️&lt;/p>
&lt;p>I feel guilty I didn’t click pictures, maybe next time.&lt;/p></description></item><item><title>Version control your install directory - GIT</title><link>https://jacobaloysious.in/post/tech_version_install_dir_git/</link><pubDate>Sun, 05 Jul 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_version_install_dir_git/</guid><description>&lt;h3 id="what-problem-are-we-trying-to-solve">What problem are we trying to Solve?&lt;/h3>
&lt;p>Context: Desktop software installed on client computer, inside a private network and no access to internet.&lt;/p>
&lt;h4 id="use-cases">Use Cases:&lt;/h4>
&lt;ul>
&lt;li>Shipping and applying multiple patches for a given version of the software.&lt;/li>
&lt;li>Reverting a patch&lt;/li>
&lt;li>Keeping track of patches installed&lt;/li>
&lt;li>Check for sanity of the installation and tack &lt;strong>manual&lt;/strong> edits (configuration files etc..)&lt;/li>
&lt;li>User can apply a temporary patch on a server (i.e. common machine) and test, once done revert&lt;/li>
&lt;/ul>
&lt;h3 id="how-are-we-trying-to-solve">How are we trying to solve?&lt;/h3>
&lt;p>Bring the content of the install directory under version control. We will be using GIT version control, to explain how it could be achived.&lt;/p>
&lt;blockquote>
&lt;p>PreRequisite &amp;ldquo;git&amp;rdquo; should be installed and available in the path&lt;/p>
&lt;/blockquote>
&lt;h3 id="why-use-git">Why use GIT?&lt;/h3>
&lt;p>
&lt;a href="https://git-scm.com/" target="_blank" rel="noopener">Git&lt;/a> is a distributed version control system designed to handle everything from small to very large projects with speed and efficiency.&lt;/p>
&lt;p>So, with Git any &lt;strong>local folder&lt;/strong> can be converted into a &lt;strong>git repository&lt;/strong> by just running the &lt;strong>init&lt;/strong> command.&lt;/p>
&lt;pre>&lt;code>D:\Foo\1.0.0&amp;gt;git init
Initialized empty Git repository in D:/Foo/1.0.0/.git/
&lt;/code>&lt;/pre>
&lt;p>Now your installed directory is version controlled. You can add files, commit, create branch(s), switch branches etc&amp;hellip; Since Git is distributed - &lt;strong>N0 Server nor Internet required&lt;/strong> 😄&lt;/p>
&lt;p>At any point of time, you could use &lt;strong>status&lt;/strong> to check if the install directory has any &lt;strong>modified&lt;/strong>, &lt;strong>new&lt;/strong> or &lt;strong>deleted&lt;/strong> files.&lt;/p>
&lt;pre>&lt;code>D:\Foo\1.0.0&amp;gt;git status
On branch base_install
Changes not staged for commit:
(use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to update what will be committed)
(use &amp;quot;git checkout -- &amp;lt;file&amp;gt;...&amp;quot; to discard changes in working directory)
modified: config/params.toml
Untracked files:
(use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to include in what will be committed)
config/menus.toml
config/languages.toml
&lt;/code>&lt;/pre>
&lt;p>You could use &lt;strong>git diff&lt;/strong> command to compare changes across two branches like &lt;strong>base_install&lt;/strong> vs &lt;strong>patch_1&lt;/strong>&lt;/p>
&lt;pre>&lt;code>D:\Foo\1.0.0&amp;gt;git diff base_install patch_1
diff --git a/Config/params.toml
index b32de60..e8e1694 100644
--- a/Config/params.toml
+++ b/Config/params.toml
@@ -29,7 +29,7 @@
- main_menu = {align = &amp;quot;l&amp;quot;, show_logo = true}
+ main_menu = {align = &amp;quot;l&amp;quot;, show_logo = false}
&lt;/code>&lt;/pre>
&lt;p>Creating a branch is a trivial operation. As a user you could&lt;/p>
&lt;ul>
&lt;li>Create a new (personal) branch from current (master) branch&lt;/li>
&lt;li>Apply the patch files (edit or new) -&amp;gt; Commit your changes to your &lt;em>personal&lt;/em> branch&lt;/li>
&lt;li>Run your tests&lt;/li>
&lt;li>Once you are done, switch to the original (master) branch&lt;/li>
&lt;/ul>
&lt;p>If you observe - &lt;strong>you don&amp;rsquo;t have to delete your patch&lt;/strong> - at any point of time when you have server time you could come back and switch to your branch&amp;hellip;&lt;/p>
&lt;pre>&lt;code>D:\Foo\1.0.0&amp;gt;git checkout jac_logo_patch
Switched to branch 'jac_logo_patch'
&lt;/code>&lt;/pre>
&lt;h2 id="installer-workflow-and-scripts-sequence">Installer workflow and Scripts sequence&amp;hellip;&lt;/h2>
&lt;h3 id="post-install">POST INSTALL&lt;/h3>
&lt;ol>
&lt;li>Installer should copy this file into the root of destination directory and execute&lt;/li>
&lt;li>Example: &amp;ldquo;D:\Foo\&amp;laquo;_Build_Number_&amp;raquo;&amp;rdquo;&lt;/li>
&lt;li>Run this file post installation&lt;/li>
&lt;/ol>
&lt;h4 id="steps">Steps:&lt;/h4>
&lt;ol>
&lt;li>Initialize git.&lt;/li>
&lt;li>Create a .gitignore file.&lt;/li>
&lt;li>Add contents into .gitignore.&lt;/li>
&lt;li>Create a branch &lt;strong>base_Install&lt;/strong>.&lt;/li>
&lt;li>Commit all contents into git repo with msg &lt;em>Base Install Commit&lt;/em>.&lt;/li>
&lt;/ol>
&lt;pre>&lt;code class="language-bash">@echo off
echo Initializing Git
call git init
echo Add git ignore files
call touch .gitignore
echo Add files to .git ignore for installer cmd files
call PostInstall.cmd &amp;gt;&amp;gt; .gitignore
echo Add all the files and create a initial commit named Base Install. This would take a while!!
call git add -A &amp;amp;&amp;amp; git commit -m &amp;quot;Base Install Commit&amp;quot;
echo Creating a new branch base_install
call git branch base_install
&lt;/code>&lt;/pre>
&lt;h3 id="patch-installer">PATCH INSTALLER&lt;/h3>
&lt;h4 id="pre-install">PRE INSTALL&lt;/h4>
&lt;p>Copy this file into the root of destination directory - D:\Foo\&amp;laquo;Build_Number&amp;raquo;&amp;rdquo;&lt;/p>
&lt;ol>
&lt;li>Check if branch exists&lt;/li>
&lt;li>Add all existing UNTRACKED FILES into the current branch&lt;/li>
&lt;li>Add add a commit message &lt;strong>PrePatch_&amp;lt;PATCH_NAME&amp;gt;&lt;/strong>&lt;/li>
&lt;li>Add the current branch to a known file &lt;strong>LastKnownWorkingBranch&lt;/strong>; useful for un-installation&lt;/li>
&lt;li>Create a &lt;em>new branch&lt;/em> &lt;strong>PATCH_&amp;lt;PATCH_NAME&amp;gt;&lt;/strong>&lt;/li>
&lt;li>Switch to new branch with PATCH_&amp;lt;PATCH_NAME&amp;gt;&lt;/li>
&lt;li>Apply the patch using &lt;strong>git am&lt;/strong>. Note: &lt;strong>am&lt;/strong> would allow you to sign off an applied patch. This maybe useful for future reference.&lt;/li>
&lt;li>Add all existing UNTRACKED FILES into new/current branch i.e. PATCH_&amp;lt;PATCH_NAME&amp;gt;&lt;/li>
&lt;li>Done - we have a new branch with all patches&lt;/li>
&lt;/ol>
&lt;pre>&lt;code class="language-bash">REM TODO: This could be an enviornment variable
set patchName=Patch_1
set branchName=Patch_%patchName%
echo Check if git installed
call git --version
if ERRORLEVEL 1 (
echo Git not installed!!!
goto :Cleanup
)
echo Check if valid git repository
call git rev-parse --is-inside-work-tree
if ERRORLEVEL 1 (
echo Not a valid git repo : %cd%
REM TODO - Should we create a new git repo? or fall back scripts to use .keep solution
goto :Cleanup
)
set commitMsg=&amp;quot;PrePatch_%patchName%&amp;quot;
echo Add all un-tracked files and create a
call git add -A &amp;amp;&amp;amp; git commit -m %commitMsg%
echo Add the current branch name into a temporary file - LastKnownWorkingBranch
call git symbolic-ref --short HEAD &amp;gt; LastKnownWorkingBranch
echo Check if branch exits
git rev-parse --verify %branchName%
if ERRORLEVEL 0 (
echo Branch exists : %branchName%
)
echo Create a new branch
git branch %branchName%
echo Checkout the new branch
git checkout %branchName%
echo Apply the .git patch
git am --signoff &amp;lt; %patchName%.patch
:Cleanup
echo exit
&lt;/code>&lt;/pre>
&lt;p>User can always go back to the base install by switching branches.&lt;/p>
&lt;h3 id="post-install-1">POST INSTALL&lt;/h3>
&lt;h4 id="steps-1">Steps&lt;/h4>
&lt;ol>
&lt;li>Now we are in the new branch for the Patch&lt;/li>
&lt;li>And install script has already installed all the patch files&lt;/li>
&lt;li>Just commit all the changes and we are good to go!!&lt;/li>
&lt;li>Patch installation done!!&lt;/li>
&lt;/ol>
&lt;pre>&lt;code class="language-bash">REM TODO: This should be an enviornment variable
set patchName=Patch_1
set branchName=Patch_%patchName%
set commitMsg=&amp;quot;Patch_%patchName%&amp;quot;
echo Add all un-tracked files and create a
call git add -A &amp;amp;&amp;amp; git commit -m %commitMsg%
echo Patch installed and avaialble in branch %branchName%
&lt;/code>&lt;/pre>
&lt;h3 id="patch-un-installer">PATCH UN-INSTALLER&lt;/h3>
&lt;h4 id="steps-2">Steps&lt;/h4>
&lt;ol>
&lt;li>Read the &lt;strong>lastKnownWorkingBranch&lt;/strong> from a file&lt;/li>
&lt;li>git checkout lastKnownWorkingBranch&lt;/li>
&lt;li>Voila thats it!!&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;strong>Note:&lt;/strong> File &amp;ldquo;lastKnownWorkingBranch&amp;rdquo; file should be under .gitignore (?) so that its shared across branches and its updated only by the patch installer.&lt;/p>
&lt;/blockquote>
&lt;pre>&lt;code class="language-bash">for /f &amp;quot;delims=&amp;quot; %%a in ('type LastKnownWorkingBranch') do (
set lastKnownWorkingBranch=%%a
break
)
echo lastKnownWorkingBranch: %lastKnownWorkingBranch%
echo Checkout the lastKnownWorkingBranch: %lastKnownWorkingBranch%
git checkout %lastKnownWorkingBranch%
echo Voila we have reverted the previous install
&lt;/code>&lt;/pre>
&lt;h2 id="advantages">ADVANTAGES&lt;/h2>
&lt;ul>
&lt;li>User could compare what has changed across branches aka patches&lt;/li>
&lt;li>User could always go back to base_install at any point of time&lt;/li>
&lt;li>Files are never deleted&lt;/li>
&lt;li>Uninstall is just switching a branch - no file deletes.&lt;/li>
&lt;li>Any number of branches can be created for &lt;strong>personal&lt;/strong> testing.&lt;/li>
&lt;/ul></description></item><item><title>Book - Atomic Habits by James Clear</title><link>https://jacobaloysious.in/post/book_atmoic-habits/</link><pubDate>Sun, 21 Jun 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/book_atmoic-habits/</guid><description>&lt;p>As of today (Jun'2020) - If someone asks me if there is ONE book I could recommend - without a second thought - it would be this book.
Irrespective of profession or title - this book will definitely ring a bell.&lt;/p>
&lt;p>The book covers what could be considered as ideas of common sense, but presents these ideas in a well-organized, clear, practical and logical way in developing good habits.&lt;/p>
&lt;p>One of the first questions in the book was - &amp;ldquo;&lt;em>Write down your current habits&lt;/em>&amp;quot;. I tried and honestly there was NONE - except for the trivial ones like brush/sleep.. It was a good ice breaker for me to start thinking.&lt;/p>
&lt;h3 id="key-takeaways">Key Takeaways:&lt;/h3>
&lt;blockquote>
&lt;p>“Habits do not restrict freedom. They create it. Building habits in the present allows you to do more of what you want in the future.”&lt;/p>
&lt;/blockquote>
&lt;h4 id="habit-stacking">Habit stacking:&lt;/h4>
&lt;p>If you have an existing habit - which is working well. Add the &lt;strong>new&lt;/strong> habit along/right before or after the existing one. So that the environment is already set - and you don&amp;rsquo;t need additional motivation. In my case, &amp;ldquo;writing Journal as I have tea&amp;rdquo;. Tea is a must have for me, I can never skip it - so why not add a habit while I drink it 😄. Previously I always lacked the motivation to write/continue a Journal.&lt;/p>
&lt;h4 id="habit-cues">Habit Cues:&lt;/h4>
&lt;p>Setting up the environment for doing the habits. The environment should be both enabling and welcoming you to do your habits. In my case, before I sleep, I ensure - I keep the Journal book on the dining table - where I have my tea. And Kindle on my pillow, so I see it when I go to bed.&lt;/p>
&lt;p>&lt;strong>On bad habits&lt;/strong> - one of the practical way is to reduce exposure - like hide the TV remote so its hard to find 😉&lt;/p>
&lt;blockquote>
&lt;p>“&lt;em>it is easier to avoid temptation than resist it&lt;/em>.”&lt;/p>
&lt;/blockquote>
&lt;h4 id="compound-effect">Compound Effect:&lt;/h4>
&lt;p>Very small change overtime will have a great impact. I have started realizing that as my reading time and consistency has improved.&lt;/p>
&lt;p>One month after I completed this book, as I am writing this blog. I have a list of things &amp;hellip;
&lt;strong>Start of Day:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Wakeup, Clean the dust bin at home&lt;/li>
&lt;li>5 min workout (it isn’t much, but makes a difference for me)&lt;/li>
&lt;li>Freshen up, Make Tea&lt;/li>
&lt;li>Write Journal Book - Plan for the day (as I have tea)&lt;/li>
&lt;li>Read a technical book ( Kindle)&lt;/li>
&lt;li>Off to work&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>End of the day:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Update the Journal, review the day&lt;/li>
&lt;li>Keep the Journal at the dining table (where, I have my tea)&lt;/li>
&lt;li>Pray/Gratitude&lt;/li>
&lt;li>Read a non-tech/non-fiction book (Kindle)&lt;/li>
&lt;li>Sleep&lt;/li>
&lt;/ul>
&lt;p>There isn’t much - but still I feel a change - I have something that I could call as a habit - be it writing a journal or having a planned reading time. Thanks to this book - which gave me both the framework (practical ways of implementing a system) and the motivation in building habits.&lt;/p>
&lt;blockquote>
&lt;p>“Every action you take is a vote for the type of person you wish to become. No single instance will transform your beliefs, but as the votes build up, so does the evidence of your new identity.”&lt;/p>
&lt;/blockquote>
&lt;p>I addition to having a Kindle copy - I am planning to order a hard copy - I hope it shall be a visible reminder - to add a new &lt;strong>Good&lt;/strong> habit and get rid of the &lt;strong>bad&lt;/strong> habit. I believe - even if the book it doesn’t completely change your behavior, it will make you more &lt;strong>aware&lt;/strong> of yourself.&lt;/p>
&lt;h4 id="highly-recommended">Highly Recommended!!&lt;/h4></description></item><item><title>Book - My Good Reads, Technical</title><link>https://jacobaloysious.in/post/book_list-tech-books/</link><pubDate>Sun, 14 Jun 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/book_list-tech-books/</guid><description>&lt;h2 id="podcasts">Podcasts&lt;/h2>
&lt;ul>
&lt;li>
&lt;a href="https://www.hanselminutes.com/" target="_blank" rel="noopener">Hanselminutes&lt;/a>, by Scott Hanselman&lt;/li>
&lt;li>
&lt;a href="https://www.dataengineeringpodcast.com/" target="_blank" rel="noopener">Data Engineering&lt;/a>, by Tobias Macey&lt;/li>
&lt;li>
&lt;a href="https://talkpython.fm/" target="_blank" rel="noopener">Talk Python To Me&lt;/a>, by Michael Kennedy&lt;/li>
&lt;li>
&lt;a href="https://pythonbytes.fm/" target="_blank" rel="noopener">Python Bytes&lt;/a>, by Michael Kennedy and Brian Okken&lt;/li>
&lt;li>
&lt;a href="https://www.dotnetrocks.com/" target="_blank" rel="noopener">.Net Rocks&lt;/a>, by Carl Franklin and Richard Campbell&lt;/li>
&lt;/ul>
&lt;h2 id="in-progress">In Progress&lt;/h2>
&lt;ul>
&lt;li>
&lt;a href="https://www.shroffpublishers.com/books/9789351100744/" target="_blank" rel="noopener">MongoDB Applied Design Patterns&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/" target="_blank" rel="noopener">Designing Data-Intensive Applications&lt;/a>, by Martin Kleppmann&lt;/li>
&lt;/ul>
&lt;h2 id="done">Done&lt;/h2>
&lt;ul>
&lt;li>
&lt;a href="https://www.manning.com/books/big-data" target="_blank" rel="noopener">Big Data: Lamda Architecture&lt;/a>, by Nathan Marz and James Warren&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/36411996-docker-deep-dive" target="_blank" rel="noopener">Docker Deep Dive&lt;/a>, by Nigel Poulton&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/35516296-chaos-engineering" target="_blank" rel="noopener">Chaos Engineering&lt;/a> by Casey Rosenthal&lt;/li>
&lt;li>
&lt;a href="https://www.manning.com/books/c-sharp-in-depth-fourth-edition" target="_blank" rel="noopener">C# in Depth&lt;/a>, by Jon Skeet&lt;/li>
&lt;li>
&lt;a href="https://git-scm.com/book/en/v2" target="_blank" rel="noopener">Pro Git&lt;/a>, by Scott Chacon and Ben Straub&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/clean-code/9780136083238/" target="_blank" rel="noopener">Clean Code&lt;/a>, by Robert C Martin&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/" target="_blank" rel="noopener">Clean Architecture&lt;/a>, by Robert C Martin&lt;/li>
&lt;li>
&lt;a href="https://www.oreilly.com/library/view/working-effectively-with/0131177052/" target="_blank" rel="noopener">Working Effectively with Legacy Code&lt;/a>, by Michael Feathers&lt;/li>
&lt;/ul></description></item><item><title>Review - Forest App</title><link>https://jacobaloysious.in/post/diary_forest_app/</link><pubDate>Tue, 09 Jun 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_forest_app/</guid><description>&lt;p>I have been recently fascinated by this idea of &lt;strong>getting into the flow&lt;/strong> - to get work done.&lt;/p>
&lt;p>Since I am working from home (due to Covid19); personally it’s quite challenging to manage interruptions and get focussed time - to get things done - so that I get to feel productive over the work week.&lt;/p>
&lt;p>I started to look around for help and stumbled upon -
&lt;a href="https://en.wikipedia.org/wiki/Pomodoro_Technique" target="_blank" rel="noopener">Pomodoro Technique&lt;/a>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>The Pomodoro Technique is a time management method developed by Francesco Cirillo in the late 1980s.
The technique uses a timer to break down work into intervals, traditionally 25 minutes in length, separated by short breaks.
Each interval is known as a pomodoro, from the Italian word for &amp;lsquo;tomato&amp;rsquo;, after the tomato-shaped kitchen timer that Cirillo used as a university student&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>First: I tried to use my phone alarm - set to 25mins from now. It didn&amp;rsquo;t work - lost motivation to set up an alarm each time.&lt;/p>
&lt;p>Next: Downloaded an app which supports Pomodoro Technique; it was better - but still I wasn&amp;rsquo;t completely in - I continue to get pulled into looking at my phone/emails.&lt;/p>
&lt;p>Finally: As part of one of the self-help videos - I was introduced to this app
&lt;a href="https://www.forestapp.cc" target="_blank" rel="noopener">&lt;strong>FOREST&lt;/strong> - Stay focussed, be Present&lt;/a>. First time I started using it - fell in love with it 😍.&lt;/p>
&lt;h4 id="idea-behind-forest-app---is-pretty-simple">Idea behind Forest app - is pretty simple:&lt;/h4>
&lt;ul>
&lt;li>Whenever you want to stay focussed, plant a tree.&lt;/li>
&lt;li>Your tree will grow while you focus on your work.&lt;/li>
&lt;li>Leaving the app halfway will cause your tree to Die.&lt;/li>
&lt;/ul>
&lt;p>Over the day-weeks-month you could see how many trees you have planted and how your forest looks like.
And when you review your progress, its a visual treat to see the number of trees you have planted in your forest 😆&lt;/p>
&lt;p>This app gives you - both a feeling that you are growing something (visual stimulation) and at the same time getting work done (stay productive).&lt;/p>
&lt;p>I personally prefer apps - which does only one thing and does it really well - this is one such app..&lt;/p>
&lt;p>Nowadays: When I am planting a tree (read, focussed time) - when I get some notification - the urge for me to check it out is NO longer there. Coz; if I need to check the notification - I would have to quit the app and if I quit the app &lt;strong>my tree&lt;/strong>, which I have been planting all this while - &lt;strong>would die&lt;/strong>.&lt;/p>
&lt;p>A simple but a beautiful idea. Taking us closer to our goal of getting into the flow and getting things done - In addition giving a visual treat.&lt;/p>
&lt;p>I am growing a new tree as I write this.. Highly recommended! 😄&lt;/p></description></item><item><title>Diary - 4 Movies per weekend - TO - One in 4 Weekends</title><link>https://jacobaloysious.in/post/diary_4_movies_1_movie/</link><pubDate>Sun, 24 May 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/diary_4_movies_1_movie/</guid><description>&lt;p>Its week #7 in lockdown - Work From Home (WFH) due to COVID19 at Chennai, India.&lt;/p>
&lt;p>First two weeks was just chaotic to be honest&amp;hellip; Week #3, on a Wednesday - I was about to have lunch and was feeling incredibly exhausted (read burn out) 😓.
Since it was already half the week, took a moment to pause and look at how productive I was in this week. To my dismay, I couldn&amp;rsquo;t add even one single item onto my &lt;strong>Done list&lt;/strong>.&lt;/p>
&lt;p>I knew something was not right, wanted to dig deep - I looked at my calendar and realized there wasn&amp;rsquo;t even a single 1hr free slot.
I counted the number of meeting I have attended &lt;em>only&lt;/em> this week till now - it was &lt;strong>25! Planned meeting&lt;/strong>, this is excluding adhoc phone calls and IM chat(s) discussion/queries.&lt;/p>
&lt;p>I decided to go back a little and see how my past 2 weeks have been, and it wasn&amp;rsquo;t any better. Though the team was delivering and it was business as usual - personally felt I was low on my &lt;em>actual&lt;/em> contribution/work.&lt;/p>
&lt;p>In the mean time - Scott had
&lt;a href="https://twitter.com/shanselman/status/1252040170783641600?lang=en" target="_blank" rel="noopener">tweeted this&lt;/a>&lt;/p>
&lt;pre>&lt;code> Qurantine_Work != Remote_Work
&lt;/code>&lt;/pre>
&lt;p>I could easily relate to him - there were lot of additional chores I was running into esp with a 5yr old kid at home.
If the worlds best productivity guru is talking about &lt;em>burn out&lt;/em> - it actually feels good to know &amp;ldquo;I am not alone and its Ok&amp;rdquo;.&lt;/p>
&lt;p>Since these are abnormal times, there wasn&amp;rsquo;t much I could do to fix my week day plans - decided to hang in there and go with the flow - for now!!&lt;/p>
&lt;p>So, I decided to take a look at how I was doing over weekends - &lt;strong>&amp;ldquo;Binge Watching!!&amp;quot;&lt;/strong> ➿. As a movie buff, I always thought watching movies (more&amp;hellip;) was relaxing, but it wasn&amp;rsquo;t. It was just adding more strain - as I wasn&amp;rsquo;t spending enough time with family and supporting house hold chores. And when the weekend actually ended I was feeling more exhausted.&lt;/p>
&lt;p>I needed support - So, I went online and started looking for productivity tips. And I stumbled up this one adhoc tip, which hit the nail - &lt;strong>Light Bulb Moment!!&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Always watch movies (tv shows) - only when you have someone to accompany you&lt;/p>
&lt;/blockquote>
&lt;p>Personally, this was possibly the best tip - I decided, from now onwards I am never gona watch any movie alone - &lt;strong>It was an extremely hard decision&lt;/strong>.&lt;/p>
&lt;p>Four weeks later, when I look back - I have watched just ONE movie (with my wife). Personally, feels much better - I feel I have lots of time over the weekend. I am able to spend time more effectively - writing a blog (like this), call up friends/ family and even try a hand on cooking (making tea 😉).&lt;/p>
&lt;p>At the end of the day - I still get to work.. I am blessed. No Lie. ❤️ 💻 😌&lt;/p>
&lt;h5 id="for-now--stay-home-stay-safe---and-remember---this-too-will-pass-">For now &amp;hellip; Stay home, Stay Safe - and remember - This too will pass !!&lt;/h5></description></item><item><title>Book - My Good Reads, Non-Technical</title><link>https://jacobaloysious.in/post/book_list-non-tech-books/</link><pubDate>Sat, 23 May 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/book_list-non-tech-books/</guid><description>&lt;h2 id="in-progress">In Progress&lt;/h2>
&lt;ul>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/31138556-homo-deus" target="_blank" rel="noopener">Homo Deus: A History of Tomorrow&lt;/a>, by Yuval Noah Harari&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/37976541-bad-blood" target="_blank" rel="noopener">Bad Blood&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/29342515-the-coaching-habit" target="_blank" rel="noopener">The Coaching Habit&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/55557541-practical-ways-to-manage-yourself" target="_blank" rel="noopener">Practical Ways to Manage Yourself&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="done">Done&lt;/h2>
&lt;h4 id="2021">2021:&lt;/h4>
&lt;ul>
&lt;li>Backlog:
&lt;a href="https://www.goodreads.com/book/show/27213329-grit" target="_blank" rel="noopener">GRIT&lt;/a>,
&lt;a href="https://www.goodreads.com/book/show/48855.The_Diary_of_a_Young_Girl" target="_blank" rel="noopener">The Diary of a Young Girl&lt;/a>&lt;/li>
&lt;/ul>
&lt;h4 id="2020">2020:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/67825.Peopleware" target="_blank" rel="noopener">Peopleware: Productive Projects and Teams&lt;/a>, by Tom DeMarco, Timothy R. Lister&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/16248196-the-art-of-thinking-clearly" target="_blank" rel="noopener">Art of Thinking Clearly&lt;/a>, by Rolf Dobelli&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/13099738-steal-like-an-artist" target="_blank" rel="noopener">Steal Like An Artist&lt;/a>, by Austin Kleon&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/37880811-make-time" target="_blank" rel="noopener">Make Time&lt;/a>, by Jake Knapp &amp;amp; John Zeratsky&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/en/book/show/38821039" target="_blank" rel="noopener">The Making of a Manager&lt;/a>, by Julie Zhuo&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/40121378-atomic-habits" target="_blank" rel="noopener">Atomic Habits&lt;/a>, by James Clear&lt;/li>
&lt;li>
&lt;a href="https://www.ynharari.com/book/sapiens/" target="_blank" rel="noopener">Sapiens&lt;/a>, by Yuval Noah Harari&lt;/li>
&lt;li>
&lt;a href="https://austinkleon.com/show-your-work/" target="_blank" rel="noopener">Show Your Work&lt;/a>, by Austin Kleon&lt;/li>
&lt;li>
&lt;a href="https://sivers.org/a" target="_blank" rel="noopener">Anything You Want&lt;/a>, by Derek Sivers&lt;/li>
&lt;li>
&lt;a href="https://www.mitchalbom.com/books/tuesdays-with-morrie/" target="_blank" rel="noopener">Tuesdays with Morrie&lt;/a>, by Mitch Albom&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/25899336-when-breath-becomes-air" target="_blank" rel="noopener">When Breath Becomes Air&lt;/a>, by Dr. Paul Kalanithi&lt;/li>
&lt;li>
&lt;a href="https://www.amazon.in/Ikigai-H%C3%A9ctor-Garc%C3%ADa/dp/178633089X" target="_blank" rel="noopener">Ikigai&lt;/a>, by Hector Garcia and Francesc Miralles&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/35697998-the-joy-of-leadership" target="_blank" rel="noopener">The Joy of Leadership&lt;/a>, by Tal Ben-Shahar, Angus Ridgway&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/15824362-conquering-the-chaos" target="_blank" rel="noopener">Conquering the Chaos&lt;/a>, by Ravi Venkatesan&lt;/li>
&lt;/ul>
&lt;h4 id="2019">2019:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/4069.Man_s_Search_for_Meaning" target="_blank" rel="noopener">Man&amp;rsquo;s Search For Meaning&lt;/a>, by Vicktor E. Frankl&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/18144590-the-alchemist" target="_blank" rel="noopener">The Alchemist&lt;/a>, by Coelho Paulo&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/15014.Crucial_Conversations" target="_blank" rel="noopener">Crucial Conversations&lt;/a>, by Kerry Patterson, Joseph Grenny, Ron McMillan,&lt;/li>
&lt;/ul>
&lt;h4 id="older">Older:&lt;/h4>
&lt;ul>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/4894.Who_Moved_My_Cheese_" target="_blank" rel="noopener">Who Moved My Cheese&lt;/a>, by Spencer Johnson&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/60283.The_Present" target="_blank" rel="noopener">The Present&lt;/a>, spencer Johnson&lt;/li>
&lt;li>The Situational Leader, by Paul Hersey&lt;/li>
&lt;/ul>
&lt;h2 id="backlog">Backlog&lt;/h2>
&lt;ul>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/37976541-bad-blood" target="_blank" rel="noopener">Bad Blood: Secrets and Lies in a Silicon Valley Startup&lt;/a> by John Carreyrou&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/38820046-21-lessons-for-the-21st-century" target="_blank" rel="noopener">21 Lessons for the 21st Century&lt;/a>, by Yuval Noah Harari)&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/16181775-the-rosie-project" target="_blank" rel="noopener">The Rosie Project&lt;/a>, by Graeme Simsion&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/34342016-elastic" target="_blank" rel="noopener">Elastic: Flexible Thinking in a Time of Change&lt;/a>, by Leonard Mlodinow&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/en/book/show/50714359-the-unfair-advantage" target="_blank" rel="noopener">The Unfair Advantage&lt;/a>, by Ash Ali, Hasan Kubba&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/449573.The_Theory_of_Everything" target="_blank" rel="noopener">The Theory of Everything: The Origin and Fate of the Universe&lt;/a>, by Stephen Hawking&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/3869.A_Brief_History_of_Timei" target="_blank" rel="noopener">A Brief History of Time&lt;/a> by Stephen Hawking&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/17788725-the-motivation-hacker" target="_blank" rel="noopener">The Motivation Hacker&lt;/a>, by Nick Winter&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/36072.The_7_Habits_of_Highly_Effective_People" target="_blank" rel="noopener">7 Habits of Highly Effective People&lt;/a>, by Stephen R.Covey&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/3063393-pragmatic-thinking-and-learning" target="_blank" rel="noopener">Pragmatic Thinking and Learning&lt;/a>, by Andy Hunt&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/22571656-the-happiness-equation" target="_blank" rel="noopener">The Happiness Equation&lt;/a>, by Neil Pasricha&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/4866.How_to_Stop_Worrying_and_Start_Living" target="_blank" rel="noopener">How to Stop Worrying and Start Living&lt;/a>, by Dale Carnegie&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/4865.How_to_Win_Friends_and_Influence_People" target="_blank" rel="noopener">How to Win Friends and Influence People&lt;/a>, by Dale Carnegie&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/29939161-radical-candor" target="_blank" rel="noopener">Radical Candor&lt;/a>, by Kim Malone Scott&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/1317946.Managing_Humans" target="_blank" rel="noopener">Managing Humans&lt;/a>, by Michael Lopp&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/21343.The_Five_Dysfunctions_of_a_Team" target="_blank" rel="noopener">The Five Dysfunctions of a Team&lt;/a>, by Patrick Lencioni&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/324750.High_Output_Management" target="_blank" rel="noopener">High Output Management&lt;/a>, by Andrew S. Grove&lt;/li>
&lt;/ul>
&lt;h2 id="started-and-shelved-">Started and Shelved 😞&lt;/h2>
&lt;ul>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/41795733-range" target="_blank" rel="noopener">Range: Why Generalists Triumph in a Specialized World&lt;/a>, by David Epstein&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/143880.The_Book_of_Life" target="_blank" rel="noopener">The Book of Life&lt;/a>, by Jiddu Krishnamurti&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/34684622-leonardo-da-vinci" target="_blank" rel="noopener">Leonardo da Vinci Autobiogrphy&lt;/a>, by Walter Isaacson&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/368593.The_4_Hour_Workweek?ac=1&amp;amp;from_search=true&amp;amp;qid=ePtTHyOIm7&amp;amp;rank=3" target="_blank" rel="noopener">The 4-Hour Work Week&lt;/a>, by Timothy Ferriss&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/34066798-a-gentleman-in-moscow" target="_blank" rel="noopener">A Gentleman in Moscow&lt;/a>, by Towles Amor&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/34890015-factfulness" target="_blank" rel="noopener">Factfulness&lt;/a>, Rosling Hans&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/17851885-i-am-malala" target="_blank" rel="noopener">I am Malala&lt;/a>, by Malala Yousafzai, Christina Lamb&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow" target="_blank" rel="noopener">Thinking, Fast and Slow&lt;/a>, by Daniel Kahneman&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/43877.The_Monk_Who_Sold_His_Ferrari" target="_blank" rel="noopener">The Monk Who Sold His Ferrari&lt;/a>, by Robin Sharma&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/25431805-the-leader-who-had-no-title" target="_blank" rel="noopener">The Leader Who Had No Title&lt;/a>, by Robin Sharma&lt;/li>
&lt;li>
&lt;a href="https://penguin.co.in/book/the-doctor-and-the-saint/" target="_blank" rel="noopener">The Doctor and the Saint&lt;/a>, by Arundhati Roy&lt;/li>
&lt;li>
&lt;a href="https://www.goodreads.com/book/show/29513878-inner-engineering" target="_blank" rel="noopener">Inner Engineering: A Yogi’s Guide to Joy&lt;/a>, by Sadhguru&lt;/li>
&lt;/ul></description></item><item><title>Tech - My Website</title><link>https://jacobaloysious.in/post/tech_my-website/</link><pubDate>Wed, 20 May 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/tech_my-website/</guid><description>&lt;p>I registered my domain name on
&lt;a href="https://in.godaddy.com/" target="_blank" rel="noopener">GoDaddy&lt;/a> couple of years back (2018). I can&amp;rsquo;t really remember the motivation to get one registered.
I almost forgot about this, until I got a reminder to renew.&lt;/p>
&lt;p>Thanks to
&lt;a href="https://www.hanselman.com/" target="_blank" rel="noopener">Scott&lt;/a>, I realized the importance of key stroke - the nubmer of keystroke in your life time are finite. So if you worked on something interesting - why waste it in an email which you are never sure the recipient may or not read. Instead, write it in a blog and it would be there forever and could potentially help someone new in future.&lt;/p>
&lt;p>On hindsight - this website should have ideally taken less than half a day to setup, but I ended up spending almost 2 days to set the first version. Well I was just getting my hands dirty.&lt;/p>
&lt;p>This is a static website:&lt;/p>
&lt;ol>
&lt;li>Original Content on
&lt;a href="https://github.com/jacobaloysious/" target="_blank" rel="noopener">GitHub&lt;/a> - my private repo&lt;/li>
&lt;li>Static files Generated using
&lt;a href="https://gohugo.io/" target="_blank" rel="noopener">HUGO Extended&lt;/a>&lt;/li>
&lt;li>Themes from
&lt;a href="https://themes.gohugo.io/academia-hugo/" target="_blank" rel="noopener">Academia&lt;/a>&lt;/li>
&lt;li>Static files Hosted on
&lt;a href="https://aws.amazon.com/s3" target="_blank" rel="noopener">AWS S3&lt;/a>&lt;/li>
&lt;li>Domain DNS
&lt;a href="https://aws.amazon.com/route53/" target="_blank" rel="noopener">AWS Route S3&lt;/a>&lt;/li>
&lt;li>Continous Deployment
&lt;a href="https://github.com/features/actions" target="_blank" rel="noopener">Github Actions&lt;/a>&lt;/li>
&lt;/ol>
&lt;h3 id="godaddy">Godaddy&lt;/h3>
&lt;p>This is a very trivial step, go to
&lt;a href="https://in.godaddy.com/" target="_blank" rel="noopener">GoDaddy&lt;/a>. Search if your expected domain name is available. If yes, just follow the steps that show up.
Note: There are many providers GoDaddy is just one of them. I dont have a good reason why I chose GoDaddy or I haven&amp;rsquo;t seen a good reason to try other providers (read, lazy me).&lt;/p>
&lt;h3 id="hugo">Hugo&lt;/h3>
&lt;p>Hugo again has extensive documentation (bit overwhelming at times) on setting up.
Every theme you donwload come with an
&lt;a href="https://github.com/gcushen/hugo-academic/tree/master/exampleSite" target="_blank" rel="noopener">example site&lt;/a>, all you need to do is just start deleting content.&lt;/p>
&lt;p>One item I really like is the &lt;strong>live reload&lt;/strong> - when &lt;strong>hugo server&lt;/strong> is running (locally) - the website would be auto deployed and page reloaded with new content as and when you save your file.&lt;/p>
&lt;p>&lt;strong>Tip:&lt;/strong> Theme I downloaded was using Hugo &lt;strong>Extended&lt;/strong> and not the default one. It took me almost half a day to figure this out :-( debugging through css generation failures etc..&lt;/p>
&lt;h3 id="aws-configuration">AWS Configuration&lt;/h3>
&lt;p>This article walks you through pretty much all the steps. If you are getting started, recomend to skip the cloundfront part:
&lt;a href="https://medium.com/faun/how-to-host-your-static-website-with-s3-cloudfront-and-set-up-an-ssl-certificate-9ee48cd701f9" target="_blank" rel="noopener">how-to-host-your-static-website-with-s3&lt;/a>&lt;/p>
&lt;h3 id="continous-deploy-actions">Continous Deploy (Actions)&lt;/h3>
&lt;p>This was my favourite part, I am personally a CI/CD enthusiast. I wanted to deploy my website every time I push changes into my GitRepo.&lt;/p>
&lt;p>I used
&lt;a href="https://github.com/marketplace/actions/s3-sync" target="_blank" rel="noopener">S3 Sync Actions&lt;/a> from marketplace. It has a few additional steps like generting &lt;em>AWS_ACCESS_KEY_ID&lt;/em> and &lt;em>AWS_SECRET_ACCESS_KEY&lt;/em> to get it configured.&lt;/p>
&lt;p>&lt;strong>Important: Secure you keys, by setting it up as secure env variable in github - so that it doesn&amp;rsquo;t show up in console log&lt;/strong>&lt;/p>
&lt;p>Use my icon for the website:
Every theme comes with its own default icon. Since I have referenced the theme as a GIT Submodule - as part of CD/workflow build is was always overwritten.
Did a minor hack - I checked in my icon into my repo and as part of build replaced the default theme icons with mine before build step.&lt;/p>
&lt;p>Below is the GitHub Action I stitched together.&lt;/p>
&lt;pre>&lt;code> name: CD
on:
push:
branches:
- master
jobs:
deploy:
name: deploy-website
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout master
uses: actions/checkout@master
- name: Update theme
run: git submodule update --init --recursive
- name: Setup hugo #https://github.com/peaceiris/actions-hugo
uses: peaceiris/actions-hugo@v2
with:
extended: true #This website is based on Hugo-Extended
hugo-version: &amp;quot;0.70.0&amp;quot; #We could also use latest
- name: copy my icon
run: cp -f ./assets/images/icon.png ./themes/academic/assets/images/icon.png
- name: Build Website
run: hugo --minify
- name: Publish To AWS S3
uses: jakejarvis/s3-sync-action@master
with:
args: --acl public-read --follow-symlinks --delete --exclude '.git/*'
env:
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: 'ap-south-1' # optional: defaults to us-east-1
SOURCE_DIR: 'public' # Req: hugo gen - static files into this dir
&lt;/code>&lt;/pre></description></item><item><title>Book - Anything you want by Derek Sivers</title><link>https://jacobaloysious.in/post/book_anything-you-want/</link><pubDate>Sun, 17 May 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/book_anything-you-want/</guid><description>&lt;p>For the second time, I completed reading a book in a day. Agree, its small and meant to be completed in 1hr :).&lt;/p>
&lt;p>In this book
&lt;a href="https://sivers.org/" target="_blank" rel="noopener">Derek Sivers&lt;/a> shares his experience of starting, running and donating a million dollar company.
Interestingly he started his
&lt;a href="https://cdbaby.com/" target="_blank" rel="noopener">&amp;ldquo;CD Baby&amp;rdquo;&lt;/a> without realizing he has started a business. Yeah, its true - he just wanted to help himself and then his musician friends to try sell their independent work. It gained popularity initially - just by word of mouth - friends telling their friends; and eventually turned into a million dollar business&amp;hellip;&lt;/p>
&lt;p>There are lots of details in this book Derek walks us through - &lt;strong>my key take aways&lt;/strong>:&lt;/p>
&lt;h4 id="dont-punish-everyone-for-one-person">Dont punish everyone for one person:&lt;/h4>
&lt;p>Don&amp;rsquo;t bring in rules just because one of your hundred(s) customer or employee did a single mistake.&lt;/p>
&lt;h4 id="delegate-or-die">Delegate or Die:&lt;/h4>
&lt;p>I could personally relate to this and its something I sincerly want to follow i.e. it should be business as usual irrespective of - I am avaiable or not in office&lt;/p>
&lt;h4 id="delegate-but-dont-abdicate">Delegate, but dont abdicate:&lt;/h4>
&lt;p>You need to be careful what and how much you are delegating esp when you have the responsiblity and ownership. Have a process checkpoint like review and ensure critical decisions are in control.&lt;/p>
&lt;h3 id="programmer-himself">Programmer Himself:&lt;/h3>
&lt;p>This was my &lt;strong>favourite part&lt;/strong>. Derek is a musician by profession. He started this
&lt;a href="https://cdbaby.com/" target="_blank" rel="noopener">website&lt;/a> as it was a necessity just for himself. Later when the business grew, he wanted more than plain HTML on his website. Since he couldn&amp;rsquo;t afford to hire a programmer - he went to the bookstore and got a book on &lt;strong>PHP&lt;/strong> and &lt;strong>MYSQL&lt;/strong> programming. Until the day he sold his company - he was the sole software programmer of the company&amp;rsquo;s website&amp;hellip; A business purely based on an online website making millions of dollars &lt;strong>WoW!!!!&lt;/strong>. One of the points he mentioned - he liked doing it as it was creative, but &lt;em>he only had to learn just enough to get the things done&lt;/em> - &lt;strong>#LightBulb moment&lt;/strong> for me :)&lt;/p>
&lt;h3 id="interseting-quotes">Interseting Quotes&lt;/h3>
&lt;blockquote>
&lt;p>Anything you hate to do, someone else loves. So find that person and let he or she do it&lt;/p>
&lt;/blockquote>
&lt;p>Making money was never an objective for
&lt;a href="https://cdbaby.com/" target="_blank" rel="noopener">&amp;ldquo;CD Baby&amp;rdquo;&lt;/a> and that was the reason it grew faster than he thought.&lt;/p>
&lt;p>Do things which make you happy, you might do it better than you would like to !&lt;/p>
&lt;p>Highly Recommended!&lt;/p></description></item><item><title>Book - Show Your Work by Austin Kleon</title><link>https://jacobaloysious.in/post/book_show-your-work/</link><pubDate>Sat, 16 May 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/book_show-your-work/</guid><description>&lt;p>For the first time, I completed reading a book in a day. Though I like physical books, since the entire city is currently in lockdown due to COVID19, non essential services are not available. Thanks to Amazon Kindle, I am kindaa liking it.&lt;/p>
&lt;p>I stumbled upon this
&lt;a href="https://www.youtube.com/watch?v=hv1gOEY3cs4" target="_blank" rel="noopener">3-Books that Changed my Life&lt;/a> - what actually caught me - author said &lt;em>I read couple of these books in less than an hour each&lt;/em>.&lt;/p>
&lt;p>Though the size of this book was relatively small, I should give credits to the author
&lt;a href="https://austinkleon.com/" target="_blank" rel="noopener">Austin Kleon&lt;/a>, for keeping it interesting all through; esp. the doodles – it was easy to connect. His ideas are simple but incredibly profound, easy to grasp and put to use. I got a feeling, he is sitting right across the table and conversing with me.&lt;/p>
&lt;p>I always thought one should not show your work until is finished. After reading this book, I realize more than the final product the process of doing it is equally important, as it makes you happy!!&lt;/p>
&lt;blockquote>
&lt;p>Give what you have. To someone, it may be better than you dare to thing - &lt;em>Henry Wadsoworth&lt;/em>.&lt;/p>
&lt;/blockquote>
&lt;p>My key take away - We don&amp;rsquo;t really have to be terrified of being revealed as amateurs; its perfectly fine (read normal).&lt;/p>
&lt;p>Author talks about &lt;em>Amateurs&lt;/em> and &lt;em>Curiosity&lt;/em> - The day you presume, you know lots (read, mastery) - then the curiosity might fade away and complacency might step in. Being an amateur - you take chances, exxperiment and follow your whims - and in the process keep learning .&lt;/p>
&lt;blockquote>
&lt;p>That&amp;rsquo;s all any of us are: amateurs. We don&amp;rsquo;t live long enough to be anything else - &lt;em>Charlie Chaplin&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>Honestly, I feel good and motivated. I will probably start writing about the things that I find interesting esp. the once I am working on. Thank you Mr Kleon, you have definitely made a huge impact.&lt;/p>
&lt;p>Highly Recommended! I already sent it to few of my close friends :)&lt;/p></description></item><item><title>Welcome</title><link>https://jacobaloysious.in/post/welcome/</link><pubDate>Sun, 10 May 2020 00:00:00 +0000</pubDate><guid>https://jacobaloysious.in/post/welcome/</guid><description>&lt;p>If you know me and you are here, welcome back! If you dont know me and you are here, I am plesantly Surprised - thank you!&lt;/p>
&lt;p>As the world is experiencing the pandemic (COVID-19), as a developer I am trying to get myself occupied with something which make me feel good.&lt;/p></description></item></channel></rss>