There are three essential elements of software:
Everything else in software can be reduced to these three.
We use types to construct models, operations to act on and between models and constructs to organise execution.
Types may be provided by the language though these tend to be primitive: numeric types (integers, floating points, complex numbers), boolean types, strings, containers (sequence, mapping etc.). Better still are user-defined types either using structures or classes.
Operations may also be provide and depend on the types involved. For instance, numerical types admit numerical operations such as the common arithmetic operations or more exotic operations such as floor, divmod and so on. With user-defined types, these operations often take the form of generic functions that apply on those types or methods defined on the class namespace.
Finally, there are conventional constructs found in most language which typify the language (if, while, for, with etc.) which are idiosyncratic variations on the same idea and there are are also language specific constructs such as how various languages will allow users to work with multiple threads natively as exemplified in Go.
While learning programming will typically involve mastering how a particular language uses these elements, writing software will consist of increasing levels of sophistication on how to reduce complex requirements into simple expressions. This tends to involve identifying persistent types and operations for a particular domain that best fulfils the needs of that domain.