Make it easy for others to answer your question.
Let's talk about my favorite part of the Community: questions. I love reading the myriad questions posted here, chiming in when I think I know the answer, and seeing the care and attention so many people are putting into helping others.
Sometimes though... sometimes I see a question and my initial response is:
Huh?
Some questions are framed poorly; others lack the context required to solve the problem. And some questions are asked in such a way that all the words individually make sense, but when put in that specific order end up being meaningless. And that sucks, because every question is a request for help, and helping each other is one of the core foundations of any community. If you structure your questions in the best possible way, you'll get the best possible answer.
But why listen to me?
I know a thing or two about a thing or two.
Before I was a developer at ServiceNow, I was on the Support team. Before that, I held several technical support and web development roles at other companies. Altogether I've been fixing problems and helping others fix problems for about 15 years. I know what I need to see in a problem description to quickly understand the context of the question and the likely places to look for a solution- which sometimes means addressing it in a different way than the question was framed. This month is my 4-year anniversary at ServiceNow, and in that time I've answered hundreds of Incidents, pushed thousands of lines of code, and generally tried my best to make sure that every question that comes across my desk has been answered fully.
What makes a question easier to answer?
When I can look at new questions on the Community, I look for questions that have purpose, context, and clarity. If your question displays those three qualities, I know that you've already done the basic research and it's unlikely the answer can be found with a simple Wiki search. It's interesting and therefore likely to draw attention. It also has everything I need to get started on a solution.
What is Purpose?
Purpose is the problem you are trying to solve. It's the use-case or business case for the question. Purpose tells people what the end result is going to be, not necessarily the specific difficulty you are having. You should be able to define why you are doing the project- why are you updating this Business Rule, why you're writing this Script Include, or why it's important that this field on your form have a Red highlight for Itil users but a Green highlight for their managers. In some cases knowing the purpose can help us determine if the solution you are struggling with is the best way to accomplish your goal. perhaps you've spent the better part of a day wrestling with the login in an after Business Rule when the best way to solve your issue is with an event. For some examples, look at just about any question posed by rfedoruk :
Every question includes purpose. There is a problem to be solved, an attempted approach and finally a specific issue with this approach that is yet to be overcome.
What is context?
When you describe the issue you are having, it's almost always necessary to know where this is occurring. Let's say you're having an issue with a specific script. You must, at the very least, post the problem you have and the content of the script in question:
The answer from my Script Include is always null when my script runs.
var ga = new GlideAjax("x_emp.DataGenericUtil");
ga.addParam("sysparm_name","doStuff");
ga.addParam("sysparm_input", g_form.getValue("u_foo"));
ga.getXML(myCallback);
With this example, we may be able to determine that the "foo" field on the table is probably not supposed to be prefixed with "u_", since this is likely running on a custom table in the app scope "x_emp". Likewise, we could probably say that the "x_emp" prefix on the script include name is not needed here. However, those would be guesses- and pretty poor ones if this is actually a Client Script running on the global table "Foobars" which really does have a field named "u_foo" on it, and it's calling a scoped Script Include called "DataGenericUtil" in the scope "x_emp", even though the script itself is in the global scope.
To get help with this script, we'd need to also include the content of the DataGenericUtil Script Include's doStuff function:
doStuff : function() {
var input = this.getParameter("sysparm_input");
gs.info("Parameter sent was {0}", input);
return "plonk";
}
We also need to know if the script was marked Client Callable, if it's accessible from All application scopes or This application scope only, and if it's currently marked Active.
We need to know about the table this runs on:
- Does it have a u_foo field?
- What kind of data does it have?
- Is it a String field or a Date field?
- Does it have instance-specific formatting?
- Is it a String field or a Date field?
- What scope is the table in?
- Does the field have data at the time the script runs?
Speaking of our script, we need more information about that as well:
- What kind of script is it?
- Client Script?
- UI Script?
- Does it run onLoad, onChange, or onSubmit?
- If it's onChange, what field does it react to?
- Client Script?
- What scope is the script in?
- What is the content of the myCallback function?
That's not to say that we want to see everything. Include enough code so that someone can reproduce the problem- or set up a minimal test-case of your own on one of our demo instances, and point people to it. We want to be able to examine the relevant code and run the program- in our heads if it's small enough, or on a live system exhibiting the problem if it's really complicated.
Finally we want to know if any errors are thrown. This script runs client-side, but it also invokes a server-side script to do some processing. Errors on either side can cause unexpected results. We want to know if you are seeing errors in your browsers console, if there are any errors in your System Logs, and if there is anything that stands out around the transaction in your node log. Errors thrown by your code are designed to be descriptive. A good error message tells you what went wrong, where it went wrong, and (usually by context) how to fix it.
That seems like a lot of work for one measly script question, but that's only because you don't need to be brought up to speed on the whole problem- you're already in the middle of it. For the rest of us, the more relevant information you provide, the less time we spend trying to catch up from the back, the quicker we can join you in the middle, and the quicker we can push forward to the solution.
What is clarity?
Some problems in technology are truly hard. One of them is being able to describe a problem with a system that you are intimately familiar with, to a person who isn't familiar with it. There are at least 2 potential language barriers: are you both able to express yourselves in the same language, and do you both understand the same jargon? And there are differing levels of ability- some people have been troubleshooting issues for years, and other people just started learning the platform.
When you describe your problem, you want to make sure that the person reading it comes away with a good idea of exactly where this issue occurs. Write in complete sentences. Separate multiple questions into a list, or into multiple paragraphs. Add screenshots to the text near where you reference them. Don't abbreviate unnecessarily. If you don't know the jargon for something, that's OK; if you can describe it well enough, name it, and then refer to it that way consistently then can still communicate about it.
Writing in complete sentences, capitalization and punctuation are important. Humanity has been communicating ideas via the written word for millennia. These conventions exist because they are useful. They improve the presentation of your ideas, and they make consumption of them faster. You don't have to be an English major with a Ph.D. in the classics to get your point across- but if you are, think Around the World in 80 Days not Finnegans Wake.
Your question title is the first thing people when see when they look at the posts on the Community. Do you think it accurately describes the question you have? Does it sound like an interesting problem to solve? Here are some examples of good and bad problem titles:
Bad: script value null
Good: Answer from Script Include is null, only when called from scoped Client Script
Bad: Javascript error
Good: What is causing "ScopedGlideAjaxGenerator is undefined" error when loading Incident on tablet interface?
Bad: Business Rule doesn't work
Good: gs.eventQueue does not insert events when called from Before business rule on Task table
Bringing it all together
So with the script problem I invented earlier, a post like the one below is the most likely to get accurate help quickly. As a bonus, just by writing the problem out and thinking through it logically, you might even come to a resolution before you even submit!
Answer attribute is null in GlideAjax response to scoped Script Include
I am creating a scoped custom application on my instance, which adds a Client Script to a table outside of my scope. This table is part of a legacy system I have inherited, and I haven't been able to recreate it and merge it into my scoped application yet. The client script in question is an onChange script, that fires on changes to the u_bar field, and sends the value of u_foo to the server. I expect to get the result "plonk" back in my answer attribute on the GlideAjax response, but it is just a null value. The u_foo field contains the number of people who have agreed to attend an event (it's an integer field) and u_bar is the location of the pub we are going to (a reference field to cmn_location). Every time we change pubs, the number of people in u_foo changes, and we want to track that in real time so we know the pub most likely to boost attendance.
This is my onChange script:
onChange(newValue,oldValue,isLoading) {
if (isLoading)
return;
console.log("New bar value: " + newValue);
console.log("Foo value: " + g_form.getValue("u_foo"));
var ga = new GlideAjax("DataGenericUtil");
ga.addParam("sysparm_name","doStuff");
ga.addParam("sysparm_input", g_form.getValue("u_foo"));
ga.getXML(myCallback);
function myCallback(response) {
var answer = response.responseXML.documentElement.getAttribute("answer");
console.log("Response from server is: " + answer);
}
}
My Script Include is pretty basic. I took an existing include which was doing the work server-side and made it client-callable:
var DataGenericUtil = Class.create();
DataGenericUtil.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
initialize : function() {
//nothing to do here
},
doStuff : function() {
var input = this.getParameter("sysparm_input");
gs.info("Parameter sent was {0}", input);
return "plonk";
},
type: 'DataGenericUtil'
});
When I converted it, I made sure to mark it Client callable. It was already Active, obviously, but I did have to extend AbstractAjaxProcessor. I already tried extending global.AbstractAjaxProcessor (as you can see) but that hasn't fixed it.
I have verified that the fields on this table exist- the console.log calls output a valid sys_id and an integer between 1 and 25 each time it runs. I don't get any errors in my JavaScript console, and the instance logs are similarly barren.
- Is there additional logging I could do to help track this down?
- Does the table this script runs on need to be in the same scope as the client script?
- Would it help to capture the request headers or the response directly, and post them here?
I hope this post is useful. I really do love coming to the Community and trying to solve problems. If you have a question to ask, spend a little extra time doing the write-up, and I promise that you'll get it all back plus more when the answers start rolling in.
https://www.servicenow.com/community/developer-blog/make-it-easy-for-others-to-answer-your-question/ba-p/2270360