{"id":19364548,"url":"https://github.com/math2001/mydevto","last_synced_at":"2026-06-13T02:32:15.888Z","repository":{"id":74806454,"uuid":"151208591","full_name":"math2001/mydevto","owner":"math2001","description":"my dev.to build with go. ","archived":false,"fork":false,"pushed_at":"2018-10-07T01:20:59.000Z","size":136,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-24T13:13:43.836Z","etag":null,"topics":["blog","go"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/math2001.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-02T06:13:39.000Z","updated_at":"2018-11-23T16:19:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"c1795a47-e4c9-47ea-8d86-c82e5ddccee8","html_url":"https://github.com/math2001/mydevto","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/math2001/mydevto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/math2001%2Fmydevto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/math2001%2Fmydevto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/math2001%2Fmydevto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/math2001%2Fmydevto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/math2001","download_url":"https://codeload.github.com/math2001/mydevto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/math2001%2Fmydevto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34270414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blog","go"],"created_at":"2024-11-10T07:37:40.692Z","updated_at":"2026-06-13T02:32:15.852Z","avatar_url":"https://github.com/math2001.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# My dev.to\n\n\u003e This is a learning project. In other words: I'm messing around, things get\n\u003e broken every ~~day~~ commit.\n\n## The idea\n\n\u003e This is what I'm aiming to achieve. Maybe it isn't what is actually happening\n\u003e though. See for yourself I guess.\n\nI'm trying to build a *reliable*, *performant* web application like [dev.to][]. The priority is\nthe user end-result.\n\n### Performant\n\nServer side rendering is good for SEO and first paint. It's pain once you're\nbrowsing though. The answer is to combine both worlds:\n\n\u003e Server side rendering by simulating what a browser would do. And then, the\n\u003e client's browser does the job.\n\nHow it works? It's explained a bit below...\n\n### Reliable\n\n\u003e Right now the tests are a mess. Please don't look at the code :laugh:\n\nTesting. The user doesn't care if all the unit test pass, he just wants the\n*result* to work.\n\nThis means that I test the *result*. Unit test are there to facilitate\n*debugging*, not to *detect* bugs.\n\nFor example, to check whether the action `/api/posts/write` works (it\ncreates/updates a post in the database), we check that when we *then* call\n`/api/posts/get?id=:id`, we do get the post.\n\nThis doesn't mean you can't check that `/api/posts/write` made the right SQL\nrequest, whether it called `users.Current()` to check that the user was logged\nin, etc... It just means that these are *extras* tests. Just to facilitate the\ndev's job (which isn't the priority. The priority is the **user**).\n\n## How it's organized\n\n\u003e Any battle is already won before it has even fought\n\nYep, I just put a life quote in my README. I know.\n\nAnyway, I think it can be applied to programs as well. A well structured program\nwill perform much better that a clunky one, that's known. Therefore, this is what\nI'm trying to figure out (and why the commit rate is so slow): the right\nstructure.\n\n### Timeline\n\n```\n|\u003c- request\n|\n|- get required components from tetsu.json\n|\n|-\u003e send them off to NodeJS\n|   use the /api to render stuff\n|\u003c- get the HTML back\n|\n|-\u003e send the html to the client\n|   First paint, DOMContentLoaded\n|-\u003e push to the client the components they are going to need\n|   (based on the link there are on the page)\n\nTODO: user interaction (shouldn't be to hard)\n```\n\nHere's the file structure I've decided to adopt for now.\n\n#### `/`\n\nThis is where the `main.go` file lives. The rest is just meta data for the\nproject. This file starts *everything* it can start without knowing anything\nabout any connection. This globally means initiate every services (see below).\n\n#### `/services`\n\nServices are just external resources that the API uses.\n\nEvery service creates their own package (therefore, they're in their own folder).\n\nA good rule of thumb to know whether a package should be a service is whether\nit needs to be *initiated*. If it does, then it most likely needs to be a\nservice.\n\nTo be initialized, a service must implement the `init` method in the package\n(Go will automatically call it *at most once*, when it is imported), and\n*import it* in `main.go`, even if it doesn't use it straight away, like so:\n\n```go\nimport _ \"myservices\" // just for side effects (init)\n```\n\nServices can be tiny, and they can do *very* different things. Have a look:\n\n`/services/db`: manages the connection with database. Makes sure that there\nis only one connection.\n\n`/services/uli`: a sort of log wrapper. It's displays information about the\nrequest.\n\n#### `/api`\n\nThe API is the core of the application. It's a REST API, although this might\nchange if I wake up feeling like messing around with GraphQL, this'll change.\n\nThe API is split up into controllers, that are then split up into actions (the\nnames are stolen from CakePHP).\n\nTherefore, this is reflected in the both the URL and the file structure.\n\nEvery controller is a sub-folder in `/api`, and every action is a handler in\nthis sub-folder.\n\nEvery controller must export a function (`Manage`), which will manage the\nrouting of URLs to actions. This function is usually defined in a file with the\nsame name as the controller.\n\n```\n/api\n    /posts\n        get.go\n        list.go\n        write.go\n        posts.go // Manage is in this file\n    /users\n        auth.go\n        current.go\n        users.go\n    ...\n```\n\nControllers can *depend* on each other. For example, the controller `users` can\nexport a function `Current` that returns the current user's data, and other\ncontroller can use it by doing `u := users.Current()`.\n\nThose kind of function should be quite simple, and therefore defined in the\neponymous file (`posts.go` for the controller `posts`)\n\nVarious util functions can be stored in the `/api` package directly. This is\nused for functions such as writing JSON from an object, internal error\nmessages, etc...\n\n*Note: right now, those functions are in their own package, `resp` which is a\nservice. It's a bad idea. It's going to be moved*\n\n### `/web`\n\n\u003e I haven't messed around with the front end yet. This is what I think I will\n\u003e do, and it should kind of work.\n\n*Just some thoughts...*\n\nThis folder manages the views. Now, in order to be able to do both server side\nrendering *and* client side rendering, I need one thing: a server side\nidentical to a client side.\n\nNodeJS, here I come.\n\nViews are actually *extremely* simple. They are just a list components. More on\nthat below.\n\nThe template they are plugged in is always the same for every dynamic page on\nthe website. It contains the HTML.\n\n#### `/web/components`\n\nEvery component will live in its own `.js` files (yes, no preprocessor), under\nthe `components` folder. The filename should exactly match the name of the\ncomponent.\n\nWhat I mean by concatenable components is that if you want to load 2\ncomponents, instead of making 2 requests, you add one after the other, and\nserve it as a single file. No bundler. This means components should be in IIFE,\nlike so:\n\n```js\n;(function () {\n    // your component code goes here.\n})();\n```\n\nThey have the role of fetching the data they need, and add it to the page.\n\nNote that components may depend on other components, in which case they need to\nbe added *explicitely* to each view they occur in. See below.\n\n#### `/web/\u003ccontroller\u003e.go`\n\nSince views are very simple, they can all be grouped in one single file per\ncontroller.\n\nEach view is a function (an `http.Handler`) that is going to send the\ncomponents needed to\n\n[dev.to]: https://dev.to\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmath2001%2Fmydevto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmath2001%2Fmydevto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmath2001%2Fmydevto/lists"}