I was recently asked something like the following question, which I am citing with a few minor edits.
We would like to do a course about SW development with Python, preferably an online course, so that we can start at our own pace.
We don’t want a Python course, but would instead like a course more about SW development. It would be great if it were in Python because we are comfortable with it.
The interesting topics would be:
- object-oriented programming
- functional programming
- design patterns
- good coding practices
As well as other important topics such as:
- Testing
- Documenting
- Version control
- Working in a team with version control
The course doesn’t have to contain all these topics. It can be also several courses or it can be toy-projects from somewhere.
I have very little familiarity with courses as I’ve usually been tasked with figuring out how to do things before others have gotten to it. Of late, I’ve been teaching courses, not taking them.
So, how did I learn what I know about software development? When I started writing software, there was nothing available online, outside of a bunch of GeoCities pages (one of which was mine). MSDN was on CDs or local help files.
I read some books, OOSC and OOSC2, as well as the Gang of Four’s Design Patterns. I can’t remember what else, but that’s partly how I leveled up my skills. I had the great fortune of being able to build and work on large frameworks, from which I drew many lessons. I worked with very good people, who challenged me and taught me a lot.
Nowadays, I use DuckDuckGo as my online reference. I have developed a relatively advanced skill at searching for what I’m looking for. I very often get it within minutes. I almost never use videos.
a primary skill in software development is to be able to imagine what you should be looking for. That is, you don’t have to know how to do everything without looking it up, but you do have to imagine that it might exist.
For example, I don’t know how to write automated tests in Python, but I know that it should be possible. I know that I should figure that out very early in my experiments with Python. I know what to expect from an automated-testing environment. I know which settings to look for and expect.
That kind of knowledge transfers from one language or development environment to another. I know that I code-completion makes me faster, I know that I would like to avoid runtime errors—how can I best use Python to achieve those ends?
I took a quick look around for online courses, but was not immediately convinced that I am equipped to be able to distinguish between scams and actually worthwhile courses. Does the course even mention general software-development principles? How much time is allocated to that?
The Complete Software Engineering Course with Python (Udemy) looks as follows:
What about general programming?
Just over nine minutes? And you can’t even be bothered to describe it in something approaching well-written English? No, thanks.
The course Learning To Program − Part 2: Abstractions (PluralSight) looks a bit more professional, but it still has some quirks (especially for $29 per month).
There is an assessment that you can take, but you have to sign up first.
Maybe PluralSight is able to tell you which courses you need, but I doubt it will err on the “you need fewer courses” side.
I’ve recently heard from a source I’ve been watching for a while that this course is quite good for C# developers: From Zero to Hero: Test-Driven Development in C# by Guilherme Ferreira. The person recommending it releases quite interesting/advanced videos on YouTube and has his own range of courses at DomeTrain.
How would I teach basic software-development principles? I would probably start with very abstract principles that try to answer the classic questions for “use cases”:
A question people tend to start with is: which programming language should I use?
That’s the wrong question.
The applicability of programming languages to fields differ widely, but most languages have a large overlap in functionality. Where they differ is in the degree of runtime or library support for specific tasks.
For example, Python famously has a lot of libraries for number-crunching and data-analysis (although I feel that this advantage is grossly exaggerated) whereas it’s terrible for writing Windows GUI applications. C#/.NET has excellent web and desktop technology support. The Python runtime is notoriously slow (with essential libraries written in C++) whereas .NET is known as a very performant cross-platform runtime.
Do you see how quickly the conversation turns from “what can the language do?” to “what can the standard runtime/libraries/environment do?” That’s because you can do most tasks with most languages.
Instead, we want to think about this at a higher level. We want to,
Programming languages exist on several spectra. One of these is “the degree of developer discipline required to use the language effectively and safely.”
What does that mean? For example, Python and JavaScript have a dynamic type system. While there are mechanisms, practices, and IDE support that you can use to set up guardrails missing in the language, but they are optional and Idiomatically written code in both of these languages tends not to use any of it. It’s the wild west, for the most part, with a lot of assumptions that nothing will ever go wrong.
More strict languages force you to consider all possibilities before your program even compiles or runs. For example, Haskell and Rust are famously picky. If you have a function that returns a value under certain conditions, those languages will make you explicitly indicate what to return when those conditions don’t hold. Forgiving languages will just use some default value, usually null
or undefined
.
This is called “happy path” programming because you only write the code for the hoped-for path through your use case. For example, the user selects a valid file with the expected data format with an acceptable length with no validation or processing errors, generating a data file to which the initiating user has access.
Writing programs in this fashion is a dangerous thing to do with a strict language, and it’s even worse to do in a lax language.
Even the simplest software has many, many branches. The less your language or compiler or IDE reminds you of them, the more you have to fill that gap with developer discipline.
To get more concrete, some good questions to consider are:
If these don’t make any sense to you, don’t worry. But they are questions that are important when you’re choosing a tool for building software.
The whole point of a programming language is to express intent. You indicate what you intend to happen when a given event occurs.
An programmer expresses an intent by writing that, “when this thing happens, I intend for this other thing to happen.”
For example,
How do we choose a programming language? You’re not just choosing a programming language, you’re also implicitly deciding which subset of language features to use. This is predicated, of course, on knowing about these features. It’s best to inform yourself about what your language/libraries/runtime (let’s call it a software-development tool) can do for you—or find someone who is well-informed to help.
For each feature, you should ask yourself: how useful is it? Does it help me achieve my task?
Let’s take a look at high-level features of a software-development tool that may be important.
For code designed to be reusable (libraries, frameworks), you can also consider:
Which of the features above matters more depends on what you’re building. A one-off script doesn’t need to satisfy many of these features. A full-blown application that needs to be maintained for 10-20 years by different teams has to be much, much more careful.
This isn’t the first time I’ve written about these ideas, so I’ve included links to other, similar articles below.
These articles discuss the topic of software-development on a similar level to the discussion above.
The articles below are more recent, are more-or-less on the same level, but are also more targeted.
These white papers were written from 2006 to 2019 when I was still employed at Encodo Systems AG. They expand on recommended practices of specific facets of software development. They are presented in reverse-chronological order, but can be read in any order.
This is a YouTube playlist I’ve maintained for years that I continuously update whenever I watch a video that I think would be interesting for other developers. It’s only technology videos, but it’s pretty eclectic (i.e., it’s language- and technology-agnostic).
Developer suggestions (YouTube)
Pace yourself. You can’t have everything all at once. Programming takes wisdom. Wisdom takes time. It takes practice. It comes, or it doesn’t. It takes different forms.
As Rainer Maria Rilke wrote in 1903[2],
“Forschen Sie jetzt nicht nach den Antworten, die Ihnen nicht gegeben werden können, weil Sie sie nicht leben könnten. Und es handelt sich darum, alles zu leben. Leben Sie jetzt die Fragen. Vielleicht leben Sie dann allmählich, ohne es zu merken, eines fernen Tages in die Antwort hinein.”
Good luck.