Arquitectura de Software
Table of Contents
- 1. Arquitectura de software
- 1.1. Software metaphors
- 1.2. Awesome Software architecture
- 1.3. Groups of People
- 1.4. Software architecture blogs that I like
- 1.5. Suffering-oriented programming - thoughts from the red planet - thoughts from the red planet
- 1.6. Functional Programming
- 1.7. The Grug Brained Developer
- 1.8. Principles
- 1.8.1. Arquitectura de software es lo que te permite retrasar decisiones
- 1.8.2. Software architecture as finacial options
- 1.8.3. Rate of change and shared resources
- 1.8.4. Simplificación / Minimalismo
- 1.8.5. Uncoupling
- 1.8.6. distributed systems
- 1.8.7. https://rotemtam.com/2020/05/18/the-dry-principle-is-bad-advice/
- 1.8.8. You should be reading academic computer science papers - Stack Overflow Blog read
- 1.8.9. Design Patterns (Gang of Four)
- 1.8.10. Patterns of Enterprise Architecture
- 1.8.11. https://refactoring.guru/
- 1.8.12. Game Programming Patterns
- 1.8.13. Epigrams in Programming | Computer Science
- 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
- 1.9.3. Crafting Interpreters: A Review
- 1.9.4. 10 Books Every Senior Engineer Should Read
- 1.9.5. Thomas, David. The Pragmatic Programmer, 2nd edition (The DRY principle is not always right)
- 1.9.6. Classics I’ve Read
- 1.10. Barbell strategies in Software Architecture
- 1.11. _ envy
- 1.12. SOLID
- 1.13. Cohesion
- 1.14. CUPID instead of SOLID
- 1.15. Continuous Integration / Continuous Delivery
- 1.16. Decoupling database migrations from server startup: why and how
- 1.17. In defense of complicated programming languages
- 1.18. Five Koans of Software Architecture | by Marianne Bellotti | Apr, 2022 | Medium
- 1.19. Manifestos
- 1.20. Everything is an X
- 1.21. What does Everything Is A File do? · sunfishcode’s blog
- 1.22. Leaky abstractions
- 1.23. https://en.wikipedia.org/wiki/Unix_philosophy
- 1.24. Test smarter, not harder - lukeplant.me.uk
- 1.25. Big Ball of Mud (Anti Design Pattern)
- 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
- 1.29. Timezones are difficult
- 1.29.1. The Problem with Time & Timezones - Computerphile - YouTube
- 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?
- 1.29.4. An Introduction to Time Representation, Serialization and Management in Software :: Mirko Caserta — Software Engineer
- 1.30. str-datetime types are difficult
- 1.31. Innovating beyond libraries and frameworks
- 1.32. Inversion of control - Wikipedia
- 1.33. Layers/Features Naked Objects
- 1.34. Links
- 1.35. Principles Wiki [Principles Wiki]
1. Arquitectura de software
1.1. Software metaphors
1.1.1. Software gardening
1.1.2. Software building
1.1.3. Software cooking
1.1.4. Factorio and Software Engineering · Krishna’s words
https://blog.nindalf.com/posts/factorio-and-software-engineering/ Software explicado para gente de fuera
https://www.reddit.com/r/programming/comments/ibaok7/factorio_and_software_engineering/
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
- The Hillside Group
- Kent Beck
- Grady Booch
- Ralph Johnson (Gang of Four, Dessign Patterns)
- Ward Cunningham (Creator of the Wiki)
- Richard Gabriel
- Kent Beck
- The eXtreme Programming (XP) Group
- Kent Beck
- Ward Cunningham (Creator of the Wiki)
- Martin Fowler
- Michael Feathers (Working Effectively with Legacy Code)
- Ron Jeffries
- Kent Beck
- ThoughtWorks London
- Lean enterprise, Devops Handbook, Accelerate (Books)
- Jez Humble, Dave Farley (Ontinuous Delivery)
- Dan North (BDD)
- Nat Pryce
- Sam Newman (Microservices)
- Lean enterprise, Devops Handbook, Accelerate (Books)
- Stack Overflow creators
- Coding Horror (Jeff Atwood)
- Joel on Software (Joel Spolsky)
- Coding Horror (Jeff Atwood)
1.4. Software architecture blogs that I like
- https://zwischenzugs.com
- https://lukeplant.me.uk
- https://thevaluable.dev/
- https://www.destroyallsoftware.com
- https://blog.sunfishcode.online/
- https://jessitron.com/
- https://jvns.ca/
- https://lethain.com/
- EA Voices – Aggregated enterprise architecture wisdom
Want to get an overview of what the enterprise architecture community blogs about? I did, so I created this ‘planet’.
A river of news and opinions about enterprise architecture, EA Voices is a thematic aggregator of enterprise architecture blog feeds.
A robot fetches blog posts from over 250 enterprise architecture bloggers within the hour of being published to the original blog.
1.4.1. https://lethain.com/forty-year-career/ (Compilation of links)
- Everyone who leverages success in one company or role into success at company or role that’s a bit bigger, a bit better known
- Can and Ranjan’s The Margins newsletter has connected them to venture capitalists, journalists and each email is now being read by many 1,000s of folks
- Cindy’s life-changingly good blog posts on infrastructure
- Julia’s zines are novel, innovative and totally unique, and each new one pushes her star a bit higher
- Julie writing and publishing The Making of a Manager
- Kelley’s appearance on 5 minute mentor, TWIML Talk, and with Rob on Software Engineering Daily (and of course Jeff’s work creating Software Engineering Daily which has been a vehicle of prestige creation for many, many folks)
- Sweta writing Post-mortems to the rescue for Increment’s Documentation issue
- Tramale speaking about the EM Kata at Abstractions Con
- Uma’s appearance on Software Engineering Daily podcast and speaking at Velocity
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.2. Software architecture as finacial options
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/
- Worse Is Better
- 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
- Worse Is Better process
- Main Page - Worse Is Better
1.8.4.2. The Duct Tape Programmer – Joel on Software
1.8.4.3. software that sucks less | suckless.org software that sucks less
https://suckless.org/philosophy/
Design Philosophy
https://programmingisterrible.com/post/173883533613/code-to-debug
https://suckless.org/philosophy/
http://www.joelonsoftware.com/items/2009/09/23.html
http://www.250bpm.com/blog:4 (C vs C++, return values (local) vs exceptions (non-local), for systems programming use C)
https://adamdrake.com/command-line-tools-can-be-235x-faster-than-your-hadoop-cluster.html
1.8.5. Uncoupling
1.8.6. distributed systems
1.8.7. https://rotemtam.com/2020/05/18/the-dry-principle-is-bad-advice/
- DRY code can result in tight-coupling as it reduces functional coupling by introducing development coupling
- DRY code can be harder to read
“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.9. Design Patterns (Gang of Four)
1.8.10. Patterns of Enterprise Architecture
1.8.11. https://refactoring.guru/
1.8.12. Game Programming Patterns
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
- Extreme Programming Explained: Embrace Change (2nd Edition) by Kent Beck
- Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation by Jez Humble and David Farley
- Remote: Office Not Required by Jason Fried and David Heinemeier Hansson
- The Mythical Man-Month by Frederick P. Brooks Jr.
- Getting Real
- Designing Data-Intensive Apps by Martin Kleppmann
- Site Reliability Engineering
- The Phoenix Project by Gene Kim, Kevin Behr, and George Spafford
- Building Microservices: Designing Fine-Grained Systems by Sam Newman
- 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.9.6. Classics I’ve Read
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.11.3. Microservices envy
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
- Accidental Duplication
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
height = 30 slope = 1 use_ascii = True if use_ascii: bottom = "_" left = "/" right = '\\' else: bottom = "▁" left = "╱" right = "╲" return "\n".join([slope*(height-i)*" "+left+2*slope*i*(bottom*(i==(height-1))+" "*(i!=(height-1)))+right for i in range(height)])
/\
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/__________________________________________________________\
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.15. Continuous Integration / Continuous Delivery
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
- 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
- Physical capatilities of the machine (disk space, memory usage, speed of computation)
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
- “Those who should decide on the architecture are those that will be on call for it”
- “Build it the stupid way first”
- “Optimization is death”
- “Graph databases are lies”
- “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”.
- 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.
- 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
- 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.
- producing an under-powered interface for some things, which has to be patched up in some way.
- 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
- 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:
- Examples
- 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]
- instances are objects
- ML family languages, like Haskell/OCaml and relatives: everything is an expression.
So, for example, there is noif
statement, there is instead anif
expression. Assignments, too, are actually expressions — for example alet
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 asderiving
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.
- Java: everything is a class (sort of).
- 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).
- help manuals
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:
- rows are sheets (or can be viewed as such)
- column meta-data is a sheet (and not just read-only - you can manipulate it)
- the list of sheets is a sheet
- configuration is a sheet
…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.
- rows are sheets (or can be viewed as such)
- 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).
- Programming
- 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?
- 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?
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
https://swizec.com/blog/saving-time-in-utc-doesnt-work-and-offsets-arent-enough/
tldr; save timestamp and timezone
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
https://mirkocaserta.com/posts/2013/04/an-introduction-to-time-representation-serialization-and-management-in-software/
Zonas horarias
Links interesantes abajo
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/
- I have been a big fan of the write libraries, not frameworks argument. we should start to value principles over patterns, patterns over libraries, and libraries over frameworks.
- Definitions
- Framework: Usually someone else’s code that calls your code. Your code will need to conform to constraints/boundaries/conventions
- ↓ often hard to code around these constraints
- ↑ quicker coding since you tend to get a lot of useful functionality out of the box
- ↓ often hard to code around these constraints
- Library: usually someone else’s code that you call from your code. A library tends to be some code that imposes fewer constraints on your code as compared to frameworks. By using one or more libraries you’re able to reuse someone else’s code to solve your problems. Libraries are easier to combine and interchange, while putting frameworks on top of frameworks can lead to a bad time.
- ↑ fewer constraints that a framework
- ↑ reuse someone else’s code to solve your problems
- ↑ easier to combine an interchange
- ↑ fewer constraints that a framework
- Pattern: descriptive, reusable approach to writing your code (see: software design pattern). Patterns range in their vaguenes, applicability and prescriptiveness.
Examples of programming patterns include early-return pattern, builder-pattern, actor model, model-view-controller, onion architecture, microservices, majestic monolith, monorepos, and flux architecture. - Principle: This is some general guidance or philosophy expressed as rules (like a rule of thumb) that helps you write good code.
Examples of principles include SOLID principles, Don’t repeat yourself (DRY), You Aren’t Gonna Need It (YAGNI), Agile manifesto, Law of Demeter, Hyrum’s law. There are many more to be found out there, and as I write this I just discovered this site that collects programming principles, nice!
- Framework: Usually someone else’s code that calls your code. Your code will need to conform to constraints/boundaries/conventions
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
- Constructor 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
- 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
- Domain-Driven Design - Tackling Complexity in the Heart of Software - Eric Evans (Addison-Wesley, 2004)
- Clean Architecture - A Craftsman’s Guide to Software Structure and Design - Robert C. Martin (Pearson, 2017)
- http://aosabook.org/en/index.html
- 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.2. By features
http://www.nakedobjects.org/book/content.html
Domain-Driven Design using Naked Objects
https://stackoverflow.com/questions/167517/naked-objects-good-or-bad
https://javadevguy.wordpress.com/2019/06/06/data-boundaries-are-the-root-cause-of-maintenance-problems/
https://javadevguy.wordpress.com/2017/07/27/a-detailed-analysis-of-the-clean-architecture-from-an-object-oriented-perspective/
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
Término crítico de búsqueda
1.33.5. Naked Objects
[X]
Hacer UML en LectureNotes[ ]
Vertical slice architecture -> Término clave[ ]
Sacar beneficios/limitaciones de la tesis y juntar con lo mío[ ]
https://py3traits.readthedocs.io/en/latest/readme.html[ ]
https://github.com/bgk0018/vertical-slices Proyecto usando verticalidad[ ]
https://www.youtube.com/watch?v=wTd-VcJCs_M
1.34. Links
1.34.1. Why You Hate Matplotlib
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, …)