Arquitectura de Software

Table of Contents

1. Arquitectura de software

1.1. Software metaphors

1.1.2. Software building

1.1.4. Factorio and Software Engineering · Krishna’s words

1.1.4.1. Analogía con Fábrica para deuda técnica

Fábrica en la que van pasando cosas por cintas.

  • El proceso de pegado lo haces junto con el templado en el horno y ahora necesitas un tipo de pegamento más resistente que va en frío

1.2. Awesome Software architecture

1.2.3. binhnguyennus/awesome-scalability: The Patterns of Scalable, Reliable, and Performant Large-Scale Systems

1.3. Groups of People

1.4. Software architecture blogs that I like

1.4.1. https://lethain.com/forty-year-career/ (Compilation of links)

1.5. Suffering-oriented programming - thoughts from the red planet - thoughts from the red planet

I have a mantra for suffering-oriented programming: “First make it possible. Then make it beautiful. Then make it fast.”

1.5.1. First make it possible

“Making it possible” is about learning the performance and resource characteristics of the problem space

  • Don’t build it generic
    If you try to build a “general” or “extensible” solution right off the bat, you’ll make things generic that needn’t be, adding complexity and wasting time, since you just don’t understand the problem domain well enough to anticipate what your needs will be in the future.

1.5.2. Then make it beautiful

“Making it beautiful” is about designing and implementing the simplest set of abstractions that solve the concrete use cases you already have, distill the problem space into simple abstractions that can be composed together, while taking into account the performance and resource characteristics you discovered before

  • Avoid overengineering
    It’s a mistake to try to anticipate use cases you don’t actually have (overengineering)
    The bigger the investment you’re trying to make, the deeper you need to understand the problem domain and the more diverse your use cases need to be. Otherwise you risk the second-system effect.
  • Developing abstractions as statistical regression
    The more use cases you have, the better you’ll be able to find the right curve to fit those points. If you don’t have enough points, you’re likely to either overfit or underfit the graph, leading to wasted work and overengineering.

1.5.3. Then make it fast

“Making it fast” is about micro-optimizations and tightening up the code to be more resource efficient

  • Premature optimization
    Doing optimization too early will just waste time, because you still might rethink the design
  • Scalability is “make it beautiful”, concrete benchmarking is “make it fast”
    you might worry about things like asymptotic complexity in the “make it beautiful” phase and focus on the constant-time factors in the “make it fast” phase.

1.5.4. Rinse and repeat

Suffering-oriented programming is a continuous process. The beautiful systems you build give you new capabilities, which allow you to “make it possible” in new and deeper areas of the problem space. This feeds learning back to the technology. You often have to tweak or add to the abstractions you’ve already come up with to handle more and more use cases.

1.6. Functional Programming

Functional programming seems necessary only when dealing with distributed systems.
Therefore, unless you’re dealing with a distributed enough system, you can get away with not using functional programming, i.e., imperative

1.6.1. Developers Don’t Solve Big Problems - Design Patterns exist only because of limitations compared to functional style

1.6.1.1. Does functional programming replace GoF design patterns? - Stack Overflow
1.6.1.2. Design Patterns in Dynamic Languages

16 of 23 patterns are either invisible or simpler, due to:
 First-class types (6): Abstract-Factory,Flyweight, Factory-Method, State, Proxy,Chain-Of-Responsibility
 First-class functions (4): Command, Strategy,Template-Method, Visitor
 Macros (2): Interpreter, Iterator
 Method Combination (2): Mediator, Observer
 Multimethods (1): Builder
 Modules (1): Facade

1.6.1.3. Worse Is Better

1.8. Principles

1.8.1. Arquitectura de software es lo que te permite retrasar decisiones

Clean Architecture:140

The goal of the architect is to create a shape for the system that recognizes
policy as the most essential element of the system while making the details
irrelevant to that policy. This allows decisions about those details to be
delayed and deferred.

  • Busca estándares que estén soportados por todo para mantener las opciones abiertas
  • Algo que no vaya a cambiar (tienes que saber predecir aprox el ritmo de cambio de cada componente), que lleve mucho tiempo usándose
  • Ejemplo perfecto: variables de entorno, se llevan usando desde 1979, introducidas por UNIX

1.8.3. Rate of change and shared resources

Configs suck, use code is about dumb vs smart configuration
Share resources (e.g. dependencies) or not
You can share resources when they are not expected to change (e.g. OS level) but not when they change rapidly (e.g. installed python packages in a particular venv)

  • Share if the rate of change is slow
  • Isolate if the rate of change is high

1.8.4. Simplificación / Minimalismo

1.8.4.1. https://blog.codinghorror.com/worse-is-better/
  1. Worse Is Better
    1. Worse Is Better   process

      Some things about functional programming and/org Common Lisp, Gang of Four patterns are included in Lisp, etc, etc, etc
      The right thing (MIT Approach) → Common Lisp and Scheme
      Worse is begger (New Jersey Approach) → C and Unix

  2. Main Page - Worse Is Better
    1. Growable-is-better - Worse Is Better
    2. Externalities in worse-is-better - Worse Is Better
1.8.4.2. The Duct Tape Programmer – Joel on Software

1.8.5. Uncoupling

1.8.7. https://rotemtam.com/2020/05/18/the-dry-principle-is-bad-advice/

“A thing is well designed if it adapts to the people who use it. For code, that means it must adapt by changing. So we believe in the ETC principle: Easier to Change. ETC. That’s it. As far as we can tell, every design principle out there is a special case of ETC. Why is decoupling good? Because by isolating concerns we make each easier to change. ETC. Why is the single responsibility principle useful? Because a change in requirements is mirrored by a change in just one module. ETC.

Source: The Pragmatic Programmer, 2nd Edition, Topic 8: The Essence of Good Design

1.8.8. You should be reading academic computer science papers - Stack Overflow Blog   read

1.8.10. Patterns of Enterprise Architecture

1.9. Lista de libros arquitectura de software   read book

1.9.1. Charles Petzold’s CODE then bought The Elements of Computing Systems

1.9.2. https://bastibe.de/2022-01-04-books-of-2021.html

For me, the answer came in three books: Charles Petzold’s Code: The Hidden Language of Computer Hardware and Software explained to me how processors work. The Arpaci-Dusseau’s Operating Systems: Three Easy Pieces describes the infrastructure of operating systems that make processors and storage and network available to programs. And now, finally, Robert Nystrom’s Crafting Interpreters filled in the last step, how a programming language is built.

1.9.4. 10 Books Every Senior Engineer Should Read

https://semaphoreci.medium.com/10-books-every-senior-engineer-should-read-a61c1917e2a7

  1. Extreme Programming Explained: Embrace Change (2nd Edition) by Kent Beck
  2. Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation by Jez Humble and David Farley
  3. Remote: Office Not Required by Jason Fried and David Heinemeier Hansson
  4. The Mythical Man-Month by Frederick P. Brooks Jr.
  5. Getting Real
  6. Designing Data-Intensive Apps by Martin Kleppmann
  7. Site Reliability Engineering
  8. The Phoenix Project by Gene Kim, Kevin Behr, and George Spafford
  9. Building Microservices: Designing Fine-Grained Systems by Sam Newman
  10. Modern Software Engineering: Doing What Works to Build Better Software Faster by Dave Farley

1.9.5. Thomas, David. The Pragmatic Programmer, 2nd edition (The DRY principle is not always right)

1.10. Barbell strategies in Software Architecture

  • Backups (maximum consistency, no liveness)
  • Version control (as an extension of backups)
  • Tests

1.11. _ envy

1.11.1. Web Scale envy

https://www.thoughtworks.com/radar/techniques/high-performance-envy-web-scale-envy
We see many teams run into trouble because they have chosen complex tools, frameworks or architectures because they “might need to scale”. Companies such as Twitter and Netflix need to be able to support extreme loads and so need these architectures, but they also have extremely skilled development teams able to handle the complexity. Most situations do not require these kinds of engineering feats; teams should keep their web scale envy in check in favor of simpler solutions that still get the job done.

1.11.2. Big Data envy

https://www.thoughtworks.com/radar/techniques/big-data-envy
We continue to see organizations chasing “cool” technologies, taking on unnecessary complexity and risk when a simpler choice would be better. One particular theme is using distributed, Big Data systems for relatively small data sets. This behavior prompts us to put Big Data envy on hold once more, with some additional data points from our recent experience.

1.12. SOLID

1.12.1. Single Responsibility Principle

A module should be responsible to one, and only one, actor

Actor
A group of people who wants the system changed in the same way
(no term)
Symtompts
  • Accidental Duplication
  • Merges

1.12.2. Open-Closed Principle

A software artifact should be open for extension but closed for modification

It should be easy to change the behavior by changing the defined interfaces of change (extensions) instead of having to modify the “core” behavior (modification)

1.12.3. Interface Segregation Principle

Don’t depend on things that contain more than you need.
Segregate into what you need (as small as possible) and what is implemented by the thing you use (which can be bigger)

1.12.3.1. Segregation of Mutability (You wanted a banana🍌 but you got a gorilla🦍 holding the banana🍌)

I think the lack of reusability comes in object-oriented languages, not functional languages. Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.
If you have referentially transparent code, if you have pure functions — all the data comes in its input arguments and everything goes out and leave no state behind — it’s incredibly reusable.

1.12.4. Dependency Inversion Principle

Implementation depends on / imports the interface, and the caller depends on / imports the interface, instead of depending on / importing the implementation
DIP violations cannot be entirely removed

1.13. Cohesion

                                      CRP (ISP)
                                Split to avoid unneeded releases
                                exclusive (smaller components)

                                          /\
                                         /  \
                                        /    \
                                       /      \
                                      /        \
                                     /          \
                                    /            \
                                   /              \
                                  /                \
                                 /                  \
                                /                    \
                               /                      \
                              /                        \
                             /                          \
                  Too many  /                            \ hard
                components /                              \ to
                   change /                                \ reuse
                         /                                  \
                        /                                    \
                       /                                      \
                      /                                        \
                     /                                          \
                    /                                            \
                   /                                              \
                  /                                                \
                 /                                                  \
                /                                                    \
               /                                                      \
              /                                                        \
             /__________________________________________________________\
                              Too many unneeded releases
    REP (weak)                                                           CCP (SRP, ~OCP)
    Regroup for reusers                                                  Group for maintenance
    reusability                                                          developability
    inclusive (larger components)                                        inclusive (larger components)

1.13.1. Reuse/Release Equivalence Principle

People who want to reuse software components cannot, and will not, do so unless those components are tracked through a release process and are given release numbers (or hashes)

1.13.2. Common Closure Principle

Gather into components those classes that change for the same reasons and at the same times.
Separate into different components those classes that change at different times and for different reasons

Single Responsibility Principle restated for components

1.13.3. Common Reuse Principle

Interface Segregation Principle restated for components

1.14. CUPID instead of SOLID

Composable: plays well with others
Unix philosophy: does one thing well
Predictable: does what you expect
Idiomatic: feels natural
Domain-based: the solution domain models the problem domain in language and structure

1.17. In defense of complicated programming languages

1.17.1. In defense of complicated programming languages

1.17.1.1. Show locked doors before you show a key

You can’t understand a solution without understanding the problem it solves. If you present the solution first, it can be hard to spot there was ever a problem to begin with.

1.17.1.2. Software is not unlimited
  • Software is not physical:
    • Requires no raw materials, no specialized tools, the product has no weight, physical distribution is almost effortless, has no cost of copy and shipment
  • Software is not unlimited
    • Physical capatilities of the machine (disk space, memory usage, speed of computation)
    • Programmers have limited time to create code
    • Programmers have limited time to maintain code
1.17.1.3. Lack of constraints can lead to unbounded complexity

↑ code → ↑ complexity → ↑ time to understand → ↑ more bugs added due to misunderstanding

It’s not that software is cursed by being particularly hard to understand compared to other creative products of labour. It’s the absence of other barriers that allows programmers to create and create and create, until we have a thing with more moving parts than any physical device we could ever construct

1.17.1.4. Software structures emerge irrespective of the language supporting them

The structure and its complexity is an instantiation of the programmer’s intent about the data it represents
If a particular language doesn’t have a feature that covers that structure, the structure will be still be there without language-level support

1.17.1.5. Law of conservation of complexity

When you make the complicated stuff simple, the complexity has to move somewhere
Simple languages hide complexity by moving elsewhere

Over and over, every piece of documentation for the Go language markets it as “simple”. This is a lie. Or rather, it’s a half-truth that conveniently covers up the fact that, when you make something simple, you move complexity elsewhere.

1.18. Five Koans of Software Architecture | by Marianne Bellotti | Apr, 2022 | Medium

https://bellmar.medium.com/five-koans-of-software-architecture-f9f7305598c2

  1. “Those who should decide on the architecture are those that will be on call for it”
  2. “Build it the stupid way first”
  3. “Optimization is death”
  4. “Graph databases are lies”
  5. “Don’t let dependencies own the logic”
    Now what the value of the technology you’re building is and know where the logic that creates that value lives. And then make damn sure you own that logic.


  • Architecture Is Easier When It’s Harder
    You shouldn’t jump in with brilliant ideas if you’re not going to own them.
    You should keep things simple for as long as possible until you know what your usage goals are.
    You shouldn’t assume technology you don’t understand has some magic or secret sauce under the hood.
    You shouldn’t default to products and tools owned by other people until you know what value your software brings to the table.

1.19. Manifestos

1.19.1. The Twelve-Factor App

https://12factor.net/
The methodology was drafted by developers at Heroku, a platform-as-a-service company, and was first presented by Adam Wiggins circa 2011
Matt Ellis from Tibco said “the 12-factor apps check-list is really just a set of guidelines that dictate how a microservice should be built to properly support the concept of independently managed and iterated services. These factors are important when building decoupled, stateless microservices”

1.19.2. The Reactive Manifesto

https://www.reactivemanifesto.org/
Paradigma de programación asíncrono basado en mensajes
Muy basado en microservicios (puede ser una forma de implementarlo, pero no es fundamental)
Está basado en AKKA que es una máquina virtual de erlang implementada en Java

1.20. Everything is an X

https://lukeplant.me.uk/blog/posts/everything-is-an-x-pattern/
At the end, this is standarization
“Everything is an X” is a very high level pattern
When we say “everything” here, we’re talking very loosely — many things in the system are not, in fact, instances of “X”, but are something lower level, or just completely different. “Everything is an X” really means “a surprising number of things in this system are an X”.

  1. Advantages
    • Simplicity of implementation for the implementer. They implement a single interface that they can re-use everywhere and refine as necessary instead of one interface for every new thing
    • Simplicity for the user. They only have to learn one thing, and knowledge gained in one area is immediately applicable to many others.
    • Meta-powers. The “X” interface can be applied at a higher level, and this gives the user super-powers — they can go from manipulating X to manipulating meta-X with very little extra knowledge needed.
      When there are multiple meta-levels that don’t seem to stop, another name for this pattern is “X all the way down”.
    • Elegance and beauty. Beyond utility, systems designed like this have an aesthetic value that I think is motivating for both the implementer and the user.
  2. Disadvantages
    • For some of the things in the system, making them behave as “X” can be a very bad and awkward fit. This could have the effect of:
      • producing an under-powered interface for some things, which has to be patched up in some way.
      • giving an over-powered, bloated interface for other things.
      • making “X” too broad to be useful.
    • Giving the user a higher-level, meta interface could bring challenges, and limit how you restructure or optimise internals because you’ve given the user too much.
    • There are also issues when you have to break the “everything is an X” pattern for some pragmatic reason — you end up with an ugly corner of the design.
    • Adds complexity inside of the X by the law of conservation of complexity
    • Can become a leaky abstraction
  3. Examples
    1. Programming
      • Java: everything is a class (sort of).
        This gives a certain uniformity in how APIs work that tends to reduce the amount of work you have to do when learning a new library.
        In terms of meta-levels, Java doesn’t have so much. It has some reflection abilities that allow classes to be represented as runtime objects, although it is not very deep in terms of what it offers (contrast Python below).
        The limited power for users is undoubtedly useful for compiler writers, however — you can get excellent performance with Java due to the more limited nature of the language (again, contrast Python below).
        Java breaks its own pattern of basing everything on classes with “primitive types”, which means you have also have to deal with boxing, auto-boxing etc. Javascript has similar issues with Number.
      • Python: everything is an object.
        Note that this is very different from Java’s version of “everything is a class/object” — far more things are actually runtime objects in Python, including functions, methods, types/classes and modules, as well as instances of classes. This makes parameterisation an extremely powerful and general pattern in Python.
        You also get super powers that come from how meta-classes work:

        • instances are objects
        • classes (the things that produce instances) are objects
        • meta-classes (the things that produce classes) are objects

        So meta-class programming is just normal programming. It can be done at a REPL, or with any other technique that you have already learned. Using meta-classes of course requires learning new things, but things still work in very familiar ways. Python feels like it’s made out of Python all the way down.
        We also see the disadvantages. For example, Python integers are full Python objects, which is extremely wasteful of memory compared to compact representations (like C would use, or numpy uses for example). Plus, they are immutable (for good reasons), so doing simple addition can cause memory allocations. This is pretty horrifying from an efficiency point of view!
        [Correction - in depends on implementation; CPython caches integers between -5 and 255 and has some other optimisations, but still has a lot of overhead in terms of the size of the object]

      • ML family languages, like Haskell/OCaml and relatives: everything is an expression.
        So, for example, there is no if statement, there is instead an if expression. Assignments, too, are actually expressions — for example a let statement is instead an expression that defines some local values and returns the value of the ‘body’.
        Exceptions: Top level assignments, and type signatures. At least in Haskell, the type system feels quite separate. Due to this, AFAICS the meta level is kind of missing in Haskell. Haskell “super-powers” come from a bunch of different features, such as deriving and TemplateHaskell, and programming at type level, especially with various language extensions. These are all cool features, but they have to be learned separately, and I think this is what gives Haskell the feeling of being a big and intimidating language.
      • Lisp: everything is an s-expression.
        In contrast to Haskell, this goes much further and includes top level statements. This uniformity of syntax is hugely helpful in writing macros, probably the biggest meta-power that Lisp boasts.
    2. User interfaces
      • Emacs: everything is a buffer.
        This is one of Emacs’ big ideas — it has very few different UI elements, because almost everything appears in a buffer. As well as the text of a file to edit, you also have:

        • help manuals
        • auto-generated help for the buffer you are using (such as listing all keyboard shortcuts).
        • search results (this is an essential part of my workflow for recursive searching that remembers context)
        • many, many more things.

        Once you have learned how to navigate and use buffers, you know how to navigate these things.
        Of course, there are other UI elements, such as the toolbar and menubar, to make Emacs slightly less terrifying to new users. But these tend to be turned off by experienced users — they’re not very useful because…they’re not buffers!
        You also gain meta-powers: the list of all buffers is of course a buffer, and you can manipulate the buffer-buffer using normal mechanisms (e.g. delete line to kill a buffer).

      • RDMSs: everything is a table/relation, and can be queried as such.
        With some implementations such as PostgreSQL, as well as the normal relations you have created, internal structures are also presented as relations, including the lists of tables/relations/indexes, and runtime information.
        So you can get a table of all tables:

              SELECT  table_name
             FROM  information_schema . tables
             WHERE  table_schema  =  'public'
             ORDER  BY  table_name ;
        

        And query the currently running queries:

              SELECT  *  FROM  pg_stat_activity ;
        

        And many other things. These things benefit from all the usual powers of = SELECT=, such as joins, filtering, ordering etc.
        If you extended the meta-powers, you could create/delete tables by inserting into/deleting from the “tables table”, and similarly add/remove/alter columns by manipulating the “columns table”. Your schema then becomes data, and your power has become a super-power. I don’t know if any DB has implemented this, or if the advantages would be really compelling over normal DDL.

      • Visidata: everything is a sheet.
        At points this seems to go further than PostgreSQL in terms of giving you meta-powers and sticking to the pattern. In addition to the normal data sheets:

        …and more.
        I’m loving the power of Visidata, which is basically “Excel as a text user interface”, and I’ve realised that a lot of its power comes from its lack of power.
        In Excel, you can have multiple tables in a sheet, and put them wherever you like. You can have headers, or not, you can have a different format or data type for every cell etc. In Visidata, you have exactly one table per sheet, you must have headers, each column has exactly one data type etc. The enforced uniformity of “Everything is a sheet (and a sheet has a tightly defined structure)” is actually crucial to making Visidata so much nicer than Excel for many tasks — without it, most of the interface shortcuts and meta-powers would fail.

      • REST: everything is a resource.
        The idea of everything in your system being a “resource” which you can manipulate with a few well-understood verbs ( GET, PUT, DELETE etc.) is a really attractive part of REST.
        It comes with some meta-powers - with things like OpenAPI, the list of resources is typically also served as a resource.
        Relatively frequently with REST I feel I hit the “awkward fit” disadvantage. Modelling some actions as “manipulating a resource” is very bizarre, and what you really want is just a RPC (for example, with “clone/copy/move” actions where there are hidden properties that you also want to be handled).
      • Unix: everything is a file.
        This is a pretty successful abstraction, but it does leak quite a bit — for example, stdout and stdin are “files”, except when they are terminals, which you very often want to special case because they are not really very much like files when they have humans sitting in front of them. Also, files turn out to be much harder than you think, even before you start treating things that aren’t files as files. And in some cases you might want to deal with files as if they are not files but memory anyway (mmap).
  4. Questions

    I’m sure there are many, many more examples of this pattern, and I’m only scratching the surface. EverythingIsa on c2.com has a longer list, for example, but without much analysis. What are your favourite examples? Are there examples where it works very well — or very badly? Are there other advantages/disadvantages that I’ve missed?

  5. Links

1.21. What does Everything Is A File do? · sunfishcode’s blog

The real abstraction here is just Lots Of Things Are Streams.

1.22. Leaky abstractions

All non-trivial abstractions, to some degree, are leaky.
Abstractions fail. Sometimes a little, sometimes a lot. There’s leakage. Things go wrong. It happens all over the place when you have abstractions.
https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/
«A leaky abstraction can be falling from simple to complicated or even chaotic, according to Cynefin Framework»

1.24. Test smarter, not harder - lukeplant.me.uk

https://lukeplant.me.uk/blog/posts/test-smarter-not-harder/

  • Same concept as Configs suck, use code
  • Write explicitlly all the tests vs generate them using code
  • The “test harder” religion interprets this as:

      For every entry point
          Write a test that
              Ensures non-authenticated requests return 403
    

    That’s a lot of tests, and even worse is that you have to remember to write them.

  • “Test smarter” says:

      Write a test that
          For every entry point
              Ensures non-authenticated requests return 403
    

    That’s one test. “Write a test” is executed in developer time, so in the first example the loop (“For every entry point”) is also executed in developer time. Push the loop inside the test, and it gets executed in computer time instead.

1.25. Big Ball of Mud (Anti Design Pattern)

While much attention has been focused on high-level software architectural patterns, what is, in effect, the de-facto standard software architecture is seldom discussed. This paper examines this most frequently deployed of software architectures: the BIG BALL OF MUD. A BIG BALL OF MUD is a casually, even haphazardly, structured system. Its organization, if one can call it that, is dictated more by expediency than design. Yet, its enduring popularity cannot merely be indicative of a general disregard for architecture.
These patterns explore the forces that encourage the emergence of a BIG BALL OF MUD, and the undeniable effectiveness of this approach to software architecture. What are the people who build them doing right? If more high-minded architectural approaches are to compete, we must understand what the forces that lead to a BIG BALL OF MUD are, and examine alternative ways to resolve them.
A number of additional patterns emerge out of the BIG BALL OF MUD. We discuss them in turn. Two principal questions underlie these patterns: Why are so many existing systems architecturally undistinguished, and what can we do to improve them?

http://www.laputan.org/mud/mud.html

1.26. Linus Tolvards against 80 characters per line

1.27. Desired state systems: how React, Kubernetes and control theory have lots in common

1.28. The Forgotten History of OOP

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.
I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea. The big idea is messaging.
Alan Kay

Notably, inheritance and subclass polymorphism were NOT considered essential ingredients of OOP

1.28.1. Alan Kay

Interested on the investigation of Douglas Engelbart

1.29. Timezones are difficult

tldr; Use https://en.wikipedia.org/wiki/Tz_database unless you’re working in the energy business and have to consider time differences between countries

1.29.2. Saving time in UTC doesn’t work and offsets aren’t enough | Swizec Teller

1.29.3. UTC is Enough for Everyone, Right?

https://zachholman.com/talk/utc-is-enough-for-everyone-right
RFC 5545
Para definir recurrencias, al final habla de esto

1.29.4. An Introduction to Time Representation, Serialization and Management in Software :: Mirko Caserta — Software Engineer

1.30. str-datetime types are difficult

tldr; Use an internal representation of datetime type as long as possible and then convert to str when necessary
By keeping it as a datetime you gain flexibility as you can add/substract timedeltas

1.31. Innovating beyond libraries and frameworks

https://www.reddit.com/r/programming/comments/u21syc/innovating_beyond_libraries_and_frameworks/

caution here about not to overuse them and/or apply them in ill-fit contexts (see: Law of the instrument). For example The Wrong Abstraction → critique of developers’ tendency to apply the DRY principle at all costs.

Producer-consumer problem → When using a framework, your code is a producer and the framework is a consumer. When using a library, your code is the consumer and the library is a producer

1.31.1. https://changelog.com/news/innovating-beyond-libraries-and-frameworks-wkAk#comment-NW9

It’s interesting on one hand how libraries and frameworks can package up big ideas and offer it to end-users.
On the other hand adopting an idea (principles and patterns) directly instead of pulling them in as dependencies requires more work, but in turn it might add more flexibility and longevity to a codebase because ideas doesn’t need security updates or funding

1.32. Inversion of control - Wikipedia

IoC inverts the flow of control as compared to traditional control flow. In IoC, custom-written portions of a computer program receive the flow of control from a generic framework.
Inversion of control carries the strong connotation that the reusable code and the problem-specific code are developed independently even though they operate together in an application.
Callbacks, schedulers, event loops, dependency injection, and the template method are examples of design patterns that follow the inversion of control principle, although the term is most commonly used in the context of object-oriented programming.
Inversion of control serves the following design purposes:

  • To decouple the execution of a task from implementation.
  • To focus a module on the task it is designed for.
  • To free modules from assumptions about how other systems do what they do and instead rely on contracts.
  • To prevent side effects when replacing a module.

Inversion of control is sometimes facetiously referred to as the “Hollywood Principle: Don’t call us, we’ll call you”.

In object-oriented programming, there are several basic techniques to implement inversion of control. These are:

  • Using a service locator pattern
  • Using dependency injection; for example,
    • Constructor injection
    • Parameter injection
    • Setter injection
    • Interface injection
    • Method Injection
  • Using a contextualized lookup
  • Using the template method design pattern
  • Using the strategy design pattern

1.33. Layers/Features Naked Objects

1.33.1. By layers

  1. Designing Data-Intensive Applications - The Big Ideas Behind Reliable, Scalable, and Maintainable Systems - Martin Kleppmann (O’Reilly Media, 2017)

Más de sistemas, de mantener tuberías de datos sincronizadas, bases de datos

  1. Domain-Driven Design - Tackling Complexity in the Heart of Software - Eric Evans (Addison-Wesley, 2004)
  2. Clean Architecture - A Craftsman’s Guide to Software Structure and Design - Robert C. Martin (Pearson, 2017)
  3. http://aosabook.org/en/index.html
  4. https://dev.to/bosepchuk/why-i-cant-recommend-clean-architecture-by-robert-c-martin-ofd
    Martin Fowler - Patterns of Enterprise Application Architecture is better than Bob Martin - Clean Architecture

1.33.3. La antisimetría datos/objetos se puede aplicar a servicios/features?

Datos → servicios Objetos → features (Naked Objects)

1.33.4. Vertical Slice Architecture

1.33.5. Naked Objects

1.34. Links

1.34.2. Use mmap With Care - News - Sublime HQ

https://www.sublimetext.com/blog/articles/use-mmap-with-care
Caveats when using mmap (mounted volume is closed when reading, compatibility, multithreading and error handling)

1.35. Principles Wiki [Principles Wiki]

This wiki is a place to collect, examine, and discuss software design knowledge in a systematic way. Currently there is a strong focus on (object-oriented) design principles (SOLID, GRASP, DRY, KISS, …)

Author: Julian Lopez Carballal

Created: 2024-09-16 Mon 06:21