четверг, 1 октября 2020 г.

Three Starters

During the last weeks among other things I've been repeatedly facing each of the following three completely unrelated tasks:

  • Work with an HTTP API either to test it or to run a series of files/data-based queries, for example, to upload some data to a new service or to check how a service responds to particular kind of HTTP load,
  • Configure basic HTTP endpoints monitoring with alerts sent to a messenger,
  • Create a simple NextJS website.
I expect to run into each of these tasks again more than once, so I assembled three starter repositories, which I can simply clone and reconfigure according to the needs of the next projects. All three are available on github - feel free to use in your own endeavours.

Clojure HTTP Playground

Use REPL to run any kinds of http requests, utlizing full power and interactivity of Clojure to process the data being sent and received.

Prometheus Blackbox Probing Starter

Set up basic available/unavailable monitoring with Telegram alerts for HTTP(S) endpoints

NextJS Website Starter

Bootstrap a simple website/landing, starting with basic styling, some degree of responsiveness, a couple reusable components and (hopefully) easily reconfigurable color theme.

среда, 12 августа 2020 г.

Image magic

I've been facing the task of manipulating images for web apps and websites from time to time - like cropping, scaling and reducing file size. While some of these tasks can be done with a handy GUI tool like Photoshop (you have to pay for it), Photopea (a very powerful web-based photoshop-like editor that works with a multitude of formats including .psd) or Paint.net, sometimes a shell-based tool will do so much better. 

There is a tool like that and it's called Imagemagick

The thing let's you manipulate various raster images in different ways. I would most often use it for resizing and compressing images in batches and sometimes for cropping (here a visual tool may be better, but really depends on the scenario). 

For my own and other's reference, here are some of my usecases. Of course, there is an extensive documentation on the tool's website. 

(Since I'm on windows, I use image magick in Powershell to process many files at once).


Crop all files in the current directory and save them with a .crop suffix. This one reduces the size of the images to 1080x1732 cutting off 62px on the top (android screenshot).

Get-ChildItem -File | Foreach {convert $_.fullname -crop 1080x1732+0+62 $_.fullname.replace(".png",".crop.png")}


Scale all files in a directory down to 50% their dimensions (preserves aspect ratio):

Get-ChildItem -File | % {convert -resize 50% $_.fullname $_.fullname}


Just one file, saving a copy:

convert -strip -interlace Plane -quality 85% .\banner_1.jpg .\banner_1.comp.jpg

All files in the current directory, replacing the originals:

Get-ChildItem -File | % {convert -strip -interlace Plane -quality 85% $_.fullname $_.fullname}

A lot of other usecases - do explore them!

пятница, 7 августа 2020 г.

How to handle a programming problem

A couple students whom I mentor through a software development course recently asked me for a generic advice on a way to approach a relatively large software development - something that would help them know where and how to start producing a solution. The question definitely provoked several pretty deep discussions. Since I do expect other students to seek advice of a similar kind I decided to devote a bit more time to the framing my advice.

While contemplating and discussing the topic I came up with a number of points that depict the approach that I use to build software. Sometimes I would follow this process to the point, in other cases I just adhere to the general line of thinking that it suggests - it definitely depends on the kind and size of a particular project. Thus, even though I present the approach as a sequence of steps, it is most reasonable to treat it as a description of a way of thinking about a programming problem.

Note that it so happened that I faced the question soon after going back to the Code Complete book to check a couple chapters. Moreover, I was reading How to Solve It by George Polya roughly at the same time. Because both of these have a lot to do with the topic at hand, the post definitely builds on the ideas found there. I absolutely recommend both of these books in case you didn't give these a try yet.

So, you find yourself with the task of producing a piece of software that would solve a particular issue. What should you do?
  1. First and foremost, state your problem in writing - what are you trying to solve?
  2. What requirements should the solution satisfy? Jot every one of these down as well.
  3. Imagine the final solution, state in writing what the thing that you are about to build will look like. Focus on the general shape of the final result here. See how it will solve the problem and meet the requirements.
  4. Think over the data model. Decide what kinds of data you will be handling, how to structure it better, where it comes from and where it should go. Imagine how the information is split into tables and collections, spot the relations between them. Consider which bits you need to store and how. Do this even if you don't have any kind of database - maybe building only a frontend application - data is something that you work with in any software and it definitely plays a great role in shaping the solution. Write all of this down.
  5. Decompose your future system or program based on what you have understood so far - think over how you can split the problem and the solution into pieces. Depending on the scale of the task you may be thinking on the level of services, modules or classes and functions here. The larger the problem - the larger should be the size of units considered on this design stage.
  6. In this process follow the breadth-first approach - e.g. don't go into designing functions before you produce an overview on the level of modules. List the large-scale units first, state their purpose clearly and only once this is done permit yourself to descend to the next level of detail. Notice when your start jumping between different levels of design - like thinking of modules, then functions, then modules again. If this happens stop and pull yourself back to the highest level that still needs clarifying.
  7. Don't overdesign and keep moving. Most of the technical design will happen while you're coding. Your key goal at the moment is to draw yourself a clear image of the whole solution, its components and relations that govern them and to see how you will meet every bit of requirements. Design can consume infinite time, so don't let yourself get lost in it - details will come.
  8. After facing your components think over your past experience - each component poses a smaller problem to solve and many of these smaller problems you may have solved in the past. If so, check which bits of previous projects you can use now - this may mean anything from pulling in a dozen existing files to just reviewing how you approached a particular issue a couple months ago.
  9. Throughout all these stages use pencil, draw figures, sketch stuff, write things down - it helps you think. Once you have started producing a diagram, your mind will follow. Draw how the system or its particular component is decomposed, outline relations between the pieces, sketch the data flow, chart user actions sequence.
  10. Devise a plan. Decide in which order you will build your components. Write that down (in any form or medium) - that will help you see and maintain progress, especially with longer projects
  11. Pick the first component on the list. Jot down the steps to build it. Think how to test it, list the functions to implement, decide on the order, add checkboxes. If you don't know how to pick the starting point, pick any single one of them. At this stage it’s most important just to start the job, so start anywhere. Even if you choose a wrong initial task, you will soon be able to see and correct that.
  12. Go and start writing the code. The first lines may go hard, but with all the preparatory work you should be able to break through them and the rest will follow easily.
  13. Don't try to write perfect code from scratch - start dirty. Starting is a challenge by itself, so simplify the task and relax the requirements. It is much easier to produce a dirty solution and clean it once you see it working. Just don't forget to always clean the mess.
  14. Write tests as you go to stay confident in the state of your code. Confidence does matter a lot here and the lack of it may slow you down significantly.
  15. Iterate. Pick small tasks, complete them, polish the solution, celebrate, step back to take a look at your design and plan, repeat.
  16. When you face challenges and are not sure where to go from there, take a pencil and think. State the problem that you're trying to solve, write out the required characteristics of the solution, draw, see it and then implement it.
  17. Yes, look for what others have to say about your problem - stackoverflow, github and google are your friends. Don’t just grab any code that you find on the web though - take time to understand what it does, why it works and what kind of new issues it may throw at you.
  18. When all else fails, go away for some time - take a walk, wash the dishes, smoke a pipe, use your hammock time. Let your brain wander away. Most times you will come back with new ideas. In the worst case you will get some rest and have more energy to continue attacking the problem.
And finally, if there are no more tasks to do, everything is polished and you feel happy about the result, celebrate the success, reward yourself, think over the lessons to learn from this project and go look for the next issue to solve. If you can program, there is an infinite number of problems waiting for you!