First version of BeginnersGuide and other doc changes

This commit is contained in:
Torsten 2020-03-21 19:02:02 +02:00
parent a40d8f2e8c
commit f2c853821c
3 changed files with 298 additions and 14 deletions

238
BeginnersGuide.md Normal file
View File

@ -0,0 +1,238 @@
# Beginners Guide
We are coming up to RailsGirlsSummerOfCode, so i wrote this document for people with
very little coding or ruby experience. It can be used by other people as a check-list,
because basically anything in here is assumed when working on RubyX.
# Tools of the trade
I just want to introduce the main characters, what you need, maybe some extra.
Details for installing or using software are abound on the net, so i am not getting
into specifics, platform issues or the like. Just an overview that you may not find
on the net.
## Terminal
The terminal and editor are still the two main tools you need. A terminal is a program
that interprets typed input and starts other programs. The interpreters are called
shells, bash (Bourne Again SHell) is popular, but anything you have is fine.
The shell starts when you start a terminal (window or tab) and usually reads somehting
like .profile, or .bash_profile , where environment variables may be set. These
variables, usually with capital names, influence the behaviour of programs. The most
import one is probably the PATH variable, that determines where program executables
are searched.
Don't fuss in the beginning which terminal you use, anything is fine for starters.
When i talk about commands, i mean typing those commands in the terminal.
## Editor
Off course you need an editor to edit program files. The most important thing here is
that it supports colour highlighting for ruby. It may be an IDE like RubyMine, vim, or
i use atom. It does not really matter, as long as you know how to use it.
## Ruby, maybe with versions
There are two main ruby implementations, called MRI (Matz Ruby implementations) and
JRuby (Java Ruby), we will use MRI.
There are several versions of MRI, though that used to matter more than it does now.
Anything over 2.4 is fine for RubyX.
Because version differences were bigger, and in a professional environment it is
essential to know the exact version on is using (in development and production)
ruby version managers have been developed. There are rbenv and rvm , but since
you don't really need them i will leave it at that.
## Gems
Gems are packages of ruby code. After all, any meaningful software will rely on other
software, and so gems have been with ruby from the start as a way of packaging code.
Eg rubyx is a gem, and you can see the package definition in rubyx.gemspec in the root
folder.
gem is also a command to manage gems. A version of gem (the command) will come with
any ruby installation. gem is used to manage single packages, but for a project
we usually need many gems, and this is where bundler comes in.
## Bundler
Bundler is a program (a gem actually) to manage all the gems a project needs. The
problem it was made to solve is this: Say you need 10 gems for a project. Those 10
gems all have dependencies of their own, so really you may need 20-40 gems.
If not managed, different developers and production systems will have slightly
different versions of gems. This leads to very hard to track errors, a nightmare
basically.
A Gemfile is the bundlers way of specifying a projects dependencies. Bundler
(using the command bundle install) then resolves all dependencies and their
dependencies and installs all the needed gems.
Bundler also creates a Gemfile.lock to record all the gems that are needed. This file
is usually checked in and will ensure that every developer has the same gems.
Only when the Gemfile is changed, or one wants to update gems by hand, does bundle
install need to be run again.
## Git
Version control has always been essential to coordinate the work of many people,
and git is arguably the best tool for the job. So you need to install it and get
to know the basics, at least clone, commit, push, and basic branches.
After installing MRI and bundler you need to clone the rubyx repository.
Go to the directory and bundle (or bundle install, sama sama)
Then you can run "ruby test/test_all.rb" to determine that everything is working as it
should. If it does, you are ready to start development.
# Development process
Once you have a working environment, you'll be wanting to code. So this section is
about the basic loops we go through as developers, the recurring tasks that make
up a programmers life. I'll try to avoid jargon and rather explain why we do what we do.
## Edit => Save
The most basic cycle is undoubtedly edit and save. You edit some part of the program
and save your work. There are some details to consider about the formatting and style,
in the [Code Style](CodeStyle.md).
There are two basic needs to do this basic coding:
- you need to know what to edit, what it is you want to achieve and how to achieve it
- having finished (saved) you need a way to know if you have achieved what you set out to do
The "how to achieve it" part is the skill of programming. Like all skills, developing
this skill is a process and takes years, so i'll leave it at that.
What you want to achieve is up to you. Your imagination for the new. Your ability to
find bugs. Or your willingness to do what others have found worthy of doing (issues).
This is explained more in the next section.
So then we come to that crucial part of knowing when you achieved your goal. This has
been at the crux of programming since the dawn, and the most widely agreed upon way is
off course testing. Everybody agrees testing is the way, just how much is in dispute.
It's like being healthy: everybody agrees in principle, but many still smoke, or
eat meat or milk products (clearly shown to be unhealthy)
## Testing (or edit => save => test)
RubyX is very clear on the topic: all code needs tests. All new code needs new test.
Every bug-fix needs more tests. Tests are the only way we know things work, and
since RubyX produces programs as it's output (which should run correctly), we need
to know doubly well that everything works. Both the RubyX code, and the generated code,
must work, ie be tested. Some may call this TDD extreme, i call it common sense, and
find it is the best way to work.
Specifically RubyX uses minitest, and has several layers of tests under the test
directory. Generally speaking, test files contain ruby code called tests.
This code exercises the source code and asserts (tests)
assumptions to be correct. Minitest provides a base Test class to derive from and
about ten different assert methods to assert assumptions. Methods of the class must
start with test_ and each such method is called a test.
RubyX currently has over 1700 tests with almost 15000 assertions.
At about 7k lines of code, that is roughly 2 assertion for each line of code. this
should give you an idea how important testing is in RubyX.
## Automated testing (edit, save , autotest) or guard
Guard is a tool to run tests automatically. Similarly to bundler, Guard defines
a Guardfile to define which tests should be run, and a command-line tool (guard)
to run them automatically.
Basic tests mirror the same directory structure as the code in the test
directory. Basic (or unit) tests live in files with the same name as the source
code file name, with a "test_" prefix, in a shadowed directory. Eg for a file
/lib/parfait/word.rb , there will be a file in /test/parfait/test_word.rb .
The Guardfile defines conventions like this, in code. So there
is a basic rule in the Guardfile stating that when a source file changes
the equivalent test file should be run. Other rules may be added easily,
as a Guardfile is really just ruby code, working against the guard api.
The way to use guard is to have a terminal open and start the guard command.
Guard will listen for changes, and once a file is saved *automatically* run
affected test files.
This way we're back to edit, save, the shortest possible loop. Only when all tests
are green, and there are enough (new) tests to cover the code, can you move on to the
next phase, sharing your code.
# Contribution process
Open source is all about sharing code. It maybe for the greater good, or just fun,
but it is working together in a coordinated fashion. Git (with commit rights) is
what makes the coordination easy, some might say possible.
You start with a clean environment, either you just cloned, or pulled from github.
There are several ways to find what you want to work on, but all roads lead to
github issue. You either find an existing one, or create one. Don't start
work on something that has no issue, and the best way is to make your intention
clear, by commenting on the issue.
## Topic branches and issues
Once you have a topic (and a github issue to go with it) you want to start coding.
But don' just yet. To manage you changes with others, it is best to create what is called a topic branch. Branches are very cheap in git (very little resources required),
and make it so much easier to manage the code. It is really not advisable to
skip this step (read: your contribution may not be accepted, which really is in
no-ones interest, least your own) unless it is a tiny, non-controversial change
like a typo.
git checkout -b 65_my_bugfix
This is the command to start a new (topic) branch. You'll want to start with the
github issue number and add a short description for the task.
## work on the issue / branch
As described above, you can now edit the code and tests to work on the issue.
You may use the github issue for discussion or help. You can also push the branch
to github and collaborate on the code. Or have someone review it.
Use guard, write minitests, edit (according to code guidelines) until happy.
Commit, push and create a pull request.
## about committing
Regular small commits make for the best workflow. Where the line goes is a little
bit experience, but often it is no more than 5 affected files, no more than 50-60
lines affected. For a professional, 1-4 hours, for a beginner more.
Commits should be grouped around topics. Ideally (but not always) a commit takes the
whole project back to green (all tests working). But this is not always possible
and should not keep you from making commits. Commit when you have made some kind
of milestone, some small but cohesive change.
Usually beginners tend to make to large commits, but just to mention that there is also
a lower limit. Technical a single line may be a commit, but it would have to be a very,
possibly very very important line. Ie a critical fix, a version update know to break
things.
Usually i don't commit changes under 10 lines. If they happen, i band them together
with the next commit, possibly mention them in the (then multi-line) commit message.
About commit messages, they should describe the change in passive mode, as if the
commit made the changes. Ie "Fixes bug 36" , or "Adds method XXX to YY"
## pull request
A pull request is you asking the project owner (or anyone with commit rights) to
accept your work and merge it into the main (master) branch.
For small issues and especially when it has been discussed, this is a press of a button
for the project owner. But for larger changes, he/she may want to pull the
branch to their machine, look at it and consider.
If there are changes to be made, more discussion may follow. This may result in
you having to make more changes and so the process continues. This is why topic
branches are so important, to keep this kind of back and forth out of the main
branch and maintain a working / clean master branch.
After a pull request has been accepted, you go back to the master branch, pull
changes, and start again with a new topic. And so life for the developer continues :-)

View File

@ -14,6 +14,41 @@ While ruby allows the omission of brackets even with arguments, i try to avoid t
of readability. There may be an exception for an assignment, a single call with a single arg. of readability. There may be an exception for an assignment, a single call with a single arg.
Brackets without arguments look funny though. Brackets without arguments look funny though.
### Method length
Methods should not be more than 10 lines long. It points to bad design if they are,
spaghetti code, lack of abstraction and delegation. This may seem extreme coming from
other languages, and i admit it took me some years to see the light, but now it's pretty
much that. Longer methods will have a very very hard time to get accepted in a pull
request.
### No of arguments
Methods taking over 4 arguments are dubious. Actually 4 is already borderline. If a
method actually needs that much info, it is most likely that a class should be
created to hold some of it.
### Class length and size
On class length i am not rigid, but too large is a definitely a thing. More than 5-6
instance variables probably means the class is doing too much and should be split.
Also a total loc of more than 200-250 or method count over 20 is not a good sign.
Especially when combined with struct classes that just hold data and have too little
functionality, this may represent problems in pull request.
### Global and class variables
Global variables is one of the few design mistakes in ruby. They just should not exist,
meaning they should not be used.
Use class variables only if you are sure you understand their scoping, specifically the
difference between class variables and class instance variables. Lean towards
class instance variables.
Since classes (and thus modules) are global, class and module methods are global.
Use sparingly with good insight, as it ties the usage to the definition and
oo benefits like inheritance are lost.
## Code style ## Code style
### Module functions are global ### Module functions are global
@ -21,8 +56,8 @@ Brackets without arguments look funny though.
Often one thinks so much in classes that classes get what are basically global functions. Often one thinks so much in classes that classes get what are basically global functions.
Global functions are usually meant for a module, so module scope is fitting. Global functions are usually meant for a module, so module scope is fitting.
A perfect example are singleton accessors. These are often found clumsily on the classes but A perfect example are singleton accessors. These are often found clumsily on the classes
the code reads much nicer when they are on the module. but the code reads much nicer when they are on the module.
### Code generators ### Code generators
@ -31,3 +66,14 @@ All names are resolved to registers, or index via Type. More readable code less
As the example shows, in this case the module function name should be the instruction class name. As the example shows, in this case the module function name should be the instruction class name.
Singletons should hang off the module (not the class), eg Parfait.object_space Singletons should hang off the module (not the class), eg Parfait.object_space
## Naming
Naming must be one of the most important and difficult things in programming.
Spend some time to find good, descriptive names.
In the days of auto-complete, short cryptic names are not acceptable any more.
When naming, remember to name what something does (or is), not how. A classic misnomer
is the ruby Hash, which tells us how it is implemented (ie by hashing), but not it's
function. In Smalltalk this was called a Dictionary, which is tells us what it's for,
to look something up (with real-world reference, double points).

View File

@ -14,12 +14,12 @@ of the system, see below. The overhaul is done and rubyx produces working binari
Processing goes through layers: Ruby --> Sol --> SlotMachine --> Risc --> Arm --> binary . Processing goes through layers: Ruby --> Sol --> SlotMachine --> Risc --> Arm --> binary .
Currently most basic constructs work to some (usable) degree, ie if, while, Currently most basic constructs work to some usable degree, ie if, while,
assignment, ivars, calling and dynamic dispatch all work. Simple blocks, those assignment, ivars, calling and dynamic dispatch all work. Simple blocks, those
that ruby passes implicitly also work (lambdas not). that ruby passes implicitly also work (lambdas not).
Work continues on memory management, which turns out to be pretty basic to do just about Work continues on memory management, which turns out to be pretty basic
anything, even counting to a million. to do just about anything, even counting.
## Layers ## Layers
@ -83,26 +83,24 @@ Generating code (by descending above layers) is only half the story in an oo sys
The other half is classes, types, constant objects and a minimal run-time. This is The other half is classes, types, constant objects and a minimal run-time. This is
what is Parfait is. what is Parfait is.
Parfait has basic clases like string/array/hash, and also anything that is really needed Parfait has basic classes like string/array/hash, and also anything that is really needed
to express code, ie Class/Type/Method/Block. to express code, ie Class/Type/Method/Block.
Parfait is used at compile time, and the objects get serialised into the executable to Parfait is used at compile time, and the objects get serialised into the executable to
make up, or make up the executable, and are thus available at run time. Currently the make up, or make up the executable, and are thus available at run time. Currently the
methods are not parsed yet, so do not exist at runtime yet. methods are not parsed yet, so do not exist at runtime yet.
### Builtin ### Macros
There are a small number of methods that can not be coded in ruby. For example an There are a small number of methods that can not be coded in ruby. For example an
integer addition, or a instance variable access. These methods exists in any compiler, integer addition, or a instance variable access. These methods exists in any compiler,
and are called builtin here. and are called macros here.
Builtin methods are coded at the risc level with a dsl. Even though basically assembler, Macros are coded at the slot_machine level with a dsl. Even though basically assembler,
they are they are
([quite readable](https://github.com/ruby-x/rubyx/blob/2f07cc34f3f56c72d05c7d822f40fa6c15fd6a08/lib/risc/builtin/object.rb#L48)) ([quite readable](https://github.com/ruby-x/rubyx/blob/2f07cc34f3f56c72d05c7d822f40fa6c15fd6a08/lib/risc/builtin/object.rb#L48))
through the ruby magic. through the ruby magic.
The Macros are found in lib/slot_machine/macro .
I am in the process of converting builtin to a simple language on top of SlotMachine,
which i'm calling SlotLanguage. But this is wip.
## Types and classes, static vs dynamic ## Types and classes, static vs dynamic
@ -145,6 +143,7 @@ commands that have a linux baked in, qemu-arm in case of arm. So running
machine where qemu is installed with *qemu-arm ./hello* . machine where qemu is installed with *qemu-arm ./hello* .
On my fedora, the package to install is "qemu", quite possible on mac with homebew, too. On my fedora, the package to install is "qemu", quite possible on mac with homebew, too.
The web-page has some more [info](http://ruby-x.org/arm/qemu.html).
### Interpreter ### Interpreter
@ -161,7 +160,7 @@ out what is going on, and in finding bugs.
The above architecture is implemented. At the top level the RubyXCompiler works The above architecture is implemented. At the top level the RubyXCompiler works
pretty much as you'd expect, by falling down the layers. And when it get's pretty much as you'd expect, by falling down the layers. And when it get's
to the Risc layer it slots the builtin in there as if is were just normal code. to the Slot layer it slots the macros in there as if is were just normal code.
Specifically here is a list of what works: Specifically here is a list of what works:
- if (with or without else) - if (with or without else)
@ -175,7 +174,8 @@ Specifically here is a list of what works:
## Contributing to rubyx ## Contributing to rubyx
Probably best to talk to me, if it's not a typo or so. Probably best to talk to me, if it's not a typo or so. For beginners i have written a
[BeginnersGuide](./BeginnersGuide.md) to start from zero.
I've started to put some github issues out, some basic some not so. Also there is a todo I've started to put some github issues out, some basic some not so. Also there is a todo
for the adventurous (bigger things, no BIG things). for the adventurous (bigger things, no BIG things).