Problem and scope
Description
The apps of swapp process files. They do not choose them: the files come from the working context of the person, not from the tool she happens to be using. What carries them is a workspace, and a workspace does not fill itself.
The person has her files where she works. SPPAS runs where it is installed, which is her own machine or a server, and the two are not always the same one. Everything to be settled follows from that gap: how a file she holds gets to where an app reads it, how she says which ones are to be treated, and how what an app produced comes back to her.
An app asks for what it needs and treats what it receives, and it says for itself whether what it received is enough. What it asks for, and what the person gives, is the whole of the question.
Needs
The needs are those of the person. They name no technique: the means of satisfying them belong to the levels below.
- B1 — To have an app work on the checked files of the workspace, without checking them again in every app.
- B2 — To give files to SPPAS, and to check among them those an app is to treat.
- B5 — To have SPPAS read the files she gives it, whether or not it runs on her machine.
- B6 — To know that nothing of what was given is kept.
- B7 — To know what quantity of files SPPAS accepts.
- B8 — To know what size of file SPPAS accepts.
- B9 — To find what an app produced among her own files, ready for the next thing she does with them.
- B11 — To know which files SPPAS accepts.
- B12 — To get back the files which were produced, or where they are.
- B13 — To see which files were grouped together, and what they produced.
- B14 — To correct what one has fed, before giving it.
- B15 — To know where one stands against what is accepted, while feeding.
B5 is the need which holds the two situations together without naming either: where SPPAS runs on the machine of the person the file is already there and there is nothing to do; where it does not, the file has to get there — and the place it gets to is asked of a neighbour, which is all this domain knows of it.
B9 and B12 are two moments of one thing, and this domain serves both: what an app produced is added to the files which are known and checked among them, by this domain and never by the app, so that the next treatment finds it already designated; and it is reachable by the person wherever she reads it.
Scope
This document covers the provision of files to an app, and the return to the person of the files an app produced: where the files come from, what is handed over, when, and how what was produced is reached.
The two directions are one design and not two. A file is in place and the workspace says where it is, or it has to travel and it stands in a place a neighbour gave, bounded and perishable, which the person reaches at an address. An app says what it has produced and says when it has finished, and the delivery holds to those two.
What is not covered: the workspaces, whose functioning is established and which belong to their own domain; the place where a file stands when it had to travel — what names it, how long it lasts, who may reach it — which is an API of its own with a dossier of its own; and what an app does with the files it receives, and whether they suffice it.
Modelling
Data dictionary
Six things are handled, and they are all that is handled. The person and the apps are not among them: they are actors, and they belong to the model of communication. The words are those of the SPPAS code, and no others — save one, which the code does not carry yet, and which is said where it stands.
- D1. The file — an object stored on a machine, identified by its name where it stands. A workspace retains its name, not its content: the content is read at the moment of the treatment. What is manipulated here is its name and its size.
-
D2. The state — one single value, carried by every file of a
workspace and taken from
States(): MISSING, UNUSED, CHECKED or LOCKED, and these four only. - D3. Checked — the CHECKED value of the state. It alone says that a file is to be treated.
- D4. The workspace — the set of the files which are known, held on three levels — the path, the root, the file — each one carrying its state, together with the references. It is what carries the set to be treated, and what is handed to an app is made from it. One is active at a time.
- D5. The copy — a duplicate of a file, made where the app works, because the original is not there. It is a file in the sense of D1, and it stands in a place the deposit API gave: bounded and perishable, on that domain's terms and not on ours. A file an app produced is not a copy: it is an original, and it perishes because it stands there too.
- D6. The deposit — the copies given at one time. It exists while it is fed, and it knows the place the deposit API gave it once it is given. It is what a total volume is counted on, and what tells two copies of one name apart. This is the word the code does not carry yet.
Conceptual model of communication
The domain studied does two things: it gives an app the files it is to treat, and it gives the person back what that app produced. Nothing else. Four actors border it, two of which are neighbours it calls. The interfaces through which the person acts are not actors: they are what this document designs — the one where she feeds what she gives, and the one where she reaches what was made.
Actors
- A1. The person — she gives her files, says which of them are to be treated, asks for an app, and gets back what was produced.
- A2. An app — it asks for what it needs in order to work, judges whether what it received suffices it, and produces files.
- A3. The domain of the workspaces — the neighbouring system which holds the files that are known and their states.
- A4. The deposit API — an API, and no face: it gives a bounded and perishable place where a file may stand when it is not on the machine of the person, says what it accepts, gives an address at which one of them is reached, and forgets what is out of date without being asked.
Flows
- F1. A1 → domain — her files, and which of them are to be treated (B2, B5).
- F2. A2 → domain — the request for the files it is to treat (B1).
- F3. domain → A1 — what is accepted, before anything is given, and that nothing is kept (B6, B7, B8, B11).
- F4. domain → A3 — the files to be known, their checking, and the states this domain sets on them (B2).
- F5. A3 → domain — the workspace and the states of its files (B1).
- F6. domain → A2 — a workspace holding the files to be treated, and them only (B1).
- F7. A2 → domain — what it has produced, in the workspace it was given, as often as it has something to give back (B12).
- F8. A2 → domain — the treatment is over.
- F9. domain → A3 — the files produced, added and checked (B9).
- F10. domain → A1 — the files produced, reached where they are or at an address, and what was grouped with what (B12, B13).
- F11. domain → A1 — what was not taken in, and why; and where she stands against what is accepted (B14, B15).
- F12. domain → A4 — the request for a place, the files to put there, and the request for an address.
- F13. A4 → domain — what it accepts, the place it gives or its refusal with when to come back, and the address at which a file is reached.
- F14. A2 → domain — the request for files, when what it received does not suffice it.
It is the domain which writes into the workspace — what it was given to make known, and what an app produced, on the word of that app (F7, F9). The app never writes there itself, for it never holds it. RO9
The deposit API has no face, and that is what makes the two interfaces this domain's. A place knows neither workspace, nor root, nor app: it holds bytes and forgets them. What the person is shown — what may be given, what was refused and why, which produced file goes with which given one — is knowledge of this domain, so the containers where she reads it are of this domain too.
Conceptual model of data
Four classes. The workspace is one of them without being modelled here: its functioning is established, and it belongs to the domain of the workspaces. It appears with its identifier and no property. What it holds — the three levels, the states, the references — is read where it is written, and this document adds nothing to it.
The classes of entities
| Class | Properties | What it is |
|---|---|---|
| FILE | # machine, # name, size | A file in place, where it is (D1). A file an app produced is one of them: it stands beside the file it was made from, under the same root, and it perishes with the deposit which holds them both when that deposit is what it stands in |
| COPY | # deposit, # name, size | A duplicate made where the app works, because the original is not there (D5). It exists only inside its deposit, and is identified relatively to it |
| DEPOSIT | # deposit, place | The copies given at one time. It exists while it is fed, and it holds the place the deposit API gave it once it is given |
| WORKSPACE | # workspace | The files which are known and their states (D4). One is active at a time, and it is the only one this domain sees |
A copy is in its deposit from the moment the file is taken in, and before the deposit is given it carries a name and a size and no content: that is what the verifications of T08 are made on. The dossier has no word for a file designated and not yet duplicated, and none is invented here: it is the word which is still to be fixed.
The relations
| No. | Verb | Leg 1 | Leg 2 |
|---|---|---|---|
| R1 | belongs to | COPY (1,1) | DEPOSIT (1,n) |
| R3 | is known to | FILE (0,1) | WORKSPACE (0,n) |
| R4 | is added to | DEPOSIT (1,1) | WORKSPACE (0,1) |
R1 is an aggregation: a copy is named inside the deposit which carries it, and two deposits name a copy the same way without naming the same copy. It is also what identifies a copy — its name inside its deposit — the first rule below making sure that two of them never share one.
A copy is known to a workspace as well, and that is not a relation: it follows from R1 then R4, a copy being known to the workspace its deposit was added to. Written as a relation it would repeat what the keys already say.
R4 is the case where the files have to be brought, and nothing else. Where they are already reachable nothing is added to a workspace, whether it pre-existed or T02 made it; where they are brought, a deposit is added to the workspace T02 makes, with the names of the copies. One deposit and one only: a deposit carries the moment it was made at, so a second deposit is another deposit, standing elsewhere, and the workspace which takes the name of what holds the copies is another workspace.
FILE and COPY carry the same verb towards the workspace, and that is what is not written here: a copy is a file which perishes, D5 saying so in as many words, and the two ought to be one class and its specialisation. They are written as two classes for want of it.
Computed, and never held
- The volume of a deposit, which is the sum of the sizes of its copies, and which is compared to what the deposit API accepts (C4).
- That a file is reachable: it is, when it is in place, or when it is a copy (T01).
- The address at which a produced file is reached, which follows from the file and lives as long as it does (T05).
- What is handed to an app, which is made from the workspace when an app asks and is never kept (T03).
What the keys do not hold
- Two copies of one deposit never bear the same name: a file whose name is already taken is not deposited, and what was refused is said (F10). C12
- A copy bears the name of the file it duplicates: a deposit renames nothing, the workspace being made with the names which were deposited.
- The copies of one deposit stay within what the deposit API accepts, which that domain says and this one relays (C4).
- Only a deposit is added to a workspace: what is delivered to the person is added to none.
What is not modelled, and why
- The state and checked (D2, D3), which the workspace carries at its three levels. This domain asks for the checking (T02) and reads it (T03); it does not hold it.
- The bounds and the duration, which belong to the deposit API; and the extensions, which are SPPAS's (C4, C10).
- What names a place and what authorises reaching it, which are the deposit API's and are never read here.
- What was not deposited, and why (F10): said to the person, and not kept (B6).
- The apps, which are actors (A2): an app asks this domain for what it needs and treats what it receives, so nothing of them is held here.
Conceptual model of treatments
Eleven treatments, and they are all that the domain does. They say what is done, on what, and on which event — not when, not where, not by whom, which belongs to the organisational level. Nothing here says which case one is in: the conceptual model is the same in all of them, and that is what makes them one design and not three.
The chain runs thus: an app asks, and either it receives the workspace or there is none and files are asked for; the person is told what she may give, she composes what she gives and gives it, the files are made reachable and made known, and the app is answered. When it has finished, what it produced is made known and made reachable by the person. What was made only to be handed over does not last, and it is the deposit API which sees to that.
The events
| No. | Event | Kind | Comes from |
|---|---|---|---|
| E1 | An app asks for the files it is to treat | external | An app (A2) |
| E2 | An app asks for files | external | An app (A2) |
| E3 | The person gives what she has composed, and says which of them are to be treated | external | F1 |
| E4 | An app gives back what it has produced | external | F8 |
| E5 | There is no workspace | internal | T03 |
| E6 | The files given are reachable | internal | T01 |
| E7 | The workspace is ready | internal | T02 |
| E8 | Files have been produced | internal | T04 |
| E10 | The person designates a file, to be given | external | F1 |
| E11 | The person takes back a file she designated | external | F1 |
| E12 | An app takes a file it was given, to work on it | external | An app (A2) |
| E13 | An app gives a file back | external | An app (A2) |
| E14 | An app has finished treating | external | F12 |
Deleting what is out of date is no treatment of this domain, and no event of it either: the deposit API empties itself, nobody asking it to. What this domain has to know is that a place does not last.
T01 — Make a file reachable
Purpose: that a file given by the person exists where an app will read it.
| What | Says |
|---|---|
| Synchronisation | E3 |
| Actions | Make reachable, where an app will read it, every file of what is given which is not; verify its type on its bytes |
| Result | One copy for every file which was not reachable. When its type is accepted |
| Result | What was not deposited, and why (F10). When a type is refused |
| Result | E6, the files given are reachable. When at least one of them is |
| Result | That nothing can be deposited now, and when to come back (F10). When the deposit API refuses a place — and nothing of what was given is deposited |
What is verified here is what needs the content: the type of a file, read on its bytes and not on its name, an executable or a script not being deposited. The name, the size and the volume were verified when the file was taken in, on what was known of it before anything travelled. T08
T02 — Make the files known, and check those to be treated
Purpose: that the workspace knows the files, and that those to be treated are checked in it.
| What | Says |
|---|---|
| Synchronisation | E6 |
| Actions | Make a workspace when none exists; make it know the files which are reachable; check those the person said are to be treated |
| Result | The files to be known, and their checking (F4). Always |
| Result | E7, the workspace is ready. Always |
It examines no content.
Making a workspace when none exists belongs here and nowhere else. A deposit does not make one: it makes files reachable, which is another thing, and there are files to be made known which never went through a deposit — those a person picks on the disk of the machine where SPPAS runs, when nothing is installed to manage workspaces for her. Tying the making to the deposit would leave that case with no workspace at all, and it is the case of whoever has only a browser.
T03 — Hand to an app the files it is to treat
Purpose: to give an app what it needs in order to work.
| What | Says |
|---|---|
| Synchronisation | E1 OR E7 |
| Actions | Read the workspace; make a workspace holding the files to be treated and them only; hand it to the app which asked |
| Result | A workspace holding the files to be treated (F6). When a workspace exists |
| Result | E5, there is no workspace. When none exists |
What is handed is a workspace made for the app, holding the files to be treated and nothing else — possibly nothing at all. The one the person composed stays where it is: an app never holds it, so it cannot touch what it was not given, and « an app does not check the files it treats » stops being a rule to respect and becomes a thing it cannot do. RO9
What is handed may hold nothing. An app reads what may be empty and says itself what it needs: the domain cannot say it in its place, knowing neither how many files an app wants nor of which kind.
T04 — Add the produced files to the workspace
Purpose: that the files produced by an app are known to the workspace and checked.
| What | Says |
|---|---|
| Synchronisation | E4 |
| Actions | Take from what the app gives back the files it produced, write them into the workspace with the grouping they carry, and check them |
| Result | The files produced, added and checked (F7). Always |
| Result | E8, files have been produced. When the app produced any |
Adding them does not uncheck what was treated. The app never wrote in the workspace of the person: it never held it. RO9
An app gives back as often as it has something to give back, and nothing obliges it to wait until it has finished: a design which forbade that would forbid what no need asks to forbid, and the person would wait for her first result until the last one was made.
The app gives back the workspace it was given, enriched with what it produced. Grouping files — a path, a root, a name — is the workspace's own work, and the domain does not redo it in its place: it takes what came back and writes it where it belongs. It is also what lets the person see, at the delivery, which files were grouped together and what they produced.
T05 — Make the produced files reachable by the person
Purpose: that the person gets back what was produced without knowing where it was written.
| What | Says |
|---|---|
| Synchronisation | E8 |
| Actions | Make every produced file reachable by the person, where an app wrote it: beside the file it was made from |
| Result | The produced files (F9). When the person reaches them where they are |
| Result | An address at which every produced file is reached (F9). When she cannot reach it where it is |
What is handed over is an address and not a file: the copy the person ends up with is made by what fetches it, and this domain knows nothing of it, which is what B6 asks. The address lives as long as the file it names.
T07 — Announce what is accepted
Purpose: that the person knows what she may give, before she gives.
| What | Says |
|---|---|
| Synchronisation | E2 OR E5 |
| Actions | Say the bounds, the extensions which are accepted, and that nothing of what is given is kept |
| Result | The announcement (F3). Always |
| Result | That nothing can be deposited now, and when to come back (F3). When the deposit API says it has no place |
The announcement precedes any deposit, and it depends on no file.
Neither the bounds nor the hour to come back are decided here: they are asked of the deposit API and said as they were given. What is of this domain is that the person is told before she gives, and not after.
T08 — Take a file into what is to be given
Purpose: that what the person is about to give is known to be acceptable before anything travels.
| What | Says |
|---|---|
| Synchronisation | E10 |
| Actions | Read the name and the size of the file designated; verify that the name is not already taken, that the size does not exceed what the machine accepts, and that the volume of what is to be given stays within its bound; take it in |
| Result | The file is in what is to be given, and the volume it now makes. When the three verifications pass |
| Result | What was not taken in, and why (F10). When one of them fails |
Nothing of the content is read here. A name and a size are known before anything travels, and they are enough for these three verifications; what needs the content is T01's. It is also why the person is told at the moment she adds a file, and not once everything has travelled.
What came with a refused file may fall in the root of the one which stays, and nothing shows it: the domain cannot tell them apart, the folder the person took them from not travelling with them. What groups the files is read at the delivery, where the associations are seen.
T09 — Take a file back out of what is to be given
Purpose: that the person can correct what she is about to give, before she gives it.
| What | Says |
|---|---|
| Synchronisation | E11 |
| Actions | Take it out of what is to be given |
| Result | What is to be given, without it, and the volume it now makes. Always |
Nothing of the file had travelled when it was taken in, so taking it back undoes the taking in and nothing more. RO8
T10 — Lock a file for the app which takes it
Purpose: that a file an app is working on is known to be in use, and is not given to another.
| What | Says |
|---|---|
| Synchronisation | E12 |
| Actions | Pass the file from checked to locked, in the workspace |
| Result | The file is locked (F4). Always |
Nothing more is needed to keep a file from being given twice. A state has one single value (D2), so a locked file is no longer a checked one, and what is handed to an app holds the files to be treated — that is, the checked ones. The exclusion is in the state, not in a rule.
An app takes and gives back as it works: one file at a time for whoever reads a content and produces a result, a file held for as long as it is open for whoever edits one. The domain does not choose between the two; it marks what the app says it is doing.
T11 — Give a file back
Purpose: that a file an app has done with is available again.
| What | Says |
|---|---|
| Synchronisation | E13 |
| Actions | Pass the file from locked to checked, in the workspace |
| Result | The file is free (F4). Always |
A file given back one by one is what an app does as it works. What it still holds when it has finished is released by T12.
T12 — Release what an app still holds
Purpose: that nothing stays locked for an app which has finished.
| What | Says |
|---|---|
| Synchronisation | E14 |
| Actions | Release every file the app still holds |
| Result | Those files are free (F4). Always |
An app which gave everything back one by one leaves nothing to release, and this treatment does nothing. It is what makes an app which stops halfway harmless all the same, as far as the locks go.
Organisational level
Organisational model of treatments
One procedure per treatment, numbered as it is, and each one triggered by one event. What decides which procedures have anything to do is not where the software happens to be installed, but two questions, and they are independent: are the files already reachable, and does a workspace exist.
That makes three cases and not two. The files are in place and a workspace is there; the files are in place and there is none; the files are not in place. The fourth — files to be brought, and a workspace already there — is not a case: a deposit carries its own moment, so it stands in a folder of its own and makes a workspace of its own, and it behaves as the third.
The first two cases share every operator: what separates them is that a workspace has to be made, which T02 does when it finds none. They are one table. The third is the other.
When the files are already reachable
| PF | What it does | Triggered by | In charge | Where | When | Nature |
|---|---|---|---|---|---|---|
| PF1 (T01) | Makes a file reachable | E3 | — | — | never | none |
| PF2 (T02) | Makes the files known, and checks those to be treated | E6 | the short path, or what manages the workspaces | the machine where SPPAS runs, which is hers | when the person asks | conversational |
| PF3 (T03) | Hands to an app the files it is to treat | E1 or E7 | the domain | the same machine | at every request of an app | automated |
| PF4 (T04) | Writes the produced files into the workspace | E4 | the domain, on the word of the app | the same machine | each time an app gives something back | automated |
| PF5 (T05) | Makes the produced files reachable by the person | E8 | — | — | never | none |
| PF7 (T07) | Announces what is accepted | E2 or E5 | — | — | never | none |
| PF8 (T08) | Takes a file into what is to be given | E10 | the short path, or what manages the workspaces | the same machine | when the person designates a file | conversational |
| PF9 (T09) | Takes a file back out | E11 | the same | the same machine | when the person takes one back | conversational |
| PF10 (T10) | Locks a file for the app which takes it | E12 | the domain, on the word of the app | the same machine | each time an app takes a file | automated |
| PF11 (T11) | Gives a file back | E13 | the domain, on the word of the app | the same machine | each time an app gives one back | automated |
| PF12 (T12) | Releases what an app still holds | E14 | the domain, on the word of the app | the same machine | when an app has finished | automated |
PF1 has nothing to do because a file the person points at is already where SPPAS reads it; PF5 because the workspace says where the produced files are; PF7 because the announcement exists only where there is a refusal, and nothing is refused here. Three procedures, two modules.
When there is no workspace, the only difference is in PF2, which makes one. That is the case of a person who has on her machine a browser and nothing else, and it is served by the short path alone.
When the files are not reachable
| PF | What it does | Triggered by | In charge | Where | When | Nature |
|---|---|---|---|---|---|---|
| PF1 (T01) | Makes a file reachable | E3 | the interface of deposit, and the server | the server | when the person gives | automated |
| PF2 (T02) | Makes the files known, and checks those to be treated | E6 | the server | the server | as soon as PF1 is done | automated |
| PF3 (T03) | Hands to an app the files it is to treat | E1 or E7 | the domain | the server | at every request of an app | automated |
| PF4 (T04) | Writes the produced files into the workspace | E4 | the domain, on the word of the app | the server | each time an app gives something back | automated |
| PF5 (T05) | Makes the produced files reachable by the person | E8 | the interface of delivery | the server, then the machine of the person | each time files have been produced, then when she follows an address | automated, then conversational |
| PF7 (T07) | Announces what is accepted | E2 or E5 | the interface of deposit | the machine of the person | before she gives anything | automated |
| PF8 (T08) | Takes a file into what is to be given | E10 | the domain, on the request of the person | the browser of the person, then the server | when the person designates a file | conversational |
| PF9 (T09) | Takes a file back out | E11 | the domain, on the request of the person | the browser of the person, then the server | when she takes one back | conversational |
| PF10 (T10) | Locks a file for the app which takes it | E12 | the domain, on the word of the app | the server | each time an app takes a file | automated |
| PF11 (T11) | Gives a file back | E13 | the domain, on the word of the app | the server | each time an app gives one back | automated |
| PF12 (T12) | Releases what an app still holds | E14 | the domain, on the word of the app | the server | when an app has finished | automated |
What the two tables say
PF3, PF4, PF10, PF11 and PF12 are the same procedure in both, word for word: everything an app asks of this domain is indifferent to where the files came from. PF2 is the same work with two operators and two natures. What differs is the whole of what a deposit brings with it.
PF8 and PF9 are the only procedures which stand in two places. What the person handles is in her browser — the button, the file, its name and its size — and what decides is on the server, SPPAS being alone in knowing what it reads. What travels to be verified is a name and a size; the content stays where it is until she gives. RO8
PF8 and PF9 are already served, in the first table, by page_files
of the wx interface, which will one day become app_wkps. What that
page does is not modelled here: the code exists, and it is handled. The short
path does the poor version of it, which is what it is for.
The resources differ for one procedure only, PF1: where files have to be brought it works on the contents which travelled and on the bounds; where they are in place there is nothing to bring.
No procedure refuses anything before an app is entered, and none appears in either table for that: an app which cannot work with what it received asks for files, and that is PF7 and PF8, not a refusal at the door. RO3
When files are asked for
A person clicks on an app. The app is entered, and it asks the domain for the files it is to treat. Two questions follow, and they do not belong to the same one.
The first is the domain's: is there a workspace? There is none as long as nothing has made one — remotely before any deposit, and on the machine of the person as long as nothing has been installed to manage workspaces for her. The domain then asks the person for her files — having first said what it accepts — and answers the app with the files it asked for.
The second is the app's: is what it received enough? A workspace may be there with nothing checked in it, or with files which are not the ones that app needs. The domain cannot answer that question in its place, knowing neither how many files an app wants nor of which kind. So the app says it, and asks for files.
In both cases what the person is shown is an interface of the domain: the short path locally, the interface of deposit remotely. She is not taken away from the app she asked for — where that interface is shown, beside the app or inside its page, is settled below the organisational level and changes nothing here.
An app must not check the files it treats. Asking for files is not checking them: the interface which asks belongs to the domain, and it is the domain which writes into the workspace, wherever that interface is shown.
The short path
Locally, T02 has two operators, and they do not merge. The short path adds a few files and checks them, nothing more. What manages the workspaces will come beside it, not over it.
The poverty of the short path is not a stage to be passed: it is a strength. Whoever has one file to treat does not want to find herself in a complete interface for managing workspaces and references. The axis is therefore not the deployment but what the person intends: one file to treat now, or a corpus to organise. The occasional use exists locally too, and the short path is it.
The short path also makes the local use possible for whoever has not installed wxpython: without it, T02 has no operator locally, and an app which asks for files asks nobody — the person learns that files are missing and has no way of adding any. It is also the short path which makes the workspace in that case, T02 making one when none exists.
Where the short path is shown — beside the apps, or inside the one which asked for files — changes nothing of what it is. The interface belongs to the domain, and it is the domain which checks.
Locally, the short path browses the disk on the side of the server, which it may, the server running on the machine of the person. The field of a browser does not give a path, it gives a content to upload — and a local file has no need of a copy (T01). That, and not the deployment, is the reason why the two interfaces are two.
Rules of organisation
- RO1 — The checking is done by the domain, and never by an app which treats files: in the short path, or in what manages the workspaces.
- RO2 — Remotely, everything which is deposited is checked: one does not deposit in order to keep, one deposits in order to have it treated.
- RO3 — An app says for itself whether what it received is enough, and asks for files when it is not. The domain judges nothing in its place.
- RO4 — Remotely, the deposit and the answer to the app are one single request: what carries the files is what hands the workspace over.
- RO5 — The deletion of the copies which are out of date is done by the server at every request, nobody having asked for it.
- RO6 — Two questions decide what there is to do, and they are independent: whether the files are already reachable, and whether a workspace exists. The first is answered by the interface the person gives through — the short path gives paths, the interface of deposit gives contents; the second is answered by looking.
- RO7 — An interface of the domain requires no place of its own, and does not require the person to leave what she is doing. Where it is shown belongs to whoever assembles the software, and changes nothing of whose it is.
- RO8 — Remotely, the contents travel at the moment the person gives, and not before: nothing of what she composed is kept on the server until then. What travels while she feeds is a name and a size, which is what it takes to accept or refuse a file. In how many goes the contents travel, and under what wrapping, is not of this level.
- RO9 — No app which treats files receives the workspace of the person: what it receives is made for it, and holds the files it is to treat and nothing else. What manages the workspaces is not one of them — it belongs to that domain, and holds what is its own.
Constraints
What the code holds to
These follow from no need on their own: they are what the code has to hold to in order to serve the needs. They say nothing of the means, which belong to the decisions.
What imposes them is not one thing but four, and the difference matters, a constraint being revised where it comes from: the needs of the person; the model itself, a treatment, a relation or a rule of organisation; the neighbouring domain which gives the place; and whoever runs SPPAS on the machine, who will not have anything written there.
The deposit API is an actor, and it exchanges: it says what it accepts. The last is not one and has not to be — he exchanges nothing, he imposes; he becomes an actor the day what is accepted is said in a setting instead of being written in the code.
B7 and B8 are named nowhere below, and that is not an oversight: they are needs to know what quantity and what size are accepted, and the announcement serves them (T07, F3). A need to know is never what imposes a bound. The same holds of B11, which C10 answers for the announcing, and not for the refusing.
| No. | Constraint | Imposed by |
|---|---|---|
| C4 | What is deposited stays within what the deposit API accepts — a size, a volume, a number of places, a lifetime. None of it is fixed here: it is asked of that domain and relayed to the person. | A4 |
| C5 | The choice of the files gives paths where SPPAS runs on the machine of the person, and contents otherwise. It is what says whether a file has to be brought. | T01, and the two interfaces which offer the choice |
| C6 | No setting says which case one is in: whether a workspace exists is read, and whether the files are reachable follows from what the interface gives — a path or a content. | RO6, C5 |
| C7 | A deposit does not rename the files. | B12, and the workspace being made with the names which were deposited |
| C8 | Only the files whose extension SPPAS reads are deposited. | Whoever runs SPPAS on the machine |
| C9 | The type of a deposited file is verified on its bytes and not on its name: an executable or a script is not deposited. | Whoever runs SPPAS on the machine |
| C10 | The domain announces the extensions it accepts; what it does not accept is not deposited. | B11, C8, C9, F3 |
| C12 | A file whose name is already taken is not deposited: the first of the name stays, the others are refused. | The root: the workspace is made with the names which were deposited, and two files of one name would fall in one root |
| C14 | A file an app produced is a sibling of the one it was made from: same path, same root, the extension the person asked for. Remotely, that is the folder of the deposit. | The apps, every one of which writes there — the workspace giving the notion of sibling files, not the obligation |
Not one of these constraints carries a number, and none of the bounds of the place is written here any more. What they are worth is the deposit API's to say, and this domain's to relay before the person gives anything.
Logical level
The tables
Each class of entities becomes a table, and its identifier becomes its key.
| Table | Columns | Comes from |
|---|---|---|
| FILE | machine, name, size, workspace | The class FILE, and R3 |
| COPY | deposit, name, size | The class COPY, and R1 |
| DEPOSIT | deposit, moment, workspace | The class DEPOSIT, and R4 |
| WORKSPACE | workspace | The class WORKSPACE |
R1 is an aggregation: the aggregated class takes the key of the aggregating one, so a copy carries the name of its deposit, and the two together tell one copy from another. Two deposits carry a copy under one name without carrying the same copy.
R3 has its low cardinality on the side of FILE, which is (0,1): the table takes the key of WORKSPACE, and it may be empty — a file in place is known to the workspace, or to none. R4 has its own on the side of DEPOSIT, which is (1,1): the table takes it too, and it is never empty.
A copy holds no workspace of its own. It is known to the one its deposit was added to, which R1 and R4 already say: a column would repeat two keys and would have to be kept true.
WORKSPACE is a key and nothing else. The table exists so that the others may name it; what it holds is written elsewhere, in the domain which owns it.
Not in the tables: the volume of a deposit, whether a deposit is out of date, whether a file is reachable, the address at which a produced file is reached, and what is handed to an app. All five are computed, and none of them would stay true if it were held.
Physical level
Where each table stands
Here the machines are named, and not before. There is no database: the tables are borne by the disks where the files stand, by what runs between two requests, and by the domain of the workspaces.
| Table | Where it stands | While it runs | What the person sees |
|---|---|---|---|
| FILE | A file on the disk of the machine where it is | What the domain of the workspaces holds of it | Her file, where she put it |
| COPY | A file written in the place the API gave to its deposit | The same | Nothing: she sees the name she gave, never where it went |
| DEPOSIT | The place the API gave, holding its copies. It is asked for only at the moment the person gives | Before she gives, what is to be given is held where she stands; from the deposit on, the place and what it holds | Nothing of the place. While she feeds, the volume she has fed |
| WORKSPACE | What the domain of the workspaces writes. Remotely it takes the name of the folder which holds the copies, as a workspace of SPPAS takes the name of its own | Its object | The file manager, and what an app shows of it |
What is handed to an app stands nowhere: it is made when the app asks, and it is written down by nobody.
A deposit has two halves and only the second stands anywhere. While the person feeds it, what she has fed is held where she is, the volume is counted there, and nothing is written — RO8 says so, and nothing here may say otherwise. The place is asked of the API, and the copies written in it, at the moment she gives.
Where a place is, what names it, how long it lasts and when it is emptied are not written here. They belong to the API which gives it. This domain knows a place by what that API gave, and knows that it does not last.
Two files of one name, deposited twice, stand side by side without meeting, because two deposits are two places. Within one deposit they cannot meet, C12 seeing to it.
How the domain of the workspaces writes a workspace is not said here: it is its own, it is established, and this document reads it without naming what it holds.
Where the code goes
One module per kind of knowledge, and every procedure has one module and one only. What a module is alone in knowing is what says where a change will have to be made, and what can be tested without the rest.
| Module | What it does | Procedure |
|---|---|---|
| place | Asks the API for a place, puts the copies there, asks it for an address. The only one which calls it | PF1, PF5 |
| acceptance | Knows what SPPAS reads, and relays what the API accepts. It says both, and refuses | PF7, and what PF1 and PF8 ask of it |
| feeding | Holds what is to be given, feeds it, takes back from it, and counts the volume | PF8, PF9 |
| workspace | Makes files known and checks them, locks and releases, and writes what an app produced | PF2, PF4, PF10, PF11 |
| handing | Makes the workspace an app receives, and gives it | PF3 |
| delivery | Makes the address of a produced file, and serves it when it is followed | PF5 |
What each one promises, which is the reason for the cutting:
- The place module is the only one which calls the API, so it is the only one to read again the day that API changes.
- Acceptance decides nothing about what it has not been given: it answers on a name and on bytes, and relays what the API said of a size, a volume and a count. That is what makes it testable with no disk at all.
- Feeding is in two halves: the browser holds the file and knows its name and its size, the server says whether it is accepted. Nothing of the content crosses before the person gives, which is RO8 written as a module.
- The workspace module is the only one which speaks to the domain of the workspaces, so it is the only place to read again the day that domain changes.
- Handing is the only one which makes a workspace for an app, and that is where the door holds.
- The delivery is the only one which makes an address.
This domain is a service, not an app. Five of these modules speak only to apps: an app calls them, and there is neither a screen nor a person behind what they answer. Two face a person — where a deposit is fed, and where what was produced is fetched — and those two carry an interface.
An interface here is not an app, and not a page: it is a piece of page, a container an app places in its own. That is what RO7 says in the language of organisation — the domain requires no place of its own — and this is the same thing said in the language of the code.
Where the files are already reachable, three modules have nothing to do — the place, acceptance and the delivery. They carry exactly the three procedures the organisational model leaves empty there.
The architecture of the code
An app holds the page and receives the request: it is the only one which can, and there is no alternative. A task which belongs to this domain, it dispatches. What is behind that dispatch is this domain's own, and the app sees none of it.
What the app sees of this domain is one object — its manager — and what that object answers: the files it is to treat, whether an event was for it, and a tree to put in its page. It never holds the façade, never holds a deposit, never knows a place.
Three kinds of class, and what each may do
| Kind | What it does | What it may not do |
|---|---|---|
| A view | Builds an object — a tree — which whatever answers the request bakes. It is given what it shows | Decide anything, count anything, refuse anything, reach a disk or a neighbour, or write a string of its own |
| The controller | Reads the task the request carries, rebuilds a record from what the page transmits, calls the façade, and has a view populate its tree | Hold anything between two requests, build a tree, know a place or a workspace — and assemble anything: it is given what it uses, and building the objects of a domain is not the work of what reads a task |
| The model | The façade and its sub-models, which are the whole of chapter on the classes | Know that a page exists, or that anything is shown at all |
One controller for the two views. They never overlap in time — one deposits before, one fetches after — and a domain which holds no state between two requests would gain nothing from a second dispatch.
What assembles, and what an app holds
An app is assembled by its maker: it builds the fixed part of the page, then the view, then the controller, and it hands the controller the model and the view. This domain is not an app and has no page of its own, so it has no maker. It has an entry class — a manager — which does the same work for it: it builds the model, the two views and the controller, and it is the only thing an app holds of this domain.
That is the counterpart of the rule above. The controller assembles nothing because something else does, and the app holds no façade because it holds the manager instead. What is behind the manager is never named outside it.
How an app knows a task is ours
By asking, and by no convention of names. An app receives the events of a request and consumes what is its own; what it does not recognise, it offers to its services, and a service either consumes it or says it did not. What nobody consumed is an error, and the request is answered as such.
No prefix, no agreed vocabulary of event names between an app and its services: the manager answers whether the event was for it. An app which gains a second service adds one line and nothing else.
Which of the two views
The record says what is known, and the view follows from that and not from the task: what has been fed and not yet given is shown as a deposit; what an app has produced is shown as a delivery. It is the same mechanism as the pathway of an app which has several pages — the state of what is known chooses.
What a view owes the next request
A record serialises itself for transport and parses itself back. What a view builds therefore carries the serialised record with it, so that the next request brings it back. A view which omits it breaks the request which follows — the controller would rebuild an empty record, and a person would see her list vanish without having touched it.
The first request
There is no record. The controller makes one at its default values — nothing fed, no task, no place asked for — and what is shown is the announcement and an empty list. Of the model, only what is accepted is called.
A request which carries a task but no record is a first request as well. A record which did not come back is a record which was never made, and inventing one would show a person a state she never composed.
The record
What one request holds is an object, and it has a name: the record. It carries what the page transmitted — the names and the sizes fed so far, the task, what is to be shown — and it is rebuilt at every request from what came back with it.
That is what lets the two sides find their context again, and the alternative is to keep the state of a person on the machine between two requests — which is exactly what B6 refuses. A record which travels is not a convenience of the code: it is the promise that nothing of her is held.
A request, in order
- The app receives the request and reads the event it carries. It belongs to this domain, so it dispatches it.
- The controller starts from nothing and rebuilds its record from what the page transmitted: the names and the sizes, and no content.
- It reads the task — designate a file, take one back, give, ask for the files to treat, here is what I produced, I have finished — and checks what has to be true before it.
- It calls the façade, once. The façade calls what it has to, and answers.
- The controller puts in its record what is to be shown: a list, a volume, a refusal and its reason, an hour, addresses.
- The view populates its tree from that record.
- The app puts that tree in its page, where it chose, and bakes the whole.
Step 4 is the only one which reaches anything: a disk, a workspace, an API. Steps 2, 3, 5 and 6 run on what they were given, which is what makes them testable without a machine.
And the request which carries a content is the one which gives, and that one only. Every other request of this domain carries names, sizes and a task. RO8
UML
The classes
Those which carry the data come from the tables, one per table which needs one. Those which work come from the modules, one per module. A name says what the class handles — files, and the means by which they are exchanged — and nothing of how the application happens to be arranged.
What carries the data
| Class | From | What it is |
|---|---|---|
Deposit | DEPOSIT | What is to be given, then what was given: the files fed into it, and the place the API gave it |
DepositedFile | COPY | One file of a deposit: a name, a size, and a content which arrives only when the deposit is given |
FilesRecord | — | What one request holds: the task it carries, what has been fed so far, and what is to be shown. It serialises itself for transport and parses itself back, and it is held by nobody between two requests |
| none | FILE | A file in place is named by the domain of the workspaces, which has a class for it already |
| none | WORKSPACE | Its own domain's |
What does the work
| Class | Module | What it is alone in knowing |
|---|---|---|
FileProvision | — | The façade. It is what an app and what answers a request see, and neither of them knows what is behind it |
DepositAcceptance | acceptance | What may be deposited, and how many deposits the space takes. Reads nothing, writes nothing, knows no workspace |
FilePlace | place | How the deposit API is called: a place asked for, copies put there, an address obtained |
WorkspaceFiles | workspace | How the domain of the workspaces is spoken to |
AppExchange | handing | What an app receives, and what comes back from it |
ResultDelivery | delivery | How a produced file is reached by the person |
The feeding module has no class of its own: what it holds is a deposit being fed, rebuilt from what the page transmits at every request, and kept between none of them. It is the controller which rebuilds it.
What shows, and what dispatches
| Class | What it does |
|---|---|
DepositView | Builds the tree of what a person feeds: what is accepted, the button, the list, the volume against the bound, what gives |
DeliveryView | Builds the tree of what was produced: the files grouped by root, their addresses, the hour at which they go, and whether the app has finished |
FilesManager | Builds the model, the two views and the controller, and answers an app: the files it is to treat, whether an event was for this domain, and a tree to put in a page. It is the only object of this domain an app holds |
FilesController | Reads the task the app dispatched, rebuilds a record from what the page transmitted, calls the façade, and has a view populate its tree from that record |
A view builds a tree and does nothing else — it decides nothing, counts nothing, refuses nothing, and reaches neither a disk nor a neighbour. What it shows was decided before it was called.
The class diagram
/ marks what is derived and held by nobody. What the operations
promise is the chapter on the contracts; what they are called is a proposal,
and one pass renames them all.
| Class | Attributes | Operations |
|---|---|---|
Deposit | place, files, /volume | feed(), take_back(), volume() |
DepositedFile | name, size, content | — |
FileProvision | — | what_is_accepted(), feed(), take_back(), give(), files_for_app(), produced(), finished() |
DepositAcceptance | — | what_is_accepted(), accepts(), accepts_volume(), accepts_one_more_deposit(), accepts_content() |
FilePlace | — | what_is_accepted(), ask_for_a_place(), put(), address_of() |
WorkspaceFiles | — | make_workspace(), make_known(), check(), checked_files(), lock(), release(), write_produced() |
AppExchange | — | for_app(), back_from_app() |
ResultDelivery | — | address_of(), serve() |
FilesManager | — | files_for_app(), consumes(events), populate_view() |
FilesController | record | handle(data), populate_view() |
FilesRecord | task, fed, to_be_shown | serialize(), parse(data) |
DepositView | — | populate_tree_content(record) |
DeliveryView | — | populate_tree_content(record) |
Deposit.feed() adds and counts; it does not accept. Whether a
file may be fed in is DepositAcceptance's answer, and the façade
asks it first. A data class which decided what it may hold would hold the
rules as well as the data, and the rules would then be in two places.
What is tied to what
| Tie | Legs | What it is |
|---|---|---|
| holds | FileProvision 1 — 1 each of the five others | A composition: the façade makes them, and they go when it goes |
| holds | Deposit 1 — 1..n DepositedFile | A composition: a file of a deposit exists only inside it |
| uses | FilePlace → Deposit | A dependency: it writes them and forgets them, and keeps none |
| uses | AppExchange → WorkspaceFiles | A dependency: it asks for what is checked, and for the workspace it will hand over |
| uses | WorkspaceFiles → sppasWorkspace | A dependency, and the only tie of this domain to the neighbouring one |
| uses | ResultDelivery → FilePlace | A dependency: what an app produced is a sibling of what it read, so it stands in the folder of the deposit |
| holds | FilesManager 1 — 1 the façade, the two views, the controller | A composition: it builds them, and they go when it goes. It is what the rule « the controller assembles nothing » leans on |
| holds | FilesController 1 — 1 FilesRecord | A composition: one record per request, made by the controller and kept by nobody |
| uses | the two views → FilesRecord | A dependency: they are given it and build from it |
| uses | FilesController → FileProvision | A dependency: it calls the façade, once per request |
| uses | FilesController → the two views | A dependency: it hands them what to build from, and reads nothing back but HTML |
| none | DepositAcceptance | Tied to nothing at all: it answers on names and numbers handed to it |
| none | the two views | Tied to nothing: they are given a state and give back HTML |
AppExchange does not speak to the domain of the workspaces, and
that is deliberate: the promise that one class alone speaks to it would be
false the moment two did. It asks WorkspaceFiles for the files
which are checked and for a workspace holding them, and it holds the rule that
the one of the person never leaves.
One class holds a state, and it is Deposit. The others are given
what they work on and give back what they made. That is why nothing here has
to be invalidated when something changes upstream, and why each of them is
tested on its own.
In yUML
To be read at yuml.me, class diagram.
[FileProvision|what_is_accepted();feed();take_back();give();files_for_app();produced();finished()]
[FileProvision]++1-1>[DepositAcceptance|what_is_accepted();accepts();accepts_volume();accepts_one_more_deposit();accepts_content()]
[FileProvision]++1-1>[FilePlace|what_is_accepted();ask_for_a_place();put();address_of()]
[FileProvision]++1-1>[WorkspaceFiles|make_workspace();make_known();check();checked_files();lock();release();write_produced()]
[FileProvision]++1-1>[AppExchange|for_app();back_from_app()]
[FileProvision]++1-1>[ResultDelivery|address_of();serve()]
[Deposit|place;files;/volume|feed();take_back();volume()]++1-1..*>[DepositedFile|name;size;content]
[FilesManager|files_for_app();consumes();populate_view()]++1-1>[FileProvision]
[FilesManager]++1-1>[FilesController|handle();populate_view()]
[FilesManager]++1-1>[DepositView|populate_tree_content()]
[FilesManager]++1-1>[DeliveryView|populate_tree_content()]
[FilesController]++1-1>[FilesRecord|task;fed;to_be_shown|serialize();parse()]
[DepositView]-.->[FilesRecord]
[DeliveryView]-.->[FilesRecord]
[FilesController]-.->[FileProvision]
[FilePlace]-.->[Deposit]
[AppExchange]-.->[WorkspaceFiles]
[WorkspaceFiles]-.->[sppasWorkspace]
[ResultDelivery]-.->[FilePlace]
[sppasWorkspace]-[note:class of the neighbouring domain. Only WorkspaceFiles speaks to it]
[FilesController]-[note:called once per request. Holds nothing between two, and assembles nothing]
[FilesRecord]-[note:what one request holds. It travels with the page, which is what keeps nothing of a person on the machine]
[DepositView]-[note:builds a tree and nothing else. Decides nothing, counts nothing, refuses nothing]
[Deposit]-[note:volume is the sum of the sizes and is not held. place is what the API gave. content is absent until the person gives]
[ResultDelivery]-[note:a produced file is a sibling of the one it was made from. Same path, same root, so it stands in the folder of the deposit]
The states
| State | What is true |
|---|---|
| Fed | It holds names and sizes, it makes a volume, and it stands where the person stands. Nothing of it is on the server |
| Given | It holds the place the API gave, and its copies are written there |
| Gone | Its place did not last. The API emptied it, and nothing here was asked |
A deposit which is fed and never given leaves nothing: it was never anywhere but where the person was. That is why an abandoned deposit is not a case to be treated.
| State | What is true |
|---|---|
| Checked | It is to be treated, and it is in what is handed to an app which asks |
| Locked | An app has taken it. It is no longer checked, so it is in nothing that is handed |
The two other states belong to the domain of the workspaces, and this one neither reads nor writes them.
The sequence, when an app asks
- The app asks for the files it is to treat.
- A workspace exists: what is handed is made from it, holding the checked files and them only, and the app receives it. The sequence ends here.
- No workspace exists: what is accepted is said, and what is not — the space being full — is said as well, with when to come back.
- The person feeds what she is about to give, and is answered on each file as she adds it: the name, the size, the volume so far.
- She gives. The contents travel then, and not before.
- The types are verified on the bytes, the copies are written in the folder of the deposit, and what was refused is said.
- The files are made known to a workspace, which takes the name of that folder, and those to be treated are checked in it.
- The app is answered, as in step 2.
- It takes a file, which is locked; it gives it back, which unlocks it; as many times as it works.
- It gives back the workspace it was given, as often as it has something to give back: what it produced is written into the workspace of the person, and checked there.
- It says it has finished, and what it still held is released.
- What was produced is made reachable: it is already where the person reads it, or an address is made for each file.
Steps 3 to 7 happen only where the files have to be brought. Where they are already reachable the person feeds a workspace outside of any app, and step 2 is the whole of it.
The error policy
| Level | What happens | What is done |
|---|---|---|
| 1 | Nothing can be done: the deposit API gives no place | Nothing is deposited. The person is told, and told when to come back |
| 2 | One file is concerned: a name already taken, a size beyond what the machine accepts, a type refused on its bytes | That file is not deposited, the others are, and what was refused is said with its reason |
| 3 | Whoever runs the machine has to know: a folder which cannot be written, a workspace which cannot be made | Said where he reads, and the person is told that nothing could be deposited |
What is raised is caught by whatever answers a request, and by nothing below it. A person is never shown what a machine says to itself, and never left before a page which does nothing without a reason.
The contracts
How to read them
pre is what has to be true on the way in, and what the operation does not check; post is what the caller can count on without looking. The operations are named by what they do and not by a signature: a signature invented before the code is a name nobody will use, and the modules are named here as the level above named them.
What holds everywhere
- What is absent gives back an empty thing — an empty name, an empty list, a volume of zero — and never nothing at all.
- What is handed to an app shares nothing with the workspace of the person: no object, no file, no way back to it. Every other promise of this domain rests on that one.
- Only the workspace module speaks to the domain of the workspaces. No other class of this domain knows it exists.
- What is raised is caught by whatever answers a request. No module below it writes a catch.
Class by class
| Operation | Contract |
|---|---|
| Say what is accepted | pre: none. post: the bounds, the extensions which are read, and that nothing of what is given is kept. It depends on no file and on no deposit |
| Answer on a name | pre: none. post: refused when the name is already taken in what is being fed, or when the extension is not one SPPAS reads, and the reason is given with the refusal |
| Answer on a size, and on a volume | pre: a size and a volume of zero or more. post: refused beyond what the machine accepts, and beyond the volume of one deposit |
| Answer on a count of deposits | pre: none. post: what the deposit API answered, relayed as it was given, with the hour to come back |
| Answer on a content | pre: the bytes are those of the file. post: refused when what they say of the type is an executable or a script. The only operation of this class which needs a content |
This class reads no disk, writes nothing, and knows no workspace. Every rule of what is accepted is therefore checked without anything being installed, which is what makes it the first to be tested and the last to surprise.
| Operation | Contract |
|---|---|
| Feed a file in | pre: a name and a size. post: the file is in what is to be given, and the volume is that much greater — or nothing has changed and the refusal is said with its reason. Nothing of the file has travelled |
| Take a file back out | pre: none. post: it is no longer in what is to be given, and the volume is that much less. Taking back what is not there does nothing wrong |
| Give the volume | post: the sum of the sizes fed, zero when nothing was fed |
| Give what is to be given | post: the names and the sizes, in the order they were fed. May be empty |
This class holds nothing between two requests: what is to be given is rebuilt from what the page transmits, each time. It decides on the server, on a name and a size, the content staying where it is until the person gives. What she fed is lost if she goes away, and an abandoned deposit leaves nothing behind.
| Operation | Contract |
|---|---|
| Say what the API accepts | pre: none. post: a size, a volume, a number of places, as that API says them. Nothing is fixed here |
| Ask for a place | pre: none. post: a place, or a refusal with the hour at which there will be room. Neither is invented here |
| Put a copy in a place | pre: the place was given. post: the copy stands there under the name the person gave it |
| Ask for an address | pre: the file stands in a place. post: an address which leads to it and dies with it |
| Operation | Contract |
|---|---|
| Make what an app receives | pre: none. post: a workspace holding the files to be treated and them only, sharing nothing with the one of the person; empty when nothing is checked, and never nothing at all |
| Take back what an app gives | pre: what is given back was made by this class. post: the files the app added, and nothing of what it may have changed elsewhere |
« Sharing nothing » is the one promise a test has to hold on to: a change made in what an app received is never seen in the workspace of the person, whatever the app does with it.
| Operation | Contract |
|---|---|
| Make files known, and check those to be treated | pre: the files are reachable. post: every one of them is known, and those to be treated are checked. No content is read |
| Lock a file | pre: the file is known. post: it is locked, therefore no longer checked, therefore in nothing that is handed |
| Release a file | pre: none. post: it is checked again. Releasing what is not locked does nothing wrong |
| Write what an app produced | pre: the files come from what the app gave back. post: they are known and checked, and nothing which was checked before has been unchecked |
| Operation | Contract |
|---|---|
| Make the address of a produced file | pre: the file exists where the app wrote it. post: an address which leads to it, and which lives exactly as long as the file does |
| Serve what an address names | pre: none. post: the file, or nothing at all when it is out of date or when the address names none. Nothing else of the machine is ever reached through an address |
The last clause is not a nicety: an address the domain makes is followed by whoever holds it, and what it can reach is what the domain is answerable for.
| Operation | Contract |
|---|---|
| Be built | pre: a model and a view are given to it. post: a record with its default values, nothing read and nothing called |
| Handle what the page sent | pre: none — what carries no task of this domain gives the record back to its default values. post: the record holds what the page transmitted, the façade has been called at most once, and nothing is held after it answered |
| Rebuild what is fed | pre: none. post: the record holds exactly the names and the sizes the page transmitted, in the order they were fed; empty when it transmitted nothing. No content, ever |
| Populate the view | pre: what the page sent has been handled. post: the view has built its tree from the record, and the controller has changed nothing meanwhile |
It never raises. What goes wrong is put in the record and written where whoever runs the machine reads it — a refusal with its reason, an hour to come back — because a person is never left before a page which does nothing without a reason. That is what the controllers of the apps already do, and this one does not invent another way.
| Operation | Contract |
|---|---|
| Be built | pre: none. post: the model, the two views and the controller exist and are tied; nothing has been read, called or shown |
| Answer whether an event was for this domain | pre: none. post: true when it was consumed, false when it was not — and nothing is changed in that second case. It is never an error here: what nobody consumed is the app's to answer |
| Give an app the files it is to treat | pre: none. post: what the façade answers, handed on untouched |
| Populate a view | pre: an event was consumed, or it is a first request. post: the tree is built from the record |
| Operation | Contract |
|---|---|
| Serialise itself | pre: none. post: what a page can carry and a next request bring back, holding names, sizes, a task and what is to be shown — and no content, ever |
| Parse what came back | pre: none. post: the record holds what was transmitted; what was not transmitted takes its default value, and what is not understood is ignored rather than guessed |
| Be made with nothing | pre: none. post: no task, nothing fed, nothing to show — which is a first request |
A record parses what came back and never trusts it further than that: it is a page which sends it, and a page is not a place this domain holds. What is not understood is dropped, and the person sees a state she can still correct.
That shape holds wherever the app runs. One of the apps it was read from is served on a machine and nowhere else; the other is served both ways. Their controllers are written the same, which says that this one has no reason to differ either.
| Operation | Contract |
|---|---|
| Populate the tree of a deposit | pre: the record comes from the controller. post: what is accepted, what has been fed, the volume against the bound, every refusal with its reason, and what gives — and nothing the record did not say |
| Populate it when no deposit can be made | pre: the record says there is no place. post: no control which gives is built at all. Not one which is built and disabled: one which is not there |
| Populate the tree of a delivery | pre: the record comes from the controller. post: the produced files grouped as the record groups them, one address for each, the hour at which they go, and whether the app has finished |
| Populate it with nothing in it | pre: the record holds no produced file. post: the tree of nothing yet, and never an empty one |
| Carry the record back | pre: none. post: what is built holds the serialised record, so that the next request brings it back. A tree without it breaks the request which follows |
A view builds a tree, which is baked into HTML by whatever answers the request. It is not given a page to write into and it writes no string of its own: that is the shape the apps already have.
Three promises hold for both, and they are what a test holds on to. A view is called with everything it needs and asks for nothing. The same record gives the same tree — no clock read, no order which shifts. And a view never writes what it was not given: no path, no place, no name of a folder, nothing of the machine. What the person may see was chosen before the view was called.
What is tested, and where
Without a disk
On a machine where nothing is installed: no place, no API, no workspace, no server, no person.
| No. | What is checked | What it holds |
|---|---|---|
| TE1 | What is accepted is said before anything is given, and depends on no file and on no deposit | B7, B8 |
| TE2 | A name already taken in what is being fed is refused, and the reason is given with the refusal | C12 |
| TE3 | An extension SPPAS does not read is refused, with its reason | C10 |
| TE4 | A size beyond what the machine accepts is refused; the size one under it passes | C4 |
| TE5 | A volume beyond that of one deposit is refused; the volume one under it passes | C4 |
| TE6 | A count beyond the number of deposits is refused, and the refusal says when to come back | C4, relayed and not invented |
| TE7 | A handful of bytes which say an executable or a script is refused. The only check which needs a content | T01 |
| TE8 | A file fed in raises the volume by its size | T08 |
| TE9 | A file taken back lowers it, and taking back what was never fed does nothing wrong | T09 |
| TE10 | What is to be given comes back in the order it was fed | T08 |
| TE11 | Nothing of a content travels while the person feeds: what is held is a name and a size | RO8 |
| TE12 | A state handed to a view gives a tree which holds what that state said and nothing more: no refusal it invented, no total it counted | D1 |
| TE13 | A state which says nothing gives a tree which says nothing | D1 |
| TE14 | What is handed to an app holds the checked files and them only | B1, RO9 |
| TE15 | Everything in what was handed is changed, emptied and added to — and the workspace of the person has not moved | RO9 |
TE1 to TE7 are the whole of what acceptance does. It holds every rule of what is accepted and reads nothing, so all of them are checked with no place and no API at all. Each refusal gives its reason, and the refusal on a count gives when to come back.
TE11 is RO8 written as a test. A test which found a file written on a server before the person gave would be a test which found that rule broken.
TE12 and TE13 catch a view which decided something. A view which counted a total or invented a refusal is caught by a state which says nothing at all.
TE15 is the one test the whole design rests on. A door which is not tested is a consigne.
With a disk
| No. | What is checked | What it holds |
|---|---|---|
| TE16 | A place is asked of the deposit API and obtained; a copy is put there under the name it was given; an address leads to it | T01, T05 |
| TE17 | A refusal of that API is relayed as it was given, with its hour, and nothing of it is invented here | F13, D2 |
| TE18 | An address reaches its file, and nothing else of the machine | B13 |
| TE19 | Nothing at all when the file is out of date, and when the address names none | B13 |
TE16 and TE17 are the only tests which need that API, the place module being the only module which calls it.
With the domain of the workspaces
| No. | What is checked | What it holds |
|---|---|---|
| TE20 | Locking a file makes it no longer checked, so it is absent from what is handed next: checked by handing twice around a lock | T10 |
| TE21 | Releasing it puts it back among what is handed | T11, T12 |
| TE22 | Writing what an app produced unchecks nothing of what was checked before | T04 |
The workspace module is the only one which needs that domain to run, and these three are the only tests which do.
What no test covers, and where they stand
- What an app does with what it received: it is the app's, and this domain is answerable only for what it handed and for what came back.
- How the domain of the workspaces writes a workspace: it is established, and it has its own tests or it has not.
- The page which feeds a workspace in the wx interface: it exists, it is in production, and it is handled.
TE1 to TE15 are the ones to write first. They need nothing to run, and they hold the whole of what was decided: what is accepted, what is counted, and the door. The seven others need a disk or a neighbour, and they check that what was decided was also done.
They stand beside the code, in the folder of this service.
The decisions of the tool
What is decided here
The bounds of a place and how long it lasts are not decided here: they are the deposit API's, and its dossier holds them with the reason for each. What this domain decides of the tool is what follows.
D1. No business logic in the view. What says whether a file is accepted is SPPAS, which alone knows what it reads, and the deposit API, which alone knows what it takes. Deciding it in the page would put half the rules in one language and half in the other, and would have to be written twice the day one of them changes.
D2. One module calls the deposit API, and one only. The day that API changes, there is one file to read again. It is the same reason which keeps the domain of the workspaces behind a single module.
Decided elsewhere
Two decisions of the tool are written where they are read, and are named here so that this chapter is the place one looks: a workspace takes the name of the place which holds the copies, said where each table stands; and the bounds, the duration, what names a place and when it is emptied, which are the deposit API's and are written in its dossier.
What was set aside
Considered, and decided against
These are not missing. Each was written, weighed, and left out for the reason beside it — which is what keeps the question from being reopened in six months, and answered the other way for want of the reason.
| What | Why |
|---|---|
| Sending the contents as the person feeds, rather than when she gives | A composition which takes an hour would expire under the person making it, and be deleted by the request of somebody else. A deposit cannot begin to age before it exists |
| Refusing a whole deposit because two of its files bear one name | The domain cannot see how files group in any case, the folder they were taken from not travelling with them. Refusing everything would cost two hundred files for one collision, and would not buy what it was meant to buy |
| Refusing to enter an app, before it is entered, for want of files | Only an app knows what it needs — one file, a sound, two of them. A launcher can ask whether anything is checked and nothing more, which never relieves the app of the case. It doubles a responsibility instead of taking one |
| Handing an app the workspace of the person | A rule an app is asked to respect is not a door. What is handed is made for it, so what it can damage is its own |
| Offering an app a list of files or a workspace, whichever suits it | Two contracts to hold for one need, two ways of giving back, and no gain: the apps already speak the workspace, and those which work by root need what a list does not carry |
| Deciding in the page whether a file is accepted | The rules would live half in one language and half in the other, and would be written twice the day one of them changes. What is read online is the exception, and the logic has no reason to emigrate for it |
| Waiting for an app to have finished before giving back what it produced | A design which forbade giving back as one goes would forbid what no need asks to forbid, and the person would wait for the last result to see the first |
| Making this domain the gate through which anything touching a workspace must pass | A gate one can walk around is not a gate: nothing obliges an app to call it. What makes the door hold is what is handed, not a rule — and each writes what it is responsible for |
Left open
These are neither decided nor dropped. They are known, and they wait.
- One word is not settled: the one for a file designated and not yet duplicated. What is given at one time is written deposit throughout, and that one is settled.
Annexes
Annex: Legal notices
- Author: Brigitte Bigi
- Document License: GNU Free Documentation License (GFDL) 1.3
- Copyright (C) 2026 Brigitte Bigi, CNRS
- Creation Date: 2026-09-11
- Last update: 2026-09-13