diff --git a/404.html b/404.html index 9c7615b..34265e5 100644 --- a/404.html +++ b/404.html @@ -5,7 +5,7 @@ Page Not Found | Denny's blog - + diff --git a/assets/js/15e7fec8.0ce20a00.js b/assets/js/15e7fec8.0ce20a00.js deleted file mode 100644 index 00cf431..0000000 --- a/assets/js/15e7fec8.0ce20a00.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[872],{6103:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>s,default:()=>m,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var a=n(5893),i=n(1151);const o={slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},s=void 0,r={permalink:"/mynameis/blog/tq-devlog-1",source:"@site/blog/05-tq-devlog-1/index.md",title:"PaaS devlog |#1",description:"Devlog |#1",date:"2024-09-03T18:48:09.000Z",formattedDate:"September 3, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.295,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"PaaS devlog |#0",permalink:"/mynameis/blog/tq-devlog-0"}},d={authorsImageUrls:[void 0]},l=[{value:"Devlog |#1",id:"devlog-1",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",img:"img",p:"p",pre:"pre",strong:"strong",...(0,i.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-1",children:"Devlog |#1"}),"\n",(0,a.jsx)(t.p,{children:"Another day I actually started working on the project (what a surprise)."}),"\n",(0,a.jsx)(t.p,{children:"I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more."}),"\n",(0,a.jsx)(t.p,{children:"Im convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data."}),"\n",(0,a.jsx)(t.p,{children:"First, docker compose. I can't imagine local environment without it. Very simple one, some volumes, passwordless acceess, expose 5432 port, done."}),"\n",(0,a.jsx)(t.p,{children:"I didn't know how my first feature will look like, a user creating, connecting a repository or saving the infrastracture state.\nBut I needed a first migration to test it, so I created a users table. Very creative, but I really will need users table, it's fine."}),"\n",(0,a.jsx)(t.p,{children:"I installed a few dependencies:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"go get github.com/golang-migrate/migrate/v4\ngo get github.com/jmoiron/sqlx\ngo get github.com/jackc/pgx\n"})}),"\n",(0,a.jsx)(t.p,{children:"I will sqlx + squirrel for query executing, pgx as a driver and migrate for running migrations, it prodes cli interface if you want to run in the jobs and go api as well."}),"\n",(0,a.jsx)(t.p,{children:"I will use go api, but I wouldn't recomment it in production, it's important to create a database backup before starting a mgiration, so the best case you have a migration job that makes a backup and then runs the migration, if it worked out - release is welcome."}),"\n",(0,a.jsx)(t.p,{children:"Then I made a few commands to work with migration like create new, up, down and fix migration."}),"\n",(0,a.jsx)(t.admonition,{type:"note",children:(0,a.jsxs)(t.p,{children:["Migration package stores the state in the same database. When it fails it writes the migration as ",(0,a.jsx)(t.code,{children:"dirty"}),". Fix command is used to force the version, it's very useful in the development process. I even used it in prod."]})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-makefile",children:'DB_DSN ?= "postgres://postgres@localhost:5432/tq?sslmode=disable"\n\nmigrate_new:\n migrate create -ext sql -dir migrations -seq -digits 4 ${MNAME}\n\nmigrate_up:\n migrate -path migrations -database ${DB_DSN} up\n\nmigrate_down:\n migrate -path migrations -database ${DB_DSN} down\n\nmigrate_fix:\n migrate -path migrations -database ${DB_DSN} force ${V}\n\nmigrate_v:\n migrate -path migrations -database ${DB_DSN} version\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Using command ",(0,a.jsx)(t.code,{children:"make migrate_new users_table"})," I create a new migration and feel it with the following sql:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-sql",children:'CREATE EXTENSION IF NOT EXISTS "uuid-ossp";\n\nCREATE TABLE IF NOT EXISTS users (\n id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,\n email varchar(85) NOT NULL,\n password varchar(255) NOT NULL,\n\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL\n);\n'})}),"\n",(0,a.jsx)(t.p,{children:"I like using uuid as an identity. It never fooled me."}),"\n",(0,a.jsx)(t.p,{children:"Then I do what I didn't recommend."}),"\n",(0,a.jsx)(t.p,{children:"Yes, I run the migrations right in the starting the app server.\nSeems ok, applied."}),"\n",(0,a.jsx)(t.p,{children:"I need something to see the result, the table, the extension.\nI use psql, but to me personnaly it's very annoying having such long interface, it matters a lot when I have a few databases to follow."}),"\n",(0,a.jsxs)(t.p,{children:["I looked for a tool again. I tried pgadmin, jetbrains embedded one.\nAnd I found Beekeeper. That's the tool I wouldn't be ashamed to create. Looks very good, easy to use, to edit, look for data with 0 sql, comfortable keyboard control.\nEverything I like.\n",(0,a.jsx)(t.strong,{children:"It's even opensourced and has a free community edition."})]}),"\n",(0,a.jsx)(t.p,{children:"I looked at the data, the migration record exists, the users table does as well."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(3114).Z+"",width:"697",height:"485"})}),"\n",(0,a.jsxs)(t.p,{children:["Finally I can commit it.\nI like using lazygit for most of my cases.\nIt also a keyboard only control.\nEven my brain can handle it, there are very few commands: arrows to navigate, space to stage a change, you can use mouse to stage only a part of the file, and push ",(0,a.jsx)(t.code,{children:"c"})," to input a commit message and ",(0,a.jsx)(t.code,{children:"Enter"})," to commit.\nIt also has bunch of things like branches list, reflog, command log."]}),"\n",(0,a.jsxs)(t.p,{children:["At least I don't repeatadly do anymore ",(0,a.jsx)(t.code,{children:"ls, gd, ga"})," file by file."]}),"\n",(0,a.jsx)(t.admonition,{type:"note",children:(0,a.jsxs)(t.p,{children:["I use zsh and it gives me many shortcuts, for instance ",(0,a.jsx)(t.code,{children:"ga"})," is equal to ",(0,a.jsx)(t.code,{children:"git add"})]})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(2772).Z+"",width:"1144",height:"368"})}),"\n",(0,a.jsxs)(t.p,{children:["Thank you for reading, come here and see what's gonna be in the end.\nRepository is here: ",(0,a.jsx)(t.a,{href:"http://github.com/treenq/treenq",children:"http://github.com/treenq/treenq"})]})]})}function m(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},3114:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/beekeeper-beaeade119f66325a55e6f5ae21ef953.png"},2772:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/git-c137585a8a0b1af52301455de126177b.png"},1151:(e,t,n)=>{n.d(t,{Z:()=>r,a:()=>s});var a=n(7294);const i={},o=a.createContext(i);function s(e){const t=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/15e7fec8.e04e84a8.js b/assets/js/15e7fec8.e04e84a8.js new file mode 100644 index 0000000..58fbce8 --- /dev/null +++ b/assets/js/15e7fec8.e04e84a8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[872],{6103:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>i,default:()=>g,frontMatter:()=>s,metadata:()=>r,toc:()=>l});var a=n(5893),o=n(1151);const s={slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},i=void 0,r={permalink:"/mynameis/blog/tq-devlog-1",source:"@site/blog/05-tq-devlog-1/index.md",title:"PaaS devlog |#1",description:"Devlog |#1: postgres, docker, beekeeper, lazygit",date:"2024-09-03T20:16:17.000Z",formattedDate:"September 3, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.315,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"PaaS devlog |#0",permalink:"/mynameis/blog/tq-devlog-0"}},d={authorsImageUrls:[void 0]},l=[{value:"Devlog |#1: postgres, docker, beekeeper, lazygit",id:"devlog-1-postgres-docker-beekeeper-lazygit",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",img:"img",p:"p",pre:"pre",strong:"strong",...(0,o.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-1-postgres-docker-beekeeper-lazygit",children:"Devlog |#1: postgres, docker, beekeeper, lazygit"}),"\n",(0,a.jsx)(t.p,{children:"Another day I actually started working on the project (what a surprise)."}),"\n",(0,a.jsx)(t.p,{children:"I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more."}),"\n",(0,a.jsx)(t.p,{children:"Im convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data."}),"\n",(0,a.jsx)(t.p,{children:"First, docker compose. I can't imagine local environment without it. Very simple one, some volumes, passwordless acceess, expose 5432 port, done."}),"\n",(0,a.jsx)(t.p,{children:"I didn't know how my first feature will look like, a user creating, connecting a repository or saving the infrastracture state.\nBut I needed a first migration to test it, so I created a users table. Very creative, but I really will need users table, it's fine."}),"\n",(0,a.jsx)(t.p,{children:"I installed a few dependencies:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"go get github.com/golang-migrate/migrate/v4\ngo get github.com/jmoiron/sqlx\ngo get github.com/jackc/pgx\n"})}),"\n",(0,a.jsx)(t.p,{children:"I will sqlx + squirrel for query executing, pgx as a driver and migrate for running migrations, it prodes cli interface if you want to run in the jobs and go api as well."}),"\n",(0,a.jsx)(t.p,{children:"I will use go api, but I wouldn't recomment it in production, it's important to create a database backup before starting a mgiration, so the best case you have a migration job that makes a backup and then runs the migration, if it worked out - release is welcome."}),"\n",(0,a.jsx)(t.p,{children:"Then I made a few commands to work with migration like create new, up, down and fix migration."}),"\n",(0,a.jsx)(t.admonition,{type:"note",children:(0,a.jsxs)(t.p,{children:["Migration package stores the state in the same database. When it fails it writes the migration as ",(0,a.jsx)(t.code,{children:"dirty"}),". Fix command is used to force the version, it's very useful in the development process. I even used it in prod."]})}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-makefile",children:'DB_DSN ?= "postgres://postgres@localhost:5432/tq?sslmode=disable"\n\nmigrate_new:\n migrate create -ext sql -dir migrations -seq -digits 4 ${MNAME}\n\nmigrate_up:\n migrate -path migrations -database ${DB_DSN} up\n\nmigrate_down:\n migrate -path migrations -database ${DB_DSN} down\n\nmigrate_fix:\n migrate -path migrations -database ${DB_DSN} force ${V}\n\nmigrate_v:\n migrate -path migrations -database ${DB_DSN} version\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Using command ",(0,a.jsx)(t.code,{children:"make migrate_new users_table"})," I create a new migration and feel it with the following sql:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-sql",children:'CREATE EXTENSION IF NOT EXISTS "uuid-ossp";\n\nCREATE TABLE IF NOT EXISTS users (\n id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,\n email varchar(85) NOT NULL,\n password varchar(255) NOT NULL,\n\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL\n);\n'})}),"\n",(0,a.jsx)(t.p,{children:"I like using uuid as an identity. It never fooled me."}),"\n",(0,a.jsx)(t.p,{children:"Then I do what I didn't recommend."}),"\n",(0,a.jsx)(t.p,{children:"Yes, I run the migrations right in the starting the app server.\nSeems ok, applied."}),"\n",(0,a.jsx)(t.p,{children:"I need something to see the result, the table, the extension.\nI use psql, but to me personnaly it's very annoying having such long interface, it matters a lot when I have a few databases to follow."}),"\n",(0,a.jsxs)(t.p,{children:["I looked for a tool again. I tried pgadmin, jetbrains embedded one.\nAnd I found Beekeeper. That's the tool I wouldn't be ashamed to create. Looks very good, easy to use, to edit, look for data with 0 sql, comfortable keyboard control.\nEverything I like.\n",(0,a.jsx)(t.strong,{children:"It's even opensourced and has a free community edition."})]}),"\n",(0,a.jsx)(t.p,{children:"I looked at the data, the migration record exists, the users table does as well."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(3114).Z+"",width:"697",height:"485"})}),"\n",(0,a.jsxs)(t.p,{children:["Finally I can commit it.\nI like using lazygit for most of my cases.\nIt also a keyboard only control.\nEven my brain can handle it, there are very few commands: arrows to navigate, space to stage a change, you can use mouse to stage only a part of the file, and push ",(0,a.jsx)(t.code,{children:"c"})," to input a commit message and ",(0,a.jsx)(t.code,{children:"Enter"})," to commit.\nIt also has bunch of things like branches list, reflog, command log."]}),"\n",(0,a.jsxs)(t.p,{children:["At least I don't repeatadly do anymore ",(0,a.jsx)(t.code,{children:"ls, gd, ga"})," file by file."]}),"\n",(0,a.jsx)(t.admonition,{type:"note",children:(0,a.jsxs)(t.p,{children:["I use zsh and it gives me many shortcuts, for instance ",(0,a.jsx)(t.code,{children:"ga"})," is equal to ",(0,a.jsx)(t.code,{children:"git add"})]})}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(2772).Z+"",width:"1144",height:"368"})}),"\n",(0,a.jsxs)(t.p,{children:["Thank you for reading, come here and see what's gonna be in the end.\nRepository is here: ",(0,a.jsx)(t.a,{href:"http://github.com/treenq/treenq",children:"http://github.com/treenq/treenq"})]})]})}function g(e={}){const{wrapper:t}={...(0,o.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},3114:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/beekeeper-beaeade119f66325a55e6f5ae21ef953.png"},2772:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/git-c137585a8a0b1af52301455de126177b.png"},1151:(e,t,n)=>{n.d(t,{Z:()=>r,a:()=>i});var a=n(7294);const o={},s=a.createContext(o);function i(e){const t=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),a.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1a1195cb.1314ed7d.js b/assets/js/1a1195cb.1314ed7d.js deleted file mode 100644 index 2ebd853..0000000 --- a/assets/js/1a1195cb.1314ed7d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[531],{7115:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>r,default:()=>c,frontMatter:()=>s,metadata:()=>l,toc:()=>d});var o=n(5893),a=n(1151);const s={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},r=void 0,l={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.955,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,prevItem:{title:"PaaS devlog |#1",permalink:"/mynameis/blog/tq-devlog-1"},nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},i={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0",id:"devlog-0",level:2}];function m(e){const t={h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h2,{id:"devlog-0",children:"Devlog |#0"}),"\n",(0,o.jsx)(t.p,{children:"Today I want to share with you my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."})]})}function c(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(m,{...e})}):m(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>l,a:()=>r});var o=n(7294);const a={},s=o.createContext(a);function r(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1a1195cb.8151e10e.js b/assets/js/1a1195cb.8151e10e.js new file mode 100644 index 0000000..732087e --- /dev/null +++ b/assets/js/1a1195cb.8151e10e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[531],{7115:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>r,metadata:()=>i,toc:()=>d});var a=n(5893),o=n(1151);const r={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},l=void 0,i={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0: planing, gpt, linear",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.965,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,prevItem:{title:"PaaS devlog |#1",permalink:"/mynameis/blog/tq-devlog-1"},nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},s={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0: planing, gpt, linear",id:"devlog-0-planing-gpt-linear",level:2}];function m(e){const t={h2:"h2",p:"p",...(0,o.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-0-planing-gpt-linear",children:"Devlog |#0: planing, gpt, linear"}),"\n",(0,a.jsx)(t.p,{children:"Today I want to share with you my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."})]})}function g(e={}){const{wrapper:t}={...(0,o.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(m,{...e})}):m(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>i,a:()=>l});var a=n(7294);const o={},r=a.createContext(o);function l(e){const t=a.useContext(r);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:l(e.components),a.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2f6ea139.b01cd6c9.js b/assets/js/2f6ea139.b01cd6c9.js deleted file mode 100644 index 40a6687..0000000 --- a/assets/js/2f6ea139.b01cd6c9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[538],{6362:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"tq-devlog-1","metadata":{"permalink":"/mynameis/blog/tq-devlog-1","source":"@site/blog/05-tq-devlog-1/index.md","title":"PaaS devlog |#1","description":"Devlog |#1","date":"2024-09-03T18:48:09.000Z","formattedDate":"September 3, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":3.295,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"tq-devlog-1","title":"PaaS devlog |#1","authors":["denis"],"tags":["software"]},"unlisted":false,"nextItem":{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0"}},"content":"## Devlog |#1\\n\\nAnother day I actually started working on the project (what a surprise).\\n\\nI want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.\\n\\n\x3c!--truncate--\x3e\\n\\nIm convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data.\\n\\nFirst, docker compose. I can\'t imagine local environment without it. Very simple one, some volumes, passwordless acceess, expose 5432 port, done.\\n\\nI didn\'t know how my first feature will look like, a user creating, connecting a repository or saving the infrastracture state.\\nBut I needed a first migration to test it, so I created a users table. Very creative, but I really will need users table, it\'s fine.\\n\\nI installed a few dependencies:\\n```shell\\ngo get github.com/golang-migrate/migrate/v4\\ngo get github.com/jmoiron/sqlx\\ngo get github.com/jackc/pgx\\n```\\n\\nI will sqlx + squirrel for query executing, pgx as a driver and migrate for running migrations, it prodes cli interface if you want to run in the jobs and go api as well.\\n\\nI will use go api, but I wouldn\'t recomment it in production, it\'s important to create a database backup before starting a mgiration, so the best case you have a migration job that makes a backup and then runs the migration, if it worked out - release is welcome.\\n\\nThen I made a few commands to work with migration like create new, up, down and fix migration.\\n\\n:::note\\nMigration package stores the state in the same database. When it fails it writes the migration as `dirty`. Fix command is used to force the version, it\'s very useful in the development process. I even used it in prod. \\n:::\\n\\n```makefile\\nDB_DSN ?= \\"postgres://postgres@localhost:5432/tq?sslmode=disable\\"\\n\\nmigrate_new:\\n migrate create -ext sql -dir migrations -seq -digits 4 ${MNAME}\\n\\nmigrate_up:\\n migrate -path migrations -database ${DB_DSN} up\\n\\nmigrate_down:\\n migrate -path migrations -database ${DB_DSN} down\\n\\nmigrate_fix:\\n migrate -path migrations -database ${DB_DSN} force ${V}\\n\\nmigrate_v:\\n migrate -path migrations -database ${DB_DSN} version\\n```\\n\\nUsing command `make migrate_new users_table` I create a new migration and feel it with the following sql:\\n```sql\\nCREATE EXTENSION IF NOT EXISTS \\"uuid-ossp\\";\\n\\nCREATE TABLE IF NOT EXISTS users (\\n id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,\\n email varchar(85) NOT NULL,\\n password varchar(255) NOT NULL,\\n\\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL\\n);\\n```\\n\\nI like using uuid as an identity. It never fooled me. \\n\\nThen I do what I didn\'t recommend.\\n\\nYes, I run the migrations right in the starting the app server.\\nSeems ok, applied.\\n\\nI need something to see the result, the table, the extension.\\nI use psql, but to me personnaly it\'s very annoying having such long interface, it matters a lot when I have a few databases to follow.\\n\\nI looked for a tool again. I tried pgadmin, jetbrains embedded one. \\nAnd I found Beekeeper. That\'s the tool I wouldn\'t be ashamed to create. Looks very good, easy to use, to edit, look for data with 0 sql, comfortable keyboard control. \\nEverything I like. \\n__It\'s even opensourced and has a free community edition.__\\n\\nI looked at the data, the migration record exists, the users table does as well. \\n\\n![img](./beekeeper.png)\\n\\nFinally I can commit it.\\nI like using lazygit for most of my cases.\\nIt also a keyboard only control.\\nEven my brain can handle it, there are very few commands: arrows to navigate, space to stage a change, you can use mouse to stage only a part of the file, and push `c` to input a commit message and `Enter` to commit. \\nIt also has bunch of things like branches list, reflog, command log. \\n\\nAt least I don\'t repeatadly do anymore `ls, gd, ga` file by file.\\n\\n:::note\\nI use zsh and it gives me many shortcuts, for instance `ga` is equal to `git add`\\n:::\\n\\n![img](./git.png)\\n\\nThank you for reading, come here and see what\'s gonna be in the end.\\nRepository is here: http://github.com/treenq/treenq"},{"id":"tq-devlog-0","metadata":{"permalink":"/mynameis/blog/tq-devlog-0","source":"@site/blog/04-tq-devlog-0/index.md","title":"PaaS devlog |#0","description":"Devlog |#0","date":"2024-09-02T20:12:28.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":3.955,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"tq-devlog-0","title":"PaaS devlog |#0","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"PaaS devlog |#1","permalink":"/mynameis/blog/tq-devlog-1"},"nextItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"}},"content":"## Devlog |#0\\n\\nToday I want to share with you my first steps of creating new project.\\nFor a long time I\'ve wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.\\n\\n\x3c!--truncate--\x3e\\n\\nThe main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.\\n\\n:::tip\\nYou can read more about cdk [here](https://developer.hashicorp.com/terraform/cdktf)\\n:::\\n\\nAll the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it).\\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me.\\n\\n### The problem\\n\\nThe technical problem exists, it\'s fun to figure out.\\nBut no the main one. The biggest fight Im gonna accept is __procrastination__. Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That\'s what will stop me from the progress.\\nSo the easiest way to move progress away - do whatever, but not the progress.\\n\\n### The planing\\n\\nSo I decided to plan everything and understand how big the actual project is gonna be.\\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck. \\nInstead of asking what I should do I explained my plan and asked to ask __more questions__ so it could help me to clarify the technical solution and the plan.\\n\\n![img](./gpt.png)\\n\\n
\\n\\nHere you can find a prompt I used\\n\\nI want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It\'s a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users\' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better.\\n
\\n\\nInitially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement.\\n\\nChatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - __remocal__.\\n\\nWhen stepped into the planning I decided to make it even longer.\\nI wanted to researched all the kanban boards, unresistable.\\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though. \\n\\nI tried Cluckup, it\'s a laggish joke, even worse than Jira to make you feel you are already enterprise.\\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist.\\n\\n### The ugly thing\\n\\nIn the end I found Linear. \\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons.\\n\\nA few minutes later I started catching.\\nKeyboard first design - that\'s what I buy.\\n\\nSo I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\\nThe basic element is an issue. It might have sub-issues. And they might have.\\nThey can be collected in a project.\\n\\nThere are bunch of other staff I don\'t use, but I will share it below.\\n- Cycle - like a sprint, hate it.\\n- Triage - inbox, it\'s a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove.\\n- Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline. \\n\\nAs a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f).\\n\\n![img](./few.png)\\n\\nThank you for reading, come here and see what\'s gonna be in the end.\\nRepository is here: http://github.com/treenq/treenq"},{"id":"do-gamedev","metadata":{"permalink":"/mynameis/blog/do-gamedev","source":"@site/blog/03-do-gamedev/index.mdx","title":"Backend Guy Ventures into Game Development","description":"In order to be engaged one explores different areas and looks for unknown software area.","date":"2024-09-02T18:32:54.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.53,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"do-gamedev","title":"Backend Guy Ventures into Game Development","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0"},"nextItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"In order to be engaged one explores different areas and looks for unknown software area.\\n\\nHere we look at the gamedev in 2024 from experience in server side software.\\n\\nIn software development, it\'s common to explore new domains to stay engaged. \\nWhether it\'s for a change of pace or to push personal boundaries, exploring the unknown can lead to fancy adventures in software. \\nThis page will share my journey as a backend developer diving into the game development in 2024.\\n\\n\x3c!--truncate--\x3e\\n\\n#### Why Gamedev? \\n\\n99% of programmes came here to make a game.\\nEither did I.\\n\\nFrom a young age, I was captivated by two genres: strategy games and action RPGs. \\nMy first PC came preloaded with classics like Red Alert 2, Heroes of Might and Magic 3, and Diablo 2. \\nThe simple yet addictive gameplay\u2014click, move, destroy, enjoy \u2014 cemented my love for these genres. \\nOver the years, I\u2019ve played many iconic RTS games like Warcraft 3 and Starcraft 2 (and still do occasionally).\\nBut I realized that Starcraft 2 and similar games leaned more towards real-time execution rather than strategic depth.\\n\\nSo I decided to make my own game with the strategy and decision making take the center stage.\\n\\n#### Choosing the Game Engine \\n\\nThere are numerous options out there\u2014Defold, RPG Maker, GameMaker, Construct, to name a few.\\n\\nBut I focused on the big three that are free to start with, offer extensive flexibility, and have been tested by major projects: Unreal Engine, Unity, and Godot.\\n\\n#### Unreal Engine: A Mixed Bag of Power and Complexity\\n\\nI chose to start with Unreal Engine. It has a large community, though not the largest. Everything Unity offers in its asset store, Unreal has an equivalent. The engine supports C++ for low-level programming and Blueprints (a visual scripting language) for level design, though you can use either approach.\\n\\nInstalling the engine is a hassle. You need to first install the Epic Games Launcher and then download the 55GB engine itself, which can be a chore if your disk space is limited.\\n\\nAfter setting up a blank project, I was impressed by the vast flexibility Unreal offers. You get all the benefits of C++\u2014dynamic dependency injection, custom components, and more.. But it adds complexity.\\n1. Compiliation time. It exists. Not just exists like a couple blinks 5-10 seconds, it takes a lot of time to build a single class to start using it in the project.\\n2. Code complexity. Write header files, manual memory management. Good package manager doesn\'t exist in 2024, now I understand why they love Rust so much. \\n3. Poor mac support. No comments, even the interface of top bar menu is different, I was struggling to find editor settings according to the documentation, and every question is like that. \\n\\nI would recommend such engine for people who likes waiting, c++ and want to make a beatiful scenes with nice action. \\nI also have to note that engine is open source and owned by a technical guy and people who actually make games. I would stop there if I liked waiting and c++.\\n\\n#### Unity: The Industry Standard.\\n\\nNext up was Unity, the most popular game engine out there. \\nUnity has a vast ecosystem, with advanced features like rendering, post-processing, and easy shader creation. \\nIt\u2019s backed by a huge asset store, which should theoretically make development easier.\\nC# - Im not a big fun, but it\'s compilable, therefore type safe, seems good.\\n\\nA basic abstraction is an object. An object has compenents to manage what is it, it might be a script to move it, a mesh to render a tree, a colission not to pass through the tree, sound to play as tree leafs on the wind and so on.\\nSeems quite simple. \\n\\nBut when I approached a real problem there are plenty of weird things.\\n1. Unity has three different render pipelines, which aren\u2019t compatible with each other. The oldest one is being deprecated, meaning half the assets in the store may soon be obsolete.\\n2. Asset store is a garbage. I tried several camera controllers, and only one partially met my needs. I had to patch it to double its functionality, which felt like reinventing the wheel.\\n\\nWe all remember the Unity pricing drama. It has a closed-source codebase, and now there\u2019s a tracker that counts installations to generate more revenue for shareholders. \\nThis has led to a lot of half-baked features and outdated documentation, which can make the engine feel unstable.\\n\\nUnity is still a solid choice, but in 2024, it feels like the engine is in a weird transitional state. \\nThe documentation isn\u2019t as up-to-date as it should be, and the engine itself seems to be in a half-finished state. \\nI might revisit it in 2025 when Unity 6 is released.\\n\\n#### Godot: Unknown creature in the Sea.\\n\\nFinally, I turned to Godot, an engine I initially underestimated. \\nKnown for its strong 2D capabilities, Godot seemed lacking in 3D support. \\nIts physics engine was also rumored to be subpar.\\n\\nSo I start doing a 3D. \\nFirst I found that asset library is poor, camera controller only for Godot 3 (previous release) and it makes no sense to use Godot 3 in 2024.\\n\\nWhat I actually see in progress.\\n0. Godot\u2019s installation bundle is just 150MB. It has a negligible memory footprint and can run smoothly even on modest hardware. Coming from Unity, this was a breath of fresh air.\\n1. Godot\u2019s editor can be extended in a similar manner to Unity, allowing you to add new UI elements and dynamically instantiate new components.\\n2. The asset library isn\u2019t a store but a repository where everything is distributed for free. Since Godot is open-source, I doubt any significant part of it will go paid, unlike Unity and Unreal, where quality assets often come with a price tag.\\n3. Physics engine implementation can be replaced with jolt easy-peasy and works very well.\\n4. The same abstractions, the same component building, but not an object has component, rather a scene (actually a node) has nodes (the others to implement actual behavior of the node).\\n5. Exporting is just a button click. I managed to build a project for windows in Mac, it\'s so good, haven\'t had such smooth exprerience.\\n\\nIt was surprisingly easy to understand the basics, the nodes design, the event bus system, for a backend guy it\'s perfect to start making a real game.\\n\\nGDScript can fail in runtime, not the best, but you can use C# for the sake of compilte time failure.\\n\\nAnd I know, the community is smaller, it will be developed slower, true. But I care about me today, not the community.\\n\\nI initially planned to give Unity a fair shot, spending a week with both engines. \\nBut after just two days with Godot, I was progressing so much faster that I decided it wasn\u2019t worth the time to continue with Unity. \\nGodot\u2019s lower entry barrier and faster development pace made it the clear choice for me.\\n\\n##### I want to finish simpler. \\n\\nIn the end, the best engine is the one that aligns with your needs and preferences. \\nRemember, Blender was once considered a niche tool while everyone used 3D Max, and now Blender is the industry standard. \\nFirebase was just a \u201cbase,\u201d and today we have Supabase, Pocketbase and many others.\\n\\nThe landscape of game development is always changing. \\nWhat matters most is finding the tool that helps you bring your vision to life, not what the industry standard is. \\nFor me, that tool is Godot.\\n\\n### Lessons\\nSpoiler, no, I didn\'t finish a game, I learned the gamedev abstractions and played with the engines a bit and I enjoyed it.\\nAnd it\'s fine, I had good time and wish everyone to find a toy you can spend some time on and make you engaged."},{"id":"big-json","metadata":{"permalink":"/mynameis/blog/big-json","source":"@site/blog/02-250mbjson-in-50mb-limit/index.mdx","title":"250mb json in a 40mb service limit","description":"This article has been created to remind us of one simple thing: HTTP is a stream.","date":"2024-05-26T15:48:12.000Z","formattedDate":"May 26, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.8,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"big-json","title":"250mb json in a 40mb service limit","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"},"nextItem":{"title":"Why this page exists","permalink":"/mynameis/blog/why-a-blog"}},"content":"This article has been created to remind us of one simple thing: HTTP is a stream.\\n\\nAs a practical outcome we can learn how to reduce memory requirements for our services in a typical task: cache warming.\\n\\n\x3c!--truncate--\x3e\\n\\nLet\'s look at the challenge first.\\n\\nWe have a service that must download the data and keep it in memory.\\nThe issue is the JSON document we have to download is 10 times larger than the encoded data. \\nTherefore we have to increase the memory limit 2-3 times to download it once. \\nLater on, the service doesn\'t consume as much memory, so it\'s a start up cost.\\n\\n\\n### The challenge: cut down the memory consumption as much as we can.\\n\\nLet\'s get back to the basic of network communication.\\n\\n:::note\\nWe skip TLS termination for the sake of simplicity.\\n:::\\n\\nThere is a great book that explains it very well: https://hpbn.co/building-blocks-of-tcp/#slow-start\\n\\n![img](./syn.svg)\\n\\nJust a litle picture to remind us how a connection starts: we do a handshake with the service.\\n\\nThen we can start exchanging data.\\nTypical API responses are at most ~50kb.\\n\\nBut what if you want to warm a cache? How much can it be? \\nIt can be a lot, around tens of megabytes.\\nIn my example, we take 250mb.\\n\\nHow does the server send such data?\\n\\n![img](./congestion.svg)\\n\\nSlowly, packet by packet.\\n\\nThe server tries to understand your throughput. The protocol itself rarely provides an accurate value of a packet size, so by relying on the imperical latency, it tunes the packet size little by little.\\nIt needs to send a lot of packets to transfer a really big response.\\n\\n### 3 Ways to do it\\n\\nBelow we will consider 3 approaches to solve this task.\\nThere is no such thing as the only right solution; all of them are fine as long as you understand the costs and risks well enough, and we are gonna cover them.\\n\\n### First, Brute Force solution.\\n\\n:::warning\\nIf you want to reproduce an example make sure to untar server/json.tar.gz; it must contain the f.json file since GitHub has a limit of up to 100mb for a file.\\n:::\\n\\nYou can imagine how the simplest Go HTTP client can implement it or just look at the code.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/543510947c0b19dbc0097adf403ae5cd6954c1cc/client/main.go)\\n\\nThe implementation is straight forward: it sends a request, gets a response, reads, marhsals it into a defined structure, holds it in the memory and ready to serve it further.\\n\\nAnd here is the pprof output:\\n\\n```shell\\nShowing nodes accounting for 229.48MB, 100% of 229.48MB total\\n flat flat% sum% cum cum%\\n 229.48MB 100% 100% 229.48MB 100% io.ReadAll\\n 0 0% 100% 229.48MB 100% main.main\\n 0 0% 100% 229.48MB 100% runtime.main\\n```\\n\\nYes, it\'s not real win, with huge memory consumption, but it works ok.\\n\\nWe see all the memory consumed on reading the HTTP stream.\\n\\nOr you might say, \\"What a noob, you must use `json.Decoder`\\" so as to let the decoder work with the HTTP pipe closer.\\n\\nAnd it\'s pretty much the same, in my example, even worse.\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b6ee7fcfd69fdffad844eb6a3d324d2fe3040985/client/main.go) to code with Decoder\\n\\n```shell\\nShowing nodes accounting for 384MB, 100% of 384MB total\\n flat flat% sum% cum cum%\\n 384MB 100% 100% 384MB 100% encoding/json.(*Decoder).refill\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).Decode\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).readValue\\n 0 0% 100% 384MB 100% main.main\\n 0 0% 100% 384MB 100% runtime.main\\n```\\n\\nTo recall why let\'s dig a little into the json/encoding library [implementation](https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/encoding/json/stream.go;l=49). \\n\\n```go\\nfunc (dec *Decoder) Decode(v any) error {\\n\\tif dec.err != nil {\\n\\t\\treturn dec.err\\n\\t}\\n\\n\\tif err := dec.tokenPrepareForDecode(); err != nil {\\n\\t\\treturn err\\n\\t}\\n\\n\\tif !dec.tokenValueAllowed() {\\n\\t\\treturn &SyntaxError{msg: \\"not at beginning of value\\", Offset: dec.InputOffset()}\\n\\t}\\n\\n\\t// Read whole value into buffer.\\n\\tn, err := dec.readValue()\\n\\tif err != nil {\\n\\t\\treturn err\\n\\t}\\n\\tdec.d.init(dec.buf[dec.scanp : dec.scanp+n])\\n\\tdec.scanp += n\\n\\n\\t// Don\'t save err from unmarshal into dec.err:\\n\\t// the connection is still usable since we read a complete JSON\\n\\t// object from it before the error happened.\\n\\terr = dec.d.unmarshal(v)\\n\\n\\t// fixup token streaming state\\n\\tdec.tokenValueEnd()\\n\\n\\treturn err\\n}\\n```\\n\\nIt does exactly the same, it calls `dec.readValue()` first to read all the response and then `dec.d.unmarshal` to parse it.\\n\\nAnd it\'s ok; the reason is very simple: **encoding/json doesn\'t know the nature of your data.**\\n\\n:::note\\nLibraries like [json-iter](https://github.com/json-iterator/go) or [easyjson](https://github.com/mailru/easyjson) offer zero improvements in memory consumption.\\n:::\\n\\n### Second, decode object by object.\\n\\nGo json library provides a method of the Decoder called [`Token`](https://pkg.go.dev/encoding/json#Decoder.Token)\\n\\nThis approach, parsing manually token by token, can give us an option to manually parse the json.\\nA token might be every symbol, such as as open bracket, quote, key, value, etc.\\nBut I found this approach quite complex. Having a deeply nested JSON object makes it very confusing to understand the relation for a given token. An solution could be to hold every key and designated level, but the decision gets worse with duplicated keys on a couple of levels.\\n\\nThat\'s why I prefer another approach.\\n\\nThere is a well-known problem on LeetCode called \\"[Valid Parentheses](https://leetcode.com/problems/valid-parentheses/description/)\\"\\n\\nWe can simply read the beginning of a given object and the end, understanding when the last bracket of the object comes.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b5890cbb74282416b5adacc92de95f18f7ee766f/client/main.go#L110)\\n\\npprof gives the following output\\n```shell\\n(pprof) top 5\\nShowing nodes accounting for 68.56MB, 100% of 68.56MB total\\nShowing top 5 nodes out of 10\\n flat flat% sum% cum cum%\\n 27.55MB 40.18% 40.18% 68.56MB 100% main.decode\\n 20MB 29.17% 69.35% 20MB 29.17% encoding/json.(*decodeState).literalStore\\n 20MB 29.17% 98.52% 20MB 29.17% bufio.NewReaderSize (inline)\\n 1.01MB 1.48% 100% 1.01MB 1.48% bufio.(*Scanner).Text (inline)\\n 0 0% 100% 20MB 29.17% encoding/json.(*decodeState).object\\n```\\n\\nUsually, the output varies between 65-80mb. \\n\\nSuch adventages is achieved due to marshalling the json **and** reading the HTTP response at the same time.\\n\\nLet\'s get back to the introduction. Such a huge response gives us a stream of HTTP chunks we read step by step until the FIN message comes.\\nWe can\'t make the HTTP server split every object in the response for us (probably we can, but it brings even more complexity).\\nInstead, every given chunk window we can ask, \\"Does it contain a valid json object?\\"\\n\\nAs soon as a valid object has come, we can marshal it and continue reading the response further **until the next valid JSON object comes**.\\n\\n### Third, the simplest: data compression.\\n\\nIt was new to me to discover that the most efficient solution will nott be related to the response handling.\\n\\n**We simply must transfer as little data as we can.**\\n\\nJSON is not the only way to represent the data.\\nIt\'s easy and human-readable, but sometimes we have to trade it.\\n\\nThere are plenty of formats we can apply:\\n- Avro\\n- Tthrift\\n- MessagePack\\n- Gob (Go only)\\n- Protobuf\\n\\nAnd most likely more I don\'t even know.\\n\\nI tried replacing decoding to MessagePack and gave very litle result (zero \\\\_(\u30c4)_/).\\n\\nThe best outcome showed Protobuf.\\n:::note\\nWe still use HTTP/1.1; we don\'t use gRPC transport.\\n:::\\n\\nThe output from pprof is even better with less effort to implement.\\nIt may vary up to 50mb sometimes.\\n\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 30.79MB, 100% of 30.79MB total\\n flat flat% sum% cum cum%\\n 30.79MB 100% 100% 30.79MB 100% io.ReadAll\\n 0 0% 100% 30.79MB 100% main.decode\\n 0 0% 100% 30.79MB 100% main.main\\n 0 0% 100% 30.79MB 100% runtime.main\\n```\\n\\nHere is the solution: [Link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L14)\\n\\nWhat we can say about Gob? \\n\\nIt offers very specific decoding and is a Go-only implementation, but it doesn\'t provide any benefit, here is the pprof output\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 70.81MB, 100% of 70.81MB total\\nShowing top 5 nodes out of 20\\n flat flat% sum% cum cum%\\n 30.53MB 43.12% 43.12% 30.53MB 43.12% internal/saferio.ReadData\\n 28.28MB 39.94% 83.05% 28.28MB 39.94% reflect.growslice\\n 12MB 16.95% 100% 12MB 16.95% encoding/gob.decString\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).Decode\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).DecodeValue\\n```\\n\\nPerhaps for someone, having schemaless implementation is valuable, so here is the solution [link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L40)\\n\\n\\n### Conclusion\\n\\nI found 2 interesting ideas to me during the investigation.\\n1. The best, or one of them, solution might be the most obvious, so obvious to one is not to everyone.\\n2. It\'s not hard to implement and dig into fundamentals; some may win from engineering a new bicycle."},{"id":"why-a-blog","metadata":{"permalink":"/mynameis/blog/why-a-blog","source":"@site/blog/01-why-you-need-a-blog/index.mdx","title":"Why this page exists","description":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".","date":"2023-12-13T21:25:34.000Z","formattedDate":"December 13, 2023","tags":[{"label":"career","permalink":"/mynameis/blog/tags/career"}],"readingTime":3.305,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"why-a-blog","title":"Why this page exists","authors":["denis"],"tags":["career"]},"unlisted":false,"prevItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".\\n\\n\x3c!--truncate--\x3e\\n\\nI have opinion on different things, especially in software. I\'ve been working on it since 2015. \\n\\nSo let\'s start from reasoning why you might want to own one.\\n\\n## It makes more than 0 chances somebody will find it and share your opinion\\n\\nOr disagree, it\'s also fine and in some cases means almost the the same for you.\\n\\nYou get audience.\xa0\\n\\nAnd it\'s a big deal.\\n\\nFirst, the audience challenges your ideas. It\'s good to find a person to discuss your ideas. It allows your either find weaknesses in the idea itself, or perhaps your mindset to find crucial vocabulary to express what it means for you, or become even more confident on a topic. After all, it\'s just a joy to discuss what you have on top of your head.\\n\\n## More than 0 chances your future team knows you\\n\\nIt\'s a well known that having a referral in a company makes hiring easier to everyone. They get plus a point in confidence they hire not a dumbass, you may skip long questionnaire. They refer you not because you are good at contribution, but it\'s easier to build ubiquitous language in the team when you know each other.\\n\\nI want to say having written something valuable for others makes you a little more known that you used to be. And if you apply to a new job and they have found it - it bumps your chances a lot.\\n\\nIm convinced in the idea that not just delivering good result to your company, but telling the best pieces to the others will pay me off later on.\\n\\nThe only thing is under question if we really have built and understood something important for the industry.\\n\\n## Memo is good\\n\\nDuring software experience I realised the wide range technologies I apply can hardly be stored in my head.\\n\\nTools such Obsidian are fancy, but Im not disciplined enough to handle my cloud to store it or just structure them well enough, it doesn\'t fit me.\\n\\nSo Im going to structure my experience here.\\n\\nIt\'s not just putting all I have in my memory, but also try structuring all new stuff I have in my head.\\n\\nFor instance, I want to memoize a way to define alerts using terraform. Even though I\'ve done it I have no idea what those queries to an observability provider mean.\xa0\\n\\nWhat should I do?\\n\\nNot to fool people. I will figure out in order to explain it to the others. Otherwise the article will be one of the thousands on medium or linkedin.\\n\\nEventually I have to push my skill up to give my audience valuable experience shared.\\n\\nIn the same time I get structured my experience and making it better by reading more in order to write a little.\\n\\n## Expressing better\\n\\nAnd my personal reason. \\n\\nIm poor at structuring my speach. If you read it you know how hard it was to catch my ideas. But I fight against it and I believe the blog may make me write more often and amend the way I express myself.\\n\\n## You are ready. what now?\\n\\nOk, let\'s say you confirmed you have a reason to have a blog.\\n\\n \\n\\nA couple of hints I want to add.\\n\\n \\n\\nPlatforms like medium blocks people from reading your content without subscription. \\nAnd definitely it\'s not what I want.\\n\\nI can understand if you want to setup patreon to provide sub only data, but I don\'t consider such option.\xa0\\nMoreover, the platforms get bigger revenue chunk of your ad and don\'t do more than google does.\\n\\nI picked docusaurus because I have full control on codebase, fonts, styles, ads, comments, structuring. And I was lucky enough to find a template I wanted to reuse by [takken](https://takken.io/).\\n\\nOr you can just clone this [project](https://github.com/dennypenta/mynameis)."}]}')}}]); \ No newline at end of file diff --git a/assets/js/2f6ea139.ef682ef4.js b/assets/js/2f6ea139.ef682ef4.js new file mode 100644 index 0000000..e7579b3 --- /dev/null +++ b/assets/js/2f6ea139.ef682ef4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[538],{6362:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"tq-devlog-1","metadata":{"permalink":"/mynameis/blog/tq-devlog-1","source":"@site/blog/05-tq-devlog-1/index.md","title":"PaaS devlog |#1","description":"Devlog |#1: postgres, docker, beekeeper, lazygit","date":"2024-09-03T20:16:17.000Z","formattedDate":"September 3, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":3.315,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"tq-devlog-1","title":"PaaS devlog |#1","authors":["denis"],"tags":["software"]},"unlisted":false,"nextItem":{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0"}},"content":"## Devlog |#1: postgres, docker, beekeeper, lazygit\\n\\nAnother day I actually started working on the project (what a surprise).\\n\\nI want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.\\n\\n\x3c!--truncate--\x3e\\n\\nIm convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data.\\n\\nFirst, docker compose. I can\'t imagine local environment without it. Very simple one, some volumes, passwordless acceess, expose 5432 port, done.\\n\\nI didn\'t know how my first feature will look like, a user creating, connecting a repository or saving the infrastracture state.\\nBut I needed a first migration to test it, so I created a users table. Very creative, but I really will need users table, it\'s fine.\\n\\nI installed a few dependencies:\\n```shell\\ngo get github.com/golang-migrate/migrate/v4\\ngo get github.com/jmoiron/sqlx\\ngo get github.com/jackc/pgx\\n```\\n\\nI will sqlx + squirrel for query executing, pgx as a driver and migrate for running migrations, it prodes cli interface if you want to run in the jobs and go api as well.\\n\\nI will use go api, but I wouldn\'t recomment it in production, it\'s important to create a database backup before starting a mgiration, so the best case you have a migration job that makes a backup and then runs the migration, if it worked out - release is welcome.\\n\\nThen I made a few commands to work with migration like create new, up, down and fix migration.\\n\\n:::note\\nMigration package stores the state in the same database. When it fails it writes the migration as `dirty`. Fix command is used to force the version, it\'s very useful in the development process. I even used it in prod. \\n:::\\n\\n```makefile\\nDB_DSN ?= \\"postgres://postgres@localhost:5432/tq?sslmode=disable\\"\\n\\nmigrate_new:\\n migrate create -ext sql -dir migrations -seq -digits 4 ${MNAME}\\n\\nmigrate_up:\\n migrate -path migrations -database ${DB_DSN} up\\n\\nmigrate_down:\\n migrate -path migrations -database ${DB_DSN} down\\n\\nmigrate_fix:\\n migrate -path migrations -database ${DB_DSN} force ${V}\\n\\nmigrate_v:\\n migrate -path migrations -database ${DB_DSN} version\\n```\\n\\nUsing command `make migrate_new users_table` I create a new migration and feel it with the following sql:\\n```sql\\nCREATE EXTENSION IF NOT EXISTS \\"uuid-ossp\\";\\n\\nCREATE TABLE IF NOT EXISTS users (\\n id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,\\n email varchar(85) NOT NULL,\\n password varchar(255) NOT NULL,\\n\\n createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,\\n updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL\\n);\\n```\\n\\nI like using uuid as an identity. It never fooled me. \\n\\nThen I do what I didn\'t recommend.\\n\\nYes, I run the migrations right in the starting the app server.\\nSeems ok, applied.\\n\\nI need something to see the result, the table, the extension.\\nI use psql, but to me personnaly it\'s very annoying having such long interface, it matters a lot when I have a few databases to follow.\\n\\nI looked for a tool again. I tried pgadmin, jetbrains embedded one. \\nAnd I found Beekeeper. That\'s the tool I wouldn\'t be ashamed to create. Looks very good, easy to use, to edit, look for data with 0 sql, comfortable keyboard control. \\nEverything I like. \\n__It\'s even opensourced and has a free community edition.__\\n\\nI looked at the data, the migration record exists, the users table does as well. \\n\\n![img](./beekeeper.png)\\n\\nFinally I can commit it.\\nI like using lazygit for most of my cases.\\nIt also a keyboard only control.\\nEven my brain can handle it, there are very few commands: arrows to navigate, space to stage a change, you can use mouse to stage only a part of the file, and push `c` to input a commit message and `Enter` to commit. \\nIt also has bunch of things like branches list, reflog, command log. \\n\\nAt least I don\'t repeatadly do anymore `ls, gd, ga` file by file.\\n\\n:::note\\nI use zsh and it gives me many shortcuts, for instance `ga` is equal to `git add`\\n:::\\n\\n![img](./git.png)\\n\\nThank you for reading, come here and see what\'s gonna be in the end.\\nRepository is here: http://github.com/treenq/treenq"},{"id":"tq-devlog-0","metadata":{"permalink":"/mynameis/blog/tq-devlog-0","source":"@site/blog/04-tq-devlog-0/index.md","title":"PaaS devlog |#0","description":"Devlog |#0: planing, gpt, linear","date":"2024-09-02T20:12:28.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":3.965,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"tq-devlog-0","title":"PaaS devlog |#0","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"PaaS devlog |#1","permalink":"/mynameis/blog/tq-devlog-1"},"nextItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"}},"content":"## Devlog |#0: planing, gpt, linear\\n\\nToday I want to share with you my first steps of creating new project.\\nFor a long time I\'ve wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.\\n\\n\x3c!--truncate--\x3e\\n\\nThe main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.\\n\\n:::tip\\nYou can read more about cdk [here](https://developer.hashicorp.com/terraform/cdktf)\\n:::\\n\\nAll the infra will be used from well known cloud providers (not aws ofc, no clue who can understand how to user it).\\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me.\\n\\n### The problem\\n\\nThe technical problem exists, it\'s fun to figure out.\\nBut no the main one. The biggest fight Im gonna accept is __procrastination__. Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That\'s what will stop me from the progress.\\nSo the easiest way to move progress away - do whatever, but not the progress.\\n\\n### The planing\\n\\nSo I decided to plan everything and understand how big the actual project is gonna be.\\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck. \\nInstead of asking what I should do I explained my plan and asked to ask __more questions__ so it could help me to clarify the technical solution and the plan.\\n\\n![img](./gpt.png)\\n\\n
\\n\\nHere you can find a prompt I used\\n\\nI want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It\'s a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users\' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better.\\n
\\n\\nInitially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement.\\n\\nChatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - __remocal__.\\n\\nWhen stepped into the planning I decided to make it even longer.\\nI wanted to researched all the kanban boards, unresistable.\\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though. \\n\\nI tried Cluckup, it\'s a laggish joke, even worse than Jira to make you feel you are already enterprise.\\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist.\\n\\n### The ugly thing\\n\\nIn the end I found Linear. \\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons.\\n\\nA few minutes later I started catching.\\nKeyboard first design - that\'s what I buy.\\n\\nSo I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\\nThe basic element is an issue. It might have sub-issues. And they might have.\\nThey can be collected in a project.\\n\\nThere are bunch of other staff I don\'t use, but I will share it below.\\n- Cycle - like a sprint, hate it.\\n- Triage - inbox, it\'s a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove.\\n- Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline. \\n\\nAs a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f).\\n\\n![img](./few.png)\\n\\nThank you for reading, come here and see what\'s gonna be in the end.\\nRepository is here: http://github.com/treenq/treenq"},{"id":"do-gamedev","metadata":{"permalink":"/mynameis/blog/do-gamedev","source":"@site/blog/03-do-gamedev/index.mdx","title":"Backend Guy Ventures into Game Development","description":"In order to be engaged one explores different areas and looks for unknown software area.","date":"2024-09-02T18:32:54.000Z","formattedDate":"September 2, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.53,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"do-gamedev","title":"Backend Guy Ventures into Game Development","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"PaaS devlog |#0","permalink":"/mynameis/blog/tq-devlog-0"},"nextItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"In order to be engaged one explores different areas and looks for unknown software area.\\n\\nHere we look at the gamedev in 2024 from experience in server side software.\\n\\nIn software development, it\'s common to explore new domains to stay engaged. \\nWhether it\'s for a change of pace or to push personal boundaries, exploring the unknown can lead to fancy adventures in software. \\nThis page will share my journey as a backend developer diving into the game development in 2024.\\n\\n\x3c!--truncate--\x3e\\n\\n#### Why Gamedev? \\n\\n99% of programmes came here to make a game.\\nEither did I.\\n\\nFrom a young age, I was captivated by two genres: strategy games and action RPGs. \\nMy first PC came preloaded with classics like Red Alert 2, Heroes of Might and Magic 3, and Diablo 2. \\nThe simple yet addictive gameplay\u2014click, move, destroy, enjoy \u2014 cemented my love for these genres. \\nOver the years, I\u2019ve played many iconic RTS games like Warcraft 3 and Starcraft 2 (and still do occasionally).\\nBut I realized that Starcraft 2 and similar games leaned more towards real-time execution rather than strategic depth.\\n\\nSo I decided to make my own game with the strategy and decision making take the center stage.\\n\\n#### Choosing the Game Engine \\n\\nThere are numerous options out there\u2014Defold, RPG Maker, GameMaker, Construct, to name a few.\\n\\nBut I focused on the big three that are free to start with, offer extensive flexibility, and have been tested by major projects: Unreal Engine, Unity, and Godot.\\n\\n#### Unreal Engine: A Mixed Bag of Power and Complexity\\n\\nI chose to start with Unreal Engine. It has a large community, though not the largest. Everything Unity offers in its asset store, Unreal has an equivalent. The engine supports C++ for low-level programming and Blueprints (a visual scripting language) for level design, though you can use either approach.\\n\\nInstalling the engine is a hassle. You need to first install the Epic Games Launcher and then download the 55GB engine itself, which can be a chore if your disk space is limited.\\n\\nAfter setting up a blank project, I was impressed by the vast flexibility Unreal offers. You get all the benefits of C++\u2014dynamic dependency injection, custom components, and more.. But it adds complexity.\\n1. Compiliation time. It exists. Not just exists like a couple blinks 5-10 seconds, it takes a lot of time to build a single class to start using it in the project.\\n2. Code complexity. Write header files, manual memory management. Good package manager doesn\'t exist in 2024, now I understand why they love Rust so much. \\n3. Poor mac support. No comments, even the interface of top bar menu is different, I was struggling to find editor settings according to the documentation, and every question is like that. \\n\\nI would recommend such engine for people who likes waiting, c++ and want to make a beatiful scenes with nice action. \\nI also have to note that engine is open source and owned by a technical guy and people who actually make games. I would stop there if I liked waiting and c++.\\n\\n#### Unity: The Industry Standard.\\n\\nNext up was Unity, the most popular game engine out there. \\nUnity has a vast ecosystem, with advanced features like rendering, post-processing, and easy shader creation. \\nIt\u2019s backed by a huge asset store, which should theoretically make development easier.\\nC# - Im not a big fun, but it\'s compilable, therefore type safe, seems good.\\n\\nA basic abstraction is an object. An object has compenents to manage what is it, it might be a script to move it, a mesh to render a tree, a colission not to pass through the tree, sound to play as tree leafs on the wind and so on.\\nSeems quite simple. \\n\\nBut when I approached a real problem there are plenty of weird things.\\n1. Unity has three different render pipelines, which aren\u2019t compatible with each other. The oldest one is being deprecated, meaning half the assets in the store may soon be obsolete.\\n2. Asset store is a garbage. I tried several camera controllers, and only one partially met my needs. I had to patch it to double its functionality, which felt like reinventing the wheel.\\n\\nWe all remember the Unity pricing drama. It has a closed-source codebase, and now there\u2019s a tracker that counts installations to generate more revenue for shareholders. \\nThis has led to a lot of half-baked features and outdated documentation, which can make the engine feel unstable.\\n\\nUnity is still a solid choice, but in 2024, it feels like the engine is in a weird transitional state. \\nThe documentation isn\u2019t as up-to-date as it should be, and the engine itself seems to be in a half-finished state. \\nI might revisit it in 2025 when Unity 6 is released.\\n\\n#### Godot: Unknown creature in the Sea.\\n\\nFinally, I turned to Godot, an engine I initially underestimated. \\nKnown for its strong 2D capabilities, Godot seemed lacking in 3D support. \\nIts physics engine was also rumored to be subpar.\\n\\nSo I start doing a 3D. \\nFirst I found that asset library is poor, camera controller only for Godot 3 (previous release) and it makes no sense to use Godot 3 in 2024.\\n\\nWhat I actually see in progress.\\n0. Godot\u2019s installation bundle is just 150MB. It has a negligible memory footprint and can run smoothly even on modest hardware. Coming from Unity, this was a breath of fresh air.\\n1. Godot\u2019s editor can be extended in a similar manner to Unity, allowing you to add new UI elements and dynamically instantiate new components.\\n2. The asset library isn\u2019t a store but a repository where everything is distributed for free. Since Godot is open-source, I doubt any significant part of it will go paid, unlike Unity and Unreal, where quality assets often come with a price tag.\\n3. Physics engine implementation can be replaced with jolt easy-peasy and works very well.\\n4. The same abstractions, the same component building, but not an object has component, rather a scene (actually a node) has nodes (the others to implement actual behavior of the node).\\n5. Exporting is just a button click. I managed to build a project for windows in Mac, it\'s so good, haven\'t had such smooth exprerience.\\n\\nIt was surprisingly easy to understand the basics, the nodes design, the event bus system, for a backend guy it\'s perfect to start making a real game.\\n\\nGDScript can fail in runtime, not the best, but you can use C# for the sake of compilte time failure.\\n\\nAnd I know, the community is smaller, it will be developed slower, true. But I care about me today, not the community.\\n\\nI initially planned to give Unity a fair shot, spending a week with both engines. \\nBut after just two days with Godot, I was progressing so much faster that I decided it wasn\u2019t worth the time to continue with Unity. \\nGodot\u2019s lower entry barrier and faster development pace made it the clear choice for me.\\n\\n##### I want to finish simpler. \\n\\nIn the end, the best engine is the one that aligns with your needs and preferences. \\nRemember, Blender was once considered a niche tool while everyone used 3D Max, and now Blender is the industry standard. \\nFirebase was just a \u201cbase,\u201d and today we have Supabase, Pocketbase and many others.\\n\\nThe landscape of game development is always changing. \\nWhat matters most is finding the tool that helps you bring your vision to life, not what the industry standard is. \\nFor me, that tool is Godot.\\n\\n### Lessons\\nSpoiler, no, I didn\'t finish a game, I learned the gamedev abstractions and played with the engines a bit and I enjoyed it.\\nAnd it\'s fine, I had good time and wish everyone to find a toy you can spend some time on and make you engaged."},{"id":"big-json","metadata":{"permalink":"/mynameis/blog/big-json","source":"@site/blog/02-250mbjson-in-50mb-limit/index.mdx","title":"250mb json in a 40mb service limit","description":"This article has been created to remind us of one simple thing: HTTP is a stream.","date":"2024-05-26T15:48:12.000Z","formattedDate":"May 26, 2024","tags":[{"label":"software","permalink":"/mynameis/blog/tags/software"}],"readingTime":6.8,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"big-json","title":"250mb json in a 40mb service limit","authors":["denis"],"tags":["software"]},"unlisted":false,"prevItem":{"title":"Backend Guy Ventures into Game Development","permalink":"/mynameis/blog/do-gamedev"},"nextItem":{"title":"Why this page exists","permalink":"/mynameis/blog/why-a-blog"}},"content":"This article has been created to remind us of one simple thing: HTTP is a stream.\\n\\nAs a practical outcome we can learn how to reduce memory requirements for our services in a typical task: cache warming.\\n\\n\x3c!--truncate--\x3e\\n\\nLet\'s look at the challenge first.\\n\\nWe have a service that must download the data and keep it in memory.\\nThe issue is the JSON document we have to download is 10 times larger than the encoded data. \\nTherefore we have to increase the memory limit 2-3 times to download it once. \\nLater on, the service doesn\'t consume as much memory, so it\'s a start up cost.\\n\\n\\n### The challenge: cut down the memory consumption as much as we can.\\n\\nLet\'s get back to the basic of network communication.\\n\\n:::note\\nWe skip TLS termination for the sake of simplicity.\\n:::\\n\\nThere is a great book that explains it very well: https://hpbn.co/building-blocks-of-tcp/#slow-start\\n\\n![img](./syn.svg)\\n\\nJust a litle picture to remind us how a connection starts: we do a handshake with the service.\\n\\nThen we can start exchanging data.\\nTypical API responses are at most ~50kb.\\n\\nBut what if you want to warm a cache? How much can it be? \\nIt can be a lot, around tens of megabytes.\\nIn my example, we take 250mb.\\n\\nHow does the server send such data?\\n\\n![img](./congestion.svg)\\n\\nSlowly, packet by packet.\\n\\nThe server tries to understand your throughput. The protocol itself rarely provides an accurate value of a packet size, so by relying on the imperical latency, it tunes the packet size little by little.\\nIt needs to send a lot of packets to transfer a really big response.\\n\\n### 3 Ways to do it\\n\\nBelow we will consider 3 approaches to solve this task.\\nThere is no such thing as the only right solution; all of them are fine as long as you understand the costs and risks well enough, and we are gonna cover them.\\n\\n### First, Brute Force solution.\\n\\n:::warning\\nIf you want to reproduce an example make sure to untar server/json.tar.gz; it must contain the f.json file since GitHub has a limit of up to 100mb for a file.\\n:::\\n\\nYou can imagine how the simplest Go HTTP client can implement it or just look at the code.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/543510947c0b19dbc0097adf403ae5cd6954c1cc/client/main.go)\\n\\nThe implementation is straight forward: it sends a request, gets a response, reads, marhsals it into a defined structure, holds it in the memory and ready to serve it further.\\n\\nAnd here is the pprof output:\\n\\n```shell\\nShowing nodes accounting for 229.48MB, 100% of 229.48MB total\\n flat flat% sum% cum cum%\\n 229.48MB 100% 100% 229.48MB 100% io.ReadAll\\n 0 0% 100% 229.48MB 100% main.main\\n 0 0% 100% 229.48MB 100% runtime.main\\n```\\n\\nYes, it\'s not real win, with huge memory consumption, but it works ok.\\n\\nWe see all the memory consumed on reading the HTTP stream.\\n\\nOr you might say, \\"What a noob, you must use `json.Decoder`\\" so as to let the decoder work with the HTTP pipe closer.\\n\\nAnd it\'s pretty much the same, in my example, even worse.\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b6ee7fcfd69fdffad844eb6a3d324d2fe3040985/client/main.go) to code with Decoder\\n\\n```shell\\nShowing nodes accounting for 384MB, 100% of 384MB total\\n flat flat% sum% cum cum%\\n 384MB 100% 100% 384MB 100% encoding/json.(*Decoder).refill\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).Decode\\n 0 0% 100% 384MB 100% encoding/json.(*Decoder).readValue\\n 0 0% 100% 384MB 100% main.main\\n 0 0% 100% 384MB 100% runtime.main\\n```\\n\\nTo recall why let\'s dig a little into the json/encoding library [implementation](https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/encoding/json/stream.go;l=49). \\n\\n```go\\nfunc (dec *Decoder) Decode(v any) error {\\n\\tif dec.err != nil {\\n\\t\\treturn dec.err\\n\\t}\\n\\n\\tif err := dec.tokenPrepareForDecode(); err != nil {\\n\\t\\treturn err\\n\\t}\\n\\n\\tif !dec.tokenValueAllowed() {\\n\\t\\treturn &SyntaxError{msg: \\"not at beginning of value\\", Offset: dec.InputOffset()}\\n\\t}\\n\\n\\t// Read whole value into buffer.\\n\\tn, err := dec.readValue()\\n\\tif err != nil {\\n\\t\\treturn err\\n\\t}\\n\\tdec.d.init(dec.buf[dec.scanp : dec.scanp+n])\\n\\tdec.scanp += n\\n\\n\\t// Don\'t save err from unmarshal into dec.err:\\n\\t// the connection is still usable since we read a complete JSON\\n\\t// object from it before the error happened.\\n\\terr = dec.d.unmarshal(v)\\n\\n\\t// fixup token streaming state\\n\\tdec.tokenValueEnd()\\n\\n\\treturn err\\n}\\n```\\n\\nIt does exactly the same, it calls `dec.readValue()` first to read all the response and then `dec.d.unmarshal` to parse it.\\n\\nAnd it\'s ok; the reason is very simple: **encoding/json doesn\'t know the nature of your data.**\\n\\n:::note\\nLibraries like [json-iter](https://github.com/json-iterator/go) or [easyjson](https://github.com/mailru/easyjson) offer zero improvements in memory consumption.\\n:::\\n\\n### Second, decode object by object.\\n\\nGo json library provides a method of the Decoder called [`Token`](https://pkg.go.dev/encoding/json#Decoder.Token)\\n\\nThis approach, parsing manually token by token, can give us an option to manually parse the json.\\nA token might be every symbol, such as as open bracket, quote, key, value, etc.\\nBut I found this approach quite complex. Having a deeply nested JSON object makes it very confusing to understand the relation for a given token. An solution could be to hold every key and designated level, but the decision gets worse with duplicated keys on a couple of levels.\\n\\nThat\'s why I prefer another approach.\\n\\nThere is a well-known problem on LeetCode called \\"[Valid Parentheses](https://leetcode.com/problems/valid-parentheses/description/)\\"\\n\\nWe can simply read the beginning of a given object and the end, understanding when the last bracket of the object comes.\\n\\n[Link](https://github.com/dennypenta/http-response-lab/blob/b5890cbb74282416b5adacc92de95f18f7ee766f/client/main.go#L110)\\n\\npprof gives the following output\\n```shell\\n(pprof) top 5\\nShowing nodes accounting for 68.56MB, 100% of 68.56MB total\\nShowing top 5 nodes out of 10\\n flat flat% sum% cum cum%\\n 27.55MB 40.18% 40.18% 68.56MB 100% main.decode\\n 20MB 29.17% 69.35% 20MB 29.17% encoding/json.(*decodeState).literalStore\\n 20MB 29.17% 98.52% 20MB 29.17% bufio.NewReaderSize (inline)\\n 1.01MB 1.48% 100% 1.01MB 1.48% bufio.(*Scanner).Text (inline)\\n 0 0% 100% 20MB 29.17% encoding/json.(*decodeState).object\\n```\\n\\nUsually, the output varies between 65-80mb. \\n\\nSuch adventages is achieved due to marshalling the json **and** reading the HTTP response at the same time.\\n\\nLet\'s get back to the introduction. Such a huge response gives us a stream of HTTP chunks we read step by step until the FIN message comes.\\nWe can\'t make the HTTP server split every object in the response for us (probably we can, but it brings even more complexity).\\nInstead, every given chunk window we can ask, \\"Does it contain a valid json object?\\"\\n\\nAs soon as a valid object has come, we can marshal it and continue reading the response further **until the next valid JSON object comes**.\\n\\n### Third, the simplest: data compression.\\n\\nIt was new to me to discover that the most efficient solution will nott be related to the response handling.\\n\\n**We simply must transfer as little data as we can.**\\n\\nJSON is not the only way to represent the data.\\nIt\'s easy and human-readable, but sometimes we have to trade it.\\n\\nThere are plenty of formats we can apply:\\n- Avro\\n- Tthrift\\n- MessagePack\\n- Gob (Go only)\\n- Protobuf\\n\\nAnd most likely more I don\'t even know.\\n\\nI tried replacing decoding to MessagePack and gave very litle result (zero \\\\_(\u30c4)_/).\\n\\nThe best outcome showed Protobuf.\\n:::note\\nWe still use HTTP/1.1; we don\'t use gRPC transport.\\n:::\\n\\nThe output from pprof is even better with less effort to implement.\\nIt may vary up to 50mb sometimes.\\n\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 30.79MB, 100% of 30.79MB total\\n flat flat% sum% cum cum%\\n 30.79MB 100% 100% 30.79MB 100% io.ReadAll\\n 0 0% 100% 30.79MB 100% main.decode\\n 0 0% 100% 30.79MB 100% main.main\\n 0 0% 100% 30.79MB 100% runtime.main\\n```\\n\\nHere is the solution: [Link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L14)\\n\\nWhat we can say about Gob? \\n\\nIt offers very specific decoding and is a Go-only implementation, but it doesn\'t provide any benefit, here is the pprof output\\n```shell\\n(pprof) top5\\nShowing nodes accounting for 70.81MB, 100% of 70.81MB total\\nShowing top 5 nodes out of 20\\n flat flat% sum% cum cum%\\n 30.53MB 43.12% 43.12% 30.53MB 43.12% internal/saferio.ReadData\\n 28.28MB 39.94% 83.05% 28.28MB 39.94% reflect.growslice\\n 12MB 16.95% 100% 12MB 16.95% encoding/gob.decString\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).Decode\\n 0 0% 100% 70.81MB 100% encoding/gob.(*Decoder).DecodeValue\\n```\\n\\nPerhaps for someone, having schemaless implementation is valuable, so here is the solution [link](https://github.com/dennypenta/http-response-lab/blob/main/client/main.go#L40)\\n\\n\\n### Conclusion\\n\\nI found 2 interesting ideas to me during the investigation.\\n1. The best, or one of them, solution might be the most obvious, so obvious to one is not to everyone.\\n2. It\'s not hard to implement and dig into fundamentals; some may win from engineering a new bicycle."},{"id":"why-a-blog","metadata":{"permalink":"/mynameis/blog/why-a-blog","source":"@site/blog/01-why-you-need-a-blog/index.mdx","title":"Why this page exists","description":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".","date":"2023-12-13T21:25:34.000Z","formattedDate":"December 13, 2023","tags":[{"label":"career","permalink":"/mynameis/blog/tags/career"}],"readingTime":3.305,"hasTruncateMarker":true,"authors":[{"name":"Denis","title":"Software Experience Dude","key":"denis"}],"frontMatter":{"slug":"why-a-blog","title":"Why this page exists","authors":["denis"],"tags":["career"]},"unlisted":false,"prevItem":{"title":"250mb json in a 40mb service limit","permalink":"/mynameis/blog/big-json"}},"content":"Blog is a\xa0 system to spread ideas across the internet. Shout out about a thing \\"Look, I have an opinion on that if you care\\".\\n\\n\x3c!--truncate--\x3e\\n\\nI have opinion on different things, especially in software. I\'ve been working on it since 2015. \\n\\nSo let\'s start from reasoning why you might want to own one.\\n\\n## It makes more than 0 chances somebody will find it and share your opinion\\n\\nOr disagree, it\'s also fine and in some cases means almost the the same for you.\\n\\nYou get audience.\xa0\\n\\nAnd it\'s a big deal.\\n\\nFirst, the audience challenges your ideas. It\'s good to find a person to discuss your ideas. It allows your either find weaknesses in the idea itself, or perhaps your mindset to find crucial vocabulary to express what it means for you, or become even more confident on a topic. After all, it\'s just a joy to discuss what you have on top of your head.\\n\\n## More than 0 chances your future team knows you\\n\\nIt\'s a well known that having a referral in a company makes hiring easier to everyone. They get plus a point in confidence they hire not a dumbass, you may skip long questionnaire. They refer you not because you are good at contribution, but it\'s easier to build ubiquitous language in the team when you know each other.\\n\\nI want to say having written something valuable for others makes you a little more known that you used to be. And if you apply to a new job and they have found it - it bumps your chances a lot.\\n\\nIm convinced in the idea that not just delivering good result to your company, but telling the best pieces to the others will pay me off later on.\\n\\nThe only thing is under question if we really have built and understood something important for the industry.\\n\\n## Memo is good\\n\\nDuring software experience I realised the wide range technologies I apply can hardly be stored in my head.\\n\\nTools such Obsidian are fancy, but Im not disciplined enough to handle my cloud to store it or just structure them well enough, it doesn\'t fit me.\\n\\nSo Im going to structure my experience here.\\n\\nIt\'s not just putting all I have in my memory, but also try structuring all new stuff I have in my head.\\n\\nFor instance, I want to memoize a way to define alerts using terraform. Even though I\'ve done it I have no idea what those queries to an observability provider mean.\xa0\\n\\nWhat should I do?\\n\\nNot to fool people. I will figure out in order to explain it to the others. Otherwise the article will be one of the thousands on medium or linkedin.\\n\\nEventually I have to push my skill up to give my audience valuable experience shared.\\n\\nIn the same time I get structured my experience and making it better by reading more in order to write a little.\\n\\n## Expressing better\\n\\nAnd my personal reason. \\n\\nIm poor at structuring my speach. If you read it you know how hard it was to catch my ideas. But I fight against it and I believe the blog may make me write more often and amend the way I express myself.\\n\\n## You are ready. what now?\\n\\nOk, let\'s say you confirmed you have a reason to have a blog.\\n\\n \\n\\nA couple of hints I want to add.\\n\\n \\n\\nPlatforms like medium blocks people from reading your content without subscription. \\nAnd definitely it\'s not what I want.\\n\\nI can understand if you want to setup patreon to provide sub only data, but I don\'t consider such option.\xa0\\nMoreover, the platforms get bigger revenue chunk of your ad and don\'t do more than google does.\\n\\nI picked docusaurus because I have full control on codebase, fonts, styles, ads, comments, structuring. And I was lucky enough to find a template I wanted to reuse by [takken](https://takken.io/).\\n\\nOr you can just clone this [project](https://github.com/dennypenta/mynameis)."}]}')}}]); \ No newline at end of file diff --git a/assets/js/5ea76644.4806c503.js b/assets/js/5ea76644.4806c503.js new file mode 100644 index 0000000..1ddd3d9 --- /dev/null +++ b/assets/js/5ea76644.4806c503.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[644],{8826:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=n(5893),i=n(1151);const o={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},r=void 0,s={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0: planing, gpt, linear",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.965,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,prevItem:{title:"PaaS devlog |#1",permalink:"/mynameis/blog/tq-devlog-1"},nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},l={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0: planing, gpt, linear",id:"devlog-0-planing-gpt-linear",level:2},{value:"The problem",id:"the-problem",level:3},{value:"The planing",id:"the-planing",level:3},{value:"The ugly thing",id:"the-ugly-thing",level:3}];function c(e){const t={a:"a",admonition:"admonition",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.a)(),...e.components},{Details:o}=t;return o||function(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-0-planing-gpt-linear",children:"Devlog |#0: planing, gpt, linear"}),"\n",(0,a.jsx)(t.p,{children:"Today I want to share with you my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."}),"\n",(0,a.jsx)(t.p,{children:"The main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration."}),"\n",(0,a.jsx)(t.admonition,{type:"tip",children:(0,a.jsxs)(t.p,{children:["You can read more about cdk ",(0,a.jsx)(t.a,{href:"https://developer.hashicorp.com/terraform/cdktf",children:"here"})]})}),"\n",(0,a.jsx)(t.p,{children:"All the infra will be used from well known cloud providers (not aws ofc, no clue who can understand how to user it).\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me."}),"\n",(0,a.jsx)(t.h3,{id:"the-problem",children:"The problem"}),"\n",(0,a.jsxs)(t.p,{children:["The technical problem exists, it's fun to figure out.\nBut no the main one. The biggest fight Im gonna accept is ",(0,a.jsx)(t.strong,{children:"procrastination"}),". Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That's what will stop me from the progress.\nSo the easiest way to move progress away - do whatever, but not the progress."]}),"\n",(0,a.jsx)(t.h3,{id:"the-planing",children:"The planing"}),"\n",(0,a.jsxs)(t.p,{children:["So I decided to plan everything and understand how big the actual project is gonna be.\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck.\nInstead of asking what I should do I explained my plan and asked to ask ",(0,a.jsx)(t.strong,{children:"more questions"})," so it could help me to clarify the technical solution and the plan."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(8323).Z+"",width:"817",height:"1036"})}),"\n",(0,a.jsxs)(o,{children:[(0,a.jsx)("summary",{children:(0,a.jsx)(t.p,{children:"Here you can find a prompt I used"})}),(0,a.jsx)(t.p,{children:"I want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It's a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better."})]}),"\n",(0,a.jsx)(t.p,{children:"Initially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement."}),"\n",(0,a.jsxs)(t.p,{children:["Chatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - ",(0,a.jsx)(t.strong,{children:"remocal"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"When stepped into the planning I decided to make it even longer.\nI wanted to researched all the kanban boards, unresistable.\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though."}),"\n",(0,a.jsx)(t.p,{children:"I tried Cluckup, it's a laggish joke, even worse than Jira to make you feel you are already enterprise.\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist."}),"\n",(0,a.jsx)(t.h3,{id:"the-ugly-thing",children:"The ugly thing"}),"\n",(0,a.jsx)(t.p,{children:"In the end I found Linear.\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons."}),"\n",(0,a.jsx)(t.p,{children:"A few minutes later I started catching.\nKeyboard first design - that's what I buy."}),"\n",(0,a.jsx)(t.p,{children:"So I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\nThe basic element is an issue. It might have sub-issues. And they might have.\nThey can be collected in a project."}),"\n",(0,a.jsx)(t.p,{children:"There are bunch of other staff I don't use, but I will share it below."}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Cycle - like a sprint, hate it."}),"\n",(0,a.jsx)(t.li,{children:"Triage - inbox, it's a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove."}),"\n",(0,a.jsx)(t.li,{children:"Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline."}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"As a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f)."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(4753).Z+"",width:"1632",height:"1121"})}),"\n",(0,a.jsxs)(t.p,{children:["Thank you for reading, come here and see what's gonna be in the end.\nRepository is here: ",(0,a.jsx)(t.a,{href:"http://github.com/treenq/treenq",children:"http://github.com/treenq/treenq"})]})]})}function h(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},4753:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/few-a8829c782e27ba5f7f88f18ced787cf4.png"},8323:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/gpt-b6084e0c9c75c7a74f335fb999dde350.png"},1151:(e,t,n)=>{n.d(t,{Z:()=>s,a:()=>r});var a=n(7294);const i={},o=a.createContext(i);function r(e){const t=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function s(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5ea76644.65448e33.js b/assets/js/5ea76644.65448e33.js deleted file mode 100644 index 35f34f3..0000000 --- a/assets/js/5ea76644.65448e33.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[644],{8826:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=n(5893),i=n(1151);const o={slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},r=void 0,s={permalink:"/mynameis/blog/tq-devlog-0",source:"@site/blog/04-tq-devlog-0/index.md",title:"PaaS devlog |#0",description:"Devlog |#0",date:"2024-09-02T20:12:28.000Z",formattedDate:"September 2, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.955,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-0",title:"PaaS devlog |#0",authors:["denis"],tags:["software"]},unlisted:!1,prevItem:{title:"PaaS devlog |#1",permalink:"/mynameis/blog/tq-devlog-1"},nextItem:{title:"Backend Guy Ventures into Game Development",permalink:"/mynameis/blog/do-gamedev"}},l={authorsImageUrls:[void 0]},d=[{value:"Devlog |#0",id:"devlog-0",level:2},{value:"The problem",id:"the-problem",level:3},{value:"The planing",id:"the-planing",level:3},{value:"The ugly thing",id:"the-ugly-thing",level:3}];function c(e){const t={a:"a",admonition:"admonition",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",strong:"strong",ul:"ul",...(0,i.a)(),...e.components},{Details:o}=t;return o||function(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h2,{id:"devlog-0",children:"Devlog |#0"}),"\n",(0,a.jsx)(t.p,{children:"Today I want to share with you my first steps of creating new project.\nFor a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service."}),"\n",(0,a.jsx)(t.p,{children:"The main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration."}),"\n",(0,a.jsx)(t.admonition,{type:"tip",children:(0,a.jsxs)(t.p,{children:["You can read more about cdk ",(0,a.jsx)(t.a,{href:"https://developer.hashicorp.com/terraform/cdktf",children:"here"})]})}),"\n",(0,a.jsx)(t.p,{children:"All the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it).\nFirst iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me."}),"\n",(0,a.jsx)(t.h3,{id:"the-problem",children:"The problem"}),"\n",(0,a.jsxs)(t.p,{children:["The technical problem exists, it's fun to figure out.\nBut no the main one. The biggest fight Im gonna accept is ",(0,a.jsx)(t.strong,{children:"procrastination"}),". Im such a person who pushes further all the tasks very often. I just have little to do with time discipline. That's what will stop me from the progress.\nSo the easiest way to move progress away - do whatever, but not the progress."]}),"\n",(0,a.jsx)(t.h3,{id:"the-planing",children:"The planing"}),"\n",(0,a.jsxs)(t.p,{children:["So I decided to plan everything and understand how big the actual project is gonna be.\nSo I start speaking with GPT in order to express my mind, kinda talking to a duck.\nInstead of asking what I should do I explained my plan and asked to ask ",(0,a.jsx)(t.strong,{children:"more questions"})," so it could help me to clarify the technical solution and the plan."]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(8323).Z+"",width:"817",height:"1036"})}),"\n",(0,a.jsxs)(o,{children:[(0,a.jsx)("summary",{children:(0,a.jsx)(t.p,{children:"Here you can find a prompt I used"})}),(0,a.jsx)(t.p,{children:"I want to develop a platform like digitalocean app, vercel, render, fly.io, heroku, etc. My value is the following: I give observability with 0 code changes, and a localdev opportunity with connecting to a cloud environment, for instance a request comes from a frontend app on staging to my backend app locally so I could intercept it and make my laptop appear kinda in the cloud. It's a multitenant project. There are 2 paths: kubernetes and a custom architecture. To build a custom architecture the app must be on a few virtual machines, a load balancer on top including firewall. The challenge: ask me necessary questions so we could make a right decision. I have to highlight, we build a users' environment, not the product architecture I will create in order to reproduce the given environment, so we need to decide that would fit me and users better."})]}),"\n",(0,a.jsx)(t.p,{children:"Initially I thought I will do it providing a user set of virtual machines connected under VPC, putting a load balancer on top, back to 2000. I thought it will make it cheaper and some tools just easier to implement."}),"\n",(0,a.jsxs)(t.p,{children:["Chatting to GPT I realized - Kubernetes will provide it a way quicker, most of the stuff is just ready to go like network policies, load balancing, SSL, deployment/rollback, health monitoring, resources observability, Istio adoption. Istio is very useful for observability and local first development, it became a new word today - ",(0,a.jsx)(t.strong,{children:"remocal"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"When stepped into the planning I decided to make it even longer.\nI wanted to researched all the kanban boards, unresistable.\nI used to use Trello and it was ok, but using api in power-ups boundaries sucks. Not really somethign I need right now though."}),"\n",(0,a.jsx)(t.p,{children:"I tried Cluckup, it's a laggish joke, even worse than Jira to make you feel you are already enterprise.\nI tried Asana and saw 0 difference with Trello, I spent about 2 minutes to confirm it and exist."}),"\n",(0,a.jsx)(t.h3,{id:"the-ugly-thing",children:"The ugly thing"}),"\n",(0,a.jsx)(t.p,{children:"In the end I found Linear.\nTo be fair it looked ugly, the design is equal to supabase: fonts, buttons."}),"\n",(0,a.jsx)(t.p,{children:"A few minutes later I started catching.\nKeyboard first design - that's what I buy."}),"\n",(0,a.jsx)(t.p,{children:"So I read Linear Method, the framework they apply internally. It was hard to accept it, I think older I get more conservatibe I become, but I dig it anyway.\nThe basic element is an issue. It might have sub-issues. And they might have.\nThey can be collected in a project."}),"\n",(0,a.jsx)(t.p,{children:"There are bunch of other staff I don't use, but I will share it below."}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"Cycle - like a sprint, hate it."}),"\n",(0,a.jsx)(t.li,{children:"Triage - inbox, it's a boss feature in my opinion, you can aggregate communication channels in a single place, then an on-call person can carry them, create issues or remove."}),"\n",(0,a.jsx)(t.li,{children:"Initiative - collection of the projects, they can be presented as a time line or a strategy decision, or even a roadmap on a timeline."}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"As a result I cooked quite a few cards (48 projects in a backlog \ud83d\ude31\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f)."}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"img",src:n(4753).Z+"",width:"1632",height:"1121"})}),"\n",(0,a.jsxs)(t.p,{children:["Thank you for reading, come here and see what's gonna be in the end.\nRepository is here: ",(0,a.jsx)(t.a,{href:"http://github.com/treenq/treenq",children:"http://github.com/treenq/treenq"})]})]})}function h(e={}){const{wrapper:t}={...(0,i.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},4753:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/few-a8829c782e27ba5f7f88f18ced787cf4.png"},8323:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/gpt-b6084e0c9c75c7a74f335fb999dde350.png"},1151:(e,t,n)=>{n.d(t,{Z:()=>s,a:()=>r});var a=n(7294);const i={},o=a.createContext(i);function r(e){const t=a.useContext(o);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function s(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/dfd01fac.69c1ff4f.js b/assets/js/dfd01fac.69c1ff4f.js deleted file mode 100644 index 070a6c5..0000000 --- a/assets/js/dfd01fac.69c1ff4f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[24],{8956:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var o=n(5893),a=n(1151);const r={slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},s=void 0,i={permalink:"/mynameis/blog/tq-devlog-1",source:"@site/blog/05-tq-devlog-1/index.md",title:"PaaS devlog |#1",description:"Devlog |#1",date:"2024-09-03T18:48:09.000Z",formattedDate:"September 3, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.295,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"PaaS devlog |#0",permalink:"/mynameis/blog/tq-devlog-0"}},l={authorsImageUrls:[void 0]},c=[{value:"Devlog |#1",id:"devlog-1",level:2}];function d(e){const t={h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h2,{id:"devlog-1",children:"Devlog |#1"}),"\n",(0,o.jsx)(t.p,{children:"Another day I actually started working on the project (what a surprise)."}),"\n",(0,o.jsx)(t.p,{children:"I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more."})]})}function m(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>i,a:()=>s});var o=n(7294);const a={},r=o.createContext(a);function s(e){const t=o.useContext(r);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),o.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/dfd01fac.ec96ded6.js b/assets/js/dfd01fac.ec96ded6.js new file mode 100644 index 0000000..6465609 --- /dev/null +++ b/assets/js/dfd01fac.ec96ded6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmynameis=self.webpackChunkmynameis||[]).push([[24],{8956:(e,t,o)=>{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>g,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var n=o(5893),a=o(1151);const r={slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},s=void 0,i={permalink:"/mynameis/blog/tq-devlog-1",source:"@site/blog/05-tq-devlog-1/index.md",title:"PaaS devlog |#1",description:"Devlog |#1: postgres, docker, beekeeper, lazygit",date:"2024-09-03T20:16:17.000Z",formattedDate:"September 3, 2024",tags:[{label:"software",permalink:"/mynameis/blog/tags/software"}],readingTime:3.315,hasTruncateMarker:!0,authors:[{name:"Denis",title:"Software Experience Dude",key:"denis"}],frontMatter:{slug:"tq-devlog-1",title:"PaaS devlog |#1",authors:["denis"],tags:["software"]},unlisted:!1,nextItem:{title:"PaaS devlog |#0",permalink:"/mynameis/blog/tq-devlog-0"}},l={authorsImageUrls:[void 0]},c=[{value:"Devlog |#1: postgres, docker, beekeeper, lazygit",id:"devlog-1-postgres-docker-beekeeper-lazygit",level:2}];function d(e){const t={h2:"h2",p:"p",...(0,a.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h2,{id:"devlog-1-postgres-docker-beekeeper-lazygit",children:"Devlog |#1: postgres, docker, beekeeper, lazygit"}),"\n",(0,n.jsx)(t.p,{children:"Another day I actually started working on the project (what a surprise)."}),"\n",(0,n.jsx)(t.p,{children:"I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more."})]})}function g(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},1151:(e,t,o)=>{o.d(t,{Z:()=>i,a:()=>s});var n=o(7294);const a={},r=n.createContext(a);function s(e){const t=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),n.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.b20f0120.js b/assets/js/runtime~main.b20f0120.js new file mode 100644 index 0000000..52c0b40 --- /dev/null +++ b/assets/js/runtime~main.b20f0120.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,t,a,r,c,o={},f={};function n(e){var t=f[e];if(void 0!==t)return t.exports;var a=f[e]={id:e,loaded:!1,exports:{}};return o[e].call(a.exports,a,a.exports,n),a.loaded=!0,a.exports}n.m=o,n.c=f,e=[],n.O=(t,a,r,c)=>{if(!a){var o=1/0;for(b=0;b=c)&&Object.keys(n.O).every((e=>n.O[e](a[d])))?a.splice(d--,1):(f=!1,c0&&e[b-1][2]>c;b--)e[b]=e[b-1];e[b]=[a,r,c]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var c=Object.create(null);n.r(c);var o={};t=t||[null,a({}),a([]),a(a)];for(var f=2&r&&e;"object"==typeof f&&!~t.indexOf(f);f=a(f))Object.getOwnPropertyNames(f).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,n.d(c,o),c},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,a)=>(n.f[a](e,t),t)),[])),n.u=e=>"assets/js/"+({4:"b7209ac4",13:"01a85c17",24:"dfd01fac",68:"6c979130",85:"1f391b9e",89:"a6aa9e1f",103:"ccc49370",170:"11ca47d7",237:"1df93b7f",343:"e37f4f80",414:"393be207",445:"0c073a7b",531:"1a1195cb",535:"814f3328",538:"2f6ea139",608:"9e4087bc",610:"6875c492",644:"5ea76644",675:"7bdc3b36",682:"2e217b76",779:"c5a8c89d",806:"27df296f",831:"24ca0b60",837:"e79bf1a2",872:"15e7fec8",883:"367c4eda",925:"0e2cd4ea",977:"0e5f3422"}[e]||e)+"."+{4:"a1d73d79",13:"e8155e96",24:"ec96ded6",68:"c4f72816",85:"787747f8",89:"cdd0566c",103:"83126e0c",154:"b7a4622c",170:"dddbe21b",196:"482f5689",237:"18bcbf1c",343:"5e2ddcac",414:"599860c6",445:"f2fcad0b",460:"0fa1d751",531:"8151e10e",535:"bbd20a50",538:"ef682ef4",608:"f1fad664",610:"c4f75ad0",644:"4806c503",675:"d74ffcb3",682:"fe921355",748:"3a69f8d8",779:"f90e2fd6",806:"7bb8c709",831:"d1422d50",837:"e25bc4e1",872:"e04e84a8",883:"b26743dc",925:"35abd5c7",977:"e7d646dc"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},c="mynameis:",n.l=(e,t,a,o)=>{if(r[e])r[e].push(t);else{var f,d;if(void 0!==a)for(var i=document.getElementsByTagName("script"),b=0;b{f.onerror=f.onload=null,clearTimeout(s);var c=r[e];if(delete r[e],f.parentNode&&f.parentNode.removeChild(f),c&&c.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:f}),12e4);f.onerror=l.bind(null,f.onerror),f.onload=l.bind(null,f.onload),d&&document.head.appendChild(f)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/mynameis/",n.gca=function(e){return e={b7209ac4:"4","01a85c17":"13",dfd01fac:"24","6c979130":"68","1f391b9e":"85",a6aa9e1f:"89",ccc49370:"103","11ca47d7":"170","1df93b7f":"237",e37f4f80:"343","393be207":"414","0c073a7b":"445","1a1195cb":"531","814f3328":"535","2f6ea139":"538","9e4087bc":"608","6875c492":"610","5ea76644":"644","7bdc3b36":"675","2e217b76":"682",c5a8c89d:"779","27df296f":"806","24ca0b60":"831",e79bf1a2:"837","15e7fec8":"872","367c4eda":"883","0e2cd4ea":"925","0e5f3422":"977"}[e]||e,n.p+n.u(e)},(()=>{var e={303:0,532:0};n.f.j=(t,a)=>{var r=n.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var c=new Promise(((a,c)=>r=e[t]=[a,c]));a.push(r[2]=c);var o=n.p+n.u(t),f=new Error;n.l(o,(a=>{if(n.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var c=a&&("load"===a.type?"missing":a.type),o=a&&a.target&&a.target.src;f.message="Loading chunk "+t+" failed.\n("+c+": "+o+")",f.name="ChunkLoadError",f.type=c,f.request=o,r[1](f)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,a)=>{var r,c,o=a[0],f=a[1],d=a[2],i=0;if(o.some((t=>0!==e[t]))){for(r in f)n.o(f,r)&&(n.m[r]=f[r]);if(d)var b=d(n)}for(t&&t(a);i{"use strict";var e,t,r,a,c,o={},f={};function n(e){var t=f[e];if(void 0!==t)return t.exports;var r=f[e]={id:e,loaded:!1,exports:{}};return o[e].call(r.exports,r,r.exports,n),r.loaded=!0,r.exports}n.m=o,n.c=f,e=[],n.O=(t,r,a,c)=>{if(!r){var o=1/0;for(b=0;b=c)&&Object.keys(n.O).every((e=>n.O[e](r[d])))?r.splice(d--,1):(f=!1,c0&&e[b-1][2]>c;b--)e[b]=e[b-1];e[b]=[r,a,c]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var c=Object.create(null);n.r(c);var o={};t=t||[null,r({}),r([]),r(r)];for(var f=2&a&&e;"object"==typeof f&&!~t.indexOf(f);f=r(f))Object.getOwnPropertyNames(f).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,n.d(c,o),c},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,r)=>(n.f[r](e,t),t)),[])),n.u=e=>"assets/js/"+({4:"b7209ac4",13:"01a85c17",24:"dfd01fac",68:"6c979130",85:"1f391b9e",89:"a6aa9e1f",103:"ccc49370",170:"11ca47d7",237:"1df93b7f",343:"e37f4f80",414:"393be207",445:"0c073a7b",531:"1a1195cb",535:"814f3328",538:"2f6ea139",608:"9e4087bc",610:"6875c492",644:"5ea76644",675:"7bdc3b36",682:"2e217b76",779:"c5a8c89d",806:"27df296f",831:"24ca0b60",837:"e79bf1a2",872:"15e7fec8",883:"367c4eda",925:"0e2cd4ea",977:"0e5f3422"}[e]||e)+"."+{4:"a1d73d79",13:"e8155e96",24:"69c1ff4f",68:"c4f72816",85:"787747f8",89:"cdd0566c",103:"83126e0c",154:"b7a4622c",170:"dddbe21b",196:"482f5689",237:"18bcbf1c",343:"5e2ddcac",414:"599860c6",445:"f2fcad0b",460:"0fa1d751",531:"1314ed7d",535:"bbd20a50",538:"b01cd6c9",608:"f1fad664",610:"c4f75ad0",644:"65448e33",675:"d74ffcb3",682:"fe921355",748:"3a69f8d8",779:"f90e2fd6",806:"7bb8c709",831:"d1422d50",837:"e25bc4e1",872:"0ce20a00",883:"b26743dc",925:"35abd5c7",977:"e7d646dc"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},c="mynameis:",n.l=(e,t,r,o)=>{if(a[e])a[e].push(t);else{var f,d;if(void 0!==r)for(var i=document.getElementsByTagName("script"),b=0;b{f.onerror=f.onload=null,clearTimeout(s);var c=a[e];if(delete a[e],f.parentNode&&f.parentNode.removeChild(f),c&&c.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:f}),12e4);f.onerror=l.bind(null,f.onerror),f.onload=l.bind(null,f.onload),d&&document.head.appendChild(f)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/mynameis/",n.gca=function(e){return e={b7209ac4:"4","01a85c17":"13",dfd01fac:"24","6c979130":"68","1f391b9e":"85",a6aa9e1f:"89",ccc49370:"103","11ca47d7":"170","1df93b7f":"237",e37f4f80:"343","393be207":"414","0c073a7b":"445","1a1195cb":"531","814f3328":"535","2f6ea139":"538","9e4087bc":"608","6875c492":"610","5ea76644":"644","7bdc3b36":"675","2e217b76":"682",c5a8c89d:"779","27df296f":"806","24ca0b60":"831",e79bf1a2:"837","15e7fec8":"872","367c4eda":"883","0e2cd4ea":"925","0e5f3422":"977"}[e]||e,n.p+n.u(e)},(()=>{var e={303:0,532:0};n.f.j=(t,r)=>{var a=n.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var c=new Promise(((r,c)=>a=e[t]=[r,c]));r.push(a[2]=c);var o=n.p+n.u(t),f=new Error;n.l(o,(r=>{if(n.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var c=r&&("load"===r.type?"missing":r.type),o=r&&r.target&&r.target.src;f.message="Loading chunk "+t+" failed.\n("+c+": "+o+")",f.name="ChunkLoadError",f.type=c,f.request=o,a[1](f)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,r)=>{var a,c,o=r[0],f=r[1],d=r[2],i=0;if(o.some((t=>0!==e[t]))){for(a in f)n.o(f,a)&&(n.m[a]=f[a]);if(d)var b=d(n)}for(t&&t(r);i Archive | Denny's blog - + diff --git a/blog/atom.xml b/blog/atom.xml index 4fa65f0..98dfc38 100644 --- a/blog/atom.xml +++ b/blog/atom.xml @@ -2,7 +2,7 @@ https://dennypenta.github.io/mynameis/blog Denny's blog Blog - 2024-09-03T18:48:09.000Z + 2024-09-03T20:16:17.000Z https://github.com/jpmonette/feed Denny's blog Blog @@ -11,9 +11,9 @@ <![CDATA[PaaS devlog |#1]]> https://dennypenta.github.io/mynameis/blog/tq-devlog-1 - 2024-09-03T18:48:09.000Z - - Devlog |#1 + 2024-09-03T20:16:17.000Z + + Devlog |#1: postgres, docker, beekeeper, lazygit

Another day I actually started working on the project (what a surprise).

I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.

Im convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data.

@@ -61,13 +61,13 @@ Repository is here: https://dennypenta.github.io/mynameis/blog/tq-devlog-0 2024-09-02T20:12:28.000Z - - Devlog |#0 + + Devlog |#0: planing, gpt, linear

Today I want to share with you my first steps of creating new project. For a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.

The main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.

tip

You can read more about cdk here

-

All the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it). +

All the infra will be used from well known cloud providers (not aws ofc, no clue who can understand how to user it). First iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me.

The problem

The technical problem exists, it's fun to figure out. diff --git a/blog/big-json/index.html b/blog/big-json/index.html index 084d2bd..1194819 100644 --- a/blog/big-json/index.html +++ b/blog/big-json/index.html @@ -5,7 +5,7 @@ 250mb json in a 40mb service limit | Denny's blog - + diff --git a/blog/do-gamedev/index.html b/blog/do-gamedev/index.html index ccf3862..958c154 100644 --- a/blog/do-gamedev/index.html +++ b/blog/do-gamedev/index.html @@ -5,7 +5,7 @@ Backend Guy Ventures into Game Development | Denny's blog - + diff --git a/blog/index.html b/blog/index.html index d17194f..e7c5270 100644 --- a/blog/index.html +++ b/blog/index.html @@ -5,13 +5,13 @@ Blog | Denny's blog - + -

· 4 min read

Devlog |#1

+

· 4 min read

Devlog |#1: postgres, docker, beekeeper, lazygit

Another day I actually started working on the project (what a surprise).

-

I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.

· 4 min read

Devlog |#0

+

I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.

· 4 min read

Devlog |#0: planing, gpt, linear

Today I want to share with you my first steps of creating new project. For a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.

· 7 min read

In order to be engaged one explores different areas and looks for unknown software area.

Here we look at the gamedev in 2024 from experience in server side software.

diff --git a/blog/rss.xml b/blog/rss.xml index c85661f..def8f39 100644 --- a/blog/rss.xml +++ b/blog/rss.xml @@ -4,7 +4,7 @@ Denny's blog Blog https://dennypenta.github.io/mynameis/blog Denny's blog Blog - Tue, 03 Sep 2024 18:48:09 GMT + Tue, 03 Sep 2024 20:16:17 GMT https://validator.w3.org/feed/docs/rss2.html https://github.com/jpmonette/feed en @@ -12,9 +12,9 @@ <![CDATA[PaaS devlog |#1]]> https://dennypenta.github.io/mynameis/blog/tq-devlog-1 https://dennypenta.github.io/mynameis/blog/tq-devlog-1 - Tue, 03 Sep 2024 18:48:09 GMT - - Devlog |#1 + Tue, 03 Sep 2024 20:16:17 GMT + + Devlog |#1: postgres, docker, beekeeper, lazygit

Another day I actually started working on the project (what a surprise).

I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.

Im convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data.

@@ -59,13 +59,13 @@ Repository is here: https://dennypenta.github.io/mynameis/blog/tq-devlog-0 https://dennypenta.github.io/mynameis/blog/tq-devlog-0 Mon, 02 Sep 2024 20:12:28 GMT - - Devlog |#0 + + Devlog |#0: planing, gpt, linear

Today I want to share with you my first steps of creating new project. For a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.

The main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.

tip

You can read more about cdk here

-

All the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it). +

All the infra will be used from well known cloud providers (not aws ofc, no clue who can understand how to user it). First iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me.

The problem

The technical problem exists, it's fun to figure out. diff --git a/blog/tags/career/index.html b/blog/tags/career/index.html index 8d87465..d01cf33 100644 --- a/blog/tags/career/index.html +++ b/blog/tags/career/index.html @@ -5,7 +5,7 @@ One post tagged with "career" | Denny's blog - + diff --git a/blog/tags/index.html b/blog/tags/index.html index 2dc4e1e..2962a27 100644 --- a/blog/tags/index.html +++ b/blog/tags/index.html @@ -5,7 +5,7 @@ Tags | Denny's blog - + diff --git a/blog/tags/software/index.html b/blog/tags/software/index.html index 0011e9b..1bcf0a8 100644 --- a/blog/tags/software/index.html +++ b/blog/tags/software/index.html @@ -5,13 +5,13 @@ 4 posts tagged with "software" | Denny's blog - + -

4 posts tagged with "software"

View All Tags

· 4 min read

Devlog |#1

+

4 posts tagged with "software"

View All Tags

· 4 min read

Devlog |#1: postgres, docker, beekeeper, lazygit

Another day I actually started working on the project (what a surprise).

-

I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.

· 4 min read

Devlog |#0

+

I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.

· 4 min read

Devlog |#0: planing, gpt, linear

Today I want to share with you my first steps of creating new project. For a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.

· 7 min read

In order to be engaged one explores different areas and looks for unknown software area.

Here we look at the gamedev in 2024 from experience in server side software.

diff --git a/blog/tq-devlog-0/index.html b/blog/tq-devlog-0/index.html index 1a021ee..96a4e6f 100644 --- a/blog/tq-devlog-0/index.html +++ b/blog/tq-devlog-0/index.html @@ -3,18 +3,18 @@ -PaaS devlog |#0 | Denny's blog +PaaS devlog |#0 | Denny's blog - + -

PaaS devlog |#0

· 4 min read

Devlog |#0

+

PaaS devlog |#0

· 4 min read

Devlog |#0: planing, gpt, linear

Today I want to share with you my first steps of creating new project. For a long time I've wanted created something cool, really meaninful, and after all I step into my idea: Platform as a service.

The main tech stack has beeen defined: Go for a main backend, perhaps JavaScript for cdk integration.

tip

You can read more about cdk here

-

All the infra will be used from a well known cloud providers (not aws ofc, no clue who can understand how to user it). +

All the infra will be used from well known cloud providers (not aws ofc, no clue who can understand how to user it). First iteration will not such words as a frontend, ui, design. Ofc I want to make it, but only future history can judge me.

The problem

The technical problem exists, it's fun to figure out. @@ -50,6 +50,6 @@

The ugly thin

As a result I cooked quite a few cards (48 projects in a backlog 😱️️️️️️).

img

Thank you for reading, come here and see what's gonna be in the end. -Repository is here: http://github.com/treenq/treenq

+Repository is here: http://github.com/treenq/treenq

\ No newline at end of file diff --git a/blog/tq-devlog-1/index.html b/blog/tq-devlog-1/index.html index f43ab60..af0d192 100644 --- a/blog/tq-devlog-1/index.html +++ b/blog/tq-devlog-1/index.html @@ -3,13 +3,13 @@ -PaaS devlog |#1 | Denny's blog +PaaS devlog |#1 | Denny's blog - + -

PaaS devlog |#1

· 4 min read

Devlog |#1

+

PaaS devlog |#1

· 4 min read

Devlog |#1: postgres, docker, beekeeper, lazygit

Another day I actually started working on the project (what a surprise).

I want to setup my repository, basic development environment, something to make it cool and get a chance to procrastinate a bit more.

Im convinced I will store my data in postgres, therefore I need a local instance, migrations, a tool to lookup the data.

@@ -46,6 +46,6 @@
note

I use zsh and it gives me many shortcuts, for instance ga is equal to git add

img

Thank you for reading, come here and see what's gonna be in the end. -Repository is here: http://github.com/treenq/treenq

+Repository is here: http://github.com/treenq/treenq

\ No newline at end of file diff --git a/blog/why-a-blog/index.html b/blog/why-a-blog/index.html index 62146f9..d1cc861 100644 --- a/blog/why-a-blog/index.html +++ b/blog/why-a-blog/index.html @@ -5,7 +5,7 @@ Why this page exists | Denny's blog - + diff --git a/index.html b/index.html index 4357c53..bca9592 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ About me | Denny's blog - + diff --git a/markdown-page/index.html b/markdown-page/index.html index 780ee03..c800dfa 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -5,7 +5,7 @@ Markdown page example | Denny's blog - +