Developers, let's discuss v4 developments here!

Hello to all v4 developers :slight_smile: :waving_hand:

First of all, a big thank you for your involvement in v4. It’s so cool to see so many developers interested in this version, and we’re making huge progress thanks to you, bravo :clap:

I wanted to create a topic to discuss developments in general about v4. Think of this as a « general Â» channel for devs!

I’m starting with a first post to talk about the development process, but you can talk about anything and everything on this channel, that’s what it’s for.

@AlexTrovato @joeypic @link39 @Pti_Nico @billona @VonOx @Reno @bertrandda

Let’s talk about the development process

I’ve reviewed a lot of PRs recently, and I wanted to make a post to talk about the little things I’ve seen that keep coming up, so that we’re all on the same page :slight_smile:

I warn you: I will mainly talk about the frontend, and I know, you are more like developers in love with technology, backend (like me!). For us, often the backend is the most important: I want to change that :smiley:

For the user, Gladys is the frontend, the backend is a detail. Yes, it’s hard to make a good backend, but making a good frontend is even harder!

Note: In my developments for Gladys 4, some pieces of code that I wrote do not respect what I say here, because my thinking has evolved between the beginning of development more than a year ago, and now. I am trying to continuously improve the code to respect all this :slight_smile:

1. The development process

For me, in v4, the UI/UX of services must be the most important part of your development. Generally, when I develop in v4 now, I start first with the front end to start from what I want visually, and then I go to the technology, the backend.

The backend must be developed to meet the needs of the UI, and not the other way around!

Think about the user flow!

2. Empty states

When a user arrives on an integration, they must immediately understand what to do. They must understand why the integration is in this state, and what to do to remedy it.

Example, on the home page, by default the user can see:

  • A nice icon prevents the screen from being « empty Â»
  • The first sentence tells him why this screen is empty: his dashboard is not configured.
  • The second sentence tells him what to do: he must click on the « edit Â» button to configure his integration

Another example, the « message Â» page, the default state displays a nice icon to fill in + a message indicating how to start:

All integrations must be like this, the user must arrive on the page and know:

  • The state of the integration: Is it configured? Why is it empty?
  • What to do to move forward: Does he have to press 3 seconds on the back of his device? Does he need to configure an API key? Or does he need to find it?

The UI of the integration must be self-sufficient, the user must be able to configure the integration without going on the internet or on the forum.

For additional information, it is possible to put a link to the documentation: but only to have additional information, this should not replace the basics of the empty state + what to do.

3. « Loading Â» states

If you perform actions and the UI is waiting for something, the user must know that something is going on.

Sending a message in progress…

Loading the image of a camera..

To test all this, I advise you to put your browser in « Slow 3G Â» to test the application with a lot of loading states:

4. Error handling

When the user performs an action in the UI, they go through different states:

  • The request goes to the backend
  • The front end waits (loading state), then:
    • The front end receives a positive response: everything went well
    • The front end receives an error code + an error message

The front end must handle all the errors that the backend sends, and each error from the backend must have a translation in the UI.

Errors must follow the same rules as « empty states Â»: an explanation of what is happening + a clear action on how to solve the problem.

Example on the weather box:

The error specifies 1) what is happening, « the darksky service is not configured Â» 2) the steps to follow to configure it, « he must go to the integrations tab, etc… Â»

Conclusion

It’s hard to make a good frontend! :smiley: But what a reward, to see that users then get by without having to read 10 posts on the forum, and browse 10 docs…

I make calls with community members every day right now, and they are all excited about the simplicity of v4 compared to v3 where some spent entire weekends just to find a piece of information that could have been on the service configuration page… ^^

Thank you all for your work :folded_hands:

I’ll take this opportunity to follow up on the response to a PR I just made to @bertrandda regarding error handling.

In your code, I recommend throwing errors defined in the utils/coreErrors.js or utils/httpErrors files, with a clear error code that should be mapped to a translation in the UI.

Example of clean error handling on the backend:

const { BRIDGE_NOT_FOUND } = require('../utils/constants');

async function configureBridge(serialNumber) {
  const bridge = this.bridgesBySerialNumber.get(serialNumber);
  if (!bridge) {
    throw new NotFoundError(BRIDGE_NOT_FOUND);
  }
  // then, do the rest
}

In case of an error:

  • a native error is emitted, with a specific error code
  • in the error middleware, this error is converted to a 404 error with the error code as the message
  • in the UI, the developer can easily identify the problem and display an error from the translations! :slight_smile:

I need help :smiley:

I have this error

Invariant Violation: address should be an string or undefined
    at invariant (/home/vonox/Repository/GladysFork/server/services/onkyo/node_modules/invariant/invariant.js:40:15)
    at Onkyo.validate (/home/vonox/Repository/GladysFork/server/services/onkyo/node_modules/onkyo.js/lib/Onkyo.js:90:5)
    at new Onkyo (/home/vonox/Repository/GladysFork/server/services/onkyo/node_modules/onkyo.js/lib/Onkyo.js:48:10)
    at Object.OnkyoService [as onkyo] (/home/vonox/Repository/GladysFork/server/services/onkyo/index.js:9:25)
    at /home/vonox/Repository/GladysFork/server/lib/service/service.load.js:37:65
    at async Promise.all (index 4)
    at async Service.load (/home/vonox/Repository/GladysFork/server/lib/service/service.load.js:14:3)
    at async Object.start (/home/vonox/Repository/GladysFork/server/lib/index.js:103:9)
    at async /home/vonox/Repository/GladysFork/server/index.js:18:3 {
  framesToPop: 1
}

I think I understand but I don’t know how to fix it.

Apparently, it’s because the library I’m using has the same name as the service (onkyo)

module.exports = function OnkyoService(gladys, serviceId) {
    const { Onkyo } = require('onkyo.js');
    const { OnkyoDiscover } = require('onkyo.js');
    const discover = new OnkyoDiscover();
    const onkyoClient = new Onkyo();
    const onkyoAvrHandler = new OnkyoAvrHandler(gladys, onkyoClient, discover, serviceId);

Am I right or am I on the wrong track?

Use VSCode + Eslint + Prettier (Installed as a module in the IDE), you will immediately see the error in the IDE :slight_smile:

It’s already the case

It’s in the green, but for my service to launch, I need to remove line 7

I went to check the module you’re using:

Indeed, the address is missing from your constructor:

const onkyo = Onkyo({address: '192.168.0.100'});

OK, I didn’t think it through, I can’t do the « import Â» there.

But the error message didn’t make any sense to me :sweat_smile:

In any case, this proves that gladys starts even with a faulty service :+1: