Saturday, December 10, 2022

Abstraction - or is it Simplification?

A few posts back I mentioned I had some thoughts on abstraction, though as I think about it I'm not sure 'abstraction' is the right term for it. 

Perhaps it's that attempts to simplify something often just add complexity in a different way. 

Like whoever it was that did that risk analysis, where they said adding safety measures (like making cars safer in accidents) just make people start taking riskier actions. 

And I feel the thoughts slipping away the more I try to explain that, so I'll just move on.

One of the things to understand about computers is that there's a LOT of abstraction going on. 

Let me start by briefly talking about numbering systems with different bases.

We use a decimal system, and we're so used to it that most people don't even think about it.

9+1=10

99+1=100

We count from 1 to 9, and when we reach the number we add a '1' to the left, rollover the 9 to 0, and start counting from there.

There are other systems that use a different base, like base 16. Base 16, or hexadecimal, requires more numbers than decimal does, because it counts a little bit longer before it rolls over.  We've pretty much decided to fill in the missing numbers by using the alphabet, which is why base 16 uses A,B,C,D,E, and F.

9+1=A in hexadecimal, A+1=B, and so on until F+1=10. (Your computer probably has a calculator function which you can set to 'programmer' mode and convert between decimal, hexadecimal, octal (base 8) and binary (base 2).

I brought that up because computers use binary or base 2. That's essential since you can use electrical circuits to represent 0 or 1 - everything is either off or on. (This may change with quantum computers, but that's a whole other level).

Every single thing your computer does is basically processing a string of 0s and 1s.

Which is really, really, really hard for people to read and understand. So we abstracted a layer away.

First with assembly language, which created simple mnemonic instructions that were easier to use than the binary. This section from the wikipedia link I shared above goes into more detail:

Assembly language

A program written in assembly language consists of a series of mnemonic processor instructions and meta-statements (known variously as declarative operations, directives, pseudo-instructions, pseudo-operations and pseudo-ops), comments and data. Assembly language instructions usually consist of an opcode mnemonic followed by an operand, which might be a list of data, arguments or parameters.[24] Some instructions may be "implied," which means the data upon which the instruction operates is implicitly defined by the instruction itself—such an instruction does not take an operand. The resulting statement is translated by an assembler into machine language instructions that can be loaded into memory and executed.

For example, the instruction below tells an x86/IA-32 processor to move an immediate 8-bit value into a register. The binary code for this instruction is 10110 followed by a 3-bit identifier for which register to use. The identifier for the AL register is 000, so the following machine code loads the AL register with the data 01100001.[24]

10110000 01100001

This binary computer code can be made more human-readable by expressing it in hexadecimal as follows.

B0 61

Here, B0 means 'Move a copy of the following value into AL, and 61 is a hexadecimal representation of the value 01100001, which is 97 in decimal. Assembly language for the 8086 family provides the mnemonic MOV (an abbreviation of move) for instructions such as this, so the machine code above can be written as follows in assembly language, complete with an explanatory comment if required, after the semicolon. This is much easier to read and to remember.

MOV AL, 61h       ; Load AL with 97 decimal (61 hex)

That was a lot, and I didn't want to cut out the context so I highlighted the parts I wanted to focus on the most.

First, you see the binary data that the computer is processing. Since everything is binary, the computer mostly knows from where it's processing a program which sequence of 0s and 1s are instructions and which are the values the instructions are acting upon. 

That's what it's talking about with the opcode (operation code for doing something) versus the value. So we have:

10110000 01100001 

The first set of numbers are the instructions to move the following value to a specific place in the computer, and the second set of numbers are the value to be moved.

And then we made it slightly more human readable by converting the binary to hexadecimal.

10110000 = B0; 01100001 = 61

For the specific computer architecture in the wikipedia example, B0 becomes a mnemonic in assembly language: MOV AL. 

Basically says the computer should move the subsequent value to the location 'AL'. That value is 61 in hexadecimal, 97 in decimal. Hence the assembly language command:

MOV AL, 61h 

That's still not very easy to understand, is it?

So we abstract again, and created higher programming languages. C, C++, Python, Java, COBOL, etc.

Each have their nuances (some are better for science, since the accuracy needed and extreme sizes of numbers used in their calculations are not something every programming language handles well), but the core logic is fairly similar so once you've learned logic you mostly just have to learn the specific syntax used in each language.

And they're still fairly complicated to use. Especially since each tends to develop 'libraries', i.e. reusable code created for common tasks... and since these are common tasks, and programmers don't like reinventing the wheel, you then have to know which ones you want to use and import them into your program. (When I'm programming and need to know how to do something, half the time it's just a matter of importing the correct library and then giving the commands needed to use that library.)

Before continuing I'll add this - even though most people use the more human readable languages, that doesn't mean that nobody has to know assembly anymore. Actually, malware reverse engineers tend to look at that level to see what a malicious program is doing. And the hackers themselves may be working at this level in order to takeover a program....

Basically, if the computer is expecting a sequence of zeroes to be instructions and another sequence of zeroes to be the values it acts on, if you understand the computer architecture well enough you can sometimes overwrite the original sequence of zeroes. Instead of doing the command above, MOV AL... they may overwrite the binary to something like JMP, which will jump to another location and start reading the code there. If the hacker is able to force a JMP to their own code, then suddenly the program will start following the instructions written there.

To get back to the things I've noticed - we're dealing with some very complex things, so complex I sometimes marvel that at the heart it's all 0's and 1's, and everyone seems to be looking for ways to simplify or make things easier.

Except most of the time those 'simple' things are fairly complex in an entirely different way.

For example, when I started programming in Java our professor wanted us to use BlueJ as the development environment. There are others out there that do a lot more for you, like predictive text. She wanted us to start with something more basic so that we didn't learn to rely too much on that sort of thing. (I've noticed that when I type something out fully I tend to remember it better than when it's just a matter of typing 'ma + TAB' to select whatever is being suggested, so I think she had a decent point here).

When I took some of the later courses I decided that I needed to start using a more powerful tool. So I went looking around online, checked out the various recommendations, and decided to use IntelliJ.

It was so complicated and difficult to learn that I wondered if I'd chosen wrong, uninstalled it and installed one of the alternatives... found it just as complicated, uninstalled it and went back to IntelliJ. 

And then dug into the documentation, any videos or tutorials online, and figured out enough of it to do what I needed to do.

I still don't think I've mastered it, by any means, but it's... usable. Well, at least they also make an integrated development environment (IDE) for python so it's not like I have to relearn everything. (And I'm not really coding that much in the first place.)

Oh, and get this - it's not like we ever had any classes teaching us how to install and work with an IDE. Maybe when we started using BlueJ at the beginning, but choosing another tool was entirely up to us.

We come up with these really complicated tools to 'simplify' something, and to a certain extent they do. But they also add another layer of complexity. First, because you have to learn the tools themselves. Second, because sometimes that layer obfuscates the underlying issues, and you still have to dig deeper to figure things out. And third, because that 'simplification' leaves room for other complex actions.

I probably need to explain that in more detail, but I'm going to stop there for now. My dog needs some attention.



No comments:

Post a Comment