Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ProtoSchool #5

Open
nelsonic opened this issue Nov 22, 2018 · 14 comments
Open

ProtoSchool #5

nelsonic opened this issue Nov 22, 2018 · 14 comments
Assignees
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@nelsonic
Copy link
Member

https://proto.school

image

thanks to @alanshaw for sharing this!
image
It's Next on my "to learn" list. 🤓

@nelsonic nelsonic added enhancement New feature or request good first issue Good for newcomers labels Nov 22, 2018
@nelsonic
Copy link
Member Author

nelsonic commented Dec 5, 2018

ipfs.dag.put is used in these basic examples but "DAG" is never explained.
This is what you are looking for: https://github.com/ipfs/specs/tree/master/merkledag
that in turn points to: https://github.com/ipld/specs/
It's a bit of a "rabbit hole" ... a few ASCII diagrams but no real clarity or real-world examples. 😕

Part 1 - Basic Content Addressing

Let's get started:
image

https://proto.school/#/basics/01

image

https://proto.school/#/basics/02

image

https://proto.school/#/basics/03

image

Part 2 - Blog

image

https://proto.school/#/blog/01

Context:
image

Solution:
image

https://proto.school/#/blog/02

image

Exercise instructs learner to open Dev Tools:
image

Latest Google Chrome Browser. Thousands of errors. not very confidence inspiring ... 🙄
Mostly the same errors: Uncaught Error: already piped, failed: WebSocket opening handshake was canceled and Uncaught Error: first argument must be a buffer

I'm not "phased" by these errors, but a beginner definitely would be.

CIDs in dev tools console before making updates:
image

CIDs in dev tools console after adding the 'tags' array to each blog post:
image

OK, this is a curiosity thing to understand how the cid function works (before I go read the code...)
Question: does the CID depend on the order of the fields in the Object?
For example: at present the two blog posts are:

  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: {"/": samCid.toBaseEncodedString()},
    tags: ['outdoor', 'hobby']
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: {"/": natCid.toBaseEncodedString()},
    tags: ['hobby']
  })

And the corresponding CIDs are:

post about trees: zdpuAri55PR9iW239ahcbnfkFU2TVyD5iLmqEFmwY634KZAJV
post about computers: zdpuAqaHPSosSZFRPe7u5q3yNqgg4JuvrLaUJxGamNPLhWivX

What if we change the order of the keys and data to:

  const treePostCid = await ipfs.dag.put({
    author: {"/": samCid.toBaseEncodedString()},
    content: "trees",
    tags: ['hobby', 'outdoor']
  })
  const computerPostCid = await ipfs.dag.put({
    author: {"/": natCid.toBaseEncodedString()},
    content: "computers",
    tags: ['hobby']
  })

CIDs are identical if after re-ordering the fields and the "tags" in the first blog post. ✅

post about trees: zdpuB1fDHR9vZQfNT1knNBtbcSedwTC9n4smYskwoumWcXvu1
post about computers: zdpuAqaHPSosSZFRPe7u5q3yNqgg4JuvrLaUJxGamNPLhWivX

image

This is a good sign because the content hasn't changed, just the order of the key:value in the Object. 👍

https://proto.school/#/blog/03

Context:
image

This time the order is a deciding factor in the resulting CID ... 🙄

Exercise:
image

Solution:

  // Add your code here
  return [
    await ipfs.dag.put({
      tag: "hobby",
      posts: [
        {'/': treePostCid.toBaseEncodedString() },
        {'/': computerPostCid.toBaseEncodedString() }
      ]
    }),
    await ipfs.dag.put({
      tag: "outdoor",
      posts: [
        {'/': treePostCid.toBaseEncodedString() }
      ]
    })
  ]

Works:
image

https://proto.school/#/blog/04

The lesson in which the "DAG" acronym is finally expanded: DAG (Directed Acyclic Graph)

image

Exercise:
image

solution:

  // Add your code here
  const dogsPostCid = await ipfs.dag.put({
    content: "dogs",
    author: {"/": samCid.toBaseEncodedString()},
    tags: ["funny", "hobby"]
  })

  const hobbyTagCid = await ipfs.dag.put({
    tag: "hobby",
    posts: [
      {"/": treePostCid.toBaseEncodedString()},
      {"/": computerPostCid.toBaseEncodedString()},
      {"/": dogsPostCid.toBaseEncodedString()},
    ]
  })
  const funnyTagCid = await ipfs.dag.put({
    tag: "funny",
    posts: [
      {"/": dogsPostCid.toBaseEncodedString()}
    ]
  })

  return dogsPostCid;

image

https://proto.school/#/blog/05

Step 5: Add the code I added proactively above ...

image

Solution:

  const hobbyTagCid = await ipfs.dag.put({
    tag: "hobby",
    posts: [
      {"/": treePostCid.toBaseEncodedString()},
      {"/": computerPostCid.toBaseEncodedString()},
      {"/": dogPostCid.toBaseEncodedString()}
    ]
  })

  // Add your new code here and modify the tags above
    const funnyTagCid = await ipfs.dag.put({
    tag: "funny",
    posts: [
      {"/": dogPostCid.toBaseEncodedString()}
    ]
  })
  return [outdoorTagCid, hobbyTagCid, funnyTagCid]; // not clear *HOW* to return the 3 CIDs ...

image

https://proto.school/#/blog/06 - List posts chronologically with a chain of links

image

This exercise is pretty massive ...:
image

Fail: (I don't understand why the prev should point to a post written by a different author...?)
image

Solution:
image

https://proto.school/#/blog/07 - Traverse through all posts

image

Hit a "brick wall" trying to implement the traversePosts function:
image

Your function threw an error: TypeError: Cannot read property '/' of undefined.
image

This is basically Game Over.

Kept trying:
image

Calling it a day.

@nelsonic
Copy link
Member Author

nelsonic commented Dec 5, 2018

BEFORE: (trying too hard...)

// I added a second "list" parameter so I could write the function recursively ...
const traversePosts = async (cid, list = []) => {
  console.log('cid', cid)
  // Your code goes here
  list.push(new CID(cid.multihash));
  console.log(list);
  if(list.length === 3) { return list };
  let pcid, pCID;
  try {
    pcid = await ipfs.dag.get(cid);
    console.log('pcid', pcid)

    if(pcid && pcid.value && pcid.value.prev && pcid.value.prev['/']) {
      pCID = new CID((pcid).value.prev['/'])
      console.log('pCID', pCID)
      traversePosts(pCID, list);
    } else {
      console.log(list);
      console.log('return!!')
      return list;
    }

  } catch (e) {
    console.log('not a valid cid');
    console.log(list);
    console.log('return!!')
    return list;
  }
}

AFTER: using a while loop:
(against my better judgement... but inspired by: ProtoSchool/protoschool.github.io#68 )

const traversePosts = async (cid) => {
  let list = [];
  while (cid) {
    list.push(cid)
    const got = await ipfs.dag.get(cid)
    const prev = got.value.prev
    if (prev) {
      cid = new CID(prev['/'])
    } else {
      return list
    }
  }
}

image

Can't say that was a very beginner friendly experience ... 😕
Overall I still feel IPFS has potential ...
But I still have lots of questions!

@nelsonic
Copy link
Member Author

nelsonic commented Dec 5, 2018

Opened issue: ProtoSchool/protoschool.github.io#96 to inform creators of difficulty.

@nelsonic
Copy link
Member Author

nelsonic commented Dec 5, 2018

@alanshaw, where should I go next to continue my IPFS learning quest? 🤔

@alanshaw
Copy link
Member

alanshaw commented Dec 5, 2018

This is super good feedback for the protoschool team thank you for documenting ❤️

It's worth checking out the examples:

I can't remember if I told you about https://awesome.ipfs.io/

I have some fun videos you can watch:

@nelsonic
Copy link
Member Author

nelsonic commented Dec 5, 2018

@alanshaw thanks for the links and encouragement. 👍
Looks like I have this weekend's learning list/objective sorted. 🤓😉
I have a few practical questions regarding using IPFS for "real apps" 🤔❓
(further to our verbal discussion the other day...)
Where is the most effective place to post them? e.g: https://stackoverflow.com/questions/tagged/ipfs ?

Hope all is well in JailMake Land. ☀️
Still gutted we didn't get to see @olizilla 😞
Love to all! ❤️

@alanshaw
Copy link
Member

alanshaw commented Dec 5, 2018

We have a discussion place here https://discuss.ipfs.io/

We are on IRC #ipfs on freenode

@nelsonic
Copy link
Member Author

nelsonic commented Dec 5, 2018

@alanshaw thanks looks like I have a bit of reading to do ... https://discuss.ipfs.io/top 👍

@nelsonic nelsonic self-assigned this Dec 5, 2018
@nelsonic
Copy link
Member Author

nelsonic commented Dec 7, 2018

In light of @terichadbourne's comment on ProtoSchool/protoschool.github.io#96 (comment)
image

I'm going to go through the https://proto.school from scratch again with "shoshin" ... 🤓

@nelsonic
Copy link
Member Author

No change to home page: https://proto.school
image

https://proto.school/#/basics/01

image

image

https://proto.school/#/basics/02

image

First attempt: (faiulre)
image

I already knew how to link one item of content to another:

const run = async () => {
  let cid = await ipfs.dag.put({test: 1})
  return await ipfs.dag.put({ bar: {"/": cid } })
}

So I was able to "pass" this exercise:
image
But the following code:

return await ipfs.dag.put({ bar: cid })

Also works:
image

So we no longer need to have the {"/":cid} to link items! 🎉

https://proto.school/#/basics/03

image

Relevant line of code to make this exercise pass:

return ipfs.dag.get(cid2, '/bar/test')

image

... on to the next one ...

image

https://proto.school/#/blog/01

image

image

Solution:
image

The way of linking to related content is much better! 🎉

https://proto.school/#/blog/02

image

image

Solution:
image

https://proto.school/#/blog/03

image

image

Solution:

  // Add your code here
  const hobbyTags = await ipfs.dag.put({
    tag: "hobby",
    posts: [
      treePostCid,
      computerPostCid
    ]
  })
  const outdoorTags = await ipfs.dag.put({
    tag: "outdoor",
    posts: [
      treePostCid
    ]
  })
  return [hobbyTags, outdoorTags]

image

https://proto.school/#/blog/04

image

Solution:

  const dogPostCid = await ipfs.dag.put({
    content: "dogs",
    author: samCid,
    tags: ["funny", "hobby"]
  })

image

https://proto.school/#/blog/05

image

Solution:

  // Add your new code here and modify the tags above
  const funnyTagCid = await ipfs.dag.put({
    tag: "funny",
    posts: [ dogPostCid ]
  })

  return [funnyTagCid, hobbyTagCid, outdoorTagCid]

image

https://proto.school/#/blog/06

image

Pretty straightforward:

// Modify the blog posts below

  const treePostCid = await ipfs.dag.put({
    content: "trees",
    author: samCid,
    tags: ["outdoor", "hobby"]
  })
  const computerPostCid = await ipfs.dag.put({
    content: "computers",
    author: natCid,
    tags: ["hobby"],
    prev: treePostCid
  })
  const dogPostCid = await ipfs.dag.put({
    content: "dogs",
    author: samCid,
    tags: ["funny", "hobby"],
    prev: computerPostCid
  })

  const outdoorTagCid = await ipfs.dag.put({
    tag: "outdoor",
    posts: [ treePostCid ]
  })
  const hobbyTagCid = await ipfs.dag.put({
    tag: "hobby",
    posts: [ treePostCid, computerPostCid, dogPostCid ]
  })
  const funnyTagCid = await ipfs.dag.put({
    tag: "funny",
    posts: [ dogPostCid ]
  })
  return dogPostCid

image

https://proto.school/#/blog/07

image

Solution:

const traversePosts = async (cid) => {
  let list = [];
  while (cid) {
    list.push(cid);
    cid = (await ipfs.dag.get(cid)).value.prev
  }
  return list;
}

image

Second time round it was much easier.
I don't know if a complete beginner would "reach for" a while loop ...
But overall the way posts are linked is cleaner so I feel it's an improvement. 👍

@terichadbourne
Copy link

@nelsonic I'm glad you liked the new link API and found the instructions more clear this time!

A couple of questions out of curiosity if you have a sec:

  • Did you notice the "A perfect use case for a while loop!" in the top portion of the lesson this time, or did it not stand out? (I added it because I had the same concern originally. I actually think beginners reach for for loops before while loops.)
  • Did you notice anything new this time around about the UI on the homepage, where the lessons are listed?
  • Did you notice anything new about general functionality within the code editor, across all lessons?

@nelsonic
Copy link
Member Author

@terichadbourne I did not notice the while loop copy ... 🙄 (pebkac...)
image

It's definitely there, I just didn't see it. Other beginners will. ✅
I don't know how many will automatically figure how to put the while(cid) but
it's "enough" of a hint. 👍

The UI on the home page displays a "checkmark" whenever a lesson is complete:
image
Nice touch. 😉

The code editor seems really slick! noticed auto-saving, syntax checking and error notification.
Great implementation. Is this a custom-built ("from scratch") editor? or are you using a 3rd party open source package? 💭

Thanks again!

@terichadbourne
Copy link

@nelsonic Glad you noticed the code caching and the status indicator about whether you've completed a lesson. There are npm packages called monaco-editor and vue-monaco-editor that are used to create that code editor, but we recently built out the caching functionality ourselves by combining it with localStorage.

@nelsonic
Copy link
Member Author

@terichadbourne nice work! 🎉

Note-to-self: https://microsoft.github.io/monaco-editor
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants