4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/cra-monaco/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/cra-monaco/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `yarn start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `yarn test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `yarn build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `yarn eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `yarn build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/cra-monaco/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' }
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready.then(registration => {
134 | registration.unregister();
135 | });
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Below are my thoughts on how I would pick a stack for a web development in 2020. I value mature technologies, size of the community, "batteries included" and speed of the development.
2 |
3 | I personally use VSCode editor, again because it's very popular these days which leads to lots of problems being solved in form of questions asked, plugins shipped and bugs fixed. One decent alternative is PyCharm/WebStorm.
4 |
5 | - [Frontend](#frontend)
6 | - [Frontend framework [React with Hooks]](#frontend-framework-react-with-hooks)
7 | - [Bundler config and boilerplate [Create React App]](#bundler-config-and-boilerplate-create-react-app)
8 | - [CSS-in-JS library [styled-components]](#css-in-js-library-styled-components)
9 | - [Components library [Ant]](#components-library-ant)
10 | - [Frontend state management [React Hooks -> Redux + Redux Toolkit + Redux Thunk (+ Redux Saga)]](#frontend-state-management-react-hooks---redux--redux-toolkit--redux-thunk--redux-saga)
11 | - [Router [React Router]](#router-react-router)
12 | - [Code editor as a component [Monaco]](#code-editor-as-a-component-monaco)
13 | - [Mobile development [React Native]](#mobile-development-react-native)
14 | - [Language flavor/safety [TypeScript]](#language-flavorsafety-typescript)
15 | - [Package managers [Yarn 1.22 or npm, npx]](#package-managers-yarn-122-or-npm-npx)
16 | - [Linters and formatters [ESLint/Prettier, Husky]](#linters-and-formatters-eslintprettier-husky)
17 | - [Backend](#backend)
18 | - [Backend framework [Django]](#backend-framework-django)
19 | - [API design [Django REST Framework]](#api-design-django-rest-framework)
20 | - [Authentication [?]](#authentication-)
21 | - [Language flavor/safety [Mypy]](#language-flavorsafety-mypy)
22 | - [Package managers [Pipenv]](#package-managers-pipenv)
23 | - [Linters and formatters [Black, flake8, isort]](#linters-and-formatters-black-flake8-isort)
24 | - [DevOps](#devops)
25 | - [Frontend deployment [Zeit Now]](#frontend-deployment-zeit-now)
26 | - [Database [Postgres]](#database-postgres)
27 | - [Backend deployment [DigitalOcean Docker (+Portainer) + Managed Postgres + CloudFlare]](#backend-deployment-digitalocean-docker-portainer--managed-postgres--cloudflare)
28 | - [Linters and formatters [ShellCheck for .sh, hadolint for Dockerfile]](#linters-and-formatters-shellcheck-for-sh-hadolint-for-dockerfile)
29 | - [Bonus track: Zsh tools](#bonus-track-zsh-tools)
30 |
31 |
32 | Frontend
33 | ===
34 |
35 | Frontend framework [React with Hooks]
36 | ---
37 |
38 | React or Vue?
39 |
40 | Why switching from React (the de-facto standard and #1) if Vue has similar metrics and less ecosystem? For instance, Vue has no mainstream Monaco wrapper. Also, React Native is fun and mature.
41 |
42 | If you haven't worked with React since React Hooks emerged, you should totally catch up on that:
43 | - https://nikgraf.github.io/react-hooks/
44 | - https://github.com/enaqx/awesome-react#react-hooks
45 |
46 | Other things to look at:
47 | - https://github.com/welldone-software/why-did-you-render
48 |
49 |
50 |
51 | Bundler config and boilerplate [Create React App]
52 | ---
53 | Webpack? Parcel? Create React App? Next.js? Gatsby?
54 |
55 | Nano React App: https://hackernoon.com/create-react-app-is-way-too-bloated-5db07c3511
56 |
57 | If project can't benefit from server-side rendering or SEO or static generation, then it's not worth going the Next.js or Gatsby way - less popular meaning less support, more traps. Sticking with CRA / ejected CRA.
58 |
59 | Parcel may be good, but I don't know if it's easy to wire Parcel and Monaco, as well as any other dependencies. Sticking with CRA.
60 |
61 |
62 |
63 | CSS-in-JS library [styled-components]
64 | ---
65 | Anything competing with styled-components? CSS Modules? Not worth it.
66 |
67 | Also, look at https://styled-system.com/
68 |
69 | https://styled-components.com/docs/tooling#babel-macro
70 |
71 |
72 |
73 | Components library [Ant]
74 | ---
75 | Bootstrap? Material UI? Ant?
76 |
77 | https://ant.design/docs/react/use-in-typescript
78 |
79 | Ant has better TypeScript support and is being very actively developed
80 |
81 | To use:
82 | - https://github.com/fi3ework/vscode-antd-rush
83 | - https://marketplace.visualstudio.com/items?itemName=bang.antd-snippets
84 | - For inspiration: http://antd-admin.zuiidea.com/
85 | - And in general: https://github.com/websemantics/awesome-ant-design
86 |
87 | For forms it makes sense to look into both Formik and Yup:
88 | - https://blog.bitsrc.io/creating-forms-in-react-with-formik-and-yup-698d09363a22
89 | - https://github.com/jannikbuschke/formik-antd
90 |
91 |
92 |
93 | Frontend state management [React Hooks -> Redux + Redux Toolkit + Redux Thunk (+ Redux Saga)]
94 | ---
95 |
96 | Storing the state inside react components should be enough for the start. Once there are significant pain points
97 | and the transition to Redux is inavoidable, we can start using Redux. Redux Toolkit is a modern official way to standardize the Redux boilerplate. And, in case there's going to be some nightmare complex multi-staged interaction back and forth
98 |
99 | To better understand the whole necessity of such a complex system like Redux, you may want to meditate on Storeon:
100 | - https://github.com/storeon/storeon
101 |
102 | To read:
103 | - https://redux-toolkit.js.org/introduction/quick-start
104 |
105 |
106 |
107 | Router [React Router]
108 | ---
109 | @reach/router vs. React Router
110 |
111 | @reach/router's core feature with auto focus is actually very annoying and inavoidable by design.
112 | While it may make things more accessible, it makes a hell of auto scrolling.
113 |
114 | Features from @reach/router are slowly backported to React Router anyways. Also, not a huge difference between the two libraries,
115 | so it shouldn't be painful to switch back and forth. You may start with @reach/router and switch once you hit this auto focus trap or need more customization.
116 |
117 | - https://reacttraining.com/blog/reach-react-router-future/
118 | - https://github.com/reach/router/blob/master/website/src/markdown/pages/typescript.md
119 |
120 |
121 |
122 | Code editor as a component [Monaco]
123 | ---
124 | https://habr.com/ru/company/Voximplant/blog/445390/
125 |
126 | Monaco is compatible with pre-eject CRA: https://github.com/react-monaco-editor/react-monaco-editor/issues/263
127 | See [cra-monaco/](cra-monaco). Although this isn't maintained: https://medium.com/@kitze/configure-create-react-app-without-ejecting-d8450e96196a
128 |
129 |
130 |
131 | Mobile development [React Native]
132 | ---
133 |
134 | React Native, Code Push, Fastlane.
135 |
136 | Flutter is good but you already have React, so why make your stack more complex.
137 |
138 | Unless you build games or rely on bleeding edge APIs like VR/AR, you don't need native Swift/Kotlin development. It's more technologies => more engineering effort and cost, in terms of hours and team size and team salary and communication.
139 |
140 | Examples of large React Native projects:
141 | - https://github.com/zulip/zulip-mobile
142 | - https://github.com/mattermost/mattermost-mobile
143 |
144 |
145 |
146 | Language flavor/safety [TypeScript]
147 | ---
148 | Flow or Typescript?
149 |
150 | Looks like Flow is on par with TypeScript and it's better with React - both are maintained by Facebook. One may also migrate from Flow to TypeScript later on: https://medium.com/inato/migrating-from-flow-to-typescript-why-how-worth-it-5b7703d12089
151 |
152 | Flow is often blamed to have bad VSCode support and random bugs. Yarn and Jest migrated from Flow to TypeScript. Same for React Native's Expo.
153 |
154 | No need to use TSLint anymore: https://medium.com/palantir/tslint-in-2019-1a144c2317a9
155 |
156 | Looks like CRA doesn't have ES2016 support, let alone ES2020. What exactly are we missing: https://github.com/tc39/proposals/blob/master/finished-proposals.md It might make sense to enable it using customize-cra: https://2muchcoffee.com/blog/es7-decorators-how-to-use-the-decorator-syntax-in-react/
157 |
158 | Have a look at:
159 | - https://github.com/dzharii/awesome-typescript
160 | - https://github.com/typescript-cheatsheets/react-typescript-cheatsheet
161 | - https://github.com/jeffijoe/typesync
162 | - https://mariusschulz.com/blog/series/typescript-evolution
163 |
164 |
165 |
166 | Package managers [Yarn 1.22 or npm, npx]
167 | ---
168 | Yarn 2 can fail to work with react-app-rewired, so sticking to a Yarn 1.* like 1.22 is a safe option for now.s
169 |
170 | It looks like npm is being actively developed and is on par with Yarn these days, whereas Yarn has almost no big changes throughout 2019.
171 |
172 | - https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b
173 |
174 |
175 |
176 | Linters and formatters [ESLint/Prettier, Husky]
177 | ---
178 |
179 | ESLint/Prettier with typescript-eslint. Pre-commit hooks running necessary tools with Husky.
180 | - https://prettier.io/docs/en/integrating-with-linters.html
181 | - https://github.com/alexgorbatchev/eslint-import-resolver-typescript
182 | - https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project
183 | - https://dev.to/botreetechnologies/setting-up-husky-pre-commit-hook-with-eslint-prettier-and-lint-staged-for-react-and-react-native-d05
184 |
185 |
186 |
187 | Backend
188 | ===
189 |
190 | Backend framework [Django]
191 | ---
192 |
193 | Django or Express.js?
194 |
195 | First of all, there are tons of web frameworks, and all popular languages have several of them.
196 | The most popular ones are all pretty much equal in their maturity - if you compare Django to Rails to Laravel to ASP.NET to Play.
197 | So this is a choice of a language more than a choice of a framework - the framework should be
198 | "a single most popular for your language".
199 |
200 | Python is a winner in terms of language maturity and size of its community.
201 | It leads in all other applications - it has ML libraries, it has the support for any kind of data processing you may need to do.
202 |
203 | So the real question is, do you want to have two languages (JS + Python) in your project, or you'd rather just have one
204 | and stick to Node.js?
205 |
206 | You can assmeble a stack around Express.js. It's essential to use the RDBMS way for the main data storage (i.e. not to slip into the NoSQL trap), which leads to using sequelize as an ORM. And sequelize itself isn't as smooth as Django ORM - it requires more manual actions and verbose configuration. It was also hard to interact with using REPL due to async nature - maybe it's still hard.
207 |
208 | I love Django admin panel, Django ORM, migrations, shell, dbshell, Jupyter notebooks with Django support.
209 | It's very hard to assemble such a stack on Node.js.
210 | Also, sequelize sucks, and NoSQL as a main data storage sucks way more. So - Django.
211 |
212 | (Alternatives - async Flask equivalent is FastAPI. Why do you need an async framework though?)
213 |
214 | Django boilerplate - cookiecutter?
215 | - https://github.com/pydanny/cookiecutter-django
216 | - https://github.com/agconti/cookiecutter-django-rest
217 | - https://github.com/wsvincent/awesome-django#boilerplate
218 |
219 | Cool libraries:
220 | - https://django-extensions.readthedocs.io/
221 | - https://django-extensions.readthedocs.io/en/latest/field_extensions.html
222 | - https://django-extensions.readthedocs.io/en/latest/shell_plus.html to run Jupyter Notebook
223 | - https://github.com/jazzband/django-debug-toolbar/
224 | - https://github.com/arteria/django-hijack
225 | - https://github.com/wsvincent/awesome-django#models
226 | - https://github.com/joke2k/django-environ
227 |
228 | Open-source Django projects:
229 | - https://github.com/zulip/zulip/ with very detailed documentation https://zulip.readthedocs.io/
230 | - https://github.com/taigaio/taiga-back
231 | - https://github.com/wagtail/wagtail/
232 | - https://github.com/edx/edx-platform
233 | - https://github.com/django/djangoproject.com
234 |
235 | Blog posts:
236 | - https://vsupalov.com/django/
237 | - https://vsupalov.com/quick-django-refresher-crash-course/
238 | - https://vsupalov.com/django-custom-user-model/
239 | - https://medium.com/3yourmind/keeping-django-database-migrations-backward-compatible-727820260dbb
240 |
241 |
242 |
243 | API design [Django REST Framework]
244 | ---
245 |
246 | Should we use REST or GraphQL?
247 |
248 | Django has a very mature REST framework - Django REST framework (DRF), used by 108k projects according to Github stats.
249 | It's been actively maintained since 2011 and very well documented.
250 |
251 | GraphQL is a new technology that gives the following benefits:
252 | - typed API requests: auto checking, no need to do Swagger/Postman knowledge sharing between frontend and backend teams
253 | - no overfetching/underfetching
254 |
255 | While the technology itself is cool, it's way more supported in the Node.js world, where the express-graphql library
256 | has same 109k users. It's support in the Django world is young and limited: graphene_django has 3k users, it's poorly documented, not very actively maintained and has performance issues.
257 |
258 | So for now, Django should be used with DRF. If GraphQL is a must, one should entirely switch to the Node.js stack.
259 |
260 | On GraphQL:
261 | - https://github.com/Shopify/graphql-design-tutorial/blob/master/TUTORIAL.md
262 | - https://www.howtographql.com/
263 |
264 | On current GraphQL support for Django:
265 | - https://news.ycombinator.com/item?id=20200203
266 | - https://yeti.co/blog/migrating-from-rest-to-graphql-in-django/
267 |
268 | On DRF:
269 | - https://www.valentinog.com/blog/drf/
270 | - https://github.com/wsvincent/awesome-django#django-rest-framework
271 |
272 |
273 | Authentication [?]
274 | ---
275 |
276 | Question 1. How to authenticate API requests once the user is logged in?
277 |
278 | Options: sessions/cookies, JWT tokens, some other tokens.
279 |
280 | Sessions may be hard to work with mobile clients.
281 |
282 | - https://fractalideas.com/blog/making-react-and-django-play-well-together/
283 | - https://www.django-rest-framework.org/api-guide/authentication/
284 | - https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens
285 | - http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/
286 | - https://afdezl.github.io/post/authentication-react-native-django-1/
287 |
288 | Question 2. How to implement social authentication and allow user to sign in / sign up using Google/Facebook?
289 |
290 | Implementing social authentication is still hard. You can either rely on third party
291 | services or just plug in some libraries. Third party services like Amazon Cognito or Auth0
292 | usually cost money because that's how they make money. The possible upside of using them is that they keep
293 | integrations up-to-date. Every year or so your oauth providers like Google or Facebook change their protocol
294 | or bump their API version, and your previous sign-in button can become deprecated and broken.
295 | (Happened to me several times.)
296 |
297 | If you use your own libraries, you don't pay but you sometimes need to do integration maintenance. Plus,
298 | the existing libraries aren't really that popular or smooth.
299 |
300 | For Node.js worls, Looks like Passport.js is huge and popular.
301 |
302 | Can do plain django.contrib.auth with native pages (i.e. no React wrappers around, just redirects) - for prototyping.
303 |
304 | There is python-social-auth and Django_allauth and django-rest-auth. The latter isn't supported anymore, but it's required to wire with DRF. Also it's maybe not that painful because it's a tiny layer. No critial Issues found at their bug tracker.
305 |
306 | Google One-Tap (Google YOLO) is a great experience, but it's still not public.
307 |
308 |
309 |
310 | Language flavor/safety [Mypy]
311 | ---
312 |
313 | Should we use typed Python?
314 | https://blogs.dropbox.com/tech/2019/09/our-journey-to-type-checking-4-million-lines-of-python/
315 |
316 | Mypy is worth a try - the code should be clearer. Once I start doing Mypy - follow this guide: https://realpython.com/python-type-checking/
317 |
318 | Django-stubs is Django with types: https://sobolevn.me/2019/08/typechecking-django-and-drf
319 |
320 | Looks like Pyright (Microsoft) and Pyre (Facebook) are both maintained tools that do Mypy-like type checking, but faster.
321 |
322 |
323 |
324 | Package managers [Pipenv]
325 | ---
326 |
327 | Pipenv is a modern replacement for pip/virtualenv, although it itself isn't being actively supported since Oct 2018.
328 | Poetry isn't as mature as pipenv - eg. [pipenv is working in VSCode with zero configuration](https://code.visualstudio.com/docs/python/environments)
329 |
330 | - https://gioele.io/pyenv-pipenv
331 | - https://xkcd.com/1987/
332 |
333 |
334 |
335 | Linters and formatters [Black, flake8, isort]
336 | ---
337 |
338 | - https://github.com/vintasoftware/python-linters-and-code-analysis (also watch out for Django-specific linters)
339 | - https://github.com/DmytroLitvinov/awesome-flake8-extensions
340 | - https://github.com/vinta/awesome-python#code-analysis
341 | - https://wemake-python-stylegui.de/en/latest/pages/usage/integrations/auto-formatters.html
342 | - http://www.locallyoptimal.com/blog/2019/08/23/why-you-should-use-black-for-your-python-style-linting/
343 | - https://github.com/psf/black/issues/333#issuecomment-516088368
344 | - https://dmerej.info/blog/post/bye-bye-pylint/
345 | - https://github.com/pilat/vscode-importmagic
346 |
347 | What's suspicious about https://github.com/wemake-services/wemake-django-template ?
348 | - poetry instead of pipenv
349 | - new Caddy instead of old proven nginx - it's not worth risking with this layer of infrastructure
350 | - Gitlab CI - not a default Github CI
351 | - wemake-python-styleguide is against black, and I love auto-formatters
352 |
353 | A sample project with Black, flake8, mypy and isort are configured to work together and with Django/DRF: https://github.com/vpavlenko/drf-tutorial
354 |
355 |
356 |
357 | DevOps
358 | ===
359 |
360 | Frontend deployment [Zeit Now]
361 | ---
362 |
363 | Netlify or Zeit Now or Github Pages?
364 |
365 | Try Zeit Now and Netlify, in this order.
366 |
367 | Github Pages might be a weaker option because it's not a core business for the company => less convenient.
368 |
369 | On marrying frontend and backend:
370 | - https://fractalideas.com/blog/making-react-and-django-play-well-together/
371 | - https://fractalideas.com/blog/making-react-and-django-play-well-together-single-page-app-model/
372 |
373 |
374 |
375 | Database [Postgres]
376 | ---
377 | Postgres? (ok, at least here there's no alternative)
378 |
379 | Reasoning: I want an RDBMS because why disentangle denormalized Mongo crap if you only have one life? Postgres is top-1 RDBMS.
380 |
381 |
382 |
383 | Backend deployment [DigitalOcean Docker (+Portainer) + Managed Postgres + CloudFlare]
384 | ---
385 | Amazon/GCP/Azure? Heroku? VPS/Docker/Lambda? RDS?
386 |
387 | Heroku isn't great - need to learn + tricky pricing.
388 |
389 | DigitalOcean VPS may be good, although there's no autoscaling and Postgres-specific backups.
390 |
391 | Dev db, dev env?
392 |
393 | No Lambda - hard to reason about it given my experience with VPS and the whole Django entirety.
394 |
395 | Let's try Docker.
396 |
397 | uWSGI / gunicorn - both aren't well supported, but gunicorn had more patches over the last years.
398 |
399 | DigitalOcean has its own RDS competitor: https://www.digitalocean.com/products/managed-databases/
400 | [Loss in latency (100ms)](https://levelup.gitconnected.com/performance-aws-rds-postgres-vs-digital-ocean-postgres-8c2500197f1c), better documentation. (DigitalOcean also has its own S3)
401 |
402 | Kubernetes / Docker Swarm is probably an overkill because one instance with Docker Compose should be enough.
403 |
404 | So, DigitalOcean, Django app living in a docker, ability to add a load balancer and more dockers,
405 | and a Managed Database (Postgres) with backups.
406 |
407 | [Horizontal scaling for the Django part is better than vertical](https://coderbook.com/@marcus/how-scalable-are-websites-built-in-django-framework/)
408 |
409 | Why doesn't googling "django pgbouncer" yield a lot of results? https://stackoverflow.com/questions/40248970/django-settings-when-using-pgbouncer
410 |
411 | CloudFlare from the start: for hiding the real server API, maybe caching something, DNS configuration, protecting from malicious
412 | DDoS (they happen even at a small scale!).
413 |
414 | Monitoring: Sentry, Datadog?
415 |
416 | - https://vsupalov.com/same-docker-container-django-postgresql/ and all other articles on vsupalov.com
417 | - https://vsupalov.com/tools/portainer/
418 | - https://vsupalov.com/speed-up-python-docker-image-build/
419 | - https://vsupalov.com/deploying-like-a-startup/
420 |
421 |
422 |
423 | Linters and formatters [ShellCheck for .sh, hadolint for Dockerfile]
424 | ---
425 |
426 | - https://github.com/koalaman/shellcheck
427 | - https://github.com/hadolint/hadolint
428 |
429 |
430 |
431 | Bonus track: Zsh tools
432 | ---
433 |
434 | - https://github.com/ohmyzsh/ohmyzsh
435 | - https://denysdovhan.com/spaceship-prompt/
436 | - https://github.com/sharkdp/bat
437 | - https://github.com/ogham/exa
438 | - https://github.com/ggreer/the_silver_searcher
439 | - https://sobolevn.me/2017/10/using-better-clis
440 | - https://sobolevn.me/2017/08/instant-command-line-productivity
441 |
--------------------------------------------------------------------------------