How fast is your app, really? Alexandre Moureaux joins Jamon, Robin, and Mazen to talk about Flashlight, a tool for scoring mobile performance and spotting bottlenecks in production. If you care about React Native performance, this one's for you.
Show Notes
Connect With Us!
This episode is brought to you by Infinite Red!
Infinite Red is an expert React Native consultancy located in the USA. With nearly a decade of React Native experience and deep roots in the React Native community (hosts of Chain React and the React Native Newsletter, core React Native contributors, creators of Ignite and Reactotron, and much, much more), Infinite Red is the best choice for helping you build and deploy your next React Native app.
Todd Werth:
Welcome back to React Native Radio Podcast, brought to you by Little red down arrows.com, the leading supplier for financial reporting. Episode 3 28, flashlight.
Jamon Holmgren:
Hey everyone. Jamon here with Robin Ann Mazen, as usual, and our guest today, Alexander Mazen. You nailed his pronunciation. The pronunciation of his name earlier. Can you give it another go?
Mazen Chami:
Yeah. So welcome to the show, Alexandre Moureaux.
Jamon Holmgren:
Wow, how good was that?
Mazen Chami:
Yeah, that was really good. Nice job, Mazen. Thank you. My mom is French educated, so I have a little bit of bias there.
Jamon Holmgren:
I keep learning things about you, Mazen, that it's just like you could tell me anything and I just would not be surprised at all.
Mazen Chami:
French is one of my languages that I am conversational in. I'll put it that way. Not fluent. I
Robin Heinze:
Don't know why I didn't know that.
Mazen Chami:
There is a fourth, I don't know why this is turning into a language class, but there is a fourth language I speak to, let me guess. Lemme guess. Hold up. So English, Arabic, fluent French, conversational
Robin Heinze:
Nigerian.
Mazen Chami:
It's a dialect in Nigeria. Yeah,
Jamon Holmgren:
Yeah. There must be a dialect of that, right? So, okay. I wouldn't be able to begin to guess.
Mazen Chami:
It's called Haa.
Jamon Holmgren:
Haa.
Robin Heinze:
Okay.
Mazen Chami:
It's a language in the northern part of Nigeria. It's very close to Arabic. It has a lot of similarities. Oh really? Yeah. Well,
Robin Heinze:
I think we can all agree that MAs is better than us.
Mazen Chami:
Yeah. Yeah.
Jamon Holmgren:
Overachiever here. I just like languages. Yeah. It just reflects kind of your whole international background.
Robin Heinze:
He's obviously very humble about it because I didn't know.
Jamon Holmgren:
Yeah, this is true.
Robin Heinze:
Yeah, he doesn't brag about it. So,
Jamon Holmgren:
Alexander, are you French then?
Robin Heinze:
Yes, I am
Jamon Holmgren:
Born
Alexandre Moureaux:
And raised.
Robin Heinze:
Are you in France at the moment? Is that
Alexandre Moureaux:
What I see? Yes. I am based in Paris where we have sunny weather, hopefully coming spring. I love Paris. Me too.
Jamon Holmgren:
Yeah. That's actually where my business partners, Todd and Ken and Gantt all got together with me to decide to do our merger. Way back 10 years ago. It was in Paris, we called it the,
Robin Heinze:
Isn't it Red?
Jamon Holmgren:
Paris
Robin Heinze:
Was born in Paris in a kitchen. Oh
Jamon Holmgren:
Wow. Yeah, we call it
Robin Heinze:
Very hot kitchen peace
Jamon Holmgren:
Talks. I, which is had no idea.
Robin Heinze:
It was during a heat wave, right?
Jamon Holmgren:
Oh yeah. It was like 102, which is, I don't remember what it is in Celsius. Whatever ish.
Speaker 6:
Yeah.
Jamon Holmgren:
40. It was probably about 40. Yeah.
Alexandre Moureaux:
And Paris is really not good for the heat wave.
Jamon Holmgren:
Yeah, no AC to be found anywhere. I just remember sweating on the metro. It was horrible. Okay, so let's really quickly do the sponsor thing. Our sponsor today is Infinite Red. We are a premier React native consultancy located fully remote in the us. We have a team of 30 senior level React native developers and support staff, and have been doing this for just about a decade now. Going all the way back to those Paris Peace talks when we decided to not only merge our companies, but also start doing React native. Hit us up Infinite Red slash radio and let us know that you came, that you heard about us through the React Native Radio podcast. Alright, Alexander, I'm really looking forward to this. We are going to be talking about flashlight, which is honestly, we need to invest more time learning this tool because I think that it has, I, it's one of the things in your performance benchmarking suite that you should have on hand all the time. It's something that should always be in your checklist, something you're running all the time as a React native developer. That's my opinion. But I do want to ask you, Alexander, what's your tech background? How'd you get into React Native, that sort of thing.
Alexandre Moureaux:
Tech background. So funny story, I think I was pretty bored in high school and started to program on a calculator. So I asked on a forum a while back, how do you do this? But on a computer and someone replied, well, by learning how to program basically, which I of course did not understand at the time, but someone pointed me out to a website that French people will probably know, which was called Lucid Zero at the time, which basically made you learn programming from Xero and yeah, I fell in love with doing my first field world in c plus plus. That was pretty awesome.
Robin Heinze:
It reminds me of Code Academy.
Alexandre Moureaux:
Yeah, it's pretty much the same thing now. It's called Open Classrooms. Actually. They made a really good job expanding and I think a lot of French developers owe their careers probably to that website, myself included.
Jamon Holmgren:
Wow. Yeah. I always have this question for folks who did learn another language first, other than English, because it seems like the vast majority of programming is in English. Did you already know English pretty well before you started programming or was that kind of a transition to be like, okay, this isn't my native language. I need to not only learn to program, but I also have a bunch of keywords that are in English now.
Alexandre Moureaux:
So interestingly, that website had courses in French,
Jamon Holmgren:
But what about the programming languages themselves? They were in English, I'm sure, right? Or are there actually French programming language?
Alexandre Moureaux:
Yeah, but I mean if four and well, yeah,
Jamon Holmgren:
Those are forward the only kind of vocabulary you need right
Speaker 6:
Forward. So
Alexandre Moureaux:
That was
Jamon Holmgren:
Easy. That's fair. The words are necessarily simple and easy to learn, I suppose. Yeah, that makes a lot of sense. Alright, well please continue.
Alexandre Moureaux:
Yeah, but to be fair, I think all of my variables at the time were written in French. That's interesting. But yeah, then I went to engineering school, still was kind of doubling with computer science and stuff like that on the side. And in 2015 I joined a company called BAM, and at the time the company wanted to develop mobile apps and already doing cross-platform mobile apps, but at the time we were doing Ionic, so it was Cordova, so embedding your web view as, sorry, your website as a web view in your app. And in October, 2015, react native Android came out and we were like, oh, we should try this out. So that was really early and that was super fun. I'm sure you guys actually can remember that Android was missing probably a lot of features. Installing a native module was taking us half a day basically because of all the static linking and stuff like that. That drag and dropping stuff in Xcode that at the time I did not understand Then. Yeah, I've been developing apps in React native ever since. But a while ago I tried to focus my expertise on performance mainly because I had a project. So I think in 2020 when I was trying to measure performance, I was basically counting renders in my apps.
Like, okay,
Robin Heinze:
Yeah, console log rendered. Yeah. It's like, oh, I have, you're like, how many? Yeah, it's
Alexandre Moureaux:
Like I have fewer renders, it's probably better. It turns out that that was actually not the case quite often. So I would add memo and memo stuff and realize that there was not a lot of impact. So I think it was in 2021, late 2021, I was working on an app and we really wanted to basically spend the day with all the team improving performance of the home feed of the app. And I wanted to have a way to really know that what we were doing was improving things. I wanted to have a scientific way to measure and to prove that what I was doing, what we were doing was really had an impact on performance. So we were adding maybe memorization somewhere and really making sure that in production our app would actually be faster.
Mazen Chami:
That's a big highlight there in production. I think a lot of times we get stuck in the trying to optimize our development app and we forget, development leaves a lot of, for lack of a better term, a lot of trash behind and it's leaving a lot of traces of stuff. You might even have console logs that are still rendering in dev that's going to affect your dev profile. So you need to,
Robin Heinze:
Console logs are amazingly expensive.
Mazen Chami:
Yeah, you don't realize it. It's crazy. So always profile in production. Absolutely.
Alexandre Moureaux:
And actually on low end devices, react also has a lot of checks, a lot of checks here and there to just verify and prompt you display some warnings to you if some things go wrong and a low end devices, it tends to actually take a lot of power just to do that. So usually React actually has much better performance in production than in dev mode, which is actually nice.
Jamon Holmgren:
Yeah, totally. Yeah. Well actually there is a part of me though that is like I'm fine benchmarking in dev mode. If I can get it feeling good and working well in dev mode, I know it's going to work great in production generally. I mean obviously there can be production only bugs, but I will sometimes do that on purpose, but I just know that it's not representative of the actual performance. I'm just trying to find spots I can shave. It's sort of running it on an old older device as an example, or a lower power device. I'm building a game, I'm not building in React native. I wish I was, it'd be fun, but it's in Gadot, which is an actual game engine and I am making the game work well on my Mac on a 5K display, which is not easy. That's a lot of pixels to push for a Mac that's not really designed for gaming. So if it works well on there, I know it's going to work well on Windows machines, on gamer machines, et cetera.
Mazen Chami:
So I kind of want to go back and shift a little bit to the two talks that you gave that we've listened to that we'll put in the show notes, your React native EU talk, I believe that was in 2022. And then your app JS talk from 23. So for for our listeners, I quick TLDR on them and the first one at React native vu, you don't talk about flashlight specifically. You mentioned many other ways to profile. At the time you were using Flipper, you had Flipper plugin, you showed off the Android profiler and then fast forward to 23 at FJS where you basically introduced to the world flashlight, something you all had been working on at bam. That's a lot of different tools and there's a lot of different things to reach for there. What flow would you recommend for developers? Because if a client comes up to me and says, Hey, I want to be able to analyze or even just test my app, profile the speed, or how good is my app going to be in production? What flow would you recommend for developers to follow?
Alexandre Moureaux:
Yeah, that's a good question. So the easiest thing to do is not even a really scientific thing to do is to try the app on a low-end device because as developers I think we tend to have high-end phones usually because I mean, it's our job, we tend to phones and so we want to get the best.
Robin Heinze:
We get annoyed by slow phones and so yeah, we want the latest,
Mazen Chami:
I mean it works on the iPhone at 16, so why would it not work on the iPhone? I don't max, it doesn't make any sense. It's cross platforms. It could, right, exactly. And
Jamon Holmgren:
Then just blame JavaScript when it's slow
Alexandre Moureaux:
And the reality of the markets, at least in France and a lot of Europe and the world, I know that it can be a bit different in the US and also in the uk. But in France for example, we still have two thirds of Android market share, something like that. And the most sold devices include high-end Android phones, but also Samsung tend to be really successful with their a hundred euros range, like something they release them every year and every year they get sold a lot because well, they're cheap and they look kind of nice, but obviously they're not as powerful as the iPhone 16. And so yeah, just making sure, I mean just testing the app on the low end device usually is a good way to see how the app feels for some of your users basically.
Robin Heinze:
So it's kind of a qualitative, your first step should be a qualitative test, just how does it feel on a slow device?
Alexandre Moureaux:
I think. So also it's really easy to do. I actually had a client at some point, they had performance issues. They started to realize they had performance issues because they had slowness, but they were actually testing on iPhone 13 something, which was one of the best iPhones at the time. Needless to say, on the mid wrench Android, the app was barely usable. So it was just a lot of fun to help them out to fix those issues.
Robin Heinze:
Oh yeah, I'm sure there was a lot of low hanging fruit there. Oh
Alexandre Moureaux:
Yeah. But what they did is they actually bought a low-end phone for everyone in the company, and the next time I came to work with them, they were really excited and happy showing, oh, we all have our phones and the app actually works really well on their phones. And it was a simple step, but actually that was easier enough to put them in the right direction. That's
Robin Heinze:
Right. It's amazing how simple humans are and sometimes the easiest way to improve performance is to just cause yourself pain. Make yourself yourself, use it.
Jamon Holmgren:
I love
Robin Heinze:
It on a slow device and you will naturally make it faster because
Jamon Holmgren:
It's painful. I a hundred percent agree. It's painful to work on big time. I was curious about the US market and I thought that iPhone would have a commanding market presence here. It's actually only 57% with 43% Android, so we still have a ton of Androids in the us. I think that demographics tend to show that the iPhone users tend to be the ones who they're just more profitable long-term for app developers and whatnot, so they do still focus on them.
Robin Heinze:
I'd be curious what the stats are for React native developers specifically.
Jamon Holmgren:
That's a really
Robin Heinze:
Good question. I bet it's a much higher percentage. So
Jamon Holmgren:
We kind
Robin Heinze:
Skew I remember that on the
Jamon Holmgren:
Survey. Yeah, the React native survey, which we just did an episode about. Alright, so Alexander, I do want to explain because some people will be like, okay, so you've been talking about flashlight for a while, but they're listening as they're working out or doing something, they don't have time to go actually look it up. flashlight.dev, by the way, if you want to go look at the website, but it is both a CLI and a website and a web app basically. And under the hood you're using Maestro for running a basic test. I actually really liked how on the website you basically just drag and drop the a PK on there and then you can specify just a string that's supposed to show up once it's all loaded. And that to me was a really cool little workflow because obviously that's not enough for a complex app, but just to get started, you just build a little maestro testing flow, which looks for that string and then runs all of the benchmarking that's happening during checking the CPU usage and memory and all that stuff.
So it's not just React native too, it can benchmark any app and really any maestro flow that you might be doing, which is just a cool workflow. And of course obviously it's patterned after Lighthouse, which is a huge deal in the web performance realm. So with that said, you can drop an A PK on there, but you can't drop like an iPhone app and you can't get that to go. Do you think that's an achievable thing to do given the constraints around the security model and everything that Apple has? Or is that something that's pretty tough to achieve?
Alexandre Moureaux:
Yeah, so the whole idea, so perfect summary of how Flashlight works actually on the web. Thank you for that. And the whole idea behind flashlight was that it was black box, kind of a black box tool. So you don't have to install anything in your app. You can basically connected via CLI or in the cloud, you don't have to install anything and it works out of the box, which is nice. Also, I'm always paranoid about installing SDKs in my app, which would affect the performance of my app because sometimes what you use to measure performance affects the performance of your app and that's unkind. Gotcha.
So that already is kind of tricky to do with iOS. So on Android, basically the way we do it is somewhat documented on the website, but it's not that hard because Android is based on Linux and we basically get a lot of stat files available that we can read from very easily on iOS without jailbreaking or doing something like that. It's a lot harder to do. One way to do this is to basically, so on iOS there is a tool called Instruments on Xcode, which you can use to measure performance of applications, and it also works in production, which is really neat because on Android, Android Studio doesn't do that in production. So if we want flashlight to measure the performance of any apps in production, one way to do this is to have flashlights disguise itself as excode instruments and basically communicate with the app the same way as instruments would.
Jamon Holmgren:
Oh, that's cool.
Alexandre Moureaux:
And
Robin Heinze:
What the first time literally just puts on a costume, nothing to see exactly,
Jamon Holmgren:
Just sex. Oh, that's funny. I
Alexandre Moureaux:
Love it. The first time I heard about that I was kind of naive. I was like, oh, maybe it's just like G or PC or something like calls that are easy to spy, but it's actually really tricky. You basically have to reverse engineer the whole code of Excode instruments and try to take a look at that. So we actually had one developer, Guillaume High, if you're listening to the show, look into that. And I think it got a bit crazy afterwards and we realized that, so some people have managed to kind of do something similar, but they haven't gone as far as we wanted to. Basically they can measure CPU usage, but only total CPU usage and not per threat CPU usage. And I think any mobile app developer but also React reactive developer care about thread by thread usage because some are just more important than others. You have
Speaker 6:
The
Alexandre Moureaux:
UI thread displaying frames, you have the JS thread that we all know and love running the main logic of your app obviously. So the path that we see now, but we haven't invested a lot of time to work on it at the moment, is maybe we should get rid of this black box requirement and still make it an SDK that would be easy to install in the app, to send measures, stuff like this. But at least we would still have a way to have real time measures and a way to have thread by thread measures, which with the other method would be hard to achieve.
Jamon Holmgren:
Yeah, that sounds amazing. Obviously the more tools we have, the better, but I think one of the things that stood out to me at least in your React native EU talk was kind of how you use a lot of different tools to achieve a mental model of what's working, what's not. And I think a lot of people can learn from you and how you approach performance. I really like how you did it in the talk and also just the general philosophy behind finding these performance issues. So no one tool is going to do everything, but obviously the more that any individual tool will do the better. So yeah, definitely want people to keep thinking about this stuff and as much as possible have our tools be as powerful as possible.
Alexandre Moureaux:
Thanks first, thank you for the compliment, and this is not good for my humility, I guess. Yeah, I want to point out that flashlight is always been is a tool only for measuring performance. The idea is really to use it as an indicator of what your performance is. Like does your app have good performance or not? Or whatever you are doing, are you improving or deteriorating performance? And I'm always saying, yeah, you should use one tool. I mean not necessarily one tool, but you should have a way to measure performance. I mean, the easiest way, some other ways would be just use a timer or something if something needs to be fast or something like that. And then in the break, Navy U Talk, for example, or even in the performance workshop I did at React Native London, I use other tools like Reactive tools, the Jazz Profiler and Android studio to analyze the performance issues that were shown with flashlight. So
Robin Heinze:
Basically it sounds like you're saying measuring performance is really important and flashlight helps you do that, but it's only half the equation because you also have to know how to fix what you're seeing and also to some extent prevent. So what I see is a lot of developers that don't necessarily have good habits about writing performant code in the first place or being able to figure out why the code that is not performant is not performant. So I can look at a flame graph and be like, okay, this component is really slow, but I know there's lots of devs who could look at it and be like, I don't really know why and don't necessarily have the habits of single responsibility and limiting re-render and memorization and all these different things. So how do you recommend, are there resources or how do you recommend that developers learn those in the first place? It feels like the React native docs aren't always great about helping people establish best practices for writing performance code. So what advice do you have for developers to learn those skills?
Alexandre Moureaux:
Yeah, that's a really good question. So yeah, I totally agree with you. I mean, I would say it's not even just half of the equation because basically a performance issue is like a bug. I mean, a performance issue is a bug essentially. We could call it that way. So measuring is just a way to detect the bug. Analyzing with React dev tools or something is just a way to debug and to maybe find a fix. Then you need a way to prevent the bug from happening anymore, you need to have a long-term fix or something really understand, oh, why did we add this in the first place? Why did we code that way in the first place? And we should have done it right the first time. And then, yeah, you need to fix, implement the long-term fix, and also hopefully prioritize with the client, which can be also a different topic. But what we do, I mean we tried to do it at least, I think we're getting better at that as we just bugs. Basically we try to find the root cause of the bug and try to have an action to fix the root cause of the bug. So for example, even for performance, a lot of performance issues that we found were fixed by our internal lender.
What example do I have? Oh, actually we have, I think the first rule, the performance rule of the lender was just to say maybe don't use flat list but use something else. People who know me and have watched me give tweets or whatever, know that I talked extensively about flat List and how difficult it was to optimize compared to List or even Jay's legend list, which is the new kid on the,
Robin Heinze:
We just had him on the show a couple weeks ago talking about legend List. But yeah, flat list is usually a big, big culprit. So what you said there's a linter, so is that something that's open source?
Alexandre Moureaux:
It might be open source. I'm actually checking right now, but we haven't really advertised it or anything.
Mazen Chami:
It would be valuable if that stuff is open
Alexandre Moureaux:
Source.
Mazen Chami:
I could see you've put the time and effort into finding what these specifics are so the community can really benefit from it. And also new developers, junior developers, we have junior seniors on any given team. Having those juniors learn from those lending rules early on is Pivotal. And even sometimes the seniors can use a refresher.
Robin Heinze:
It's not always, yeah, because it's not always intuitive. Just because you're a developer doesn't necessarily mean you've internalized reacts kind of quirky ways where you're like, turns out if you put this hook right here, it's actually going to cause three times the renders of your entire app, but it's not necessarily obvious that that's going to be the result. So having a way to teach people like, oh, hey, by the way, probably not the best idea to put this here.
Jamon Holmgren:
I found Linter, but it's for Flutter. What is this Alexander? You got to explain something. Right. So our
Alexandre Moureaux:
Company actually does React native. That's the, I think maybe 60 70% of our projects are in React native, but we do also Flutter and Native, mostly composed and Swift.
Robin Heinze:
So you're a double agent?
Alexandre Moureaux:
Yeah. This that happen? No. Yeah. What happened is basically in 2015, I think we were at least in France or Europe amount. I mean we started ran native in October, 2015. So we had kind of a nudge on the other companies
Jamon Holmgren:
Same month as us.
Alexandre Moureaux:
So yeah,
And at some point we're like, Hey, there's some new technologies on the block, maybe we should try those out. Just like we tried direct Native back in the days. And so we basically have a flutter team, a native team, and a React native team. React native team is still the biggest because, well, 2015, yes, sure. Yeah. But coming back to the subject of hooks, what I'm really excited about, and I think a lot of people ourselves included, already had a good results with this, is the React compiler. Because I always think that one of the big issues with React coding, so quite often I help projects from clients with performance. Quite often people coming to us are people who haven't checked their performance in three or four years. So it's pretty bad. But one of the reasons why it's pretty bad is because of poor architecture on their side.
Like you see hooks returning maybe 10, 15, 20 parameters, but React is really, really not forgiving if you do that in terms of performance. I always say my stupidest example for performance is you put a countdown at the root of your app updating its state every second, and it'll mean that your app will re-render every second. By default, this is what's going to happen. So on one hand, architecture is really the issue, but we're not perfect developers and sometimes we make mistakes. And I know a lot of people also had a lot of sometimes issues moving from class to hooks when they were used to oriented object programming. And I think the React compiler will make React more forgiving and more, yeah, we'll be able to basically code a bit more issues in our app, our apps, and I think they will be more performance that way.
Jamon Holmgren:
There's so much more I want to talk about with you on this subject because I feel like you are a fountain of knowledge here and there's a million other things that we could be learning here and in our audience as well, and React native developers. I don't think it's too critical to say that we're still, the community is still behind in terms of knowing what's possible with performance optimizations as well as, I think even more importantly, measuring performance and monitoring performance. Because as soon as you notice an issue, now you're going to go into problem solving mode and react. Native developers are very good at that, but there's a lot of pressures, like you've got people breathing down your neck to ship features, and so it's always easy to let that slide. But I loved how you said performance issues are bugs because that's exactly what we're talking about here. So definitely want people to go check out your app JS talk where you talk about that's at the conference. You can find it on YouTube. We'll put it in the show notes about flashlight, the React native to EU talk, which wasn't technically about flashlight. It was like a precursor to flashlight, but it had all the same kind of ideas built into it, and you showed the Android studio profiling tool and some other cool things.
Robin Heinze:
Yeah, it was really, really helpful.
Jamon Holmgren:
Yes. Good stuff. Very, very good stuff. So I definitely want people to go check those talks out. You're going to learn a lot more about how to do this stuff, connect with Alexander, wherever you're on bluesky, right?
Alexandre Moureaux:
Yes, yes. On bluesky at Al Mojo A-L-M-O-U-R-O.
Robin Heinze:
We'll put that in the show notes.
Alexandre Moureaux:
BS
Jamon Holmgren:
KY, social. Yeah, just we'll put the link there. So definitely connect there. And I'm actually interested in chatting more offline, Alexander at some point and kind of just getting more info from you on how you approach this stuff. I love this stuff. Performance is one of the things that I really love to focus on, so Awesome. Thanks so much for coming on. Really wish we had more time to talk about things. But to wrap up, Robin, do you have a mom joke for us?
Robin Heinze:
I do. Thanks to Nick Morgan for this one. What did the vine say to the other vine?
Jamon Holmgren:
I don't know.
Robin Heinze:
I used to not like grapes, but now they're kind of growing on me.
Mazen Chami:
Oh, fun.
Robin Heinze:
There you
Mazen Chami:
Go. The wine joke for french fries. I was not ready for that.
Jamon Holmgren:
I was not prepared for that. Alright, well we will see you all next time. Bye.
Jed Bartausky:
As always, thanks to our editor Todd Werth, our assistant editor, Jed Bartausky, our marketing and episode release coordinator, Justin Huskey and our guest coordinator, Mazen Chami. Our producers and hosts are Jamon Holmgren, Robin Heinze and Mazen Chami. Thanks to our sponsor, Infinite Red. Check us out at https://infinite.red/radio. A special thanks to all of you listening today. Make sure to subscribe to React Native Radio on all the major podcasting platforms.
There’s no perfect time to get started. Whether you have a formal proposal or a few napkin sketches, we’re always happy to chat about your project at any stage of the process.
Schedule a call